From 4445fa31f51d078a0f1bff9011173dcf5c0242dc Mon Sep 17 00:00:00 2001 From: Alexandre Nobuharu Sato <66435071+AlexandreSato@users.noreply.github.com> Date: Sun, 7 Jul 2024 14:35:02 -0300 Subject: [PATCH 001/229] fix "telsa" typo on labeler.yaml (#32924) --- .github/labeler.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/labeler.yaml b/.github/labeler.yaml index 47d0d480a9..0c5d1a687a 100644 --- a/.github/labeler.yaml +++ b/.github/labeler.yaml @@ -44,7 +44,7 @@ subaru: tesla: - changed-files: - - any-glob-to-all-files: 'selfdrive/car/telsa/*' + - any-glob-to-all-files: 'selfdrive/car/tesla/*' toyota: - changed-files: From 241fb902af49ca43bf343c60f7f96b85128a9db9 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 7 Jul 2024 19:13:48 -0700 Subject: [PATCH 002/229] publish new docs (#32922) * push new docs * drop the new, just docs * cleanup --- .github/workflows/docs.yaml | 41 +- docs/.gitignore | 1 + docs/README.md | 23 +- docs/{new => }/docs/car-porting/brand-port.md | 0 docs/{new => }/docs/car-porting/model-port.md | 0 .../docs/car-porting/what-is-a-car-port.md | 0 .../docs/getting-started/what-is-openpilot.md | 0 .../docs/how-to/turning-the-speed-blue.md | 0 docs/{new => }/mkdocs.yml | 0 docs/new/README.md | 12 - pyproject.toml | 2 + uv.lock | 361 +++++++++++++----- 12 files changed, 308 insertions(+), 132 deletions(-) create mode 100644 docs/.gitignore rename docs/{new => }/docs/car-porting/brand-port.md (100%) rename docs/{new => }/docs/car-porting/model-port.md (100%) rename docs/{new => }/docs/car-porting/what-is-a-car-port.md (100%) rename docs/{new => }/docs/getting-started/what-is-openpilot.md (100%) rename docs/{new => }/docs/how-to/turning-the-speed-blue.md (100%) rename docs/{new => }/mkdocs.yml (100%) delete mode 100644 docs/new/README.md diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 908f06e034..012ee9dfde 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -15,56 +15,51 @@ concurrency: group: docs-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }} cancel-in-progress: true -env: - BASE_IMAGE: openpilot-base - - BUILD: selfdrive/test/docker_build.sh base - - RUN: docker run --shm-size 1G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c - jobs: docs: name: build docs runs-on: ubuntu-latest - timeout-minutes: 45 - if: false # TODO: replace this with the new docs + timeout-minutes: 1 steps: - uses: actions/checkout@v4 with: submodules: true - - uses: ./.github/workflows/setup-with-retry - - name: Build openpilot - run: | - ${{ env.RUN }} "scons -j$(nproc)" + + # Build - name: Build docs run: | - ${{ env.RUN }} "apt update && apt install -y doxygen && cd docs && make -j$(nproc) html" + # TODO: can we install just the "docs" dependency group without the normal deps? + pip install mkdocs mkdocs-terminal + cd docs + mkdocs build + # Push to docs.comma.ai - uses: actions/checkout@v4 - if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' + #if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' with: path: openpilot-docs ssh-key: ${{ secrets.OPENPILOT_DOCS_KEY }} repository: commaai/openpilot-docs - name: Push - if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' + #if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' run: | set -x source release/identity.sh cd openpilot-docs - git checkout --orphan tmp git rm -rf . - cp -r ../build/docs/html/ docs/ - cp -r ../docs/README.md . - touch docs/.nojekyll - echo -n docs.comma.ai > docs/CNAME - git add -f . + # copy over docs + cp -r ../docs/site/ site/ + # GitHub pages config + touch site/.nojekyll + echo -n docs.comma.ai > site/CNAME + + git add -f . git commit -m "build docs" # docs live in different repo to not bloat openpilot's full clone size - git push -f origin tmp:gh-pages + git push -f origin tmp:gh-pages2 diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000000..46ff2463e0 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +/site/ diff --git a/docs/README.md b/docs/README.md index 838b00e7ae..a16c772530 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,3 +1,22 @@ -# openpilot-docs +# openpilot docs -These docs are autogenerated from [this folder](https://github.com/commaai/openpilot/tree/master/docs) in the main openpilot repository. \ No newline at end of file +This is the source for [docs.comma.ai](https://docs.comma.ai). +The site is updated on pushes to master by this [workflow](../.github/workflows/docs.yaml). + +## development +``` +# install the docs dependencies +pip install .[docs] + +cd docs/ + +# for a development server +mkdocs serve + +# build the site +mkdocs build +``` + +References: +* https://www.mkdocs.org/getting-started/ +* https://github.com/ntno/mkdocs-terminal diff --git a/docs/new/docs/car-porting/brand-port.md b/docs/docs/car-porting/brand-port.md similarity index 100% rename from docs/new/docs/car-porting/brand-port.md rename to docs/docs/car-porting/brand-port.md diff --git a/docs/new/docs/car-porting/model-port.md b/docs/docs/car-porting/model-port.md similarity index 100% rename from docs/new/docs/car-porting/model-port.md rename to docs/docs/car-porting/model-port.md diff --git a/docs/new/docs/car-porting/what-is-a-car-port.md b/docs/docs/car-porting/what-is-a-car-port.md similarity index 100% rename from docs/new/docs/car-porting/what-is-a-car-port.md rename to docs/docs/car-porting/what-is-a-car-port.md diff --git a/docs/new/docs/getting-started/what-is-openpilot.md b/docs/docs/getting-started/what-is-openpilot.md similarity index 100% rename from docs/new/docs/getting-started/what-is-openpilot.md rename to docs/docs/getting-started/what-is-openpilot.md diff --git a/docs/new/docs/how-to/turning-the-speed-blue.md b/docs/docs/how-to/turning-the-speed-blue.md similarity index 100% rename from docs/new/docs/how-to/turning-the-speed-blue.md rename to docs/docs/how-to/turning-the-speed-blue.md diff --git a/docs/new/mkdocs.yml b/docs/mkdocs.yml similarity index 100% rename from docs/new/mkdocs.yml rename to docs/mkdocs.yml diff --git a/docs/new/README.md b/docs/new/README.md deleted file mode 100644 index 13980d1e18..0000000000 --- a/docs/new/README.md +++ /dev/null @@ -1,12 +0,0 @@ -This is the source for a new https://docs.comma.ai. It's not hosted anywhere yet, but it's easy to run locally. - -https://www.mkdocs.org/getting-started/ - -``` -pip install mkdocs mkdocs-terminal -mkdocs serve -``` - -inspiration: -* https://rerun.io/docs/ -* https://docs.expo.dev/ diff --git a/pyproject.toml b/pyproject.toml index 4b20c84e9f..1023de9186 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,6 +66,8 @@ dependencies = [ [project.optional-dependencies] docs = [ "Jinja2", + "mkdocs", + "mkdocs-terminal", ] testing = [ diff --git a/uv.lock b/uv.lock index 6a9f155df7..8e7a039476 100644 --- a/uv.lock +++ b/uv.lock @@ -535,6 +535,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, ] +[[distribution]] +name = "click" +version = "8.1.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } +dependencies = [ + { name = "colorama", marker = "platform_system == 'Windows'" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 }, +] + [[distribution]] name = "cloudpickle" version = "3.0.0" @@ -843,11 +855,11 @@ wheels = [ [[distribution]] name = "docutils" -version = "0.20.1" +version = "0.21.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1f/53/a5da4f2c5739cf66290fac1431ee52aff6851c7c8ffd8264f13affd7bcdd/docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b", size = 2058365 } +sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444 } wheels = [ - { url = "https://files.pythonhosted.org/packages/26/87/f238c0670b94533ac0353a4e2a1a771a0cc73277b88bff23d3ae35a256c1/docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6", size = 572666 }, + { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408 }, ] [[distribution]] @@ -909,51 +921,51 @@ wheels = [ [[distribution]] name = "fonttools" -version = "4.53.0" +version = "4.53.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a4/6e/681d39b71d5f0d6a1b1dc87d7333331f9961b5ab6a2ad6372d6cf3f8b04c/fonttools-4.53.0.tar.gz", hash = "sha256:c93ed66d32de1559b6fc348838c7572d5c0ac1e4a258e76763a5caddd8944002", size = 3449532 } +sdist = { url = "https://files.pythonhosted.org/packages/c6/cb/cd80a0da995adde8ade6044a8744aee0da5efea01301cadf770f7fbe7dcc/fonttools-4.53.1.tar.gz", hash = "sha256:e128778a8e9bc11159ce5447f76766cefbd876f44bd79aff030287254e4752c4", size = 3452797 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/a7/19bf3c42ef78ebb74bbc0ccc2b69ffcb66e4b4192a60407c8f078ff9bb6d/fonttools-4.53.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:52a6e0a7a0bf611c19bc8ec8f7592bdae79c8296c70eb05917fd831354699b20", size = 2761282 }, - { url = "https://files.pythonhosted.org/packages/4a/5d/cf58fe32c9ddc6e3189afd09a43de7e6380043e0edabcbfa9708457a36cf/fonttools-4.53.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:099634631b9dd271d4a835d2b2a9e042ccc94ecdf7e2dd9f7f34f7daf333358d", size = 2247478 }, - { url = "https://files.pythonhosted.org/packages/2c/a8/235953d020fd7775939ea569ef4efb53c3bc580ecab44fb62600eb61cefd/fonttools-4.53.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e40013572bfb843d6794a3ce076c29ef4efd15937ab833f520117f8eccc84fd6", size = 4568058 }, - { url = "https://files.pythonhosted.org/packages/7a/d0/010c65f46fb14333cdb537566d1532e64361eb981180ab73f1148e927382/fonttools-4.53.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:715b41c3e231f7334cbe79dfc698213dcb7211520ec7a3bc2ba20c8515e8a3b5", size = 4624080 }, - { url = "https://files.pythonhosted.org/packages/c8/d3/36007faf75dbadc7f0cc098745d59223cf335412b4c366c71ba3ab082766/fonttools-4.53.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74ae2441731a05b44d5988d3ac2cf784d3ee0a535dbed257cbfff4be8bb49eb9", size = 4564032 }, - { url = "https://files.pythonhosted.org/packages/6e/6b/561be0d040910b55afd5a86633908a5e5063ac9277091b43d267f707d46c/fonttools-4.53.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:95db0c6581a54b47c30860d013977b8a14febc206c8b5ff562f9fe32738a8aca", size = 4735565 }, - { url = "https://files.pythonhosted.org/packages/6c/27/147c94450d79104d42857577f79fd6d51369f58624fbc41c2a993346eef2/fonttools-4.53.0-cp310-cp310-win32.whl", hash = "sha256:9cd7a6beec6495d1dffb1033d50a3f82dfece23e9eb3c20cd3c2444d27514068", size = 2158255 }, - { url = "https://files.pythonhosted.org/packages/2d/83/76b09dce3d7f3982de64cf89a8cd58dfea0611d25eae9f2059b723092146/fonttools-4.53.0-cp310-cp310-win_amd64.whl", hash = "sha256:daaef7390e632283051e3cf3e16aff2b68b247e99aea916f64e578c0449c9c68", size = 2204469 }, - { url = "https://files.pythonhosted.org/packages/d3/0c/7236cacbe07a2ecb256525f8b3c3b70877e87770eeb1bc218839590b1888/fonttools-4.53.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a209d2e624ba492df4f3bfad5996d1f76f03069c6133c60cd04f9a9e715595ec", size = 2762370 }, - { url = "https://files.pythonhosted.org/packages/69/2d/8aa6f3ad5fa586d92b95aaa56376f6b20e0136128a99e6e80c811c5f5b4c/fonttools-4.53.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f520d9ac5b938e6494f58a25c77564beca7d0199ecf726e1bd3d56872c59749", size = 2247574 }, - { url = "https://files.pythonhosted.org/packages/86/a9/3d8e7b63b45b48ec47a180e4e312e3db7d1d9a1ef520c51706ff1562edbf/fonttools-4.53.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eceef49f457253000e6a2d0f7bd08ff4e9fe96ec4ffce2dbcb32e34d9c1b8161", size = 4872790 }, - { url = "https://files.pythonhosted.org/packages/0a/79/b5be063ea65d048a041ad8438fa1e8c7c4bf9dc3f4ac2794a850fe70c5c5/fonttools-4.53.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1f3e34373aa16045484b4d9d352d4c6b5f9f77ac77a178252ccbc851e8b2ee", size = 4920607 }, - { url = "https://files.pythonhosted.org/packages/68/ca/9c5602235e3ad781f70f9ef5c192595f24c4b40ac9f464d8bea28481241d/fonttools-4.53.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:28d072169fe8275fb1a0d35e3233f6df36a7e8474e56cb790a7258ad822b6fd6", size = 4885661 }, - { url = "https://files.pythonhosted.org/packages/e4/8b/6b0d085983c84a469e5c098ba45d2b3f60d14be22167e5fea01d8959c93f/fonttools-4.53.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4a2a6ba400d386e904fd05db81f73bee0008af37799a7586deaa4aef8cd5971e", size = 5054455 }, - { url = "https://files.pythonhosted.org/packages/71/d3/6f5b962a37cf7fb7030ba74d4ee39e0dc5f701ef14e63db14bdf07967b48/fonttools-4.53.0-cp311-cp311-win32.whl", hash = "sha256:bb7273789f69b565d88e97e9e1da602b4ee7ba733caf35a6c2affd4334d4f005", size = 2156666 }, - { url = "https://files.pythonhosted.org/packages/00/48/8e9ca9e17de09f5a18d9afb3a3f456689491b985bd144ccc1d9b0c3c06bf/fonttools-4.53.0-cp311-cp311-win_amd64.whl", hash = "sha256:9fe9096a60113e1d755e9e6bda15ef7e03391ee0554d22829aa506cdf946f796", size = 2205448 }, - { url = "https://files.pythonhosted.org/packages/c4/a8/2e1eb778736c778ae7cb4afbf7004a0a6837212c20e35ac36b760238aa91/fonttools-4.53.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d8f191a17369bd53a5557a5ee4bab91d5330ca3aefcdf17fab9a497b0e7cff7a", size = 2755864 }, - { url = "https://files.pythonhosted.org/packages/47/a4/8e17c52d95264c8532506c66a05cd1aef1b9b5db2a4b9d2c52911864b569/fonttools-4.53.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:93156dd7f90ae0a1b0e8871032a07ef3178f553f0c70c386025a808f3a63b1f4", size = 2244705 }, - { url = "https://files.pythonhosted.org/packages/79/e8/5f4b41a54a737ca1d025eaea35c7ed6969d3144bd231b678356a9f410161/fonttools-4.53.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bff98816cb144fb7b85e4b5ba3888a33b56ecef075b0e95b95bcd0a5fbf20f06", size = 4787308 }, - { url = "https://files.pythonhosted.org/packages/3a/4a/9ad09a38b4ebdaead66ad8abd5d1a74fe6db7b62cb3d2f148898cfd2f37b/fonttools-4.53.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:973d030180eca8255b1bce6ffc09ef38a05dcec0e8320cc9b7bcaa65346f341d", size = 4870889 }, - { url = "https://files.pythonhosted.org/packages/37/08/b70c4ded36db9ff34de9a659a054a9d98227dccc61c60090cc43a411ecc1/fonttools-4.53.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c4ee5a24e281fbd8261c6ab29faa7fd9a87a12e8c0eed485b705236c65999109", size = 4764431 }, - { url = "https://files.pythonhosted.org/packages/25/67/9ac0793c2eda0e7e4b678dbd2b693a4ee1c71521eb6eeca754045f418a37/fonttools-4.53.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bd5bc124fae781a4422f61b98d1d7faa47985f663a64770b78f13d2c072410c2", size = 5023389 }, - { url = "https://files.pythonhosted.org/packages/ef/c4/fa8b3836db65f593cb3d41e1462de2c8c4fd14b55948c72522f500b23217/fonttools-4.53.0-cp312-cp312-win32.whl", hash = "sha256:a239afa1126b6a619130909c8404070e2b473dd2b7fc4aacacd2e763f8597fea", size = 2145086 }, - { url = "https://files.pythonhosted.org/packages/79/3e/3d87230c46a103ae225d47ae59ac6cdbd4fa341dddaffdfaf4e89986dd88/fonttools-4.53.0-cp312-cp312-win_amd64.whl", hash = "sha256:45b4afb069039f0366a43a5d454bc54eea942bfb66b3fc3e9a2c07ef4d617380", size = 2192680 }, - { url = "https://files.pythonhosted.org/packages/02/c8/9c105fbc4119c7a049bb442e82c5a76a6511c3eda3b031285edfce4580fe/fonttools-4.53.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:93bc9e5aaa06ff928d751dc6be889ff3e7d2aa393ab873bc7f6396a99f6fbb12", size = 2759514 }, - { url = "https://files.pythonhosted.org/packages/98/0d/43ae781f5840ff49d6ff684a35e878c88cd0e7808a9e66a99e67826ef5e8/fonttools-4.53.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2367d47816cc9783a28645bc1dac07f8ffc93e0f015e8c9fc674a5b76a6da6e4", size = 2247034 }, - { url = "https://files.pythonhosted.org/packages/97/3c/2c9701084d5664c77dc85fdc89a9be49b1457107ab499b9ace08a744f2ae/fonttools-4.53.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:907fa0b662dd8fc1d7c661b90782ce81afb510fc4b7aa6ae7304d6c094b27bce", size = 4651033 }, - { url = "https://files.pythonhosted.org/packages/f3/0e/4d144e4cb8193b0cd8743ee2ac24e87ed952cebaede0da349b2a9d2fe222/fonttools-4.53.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e0ad3c6ea4bd6a289d958a1eb922767233f00982cf0fe42b177657c86c80a8f", size = 4716318 }, - { url = "https://files.pythonhosted.org/packages/c7/12/541076aefce46bcf631a73612493dbaaf80669d290d96bf53b4175bda479/fonttools-4.53.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:73121a9b7ff93ada888aaee3985a88495489cc027894458cb1a736660bdfb206", size = 4668898 }, - { url = "https://files.pythonhosted.org/packages/2f/83/dfb450bd260f3f11b5cd42f8d6226ad2908711b5f354b3a19050999165b9/fonttools-4.53.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ee595d7ba9bba130b2bec555a40aafa60c26ce68ed0cf509983e0f12d88674fd", size = 4844377 }, - { url = "https://files.pythonhosted.org/packages/0a/8a/f16f5504cc45ffaef1c0de121c14f727490480e81f97226007a91468b679/fonttools-4.53.0-cp38-cp38-win32.whl", hash = "sha256:fca66d9ff2ac89b03f5aa17e0b21a97c21f3491c46b583bb131eb32c7bab33af", size = 1480982 }, - { url = "https://files.pythonhosted.org/packages/2c/ba/cbd4c8850a41dc00501b0b0c494871659c72337d69892a9ddea4e564203c/fonttools-4.53.0-cp38-cp38-win_amd64.whl", hash = "sha256:31f0e3147375002aae30696dd1dc596636abbd22fca09d2e730ecde0baad1d6b", size = 1527801 }, - { url = "https://files.pythonhosted.org/packages/06/76/6554045fd11ab229d7aa407965cfc412d8706b72b473311bf351994db52c/fonttools-4.53.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7d6166192dcd925c78a91d599b48960e0a46fe565391c79fe6de481ac44d20ac", size = 2764291 }, - { url = "https://files.pythonhosted.org/packages/96/59/4924ea8c1177806d12bf28e18ba66019eb1e03470694db4939be285c1628/fonttools-4.53.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef50ec31649fbc3acf6afd261ed89d09eb909b97cc289d80476166df8438524d", size = 2248966 }, - { url = "https://files.pythonhosted.org/packages/28/c4/e679e91552f0e1e413d26420a78ed1d341ce8b58670851fdeeeeeaab6d36/fonttools-4.53.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f193f060391a455920d61684a70017ef5284ccbe6023bb056e15e5ac3de11d1", size = 4573717 }, - { url = "https://files.pythonhosted.org/packages/c1/cb/b1877d606dfa1daca70324bf37afec2b0a386138c467580027b9b51188a8/fonttools-4.53.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba9f09ff17f947392a855e3455a846f9855f6cf6bec33e9a427d3c1d254c712f", size = 4632305 }, - { url = "https://files.pythonhosted.org/packages/ee/6f/d1b8a1d4ec57b7b897ef11d2cccd850d2d50d02e702889b5170ce9968b5b/fonttools-4.53.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0c555e039d268445172b909b1b6bdcba42ada1cf4a60e367d68702e3f87e5f64", size = 4567595 }, - { url = "https://files.pythonhosted.org/packages/dd/72/52706c76494df490d620d481f5642c3bd3502586e17c4c6ded468ebea75b/fonttools-4.53.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a4788036201c908079e89ae3f5399b33bf45b9ea4514913f4dbbe4fac08efe0", size = 4739054 }, - { url = "https://files.pythonhosted.org/packages/5c/e8/62378ed76c378037bf987723526ee4b9224919cd608784ceb1279fe15b5d/fonttools-4.53.0-cp39-cp39-win32.whl", hash = "sha256:d1a24f51a3305362b94681120c508758a88f207fa0a681c16b5a4172e9e6c7a9", size = 2159162 }, - { url = "https://files.pythonhosted.org/packages/f1/21/2dc97c5aff32fc3e2472b4ed7125141f1467b71d24f3d356b97864ec7681/fonttools-4.53.0-cp39-cp39-win_amd64.whl", hash = "sha256:1e677bfb2b4bd0e5e99e0f7283e65e47a9814b0486cb64a41adf9ef110e078f2", size = 2204471 }, - { url = "https://files.pythonhosted.org/packages/f0/74/9244fda2577bccdaffd8a383be76c4c4d74730ecb56bc92ee4d655ea3ff1/fonttools-4.53.0-py3-none-any.whl", hash = "sha256:6b4f04b1fbc01a3569d63359f2227c89ab294550de277fd09d8fca6185669fa4", size = 1090184 }, + { url = "https://files.pythonhosted.org/packages/d4/3b/4db0513b71eb21bf73cd9fcff47ac5cebcf0146be5f3a42263eaafabdc33/fonttools-4.53.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0679a30b59d74b6242909945429dbddb08496935b82f91ea9bf6ad240ec23397", size = 2761563 }, + { url = "https://files.pythonhosted.org/packages/49/79/3976d0913db440644d14bc85ba697da7dc0847663acd6c96b0dff797f592/fonttools-4.53.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8bf06b94694251861ba7fdeea15c8ec0967f84c3d4143ae9daf42bbc7717fe3", size = 2247768 }, + { url = "https://files.pythonhosted.org/packages/b5/c8/815092e63534257469afb7dcc90a588b0bba60df5de2a06795af4d64ea8e/fonttools-4.53.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b96cd370a61f4d083c9c0053bf634279b094308d52fdc2dd9a22d8372fdd590d", size = 4568312 }, + { url = "https://files.pythonhosted.org/packages/56/61/ad19cad430aacbc3418be503e1f6daed9375c997a4e32b78a91195b3054a/fonttools-4.53.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1c7c5aa18dd3b17995898b4a9b5929d69ef6ae2af5b96d585ff4005033d82f0", size = 4624347 }, + { url = "https://files.pythonhosted.org/packages/af/a0/e8b6a6e9dc3861afb76bc449876907de4c126f817f15b21a9e44c129fdfc/fonttools-4.53.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e013aae589c1c12505da64a7d8d023e584987e51e62006e1bb30d72f26522c41", size = 4564284 }, + { url = "https://files.pythonhosted.org/packages/84/63/4ade973eb583024a50f223d0d66f6f469bfe6095cc76c4bab86385faca4d/fonttools-4.53.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9efd176f874cb6402e607e4cc9b4a9cd584d82fc34a4b0c811970b32ba62501f", size = 4735828 }, + { url = "https://files.pythonhosted.org/packages/f5/a8/e01479b8e2b7c838b67c38b98f4efd6b7edb8baa433a108164186dd1c171/fonttools-4.53.1-cp310-cp310-win32.whl", hash = "sha256:c8696544c964500aa9439efb6761947393b70b17ef4e82d73277413f291260a4", size = 2159775 }, + { url = "https://files.pythonhosted.org/packages/70/11/7b81b12a5614b5d237ab70c38bdc268de3eb3880ce7bb1269122e0a415ea/fonttools-4.53.1-cp310-cp310-win_amd64.whl", hash = "sha256:8959a59de5af6d2bec27489e98ef25a397cfa1774b375d5787509c06659b3671", size = 2203850 }, + { url = "https://files.pythonhosted.org/packages/8b/6a/206391c869ab22d1374e2575cad7cab36b93b9e3d37f48f4696eed2c6e9e/fonttools-4.53.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:da33440b1413bad53a8674393c5d29ce64d8c1a15ef8a77c642ffd900d07bfe1", size = 2762654 }, + { url = "https://files.pythonhosted.org/packages/f5/7e/4060d88dbfaf446e1c9f0fe9cf13dba36ba47c4da85ce5c1df084ce47e7d/fonttools-4.53.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ff7e5e9bad94e3a70c5cd2fa27f20b9bb9385e10cddab567b85ce5d306ea923", size = 2247865 }, + { url = "https://files.pythonhosted.org/packages/e1/67/fff766817e17d67208f8a1e72de15066149485acb5e4ff0816b11fd5fca3/fonttools-4.53.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6e7170d675d12eac12ad1a981d90f118c06cf680b42a2d74c6c931e54b50719", size = 4873046 }, + { url = "https://files.pythonhosted.org/packages/a4/22/0a0ad59d9367997fd74a00ad2e88d10559122e09f105e94d34c155aecc0a/fonttools-4.53.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bee32ea8765e859670c4447b0817514ca79054463b6b79784b08a8df3a4d78e3", size = 4920859 }, + { url = "https://files.pythonhosted.org/packages/0b/c4/b4e2f1699a5e2244373a6e8175f862f49f377b444adc6c7b1fe1f5b3d04d/fonttools-4.53.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e08f572625a1ee682115223eabebc4c6a2035a6917eac6f60350aba297ccadb", size = 4885904 }, + { url = "https://files.pythonhosted.org/packages/64/e7/b9a07c386adf8ad0348163fbcaab74daed6ef18ddb3f49b61b5c19900aeb/fonttools-4.53.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b21952c092ffd827504de7e66b62aba26fdb5f9d1e435c52477e6486e9d128b2", size = 5054708 }, + { url = "https://files.pythonhosted.org/packages/e9/53/2a79462ae38d7943e63290209c04fef89677c67b29cb329cdc549c18d4d5/fonttools-4.53.1-cp311-cp311-win32.whl", hash = "sha256:9dfdae43b7996af46ff9da520998a32b105c7f098aeea06b2226b30e74fbba88", size = 2158885 }, + { url = "https://files.pythonhosted.org/packages/c8/e1/059700c154bd7170d1c37061239836d2e51ff608f47075450f06dd3c292a/fonttools-4.53.1-cp311-cp311-win_amd64.whl", hash = "sha256:d4d0096cb1ac7a77b3b41cd78c9b6bc4a400550e21dc7a92f2b5ab53ed74eb02", size = 2205133 }, + { url = "https://files.pythonhosted.org/packages/87/63/8271f50f3e7bff8b78e03914c4c2893f2f21bd4db2975c60d11ecfbdd174/fonttools-4.53.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d92d3c2a1b39631a6131c2fa25b5406855f97969b068e7e08413325bc0afba58", size = 2756146 }, + { url = "https://files.pythonhosted.org/packages/dd/bd/cb8fd2dddd68089c112bf42a88afe188b8ace73f94406539857dcc9347a6/fonttools-4.53.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3b3c8ebafbee8d9002bd8f1195d09ed2bd9ff134ddec37ee8f6a6375e6a4f0e8", size = 2244990 }, + { url = "https://files.pythonhosted.org/packages/ae/71/2b9761e25697bdaf3dfe8269541bd4324f3eb0e4cc13f71d7f90cd272394/fonttools-4.53.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f029c095ad66c425b0ee85553d0dc326d45d7059dbc227330fc29b43e8ba60", size = 4787604 }, + { url = "https://files.pythonhosted.org/packages/db/2b/5779cfd48625e013c2dfcf0c246474d5b1f5d061a5f1e476037bf9fff3a3/fonttools-4.53.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f5e6c3510b79ea27bb1ebfcc67048cde9ec67afa87c7dd7efa5c700491ac7f", size = 4871141 }, + { url = "https://files.pythonhosted.org/packages/b8/3d/ac3cec35a503bf789d03e9d155a220c9e574f4f1573f00a3bea55695d535/fonttools-4.53.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f677ce218976496a587ab17140da141557beb91d2a5c1a14212c994093f2eae2", size = 4764714 }, + { url = "https://files.pythonhosted.org/packages/ac/9f/27135ac0328e22cca1ba23ee6a1a1f971c13e9f0387adc5598d4635c501d/fonttools-4.53.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9e6ceba2a01b448e36754983d376064730690401da1dd104ddb543519470a15f", size = 5023568 }, + { url = "https://files.pythonhosted.org/packages/04/40/44d6a94e52e91fe104f9ca95944466af34828992cbc66b666f541de137f1/fonttools-4.53.1-cp312-cp312-win32.whl", hash = "sha256:791b31ebbc05197d7aa096bbc7bd76d591f05905d2fd908bf103af4488e60670", size = 2147572 }, + { url = "https://files.pythonhosted.org/packages/6d/9a/b695930e1b4e6929cc60e294489421632a05c105ac8c56ee63ef56a47872/fonttools-4.53.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ed170b5e17da0264b9f6fae86073be3db15fa1bd74061c8331022bca6d09bab", size = 2193313 }, + { url = "https://files.pythonhosted.org/packages/88/cf/3d0c40471d38ce081b9744216b22360ed9048ab165d15a95c4848a745aee/fonttools-4.53.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c818c058404eb2bba05e728d38049438afd649e3c409796723dfc17cd3f08749", size = 2759786 }, + { url = "https://files.pythonhosted.org/packages/cc/a8/5f9e8664708e90acb1c8e625beab78bca4ef69abd45cdd1c14be84d23906/fonttools-4.53.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:651390c3b26b0c7d1f4407cad281ee7a5a85a31a110cbac5269de72a51551ba2", size = 2247323 }, + { url = "https://files.pythonhosted.org/packages/d9/e2/9f23d610ad557cd717f9b4f2744dc76038edd39d6fd4bb8ca58c8f417333/fonttools-4.53.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e54f1bba2f655924c1138bbc7fa91abd61f45c68bd65ab5ed985942712864bbb", size = 4651283 }, + { url = "https://files.pythonhosted.org/packages/f1/d1/8a596e41e4df480e186de3cd0e90a461a01b7e4f20b5443a5c2a87567e18/fonttools-4.53.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9cd19cf4fe0595ebdd1d4915882b9440c3a6d30b008f3cc7587c1da7b95be5f", size = 4716577 }, + { url = "https://files.pythonhosted.org/packages/a4/bc/e1729257506ecc5f0a064475847c05e8eacdf1f4097f7aeb76aaa83349e4/fonttools-4.53.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2af40ae9cdcb204fc1d8f26b190aa16534fcd4f0df756268df674a270eab575d", size = 4669151 }, + { url = "https://files.pythonhosted.org/packages/fc/6f/32c94dfad17483b4820d924067ecfdb28f998fa29747af7de3b2c5d19f13/fonttools-4.53.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:35250099b0cfb32d799fb5d6c651220a642fe2e3c7d2560490e6f1d3f9ae9169", size = 4844635 }, + { url = "https://files.pythonhosted.org/packages/2e/e8/c0a1386660a1897078eef5c6787624ab0e61b3625085c51df4a48493c356/fonttools-4.53.1-cp38-cp38-win32.whl", hash = "sha256:f08df60fbd8d289152079a65da4e66a447efc1d5d5a4d3f299cdd39e3b2e4a7d", size = 1483234 }, + { url = "https://files.pythonhosted.org/packages/66/5e/ef1ada47adeccce7ced24240b6502a2527a98076d8b386cb76f12fa8d42e/fonttools-4.53.1-cp38-cp38-win_amd64.whl", hash = "sha256:7b6b35e52ddc8fb0db562133894e6ef5b4e54e1283dff606fda3eed938c36fc8", size = 1527699 }, + { url = "https://files.pythonhosted.org/packages/c4/88/86aba816dc6cc4a296df93fb00f6b1dc1ba495c235ccb4241f14cc1a5872/fonttools-4.53.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75a157d8d26c06e64ace9df037ee93a4938a4606a38cb7ffaf6635e60e253b7a", size = 2764568 }, + { url = "https://files.pythonhosted.org/packages/f3/d5/bff14bc918cb2f407e336de41f4dc85aa79888c5954a0d9e4ff4c29aebd9/fonttools-4.53.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4824c198f714ab5559c5be10fd1adf876712aa7989882a4ec887bf1ef3e00e31", size = 2249254 }, + { url = "https://files.pythonhosted.org/packages/6b/0f/2b61b7c48640c20005f75ec0565b5b96ce0f579baffff610f3f6034afc04/fonttools-4.53.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:becc5d7cb89c7b7afa8321b6bb3dbee0eec2b57855c90b3e9bf5fb816671fa7c", size = 4573976 }, + { url = "https://files.pythonhosted.org/packages/7b/30/ad4483dfc5a1999f26b7bc5edc311576f433a3e00dd8aea01f2099c3a29f/fonttools-4.53.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84ec3fb43befb54be490147b4a922b5314e16372a643004f182babee9f9c3407", size = 4632564 }, + { url = "https://files.pythonhosted.org/packages/21/be/a602ba37b1213a6b07eb6b9b4134aae79cbed6b5db4a6bd2efeaeaf18196/fonttools-4.53.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:73379d3ffdeecb376640cd8ed03e9d2d0e568c9d1a4e9b16504a834ebadc2dfb", size = 4567848 }, + { url = "https://files.pythonhosted.org/packages/02/d9/d539010191d99ef8c8403138a9bec272d74b83b99aa2f3bb9c3753bdfc59/fonttools-4.53.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:02569e9a810f9d11f4ae82c391ebc6fb5730d95a0657d24d754ed7763fb2d122", size = 4739315 }, + { url = "https://files.pythonhosted.org/packages/41/4b/b4b7d04a7b3ee9cc9fea48dcf38f3c18804d8b0446eaf0f5b77e6fddc043/fonttools-4.53.1-cp39-cp39-win32.whl", hash = "sha256:aae7bd54187e8bf7fd69f8ab87b2885253d3575163ad4d669a262fe97f0136cb", size = 2160338 }, + { url = "https://files.pythonhosted.org/packages/f2/d5/f7d2122140848fb7a7bd1d59881b822dd514c19b7648984b7565d9f39d56/fonttools-4.53.1-cp39-cp39-win_amd64.whl", hash = "sha256:e5b708073ea3d684235648786f5f6153a48dc8762cdfe5563c57e80787c29fbb", size = 2204286 }, + { url = "https://files.pythonhosted.org/packages/e4/b9/0394d67056d4ad36a3807b439571934b318f1df925593a95e9ec0516b1a7/fonttools-4.53.1-py3-none-any.whl", hash = "sha256:f1f8758a2ad110bd6432203a344269f445a2907dc24ef6bccfd0ac4e14e0d71d", size = 1090472 }, ] [[distribution]] @@ -1066,6 +1078,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c4/64/7d344cfcef5efddf9cf32f59af7f855828e9d74b5f862eddf5bfd9f25323/geopandas-1.0.1-py3-none-any.whl", hash = "sha256:01e147d9420cc374d26f51fc23716ac307f32b49406e4bd8462c07e82ed1d3d6", size = 323587 }, ] +[[distribution]] +name = "ghp-import" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943 } +dependencies = [ + { name = "python-dateutil" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034 }, +] + [[distribution]] name = "google-crc32c" version = "1.5.0" @@ -1639,6 +1663,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/a6/86ef80e010cb757107ff079990b0e07d41b0b60c9eae20423be809877355/lxml-5.2.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ff69a9a0b4b17d78170c73abe2ab12084bdf1691550c5629ad1fe7849433f324", size = 3487478 }, ] +[[distribution]] +name = "markdown" +version = "3.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/02/4785861427848cc11e452cc62bb541006a1087cf04a1de83aedd5530b948/Markdown-3.6.tar.gz", hash = "sha256:ed4f41f6daecbeeb96e576ce414c41d2d876daa9a16cb35fa8ed8c2ddfad0224", size = 354715 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/b3/0c0c994fe49cd661084f8d5dc06562af53818cc0abefaca35bdc894577c3/Markdown-3.6-py3-none-any.whl", hash = "sha256:48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f", size = 105381 }, +] + [[distribution]] name = "markdown-it-py" version = "3.0.0" @@ -1720,9 +1753,9 @@ wheels = [ [[distribution]] name = "matplotlib" -version = "3.9.0" +version = "3.9.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c5/a4/a7236bf8b0137deff48737c6ccf2154ef4486e57c6a5b7c309bf515992bd/matplotlib-3.9.0.tar.gz", hash = "sha256:e6d29ea6c19e34b30fb7d88b7081f869a03014f66fe06d62cc77d5a6ea88ed7a", size = 36069890 } +sdist = { url = "https://files.pythonhosted.org/packages/22/06/9e8ba6ec8b716a215404a5d1938b61f5a28001be493cf35344dda9a4072a/matplotlib-3.9.1.tar.gz", hash = "sha256:de06b19b8db95dd33d0dc17c926c7c9ebed9f572074b6fac4f65068a6814d010", size = 36084124 } dependencies = [ { name = "contourpy" }, { name = "cycler" }, @@ -1735,34 +1768,34 @@ dependencies = [ { name = "python-dateutil" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/03/a0/669c37c6e6737de909c19eb30d7b17d1d6be6d896aa2f5dc63e66231b7f4/matplotlib-3.9.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2bcee1dffaf60fe7656183ac2190bd630842ff87b3153afb3e384d966b57fe56", size = 7883911 }, - { url = "https://files.pythonhosted.org/packages/f7/1f/a0f1a692af13b85335a9d7bd226fc0cae8d0062f1fb940980bc9b38d3b5c/matplotlib-3.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f988bafb0fa39d1074ddd5bacd958c853e11def40800c5824556eb630f94d3b", size = 7765903 }, - { url = "https://files.pythonhosted.org/packages/fc/3d/58182994c955ff2fc722f883e96ad9de3439d3ead668fce33ad1c3fe4242/matplotlib-3.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe428e191ea016bb278758c8ee82a8129c51d81d8c4bc0846c09e7e8e9057241", size = 8183679 }, - { url = "https://files.pythonhosted.org/packages/a7/68/16e7b9154fae61fb29f0f3450b39b855b89e6d2c598d67302e70f96883af/matplotlib-3.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaf3978060a106fab40c328778b148f590e27f6fa3cd15a19d6892575bce387d", size = 8296303 }, - { url = "https://files.pythonhosted.org/packages/ef/66/ad8d69aa13fd6e1b09fe7b91b512d07eaf175a0b0e7c4bcba87e8d2e01d6/matplotlib-3.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2e7f03e5cbbfacdd48c8ea394d365d91ee8f3cae7e6ec611409927b5ed997ee4", size = 8594927 }, - { url = "https://files.pythonhosted.org/packages/b9/55/6138ad64c789bad13d18e0240da75e73dbd364fdc0aa670fff87a5eef5ab/matplotlib-3.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:13beb4840317d45ffd4183a778685e215939be7b08616f431c7795276e067463", size = 7954080 }, - { url = "https://files.pythonhosted.org/packages/09/49/569b50eb5e5a75b61f7a0bacb6029e9ea9c8a1190df55a39a31789244e09/matplotlib-3.9.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:063af8587fceeac13b0936c42a2b6c732c2ab1c98d38abc3337e430e1ff75e38", size = 7893678 }, - { url = "https://files.pythonhosted.org/packages/f4/b4/c1700c8b2ff8d379c187f37055e61bd7a611eb2c544466600a7734793d54/matplotlib-3.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a2fa6d899e17ddca6d6526cf6e7ba677738bf2a6a9590d702c277204a7c6152", size = 7775027 }, - { url = "https://files.pythonhosted.org/packages/bc/9e/b09513717f60071fefcb28c7c783aa658f939f3d4ba1cefb6c05138c6657/matplotlib-3.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:550cdda3adbd596078cca7d13ed50b77879104e2e46392dcd7c75259d8f00e85", size = 8192694 }, - { url = "https://files.pythonhosted.org/packages/41/f1/115e7c79b4506b4f0533acba742babd9718ff92eeca6d4205843173b6173/matplotlib-3.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cce0f31b351e3551d1f3779420cf8f6ec0d4a8cf9c0237a3b549fd28eb4abb", size = 8307002 }, - { url = "https://files.pythonhosted.org/packages/7a/a2/5c1a64d188c4cae7368ebb8c28a354e3f262cb86b28c38ffa6ee3ad532ba/matplotlib-3.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c53aeb514ccbbcbab55a27f912d79ea30ab21ee0531ee2c09f13800efb272674", size = 8600548 }, - { url = "https://files.pythonhosted.org/packages/c6/c8/6936e8c7b279a5abac82f399d8d72ac25da530cf5f78a0e40063e492558c/matplotlib-3.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5be985db2596d761cdf0c2eaf52396f26e6a64ab46bd8cd810c48972349d1be", size = 7963606 }, - { url = "https://files.pythonhosted.org/packages/af/43/54b7dfd91ed33da92973dc5d50231ef7b2d0622c8ae72babbad26bc1a319/matplotlib-3.9.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c79f3a585f1368da6049318bdf1f85568d8d04b2e89fc24b7e02cc9b62017382", size = 7884612 }, - { url = "https://files.pythonhosted.org/packages/4c/88/15bbb864b0d871707294ff325f9ffd0dfa486db2637eb34dd5f8dcf5b9bf/matplotlib-3.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bdd1ecbe268eb3e7653e04f451635f0fb0f77f07fd070242b44c076c9106da84", size = 7769852 }, - { url = "https://files.pythonhosted.org/packages/57/af/8ed9b852fc041fc5bd101f9964682874ccbf24f9c08323edee6a1600eb04/matplotlib-3.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d38e85a1a6d732f645f1403ce5e6727fd9418cd4574521d5803d3d94911038e5", size = 8185646 }, - { url = "https://files.pythonhosted.org/packages/f4/ff/da311c1e679eed54d3aed67754a4e859bd3b773060c2fa187962e60fcb85/matplotlib-3.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a490715b3b9984fa609116481b22178348c1a220a4499cda79132000a79b4db", size = 8298411 }, - { url = "https://files.pythonhosted.org/packages/db/8c/1014baa6776503914865d87e1e8a803ee9faa7b722ca5e655463b79c966e/matplotlib-3.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8146ce83cbc5dc71c223a74a1996d446cd35cfb6a04b683e1446b7e6c73603b7", size = 8591196 }, - { url = "https://files.pythonhosted.org/packages/17/91/febbb6c1063ae05a62fdbe038c2917b348b1b35f0482cee4738e6870a44a/matplotlib-3.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:d91a4ffc587bacf5c4ce4ecfe4bcd23a4b675e76315f2866e588686cc97fccdf", size = 7968581 }, - { url = "https://files.pythonhosted.org/packages/f9/17/7fae59bf7c5ff97abaea6baad2d21cc3f68aed2c82323b0cdaac743959d5/matplotlib-3.9.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:616fabf4981a3b3c5a15cd95eba359c8489c4e20e03717aea42866d8d0465956", size = 7884763 }, - { url = "https://files.pythonhosted.org/packages/9c/2b/3b82a88735fb2fff513990963ce288f67b78b08c9ec528210387fb3a2757/matplotlib-3.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cd53c79fd02f1c1808d2cfc87dd3cf4dbc63c5244a58ee7944497107469c8d8a", size = 7766727 }, - { url = "https://files.pythonhosted.org/packages/8a/de/ed28038ba354617c442a8b09c1fc4848ac50460747577c4ebfb5ef71de53/matplotlib-3.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06a478f0d67636554fa78558cfbcd7b9dba85b51f5c3b5a0c9be49010cf5f321", size = 8185424 }, - { url = "https://files.pythonhosted.org/packages/d3/6d/45837c5b3d0005a5a9b04729b218a16bf3aa195701c6b33b2cc39ae943b6/matplotlib-3.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81c40af649d19c85f8073e25e5806926986806fa6d54be506fbf02aef47d5a89", size = 8298763 }, - { url = "https://files.pythonhosted.org/packages/96/92/7a534d63958f6ec837857b112b50ac29996e60f39d4b55ae39c6e64c8a1a/matplotlib-3.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52146fc3bd7813cc784562cb93a15788be0b2875c4655e2cc6ea646bfa30344b", size = 8597376 }, - { url = "https://files.pythonhosted.org/packages/58/ea/7f029057338138643d745fd4a88d745f8ec810ef81652cc43103324ec549/matplotlib-3.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:0fc51eaa5262553868461c083d9adadb11a6017315f3a757fc45ec6ec5f02888", size = 7949603 }, - { url = "https://files.pythonhosted.org/packages/e8/af/824734d3b5381688da89748c0ad71a3c414bf5322f55ccbb049197ce5d19/matplotlib-3.9.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bd4f2831168afac55b881db82a7730992aa41c4f007f1913465fb182d6fb20c0", size = 7873642 }, - { url = "https://files.pythonhosted.org/packages/fc/5f/2bb0cd3a28f1d4ede70d3d47ded36dcf0d0cbe012bcafc4cd8053eb53d1c/matplotlib-3.9.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:290d304e59be2b33ef5c2d768d0237f5bd132986bdcc66f80bc9bcc300066a03", size = 7757288 }, - { url = "https://files.pythonhosted.org/packages/2e/62/ce7c20b5bbf49bbbd679400d8c38a17d40f0eaaece364f7e602fe8112d75/matplotlib-3.9.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff2e239c26be4f24bfa45860c20ffccd118d270c5b5d081fa4ea409b5469fcd", size = 8298454 }, - { url = "https://files.pythonhosted.org/packages/c4/d4/668a809e3e12cb20fc73f34f7fd886a314e512073484bea48fa3480687ad/matplotlib-3.9.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:af4001b7cae70f7eaacfb063db605280058246de590fa7874f00f62259f2df7e", size = 7974664 }, + { url = "https://files.pythonhosted.org/packages/42/ba/0016c92366f93f77cd22c4fb030ac1d5924fcc2320bdaa17c5b0768afd67/matplotlib-3.9.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7ccd6270066feb9a9d8e0705aa027f1ff39f354c72a87efe8fa07632f30fc6bb", size = 7893085 }, + { url = "https://files.pythonhosted.org/packages/fe/f9/df790297f1981c81b8c6af92769535c2e4fa889c9aab7134b8d7f171fde6/matplotlib-3.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:591d3a88903a30a6d23b040c1e44d1afdd0d778758d07110eb7596f811f31842", size = 7773136 }, + { url = "https://files.pythonhosted.org/packages/0b/53/96e98ba8ab163c3a56b993e08625a48efe47744a53ec221974dcddaff7c7/matplotlib-3.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd2a59ff4b83d33bca3b5ec58203cc65985367812cb8c257f3e101632be86d92", size = 8192140 }, + { url = "https://files.pythonhosted.org/packages/32/ad/58902b481f5a294101a53ed964d68a2c2355d55622a8e9cb09fc3f517385/matplotlib-3.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fc001516ffcf1a221beb51198b194d9230199d6842c540108e4ce109ac05cc0", size = 8303732 }, + { url = "https://files.pythonhosted.org/packages/ce/29/479fe8b057a4580fb0f476b0b83e0ba7ea08bc0f55081e045d3794e830a4/matplotlib-3.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:83c6a792f1465d174c86d06f3ae85a8fe36e6f5964633ae8106312ec0921fdf5", size = 9083082 }, + { url = "https://files.pythonhosted.org/packages/be/f6/4ac7f10c1e8d51f42e320a0890ee7c8e45fb5b1178ed147f374a37900924/matplotlib-3.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:421851f4f57350bcf0811edd754a708d2275533e84f52f6760b740766c6747a7", size = 7961172 }, + { url = "https://files.pythonhosted.org/packages/ce/f5/22d0f294a76cc65c431fb7f2146a96a4e12233c09cbce6285f74bb75db96/matplotlib-3.9.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b3fce58971b465e01b5c538f9d44915640c20ec5ff31346e963c9e1cd66fa812", size = 7902698 }, + { url = "https://files.pythonhosted.org/packages/46/81/38bc95cf20ce6ed9dd5e7aec805bf1efc931e3fdeb9c5b593d00634a4747/matplotlib-3.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a973c53ad0668c53e0ed76b27d2eeeae8799836fd0d0caaa4ecc66bf4e6676c0", size = 7781109 }, + { url = "https://files.pythonhosted.org/packages/54/7e/4f8f44fcc65a8cfa6303d3469d8973d6a2ba019a9627af9a9ae545f718d6/matplotlib-3.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cd5acf8f3ef43f7532c2f230249720f5dc5dd40ecafaf1c60ac8200d46d7eb", size = 8202150 }, + { url = "https://files.pythonhosted.org/packages/b8/63/cef838d92c1918ae28afd12b8aeaa9c104a0686cf6447aa0546f7c6dd1f0/matplotlib-3.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab38a4f3772523179b2f772103d8030215b318fef6360cb40558f585bf3d017f", size = 8314134 }, + { url = "https://files.pythonhosted.org/packages/b1/9d/88eea633292d530f46e6579bcf3c1966536fc4a7601014a9d131ef584d32/matplotlib-3.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2315837485ca6188a4b632c5199900e28d33b481eb083663f6a44cfc8987ded3", size = 9091189 }, + { url = "https://files.pythonhosted.org/packages/3c/a5/54a497ca4af8e76adfe7c5a1712f3bb6b2222d464fe736b60aaafd425945/matplotlib-3.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:a0c977c5c382f6696caf0bd277ef4f936da7e2aa202ff66cad5f0ac1428ee15b", size = 7970892 }, + { url = "https://files.pythonhosted.org/packages/7f/7d/c919b41320f901ad1d0924fb045950925af8d367b0690b32fbdd970282ee/matplotlib-3.9.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:565d572efea2b94f264dd86ef27919515aa6d629252a169b42ce5f570db7f37b", size = 7892287 }, + { url = "https://files.pythonhosted.org/packages/3d/44/c4218d351df907c9a39add2d93594ede085a6dc53b5760c67f1eca7871bf/matplotlib-3.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d397fd8ccc64af2ec0af1f0efc3bacd745ebfb9d507f3f552e8adb689ed730a", size = 7775076 }, + { url = "https://files.pythonhosted.org/packages/db/9e/202f0241d3a30bbb04841be6831817d479de849fdd4510e350bb3794a161/matplotlib-3.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26040c8f5121cd1ad712abffcd4b5222a8aec3a0fe40bc8542c94331deb8780d", size = 8193023 }, + { url = "https://files.pythonhosted.org/packages/0d/cb/78283ec2ded91fb74a2ae9ae93f91a897fa578fa78c8c271a7c147f6b8d6/matplotlib-3.9.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d12cb1837cffaac087ad6b44399d5e22b78c729de3cdae4629e252067b705e2b", size = 8306066 }, + { url = "https://files.pythonhosted.org/packages/e8/6a/d26801848d5a61b2caf9cd9bf2dc1747520bb8dc074376177c9372779e83/matplotlib-3.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0e835c6988edc3d2d08794f73c323cc62483e13df0194719ecb0723b564e0b5c", size = 9086483 }, + { url = "https://files.pythonhosted.org/packages/e3/31/aeab8a3db1fb22a7d04c5215f872b92451baf7f6595ffd59004aeead0b2c/matplotlib-3.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:44a21d922f78ce40435cb35b43dd7d573cf2a30138d5c4b709d19f00e3907fd7", size = 7974774 }, + { url = "https://files.pythonhosted.org/packages/e5/8a/7ee266d4d45588529b04be1e52626c708314f559252c863c6dab46b55cdd/matplotlib-3.9.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:0c584210c755ae921283d21d01f03a49ef46d1afa184134dd0f95b0202ee6f03", size = 7894019 }, + { url = "https://files.pythonhosted.org/packages/c5/34/ad49016a943305cf44eb8f42fb6c001c3d54c6ba5781d842aea9c60e3f31/matplotlib-3.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11fed08f34fa682c2b792942f8902e7aefeed400da71f9e5816bea40a7ce28fe", size = 7773937 }, + { url = "https://files.pythonhosted.org/packages/7b/88/68ee52339a9fefb2cdaceab09e38ec157882e3d1f814a525ddf1724d5a46/matplotlib-3.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0000354e32efcfd86bda75729716b92f5c2edd5b947200be9881f0a671565c33", size = 8193851 }, + { url = "https://files.pythonhosted.org/packages/8e/67/e75134cb83d2e533e46d72e2033a413772efdc18291beb981f5d574a829f/matplotlib-3.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4db17fea0ae3aceb8e9ac69c7e3051bae0b3d083bfec932240f9bf5d0197a049", size = 8306053 }, + { url = "https://files.pythonhosted.org/packages/eb/22/3e320ab5a74670d4a3b31d1f56eba007cf357cb35d9e47fd5c0f52ccb23f/matplotlib-3.9.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:208cbce658b72bf6a8e675058fbbf59f67814057ae78165d8a2f87c45b48d0ff", size = 9085292 }, + { url = "https://files.pythonhosted.org/packages/0c/dd/8270a3114b46831b0faa7fa28e6c78f5e1264eefe2908f0c8869dce4dfbb/matplotlib-3.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:dc23f48ab630474264276be156d0d7710ac6c5a09648ccdf49fef9200d8cbe80", size = 7956580 }, + { url = "https://files.pythonhosted.org/packages/ba/af/c657eb22e5d3d455545825b80469b7d56fe2e1e05d88e0a3c2d4955ba448/matplotlib-3.9.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3fda72d4d472e2ccd1be0e9ccb6bf0d2eaf635e7f8f51d737ed7e465ac020cb3", size = 7885084 }, + { url = "https://files.pythonhosted.org/packages/75/e3/8e966205e415d17762f5715a3f5bd09ca1dbc07df38768980464df561dda/matplotlib-3.9.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:84b3ba8429935a444f1fdc80ed930babbe06725bcf09fbeb5c8757a2cd74af04", size = 7762826 }, + { url = "https://files.pythonhosted.org/packages/1e/42/273966d8150b98abf62cded0f236f6a75418ac2d35db8c36b6db1499b320/matplotlib-3.9.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b918770bf3e07845408716e5bbda17eadfc3fcbd9307dc67f37d6cf834bb3d98", size = 8305461 }, + { url = "https://files.pythonhosted.org/packages/fe/00/2eb1b5216709b9aec5ff3b1e1c84adf57ca2cb160460e946d2d43a7937ea/matplotlib-3.9.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f1f2e5d29e9435c97ad4c36fb6668e89aee13d48c75893e25cef064675038ac9", size = 7982116 }, ] [[distribution]] @@ -1786,6 +1819,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, ] +[[distribution]] +name = "mergedeep" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354 }, +] + [[distribution]] name = "metadrive-simulator" version = "0.4.2.3" @@ -1815,6 +1857,60 @@ dependencies = [ { name = "yapf" }, ] +[[distribution]] +name = "mkdocs" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/6b/26b33cc8ad54e8bc0345cddc061c2c5c23e364de0ecd97969df23f95a673/mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512", size = 3888392 } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "platform_system == 'Windows'" }, + { name = "ghp-import" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "watchdog" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/c0/930dcf5a3e96b9c8e7ad15502603fc61d495479699e2d2c381e3d37294d1/mkdocs-1.6.0-py3-none-any.whl", hash = "sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7", size = 3862264 }, +] + +[[distribution]] +name = "mkdocs-get-deps" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239 } +dependencies = [ + { name = "mergedeep" }, + { name = "platformdirs" }, + { name = "pyyaml" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521 }, +] + +[[distribution]] +name = "mkdocs-terminal" +version = "4.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/a4/afa8826c3d6971f3e93cb3669936b25579314fef2a4d648fe72729c9675f/mkdocs_terminal-4.4.0.tar.gz", hash = "sha256:d72b87b3d0edf470695811cb56c440a43b0387212590a5dfb2f26861c6e518d7", size = 619482 } +dependencies = [ + { name = "jinja2" }, + { name = "markdown" }, + { name = "mkdocs" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/65/7973dfe5ae03dd83a5a4e203b542ebacb16fd0c796e3f93f3cb98c3ffcc2/mkdocs_terminal-4.4.0-py3-none-any.whl", hash = "sha256:b2c94dc651c840e9762a1040d39371a31cc7482f7768e619e317419ebae4e40e", size = 641788 }, +] + [[distribution]] name = "mouseinfo" version = "0.1.3" @@ -2286,6 +2382,8 @@ dev = [ ] docs = [ { name = "jinja2" }, + { name = "mkdocs" }, + { name = "mkdocs-terminal" }, ] testing = [ { name = "coverage" }, @@ -2466,6 +2564,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/31/13/fe468c8c7400a8eca204e6e160a29bf7dcd45a76e20f1c030f3eaa690d93/parameterized-0.8.1-py2.py3-none-any.whl", hash = "sha256:9cbb0b69a03e8695d68b3399a8a5825200976536fe1cb79db60ed6a4c8c9efe9", size = 26354 }, ] +[[distribution]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, +] + [[distribution]] name = "pillow" version = "10.4.0" @@ -2994,6 +3101,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/c1/c8d2be418b63b1651219b8cc733a775657844afeb7ffd0012258e04c0307/pylibsrtp-0.10.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e4d9625a9667d2c0843bf9cfa731f815d8b9a04ed9ffe5b98442483b8b236f13", size = 1446423 }, ] +[[distribution]] +name = "pymdown-extensions" +version = "10.8.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/09/11/0a1da270c1011194a6efee7ec1ac07d8b75a9706eed4a80675403f6a9d70/pymdown_extensions-10.8.1.tar.gz", hash = "sha256:3ab1db5c9e21728dabf75192d71471f8e50f216627e9a1fa9535ecb0231b9940", size = 812097 } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/d7/e19f9bee2729a8d65b9bf822bb69ac364bf782bac8d761c62b4252769ae0/pymdown_extensions-10.8.1-py3-none-any.whl", hash = "sha256:f938326115884f48c6059c67377c46cf631c733ef3629b6eed1349989d1b30cb", size = 250833 }, +] + [[distribution]] name = "pymonctl" version = "0.92" @@ -6069,6 +6189,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/84/4d/82704d1ab9290b03da94e6425f5e87396b999fd7eb8e08f3a92c158402bf/PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", size = 152751 }, ] +[[distribution]] +name = "pyyaml-env-tag" +version = "0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fb/8e/da1c6c58f751b70f8ceb1eb25bc25d524e8f14fe16edcce3f4e3ba08629c/pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", size = 5631 } +dependencies = [ + { name = "pyyaml" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/66/bbb1dd374f5c870f59c5bb1db0e18cbe7fa739415a24cbd95b2d1f5ae0c4/pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069", size = 3911 }, +] + [[distribution]] name = "pyzmq" version = "26.0.3" @@ -6212,27 +6344,27 @@ wheels = [ [[distribution]] name = "ruff" -version = "0.5.0" +version = "0.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/28/9a/dde343d95ecd0747207e4e8d143c373ef961cbd6b78c61a659f67582dbd2/ruff-0.5.0.tar.gz", hash = "sha256:eb641b5873492cf9bd45bc9c5ae5320648218e04386a5f0c264ad6ccce8226a1", size = 2587996 } +sdist = { url = "https://files.pythonhosted.org/packages/aa/dc/8d95ce5e15f0f25dc1fb6e9a11d6f33379e092d528a3b0535de246e07182/ruff-0.5.1.tar.gz", hash = "sha256:3164488aebd89b1745b47fd00604fb4358d774465f20d1fcd907f9c0fc1b0655", size = 2594019 } wheels = [ - { url = "https://files.pythonhosted.org/packages/55/5d/0d9510720d61df753df39bf24a96d6c141080c94fe6025568747fbea856a/ruff-0.5.0-py3-none-linux_armv6l.whl", hash = "sha256:ee770ea8ab38918f34e7560a597cc0a8c9a193aaa01bfbd879ef43cb06bd9c4c", size = 9434156 }, - { url = "https://files.pythonhosted.org/packages/be/5a/7f466f5449dce168c2d956ad4a207d62dc7b76836d46f1c04249a4daaf34/ruff-0.5.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:38f3b8327b3cb43474559d435f5fa65dacf723351c159ed0dc567f7ab735d1b6", size = 8536948 }, - { url = "https://files.pythonhosted.org/packages/e2/a2/afc6952d5a0199e7e6c0a2051d6f4780fb70376f5bd07f27838f8bc0cf47/ruff-0.5.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7594f8df5404a5c5c8f64b8311169879f6cf42142da644c7e0ba3c3f14130370", size = 8107163 }, - { url = "https://files.pythonhosted.org/packages/34/54/ea77237405b7573298f5cc00045d1aceab609841d3cc88de3d7c3d2a6163/ruff-0.5.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:adc7012d6ec85032bc4e9065110df205752d64010bed5f958d25dbee9ce35de3", size = 9877009 }, - { url = "https://files.pythonhosted.org/packages/56/db/3f74873bc0ca915f79d26575e549eb5e633022d56315d314e6f9c0fa596a/ruff-0.5.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d505fb93b0fabef974b168d9b27c3960714d2ecda24b6ffa6a87ac432905ea38", size = 9219926 }, - { url = "https://files.pythonhosted.org/packages/57/08/1052c80f3f44321631a8c1337e55883dd7a7b02b4efe5c9282258db42358/ruff-0.5.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dc5cfd3558f14513ed0d5b70ce531e28ea81a8a3b1b07f0f48421a3d9e7d80a", size = 10031146 }, - { url = "https://files.pythonhosted.org/packages/8f/a2/f7c01c4a02b87998c9e1379ec8d7345d6a45f8b34e326e8700c13da391c3/ruff-0.5.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:db3ca35265de239a1176d56a464b51557fce41095c37d6c406e658cf80bbb362", size = 10770796 }, - { url = "https://files.pythonhosted.org/packages/12/a1/5f45ab0948a202da7fe13c6e0678f907bd88caacc7e4f4909603d3774051/ruff-0.5.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b1a321c4f68809fddd9b282fab6a8d8db796b270fff44722589a8b946925a2a8", size = 10364804 }, - { url = "https://files.pythonhosted.org/packages/7e/40/83f88d5bda41496a90871ec82dd82545def4c4683e1c2f4a42f5a168ae3e/ruff-0.5.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2c4dfcd8d34b143916994b3876b63d53f56724c03f8c1a33a253b7b1e6bf2a7d", size = 11241308 }, - { url = "https://files.pythonhosted.org/packages/af/79/8a57016a761d11491b913460a3d1545cdbe96dca6acb1279102814c9147b/ruff-0.5.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81e5facfc9f4a674c6a78c64d38becfbd5e4f739c31fcd9ce44c849f1fad9e4c", size = 10064506 }, - { url = "https://files.pythonhosted.org/packages/67/34/fd7cd8be0d8cd4bcce0dbef807933f6c9685d5dc2549b729da7ee7a7a5cc/ruff-0.5.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e589e27971c2a3efff3fadafb16e5aef7ff93250f0134ec4b52052b673cf988d", size = 9866155 }, - { url = "https://files.pythonhosted.org/packages/7b/54/8a654417265fe91de3ff303274a9d4d64774496eaa2eadd7da8e88a48b82/ruff-0.5.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2ffbc3715a52b037bcb0f6ff524a9367f642cdc5817944f6af5479bbb2eb50e", size = 9285874 }, - { url = "https://files.pythonhosted.org/packages/86/39/564161e306b12ab40d2b6be0a0bc843c692a8295cc7101fa930db89e1e7e/ruff-0.5.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cd096e23c6a4f9c819525a437fa0a99d1c67a1b6bb30948d46f33afbc53596cf", size = 9645133 }, - { url = "https://files.pythonhosted.org/packages/3b/67/3203d56ee41d3dee8d94c7926b298b13a150f105a55fef38b75ccf5e0901/ruff-0.5.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:46e193b36f2255729ad34a49c9a997d506e58f08555366b2108783b3064a0e1e", size = 10143022 }, - { url = "https://files.pythonhosted.org/packages/71/2e/1bab3c5a3929f348cdc086a3f3013ea0b8823ec3d273f3334ef621f4f83f/ruff-0.5.0-py3-none-win32.whl", hash = "sha256:49141d267100f5ceff541b4e06552e98527870eafa1acc9dec9139c9ec5af64c", size = 7735210 }, - { url = "https://files.pythonhosted.org/packages/48/05/04bf25784ba73abf0e639065fd7a785c005c895c4bf64aa2729d26a1984f/ruff-0.5.0-py3-none-win_amd64.whl", hash = "sha256:e9118f60091047444c1b90952736ee7b1792910cab56e9b9a9ac20af94cd0440", size = 8536440 }, - { url = "https://files.pythonhosted.org/packages/63/ab/a10ab4a751514d4f954079fbd2f645cc0c5982a18f510ab411048a2a5409/ruff-0.5.0-py3-none-win_arm64.whl", hash = "sha256:ed5c4df5c1fb4518abcb57725b576659542bdbe93366f4f329e8f398c4b71178", size = 7949476 }, + { url = "https://files.pythonhosted.org/packages/58/36/c4684f20bc0f6e4725177fbed8557a1d4c8dd118584112313ee03876f4dd/ruff-0.5.1-py3-none-linux_armv6l.whl", hash = "sha256:6ecf968fcf94d942d42b700af18ede94b07521bd188aaf2cd7bc898dd8cb63b6", size = 9506184 }, + { url = "https://files.pythonhosted.org/packages/40/98/80295e661ba1219c584a2d6103277bce16c6ff7cd0d9e3597bb16c115113/ruff-0.5.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:204fb0a472f00f2e6280a7c8c7c066e11e20e23a37557d63045bf27a616ba61c", size = 8606624 }, + { url = "https://files.pythonhosted.org/packages/a9/64/b0356632574dea983e2d718f064d95f8a45f8f381d094c917685f1d6fc26/ruff-0.5.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d235968460e8758d1e1297e1de59a38d94102f60cafb4d5382033c324404ee9d", size = 8184772 }, + { url = "https://files.pythonhosted.org/packages/34/57/db0df86298aa6082c396b44d4ad12a16ee891f61513849e5bdaeab0a4c7a/ruff-0.5.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38beace10b8d5f9b6bdc91619310af6d63dd2019f3fb2d17a2da26360d7962fa", size = 9981131 }, + { url = "https://files.pythonhosted.org/packages/bb/b1/63211390db6afa0e24bdd5b1d5053693074759ce940c0669576834fc6026/ruff-0.5.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e478d2f09cf06add143cf8c4540ef77b6599191e0c50ed976582f06e588c994", size = 9297773 }, + { url = "https://files.pythonhosted.org/packages/ac/7f/5824713ffcb5ce055dc7e509cb2d5d5ef405af73cd1615d27e475114dc89/ruff-0.5.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f0368d765eec8247b8550251c49ebb20554cc4e812f383ff9f5bf0d5d94190b0", size = 10087567 }, + { url = "https://files.pythonhosted.org/packages/75/3b/1ada2a113e1899e215e7542a42e59e5143d7ce4e9b04b7f9f03217414139/ruff-0.5.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3a9a9a1b582e37669b0138b7c1d9d60b9edac880b80eb2baba6d0e566bdeca4d", size = 10863472 }, + { url = "https://files.pythonhosted.org/packages/b2/f9/11ca13d8040830140d4385af241d435e1b1b1387a987df707c969c5bbfb9/ruff-0.5.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bdd9f723e16003623423affabcc0a807a66552ee6a29f90eddad87a40c750b78", size = 10448311 }, + { url = "https://files.pythonhosted.org/packages/b7/43/8546df86010041ab9f7e80f1a85cd4b8042a55338d7a30561ef835cba9e2/ruff-0.5.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:be9fd62c1e99539da05fcdc1e90d20f74aec1b7a1613463ed77870057cd6bd96", size = 11368918 }, + { url = "https://files.pythonhosted.org/packages/8a/d5/8271d42dd239b7c2d163615b3b01b1acfb187f5114bfca6d5a85e1d6a1eb/ruff-0.5.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e216fc75a80ea1fbd96af94a6233d90190d5b65cc3d5dfacf2bd48c3e067d3e1", size = 10144007 }, + { url = "https://files.pythonhosted.org/packages/39/38/c480773c22012535ca121c9488323943406c1780f22f9bb5ca51e830c2b1/ruff-0.5.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c4c2112e9883a40967827d5c24803525145e7dab315497fae149764979ac7929", size = 9940919 }, + { url = "https://files.pythonhosted.org/packages/5f/ea/6d96bd900cfe2a2401de733c4bd9ee3e5811cb27584ade3bbcdee638afc8/ruff-0.5.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dfaf11c8a116394da3b65cd4b36de30d8552fa45b8119b9ef5ca6638ab964fa3", size = 9361679 }, + { url = "https://files.pythonhosted.org/packages/7d/7c/b4ab2d5d90bab6e16ea79c261aeb437cb804b436d376c70f37f37086907c/ruff-0.5.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d7ceb9b2fe700ee09a0c6b192c5ef03c56eb82a0514218d8ff700f6ade004108", size = 9717533 }, + { url = "https://files.pythonhosted.org/packages/6d/a3/fb5a4ee18cee7b44e9309a9b8d7b8d76a12ee7f3ef53f6c0dcc71c080f2d/ruff-0.5.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:bac6288e82f6296f82ed5285f597713acb2a6ae26618ffc6b429c597b392535c", size = 10204312 }, + { url = "https://files.pythonhosted.org/packages/9c/39/da2a5cc52fd239e291c0ff473137d6733778e481b8e4469fd1c4c891c7f7/ruff-0.5.1-py3-none-win32.whl", hash = "sha256:5c441d9c24ec09e1cb190a04535c5379b36b73c4bc20aa180c54812c27d1cca4", size = 7775009 }, + { url = "https://files.pythonhosted.org/packages/a8/9f/e236acf3b95b383a5241da0f758fc8688d1796837b6bec8ee528130c3dba/ruff-0.5.1-py3-none-win_amd64.whl", hash = "sha256:b1789bf2cd3d1b5a7d38397cac1398ddf3ad7f73f4de01b1e913e2abc7dfc51d", size = 8597783 }, + { url = "https://files.pythonhosted.org/packages/f6/b1/fd215876543ac2a3ddd477487f574ca2d91973d0ecd87664095e6b249017/ruff-0.5.1-py3-none-win_arm64.whl", hash = "sha256:2875b7596a740cbbd492f32d24be73e545a4ce0a3daf51e4f4e609962bfd3cd2", size = 7998017 }, ] [[distribution]] @@ -6611,6 +6743,45 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/07/4d/410156100224c5e2f0011d435e477b57aed9576fc7fe137abcf14ec16e11/virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589", size = 5684792 }, ] +[[distribution]] +name = "watchdog" +version = "4.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/f9/b01e4632aed9a6ecc2b3e501feffd3af5aa0eb4e3b0283fc9525bf503c38/watchdog-4.0.1.tar.gz", hash = "sha256:eebaacf674fa25511e8867028d281e602ee6500045b57f43b08778082f7f8b44", size = 126583 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/51/11f6d62e07434849e47ab0ff90679443bd19c568118fbe47a1094ebcdca8/watchdog-4.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:da2dfdaa8006eb6a71051795856bedd97e5b03e57da96f98e375682c48850645", size = 101628 }, + { url = "https://files.pythonhosted.org/packages/1a/3f/4a4e866d69051d1144cbc5ebc11cdb5367b66d7ed6022bff1c7c927c3c1a/watchdog-4.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e93f451f2dfa433d97765ca2634628b789b49ba8b504fdde5837cdcf25fdb53b", size = 92462 }, + { url = "https://files.pythonhosted.org/packages/3e/a5/65044f27764c6c93c7698a2a117ddb888a55a69222da3d6fe20c39cc087c/watchdog-4.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ef0107bbb6a55f5be727cfc2ef945d5676b97bffb8425650dadbb184be9f9a2b", size = 92952 }, + { url = "https://files.pythonhosted.org/packages/1c/bc/a1ce8b77eede5a2f4fbcdc923079eb85b7c6e0f5e366ad06661b4dd807e1/watchdog-4.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:17e32f147d8bf9657e0922c0940bcde863b894cd871dbb694beb6704cfbd2fb5", size = 101627 }, + { url = "https://files.pythonhosted.org/packages/c2/84/9c66fb603bb683fe559ceeba8f3d5dbea3293b631b2eba319d7d47a2d7fb/watchdog-4.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:03e70d2df2258fb6cb0e95bbdbe06c16e608af94a3ffbd2b90c3f1e83eb10767", size = 92464 }, + { url = "https://files.pythonhosted.org/packages/5a/a5/72b9557e77ac3e6c41816fb16f643069b17cf21f745d26e2931cb1bf136c/watchdog-4.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:123587af84260c991dc5f62a6e7ef3d1c57dfddc99faacee508c71d287248459", size = 92953 }, + { url = "https://files.pythonhosted.org/packages/f3/d1/85c1f5841190ee1e39f4a8a01df6eb13b44bd366060fc735505a38613484/watchdog-4.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:093b23e6906a8b97051191a4a0c73a77ecc958121d42346274c6af6520dec175", size = 101708 }, + { url = "https://files.pythonhosted.org/packages/a9/eb/8d1f9150dd5e86082913ab15d4fd4bea436186845be1b1752efd19b020d1/watchdog-4.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:611be3904f9843f0529c35a3ff3fd617449463cb4b73b1633950b3d97fa4bfb7", size = 92508 }, + { url = "https://files.pythonhosted.org/packages/52/67/62eea67ef31214ea4867b97351ea4f6b3a52dd1c4c93360ff8ad6e4ad72f/watchdog-4.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:62c613ad689ddcb11707f030e722fa929f322ef7e4f18f5335d2b73c61a85c28", size = 92977 }, + { url = "https://files.pythonhosted.org/packages/f8/35/44650dfdeb57337dc743b89990ccac5cab42ba865f1737b1b11ee9a76572/watchdog-4.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d4925e4bf7b9bddd1c3de13c9b8a2cdb89a468f640e66fbfabaf735bd85b3e35", size = 101626 }, + { url = "https://files.pythonhosted.org/packages/84/52/2f3bbdbf02dbaf5d3a200668e41c7b474c3b6dc37fc06597901730f56f50/watchdog-4.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cad0bbd66cd59fc474b4a4376bc5ac3fc698723510cbb64091c2a793b18654db", size = 92463 }, + { url = "https://files.pythonhosted.org/packages/d5/94/62a6c6f53fee88ac8959ed418b45875fd649c63e09ed4c2afb08a3798b2a/watchdog-4.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a3c2c317a8fb53e5b3d25790553796105501a235343f5d2bf23bb8649c2c8709", size = 92953 }, + { url = "https://files.pythonhosted.org/packages/23/cd/c9eba46749e703476d65d6292d6f6de1be776315b9106f3fa42998ff6844/watchdog-4.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c9904904b6564d4ee8a1ed820db76185a3c96e05560c776c79a6ce5ab71888ba", size = 101625 }, + { url = "https://files.pythonhosted.org/packages/d4/4f/26652a5fdc0510e1c6c4a85b1dafc9e463c0db5bf74b166c0cd086e96b08/watchdog-4.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:667f3c579e813fcbad1b784db7a1aaa96524bed53437e119f6a2f5de4db04235", size = 92456 }, + { url = "https://files.pythonhosted.org/packages/cc/08/2d2460ccea7dd8a70a0096aec93d5f5dbb0305e5bbbf9c913d2d2360ac68/watchdog-4.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d10a681c9a1d5a77e75c48a3b8e1a9f2ae2928eda463e8d33660437705659682", size = 92955 }, + { url = "https://files.pythonhosted.org/packages/72/59/04de07819896f834fc35d031a8d840516ada8ac7b1cefccd62b0ed8f4fc9/watchdog-4.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0144c0ea9997b92615af1d94afc0c217e07ce2c14912c7b1a5731776329fcfc7", size = 91884 }, + { url = "https://files.pythonhosted.org/packages/45/17/3e3b159ed0b5d9456d34420c8d0262e8dd0d7bd92cbf83f811a4ee03ca9b/watchdog-4.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:998d2be6976a0ee3a81fb8e2777900c28641fb5bfbd0c84717d89bca0addcdc5", size = 92319 }, + { url = "https://files.pythonhosted.org/packages/59/1c/e6e24e713cbfd5b36a29b3f634617552f7b606509b53ec1f8ef97b20de94/watchdog-4.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e7921319fe4430b11278d924ef66d4daa469fafb1da679a2e48c935fa27af193", size = 91879 }, + { url = "https://files.pythonhosted.org/packages/1f/f1/e9199ba2a2617469daf40d89a938f488a381f406c64a92a4e1b7e53f7253/watchdog-4.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:f0de0f284248ab40188f23380b03b59126d1479cd59940f2a34f8852db710625", size = 92309 }, + { url = "https://files.pythonhosted.org/packages/3a/76/0c36f7097022470aa9fb9d090052970834f91e08b199c52791ca9772d156/watchdog-4.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bca36be5707e81b9e6ce3208d92d95540d4ca244c006b61511753583c81c70dd", size = 91877 }, + { url = "https://files.pythonhosted.org/packages/60/34/31d20941af7ddd1ebb13b5349d8e0bafee164f024a025152aa43c690b2c9/watchdog-4.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ab998f567ebdf6b1da7dc1e5accfaa7c6992244629c0fdaef062f43249bd8dee", size = 92317 }, + { url = "https://files.pythonhosted.org/packages/3a/36/28ce38b960f2bf1e1be573d85e8127c9ac66b4de63a7bef3f61b3f77ce57/watchdog-4.0.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:dddba7ca1c807045323b6af4ff80f5ddc4d654c8bce8317dde1bd96b128ed253", size = 83011 }, + { url = "https://files.pythonhosted.org/packages/05/7b/efc5b4134c97f08b161faa703327cde3fe647c5c48c156fde0c343471095/watchdog-4.0.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:4513ec234c68b14d4161440e07f995f231be21a09329051e67a2118a7a612d2d", size = 83009 }, + { url = "https://files.pythonhosted.org/packages/c3/bb/1fac328ba90ea091ef04e7bdefe638a933076530d802c1b1cf1f03fe7e89/watchdog-4.0.1-py3-none-manylinux2014_i686.whl", hash = "sha256:4107ac5ab936a63952dea2a46a734a23230aa2f6f9db1291bf171dac3ebd53c6", size = 83011 }, + { url = "https://files.pythonhosted.org/packages/ce/df/c8719022af772d9f75f1c49af453a48a785a45295bca1ce4f3f55b9923af/watchdog-4.0.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:6e8c70d2cd745daec2a08734d9f63092b793ad97612470a0ee4cbb8f5f705c57", size = 83012 }, + { url = "https://files.pythonhosted.org/packages/b0/d5/7285d52e7a7ffce2ae0b21a98dbbed345bcb227672a4268eb26d046d8d41/watchdog-4.0.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f27279d060e2ab24c0aa98363ff906d2386aa6c4dc2f1a374655d4e02a6c5e5e", size = 83011 }, + { url = "https://files.pythonhosted.org/packages/2a/09/4b07dc8dd1a9f67a7acfbc084f26fc35ee8a2e4feeb0a2c98fe9a1ef196c/watchdog-4.0.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:f8affdf3c0f0466e69f5b3917cdd042f89c8c63aebdb9f7c078996f607cdb0f5", size = 83009 }, + { url = "https://files.pythonhosted.org/packages/24/01/a4034a94a5f1828eb050230e7cf13af3ac23cf763512b6afe008d3def97c/watchdog-4.0.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ac7041b385f04c047fcc2951dc001671dee1b7e0615cde772e84b01fbf68ee84", size = 83012 }, + { url = "https://files.pythonhosted.org/packages/8f/5e/c0d7dad506adedd584188578901871fe923abf6c0c5dc9e79d9be5c7c24e/watchdog-4.0.1-py3-none-win32.whl", hash = "sha256:206afc3d964f9a233e6ad34618ec60b9837d0582b500b63687e34011e15bb429", size = 82996 }, + { url = "https://files.pythonhosted.org/packages/85/e0/2a9f43008902427b5f074c497705d6ef8f815c85d4bc25fbf83f720a6159/watchdog-4.0.1-py3-none-win_amd64.whl", hash = "sha256:7577b3c43e5909623149f76b099ac49a1a01ca4e167d1785c76eb52fa585745a", size = 83002 }, + { url = "https://files.pythonhosted.org/packages/db/54/23e5845ef68e1817b3792b2a11fb2088d7422814d41af8186d9058c4ff07/watchdog-4.0.1-py3-none-win_ia64.whl", hash = "sha256:d7b9f5f3299e8dd230880b6c55504a1f69cf1e4316275d1b215ebdd8187ec88d", size = 83002 }, +] + [[distribution]] name = "websocket-client" version = "1.8.0" From a1dbcfd62be9285037e3740eb9723b2f7999e4b4 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Mon, 8 Jul 2024 03:38:29 +0000 Subject: [PATCH 003/229] Revert "MADS: Honda Nidec: Fix enforce cruise cancel with stock PCM" --- selfdrive/car/honda/carstate.py | 2 +- selfdrive/car/honda/interface.py | 2 +- selfdrive/car/interfaces.py | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py index d412f81142..ae8746d958 100644 --- a/selfdrive/car/honda/carstate.py +++ b/selfdrive/car/honda/carstate.py @@ -242,7 +242,7 @@ class CarState(CarStateBase): ret.brakePressed = (cp.vl["POWERTRAIN_DATA"]["BRAKE_PRESSED"] != 0) or self.brake_switch_active ret.brake = cp.vl["VSA_STATUS"]["USER_BRAKE"] - ret.cruiseState.enabled = self.pcm_cruise_enabled = cp.vl["POWERTRAIN_DATA"]["ACC_STATUS"] != 0 + ret.cruiseState.enabled = cp.vl["POWERTRAIN_DATA"]["ACC_STATUS"] != 0 ret.cruiseState.available = bool(cp.vl[self.main_on_sig_msg]["MAIN_ON"]) # Gets rid of Pedal Grinding noise when brake is pressed at slow speeds for some models diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 1aba4d3119..457b095e6a 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -298,7 +298,7 @@ class CarInterface(CarInterfaceBase): if self.CP.pcmCruise and self.CP.minEnableSpeed > 0 and self.CP.pcmCruiseSpeed: if ret.gasPressed and not ret.cruiseState.enabled: self.CS.accEnabled = False - self.CS.accEnabled = self.CS.pcm_cruise_enabled + self.CS.accEnabled = ret.cruiseState.enabled or self.CS.accEnabled ret, self.CS = self.get_sp_common_state(ret, self.CS, min_enable_speed_pcm=(self.CP.pcmCruise and self.CP.minEnableSpeed > 0 and self.CP.pcmCruiseSpeed), diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 9c535244b8..a402a7797a 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -778,7 +778,6 @@ class CarStateBase(ABC): self.mads_enabled = False self.prev_mads_enabled = False self.control_initialized = False - self.pcm_cruise_enabled = False Q = [[0.0, 0.0], [0.0, 100.0]] R = 0.3 From 64a34f97aa70a88a875b7f50cf20f6bcb46c467a Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Mon, 8 Jul 2024 09:13:37 -0400 Subject: [PATCH 004/229] Revert "remove nav apt dependencies (#32792)" This reverts commit 9a084a73c5c3e6386bc5f21c46062d46878f6ca2. --- tools/install_ubuntu_dependencies.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/install_ubuntu_dependencies.sh b/tools/install_ubuntu_dependencies.sh index 4373760ce6..1fc0709095 100755 --- a/tools/install_ubuntu_dependencies.sh +++ b/tools/install_ubuntu_dependencies.sh @@ -55,7 +55,8 @@ function install_ubuntu_common_requirements() { portaudio19-dev \ qml-module-qtquick2 \ qtmultimedia5-dev \ - qtdeclarative5-dev \ + qtlocation5-dev \ + qtpositioning5-dev \ qttools5-dev-tools \ libqt5svg5-dev \ libqt5serialbus5-dev \ From 3c74ad145e0145429d782219ac255a26aa2f6135 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Mon, 8 Jul 2024 19:10:26 +0200 Subject: [PATCH 005/229] Processor definition check for __APPLE__ has a typo on replay (#32930) --- tools/replay/util.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/replay/util.cc b/tools/replay/util.cc index a08b3b3d5e..aaf73749d5 100644 --- a/tools/replay/util.cc +++ b/tools/replay/util.cc @@ -323,7 +323,7 @@ void precise_nano_sleep(int64_t nanoseconds, std::atomic &should_exit) { req.tv_sec = nanoseconds / 1000000000; req.tv_nsec = nanoseconds % 1000000000; while (!should_exit) { -#ifdef __APPLE_ +#ifdef __APPLE__ int ret = nanosleep(&req, &rem); if (ret == 0 || errno != EINTR) break; From 4a696984f12358b8cde3b32e932704fbd0f3b811 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 8 Jul 2024 10:58:08 -0700 Subject: [PATCH 006/229] [bot] Fingerprints: add missing FW versions from CAN fingerprinting cars (#32932) Export fingerprints --- selfdrive/car/hyundai/fingerprints.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index 8dbdbee0ef..c7e1418cb6 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -595,6 +595,7 @@ FW_VERSIONS = { b'\xf1\x00OS IEB \x02 210 \x02\x14 58520-K4000', b'\xf1\x00OS IEB \x02 212 \x11\x13 58520-K4000', b'\xf1\x00OS IEB \x03 210 \x02\x14 58520-K4000', + b'\xf1\x00OS IEB \x03 211 \x04\x02 58520-K4000', b'\xf1\x00OS IEB \x03 212 \x11\x13 58520-K4000', b'\xf1\x00OS IEB \r 105\x18\t\x18 58520-K4000', ], From 012eb07466ba7242a611dd57699fbbd1dd5f1d07 Mon Sep 17 00:00:00 2001 From: commaci-public <60409688+commaci-public@users.noreply.github.com> Date: Mon, 8 Jul 2024 12:10:53 -0700 Subject: [PATCH 007/229] [bot] Update Python packages and pre-commit hooks (#32931) Update Python packages and pre-commit hooks Co-authored-by: Vehicle Researcher --- .pre-commit-config.yaml | 2 +- uv.lock | 1537 +-------------------------------------- 2 files changed, 13 insertions(+), 1526 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 676fc514da..fd27ad4852 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,7 +33,7 @@ repos: - -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn - --builtins clear,rare,informal,usage,code,names,en-GB_to_en-US - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.0 + rev: v0.5.1 hooks: - id: ruff exclude: '^(third_party/)|(msgq/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)' diff --git a/uv.lock b/uv.lock index 8e7a039476..2797eee62f 100644 --- a/uv.lock +++ b/uv.lock @@ -14,21 +14,6 @@ dependencies = [ { name = "yarl" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/6b/baa5886a66dc4a9fe60df3fff543ac0cdbac3d18347889f17023b15bdceb/aiohttp-3.9.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7", size = 597148 }, - { url = "https://files.pythonhosted.org/packages/e7/3d/557ca9d4867e0e17f69694e514999c3de0a63c11964701600c9719171b97/aiohttp-3.9.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c", size = 400697 }, - { url = "https://files.pythonhosted.org/packages/a9/51/d95cab6dbee773c57ff590d218633e7b9d52a103bc51060483349f3c8e1e/aiohttp-3.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a", size = 389914 }, - { url = "https://files.pythonhosted.org/packages/ac/03/5da5d4b8e88d8af96f3b2f498141cafaad9acf3282831f0036993385b2d5/aiohttp-3.9.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430", size = 1238262 }, - { url = "https://files.pythonhosted.org/packages/7f/ee/0c83fd6ece4200145417da81565af7e7266b3a0591fbe32129b48187a472/aiohttp-3.9.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3", size = 1268632 }, - { url = "https://files.pythonhosted.org/packages/6e/05/36471e8cbcf4c56d4917fcbe0c2c6d68119ba6e83b66d7173f39ee0125b6/aiohttp-3.9.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b", size = 1304001 }, - { url = "https://files.pythonhosted.org/packages/a0/09/e7637f4f0760cad4d67347bbd8311c6ad0259a3fc01f04555af9e84bd378/aiohttp-3.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72", size = 1228434 }, - { url = "https://files.pythonhosted.org/packages/f4/46/c36596481a148014b0b6d4a62570baf5580aede5acc95901317b12cc3308/aiohttp-3.9.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0", size = 1201951 }, - { url = "https://files.pythonhosted.org/packages/db/fd/f390f2a538858c0ff5d74f11226d85956d6c52b16765cc485d4f7ba7d45d/aiohttp-3.9.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558", size = 1253651 }, - { url = "https://files.pythonhosted.org/packages/a3/5c/322ffd8b6bb4a49d399685c1fccecb0bd0f7487bfefeef202c4f4c478bd0/aiohttp-3.9.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db", size = 1209054 }, - { url = "https://files.pythonhosted.org/packages/77/4d/892098719e00bcf746a9fccc5f6854b1cfaf0d892de8ca5a646083eb12e2/aiohttp-3.9.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f", size = 1276895 }, - { url = "https://files.pythonhosted.org/packages/b8/e6/17062e803031c760bc452117f0789f36545355d287258889ccfe6f57cce8/aiohttp-3.9.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832", size = 1319624 }, - { url = "https://files.pythonhosted.org/packages/25/00/d3d4a9e23e4d810a345f8ca24550caec0aaca7307fd692e0b939746b1d78/aiohttp-3.9.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10", size = 1243253 }, - { url = "https://files.pythonhosted.org/packages/eb/cf/3b2dcbed86574b0264f9f964d1c27a120aa888a362d80cd3586de0616d1b/aiohttp-3.9.5-cp310-cp310-win32.whl", hash = "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb", size = 351398 }, - { url = "https://files.pythonhosted.org/packages/60/69/3febe2b4a12bc34721eb2ddb60b50d9e7fc8bdac98abb4019ffcd8032272/aiohttp-3.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb", size = 370706 }, { url = "https://files.pythonhosted.org/packages/67/f5/aa23d04a1bb57e5f51108a6473964a2618cc83e608e23e3543031aa2bb3a/aiohttp-3.9.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342", size = 599387 }, { url = "https://files.pythonhosted.org/packages/97/e7/575ca16871071313a7a7a03fa055f0c3d52f77eb8583b373ac17fc87ec15/aiohttp-3.9.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d", size = 402427 }, { url = "https://files.pythonhosted.org/packages/4e/78/266be6e31daad1a2dc99c777dfb12b62044691ec573b6e48409a0d804fc7/aiohttp-3.9.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424", size = 390243 }, @@ -59,36 +44,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5c/f1/f61b397a0eaf01d197e610b0f56935b0002d688f27d73af2882b282fc2f8/aiohttp-3.9.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da", size = 1319358 }, { url = "https://files.pythonhosted.org/packages/d1/5d/8cb20df780921adf9f436f214350729b12873742abd697c981229c554acc/aiohttp-3.9.5-cp312-cp312-win32.whl", hash = "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59", size = 347602 }, { url = "https://files.pythonhosted.org/packages/a0/00/cdbda8b406ce7b656b9cb765f8134b1edb999f816f54e47347d2bc67f4bf/aiohttp-3.9.5-cp312-cp312-win_amd64.whl", hash = "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888", size = 369012 }, - { url = "https://files.pythonhosted.org/packages/85/49/68a2da7fef9195b3fcfc27ebb469c06ebc2777546eb8311cdab4fe8c8aca/aiohttp-3.9.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8", size = 601191 }, - { url = "https://files.pythonhosted.org/packages/ed/aa/555091d9ad3e036a91922bfbf6d4fc9906e78b22d776c25150caa96cb387/aiohttp-3.9.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8", size = 402616 }, - { url = "https://files.pythonhosted.org/packages/69/37/ca379996ae72e7795d5b3f6bd13c0b24ad8641d11d02732606fd363b7bed/aiohttp-3.9.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78", size = 391927 }, - { url = "https://files.pythonhosted.org/packages/40/c7/331f8ef2cfa04592a0f397c451d32526778891fc5309646f6a2dbfa8b89a/aiohttp-3.9.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b", size = 1263175 }, - { url = "https://files.pythonhosted.org/packages/3a/af/efbb5c0d22f5c4656c5c19b7ef1495ef6b03aa3fb6def05a57e7e3f682e7/aiohttp-3.9.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de", size = 1315199 }, - { url = "https://files.pythonhosted.org/packages/50/31/da05d395ab732368795c01feb264e192b4e738597012d7d86a45df79640b/aiohttp-3.9.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac", size = 1349005 }, - { url = "https://files.pythonhosted.org/packages/bf/85/6166b71dc124cbca726f1d062218a61f2541d7c5192bef8c9b518b787132/aiohttp-3.9.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11", size = 1253582 }, - { url = "https://files.pythonhosted.org/packages/b7/14/61ab6b7427e252c3bc0ee94eeb06394c003cc295edf6558114e6e54ef882/aiohttp-3.9.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd", size = 1220512 }, - { url = "https://files.pythonhosted.org/packages/34/af/8d96e889d7d5f9e450545bad8694af66ef38afc0f28a77f058212d3662e2/aiohttp-3.9.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1", size = 1315483 }, - { url = "https://files.pythonhosted.org/packages/47/41/a1ace3e0d5b7dfd72ce7a30629e75afcb5e731291ed8b8aa717bc0e1b8c7/aiohttp-3.9.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e", size = 1265535 }, - { url = "https://files.pythonhosted.org/packages/6c/fc/9656ec8b3546cf0a74ba0d39d5e497fc7712b51c958ea2ec03ca28ed2a55/aiohttp-3.9.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156", size = 1344370 }, - { url = "https://files.pythonhosted.org/packages/74/ca/f55eac020a2c4df8607bf42ae0e31cddb93801406d2fd4d70b34a370fa23/aiohttp-3.9.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031", size = 1385354 }, - { url = "https://files.pythonhosted.org/packages/eb/41/a470f19879f861eb2183046493d57d0ae166ba432ef4b304ab3dd6843379/aiohttp-3.9.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe", size = 1305948 }, - { url = "https://files.pythonhosted.org/packages/53/c1/99c560b044c252cf47b71b5d7d33e9d38dc40d7a9a660579036b9d09f252/aiohttp-3.9.5-cp38-cp38-win32.whl", hash = "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da", size = 353271 }, - { url = "https://files.pythonhosted.org/packages/c5/2b/e7260c532ea3057dfdee64d84e9860ed1e84cf54b775ece475d560382d1f/aiohttp-3.9.5-cp38-cp38-win_amd64.whl", hash = "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a", size = 373122 }, - { url = "https://files.pythonhosted.org/packages/f9/9f/5ee4aaf09c95da6e71c9f0d5578449d5288ad4fdf225124c7b8124c6287a/aiohttp-3.9.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed", size = 598940 }, - { url = "https://files.pythonhosted.org/packages/74/21/6ef1ccb2bead0a5a5c9c198f56f0ef22781a759f8c0dbec067e6be947a87/aiohttp-3.9.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a", size = 401576 }, - { url = "https://files.pythonhosted.org/packages/4c/8f/04381aa090cffc3dbb6673935bdb4a7c7690d3bc40949d1e66fc136dac15/aiohttp-3.9.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372", size = 390716 }, - { url = "https://files.pythonhosted.org/packages/eb/45/eebe8d2215328434f33ccb44a05d2741ff7ed4b96b56ca507e2ecf598b73/aiohttp-3.9.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb", size = 1241694 }, - { url = "https://files.pythonhosted.org/packages/29/b0/e2728ce40ac9bd9e8998c5f1a36ff8273ada5c302607b720200607daff8b/aiohttp-3.9.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24", size = 1275633 }, - { url = "https://files.pythonhosted.org/packages/a4/76/bd2f2eae52e9e00002fcc0910428d2aabcd81edd420cb8dbc36adee99f0a/aiohttp-3.9.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2", size = 1310717 }, - { url = "https://files.pythonhosted.org/packages/94/4f/3c99f1cdab4fb55e12a914c80828f0958f04d79ef6b6ce1e05d07c30c46b/aiohttp-3.9.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106", size = 1231470 }, - { url = "https://files.pythonhosted.org/packages/46/46/dc7da6d44f66026649c6b66584b3d4362b4450a5eb1237b0f1853ac673d3/aiohttp-3.9.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b", size = 1204661 }, - { url = "https://files.pythonhosted.org/packages/3d/8d/d4ac343b9decf7458bf75020a76680163fef16c28dad4a5283084a90f06a/aiohttp-3.9.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475", size = 1254435 }, - { url = "https://files.pythonhosted.org/packages/fa/1f/f0ab436f8fed9373b8a0bc8f8aa735dd9d18f0a09df8228a4df07e0cd885/aiohttp-3.9.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed", size = 1214547 }, - { url = "https://files.pythonhosted.org/packages/32/0d/db026b8ddb76447fc0d0ff58f10819feaeb09900142c9042bdec73d409f2/aiohttp-3.9.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c", size = 1284779 }, - { url = "https://files.pythonhosted.org/packages/0a/ec/3c69a88382d0424150c109da8e85bc285b915fdbfdcaae2f72c6d430d479/aiohttp-3.9.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46", size = 1328392 }, - { url = "https://files.pythonhosted.org/packages/a0/6f/cdf328227c511dffdab5431807ee742342e489d5c984cf5a60f0ef142e28/aiohttp-3.9.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2", size = 1244976 }, - { url = "https://files.pythonhosted.org/packages/ea/54/9f0c6d42af5808b1b6dd011e9a25b219cc892a811a1067b9bc1d8ae6536d/aiohttp-3.9.5-cp39-cp39-win32.whl", hash = "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09", size = 352238 }, - { url = "https://files.pythonhosted.org/packages/e6/36/1480e47a31fe1424a991ca9e59609f37409ff74d7f891f47e096e0ac709c/aiohttp-3.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1", size = 371614 }, ] [[distribution]] @@ -127,24 +82,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/96/99/6672cf57777801c6ddacc13e1ee07f8c2151d0847a4f81455eeec998eaed/aiortc-1.9.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55505adb31d56cba19a1ef8ad6aa9b727ccdba2a83bfbfb4aa79ef3c472026a6", size = 1918600 }, { url = "https://files.pythonhosted.org/packages/76/e3/bdb76e7e51bc4fc7a5869597de2effad073ccf5ef14de3aed742d7384107/aiortc-1.9.0-cp38-abi3-win32.whl", hash = "sha256:680b703e35870e301535c930bfe32e7d012224a91ce51531aba45a3124ef07cc", size = 923055 }, { url = "https://files.pythonhosted.org/packages/6a/df/de098b31a3fbf1117f6d4cb84c14518636054e3c95a9d9f693a1123c95b3/aiortc-1.9.0-cp38-abi3-win_amd64.whl", hash = "sha256:de5e7020cfc2d2d9fb95690926ff2e3b3c30cd4f5f5bc68d5b6756a8eebb686e", size = 1009610 }, - { url = "https://files.pythonhosted.org/packages/95/26/c382db590897fe638254f948d8514772d13ff59b5ada0a71d87322f48c52/aiortc-1.9.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:34c516ae4e70e8f64494305057af09311444325722fe6938ec38dd1e111adca9", size = 1209093 }, - { url = "https://files.pythonhosted.org/packages/68/48/2fe7de04461fdc4aee8c78c67cfe03579eaa72fb215c4b063acaeb4fd118/aiortc-1.9.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:40e61c1b84914d6f4c2968ff49353a22eed9419de74b151237cdb71af431209c", size = 888818 }, - { url = "https://files.pythonhosted.org/packages/da/d5/94bf7ed6189c316ffef930787cba009387f9bcd2f1c482392b71cca3918d/aiortc-1.9.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1924e130a441507b1315956aff05c504a274f1a09802def225d0f3a3d1870320", size = 1732549 }, - { url = "https://files.pythonhosted.org/packages/e7/0a/6495c696cd7f806bafe511fb27203ce918947c4461398384a4e6bd4b7e57/aiortc-1.9.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbb62950e396c311e398925149fa76bc90b8d6525b4eccf28cba704e7ded8bf5", size = 1843911 }, - { url = "https://files.pythonhosted.org/packages/82/36/ffd0f74c73fa6abca0b76bd38473ed7d82dfbada7e57c6efe2a37ee40483/aiortc-1.9.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5234177e8d3126a0190ed9b6f8d0288daedcc0158c45cc279b4e6ac7d97f43f8", size = 1868240 }, - { url = "https://files.pythonhosted.org/packages/fb/46/8cb087a11f2f2d1139bd7e21615cc082097bffc4990d43c9f45f9cf6c8bf/aiortc-1.9.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0e31575eb050aa68e0ea4c519aef101770b2297954f49e64a5c3d73ef27702ea", size = 1004186 }, - { url = "https://files.pythonhosted.org/packages/13/3a/e93c51002274adb4010c2f8fb335ab0351a81358031d0ca46fe610f565c0/aiortc-1.9.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:33018ce36186142e8a5eccca53189ff30c6d48d3d4d0c3df952fbf80f59f17d7", size = 1209083 }, - { url = "https://files.pythonhosted.org/packages/13/b9/ee11cb88f2e152184e65ed152c5e2b4ab6c72d162651615d36eb5e43df91/aiortc-1.9.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:7d8cec50d8dcb1ea089378f885cb780357842ac39b7cb0e9361e5143c0126ecc", size = 888810 }, - { url = "https://files.pythonhosted.org/packages/21/33/bf6cd3694b691df645c33f8ebab9cc43a77afca7a0eb4f73c71902b12c7c/aiortc-1.9.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8f73ee2d738208c10bb9be8bd2dc0d7da7621de1bbd5ab709216dfa681f4585", size = 1732546 }, - { url = "https://files.pythonhosted.org/packages/74/47/3249bd5c123ff0acfe24942d5605ac951b84350f2d5c1752f7ffbf2e7ba6/aiortc-1.9.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84f16cb2a654d4e5018c8aba45e77882c75bf50c6af4eee3048ddb35af7f0c8f", size = 1843900 }, - { url = "https://files.pythonhosted.org/packages/f8/b9/dded75039b673ff63d35630a81a13f00f0d8b3393dd5f1a8585f9e537790/aiortc-1.9.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23df191d42b2937214263471a796502fcb8f86980e6b676aedbd188107e2a11d", size = 1868232 }, - { url = "https://files.pythonhosted.org/packages/0e/62/3fcc6f59f584dcefe7bf574ca7bfa75b0fee2e61d72f21aad34db1310dc6/aiortc-1.9.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:9e7bf1c892f7b0a474e85f7e2c462775dbb5a79d6bd6450cf0d0784804629020", size = 1004180 }, - { url = "https://files.pythonhosted.org/packages/4f/b1/1108b34967a876d92ae61f981e06e6d4aedc8bfd4a680f03dacdfca3de2c/aiortc-1.9.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bc9692a1b67f4eea8d3f22785b6ac9bc9c3d98478fd2326f99247ebf432b05d1", size = 1209084 }, - { url = "https://files.pythonhosted.org/packages/d1/cc/f22ec32865210bdc01ba704fbc5aeff2a61c02fa9ce77da2599d74cbf39e/aiortc-1.9.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:4d0321824d24e3db918d2e494d44f2bc4467c8abd70646bbd57a5a5a49b72583", size = 888806 }, - { url = "https://files.pythonhosted.org/packages/87/1b/5a89971655f71a83f60ddcd74a9d083733229a121a9506c53ab013eeeba7/aiortc-1.9.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7eeabe29472c9e3bb73fb58d5ad3b017269046d43189532e6ec64359c5697b8", size = 1732543 }, - { url = "https://files.pythonhosted.org/packages/86/6c/1d0b14b79117dbc855bce1445aec919f8ff3d7f30063cdfdc504395044de/aiortc-1.9.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c51f030e175569962df436d61953162da7a7c5e3d691adec660b5eee72dbba56", size = 1843906 }, - { url = "https://files.pythonhosted.org/packages/57/80/532757f4f332e396c0dcbc7fc98b34055b07442be83816ca088eae84b6ce/aiortc-1.9.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:928f136647e609eca0028f7aaf3812fff4e3a4e0fe78abdc19dd0786e65ffac8", size = 1868232 }, - { url = "https://files.pythonhosted.org/packages/63/fb/0311a31b42c88a2d3ece39c2448ac386d53ad1d8b47c1aac6d09d36cbcf9/aiortc-1.9.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1107acead0fa97e2f039d3cf00179a8b12b35822372b922f6b9f007145b171d3", size = 1004179 }, ] [[distribution]] @@ -183,12 +120,6 @@ version = "12.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/9e/e2/1c5708feb7ceb46c8ab9d2e3fbd451a725f0741d7c5336020d13be527490/av-12.2.0.tar.gz", hash = "sha256:460670325bbd64b7a6774b6bda05985cbe4582d111f81993bfbb08058f8c0484", size = 3828627 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/67/ec907d4915c1e5cf23d601795a9c7488de8590bcef6343d0779ffea47d76/av-12.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b05248d522b846338d149d887ac299e877f6a01b489b49385ca4790ea03be5fe", size = 26063168 }, - { url = "https://files.pythonhosted.org/packages/ac/23/bbb1841eefd2941a5d05014daa60245ccf299973fd1b98af8bb71ce285a8/av-12.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f1b30c26baf3e000bb5942d97c2d85ea692d8dd8847ba88fd43065ef5de71a3c", size = 20878898 }, - { url = "https://files.pythonhosted.org/packages/da/e7/aca1ea2425ca63efaca4b509f295ef6fc67e92193f241c069b895cc88eb9/av-12.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2df91ca71fbb1ad9823a843acf6c90ff00599520dbbd3fcc44cf267e8bdbd51e", size = 32370078 }, - { url = "https://files.pythonhosted.org/packages/f8/e2/8381c10a21256fa1cce982411175e2bbb4ac17f9310915a5c9c6146f5a1a/av-12.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5165110107765c70572e8c68bca39b1f495ea34e0aed5635ee5b3badd87f3699", size = 31959525 }, - { url = "https://files.pythonhosted.org/packages/e1/62/276f883854621c3675c6a98a0522626cf0159d8608b68becc87891192530/av-12.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8eeff2e5872a0310d6061d0faa5c378c71f8b664924329c05c8a0de9ae700124", size = 34284050 }, - { url = "https://files.pythonhosted.org/packages/81/26/9ff3ca88377bfb3f2f50b2fad06747bcc9530134a111c90cfa866152767c/av-12.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:bceba179304744998a011c3fd8530091e75037f9665dbb59a0dd1d2dd42c794b", size = 26825920 }, { url = "https://files.pythonhosted.org/packages/73/08/41200974e40a803da6d008cab7a801d187f950d92efa71182680b419a99a/av-12.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f74c9987798d45302b86e94b3bdb6009e9a509c57971b5599aae4353f5b8c5c0", size = 26057398 }, { url = "https://files.pythonhosted.org/packages/10/94/d4383c50b1a819e0edb43637d6cb03086b1fcc563e9c07fc0eb2840c4e2d/av-12.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7d17e4110efe449842d12bc11166141b5ca08ce821b7529f02ed9dc3b73c9291", size = 20871004 }, { url = "https://files.pythonhosted.org/packages/b8/eb/82b86e8f763dd104a75478a02228465715984e0fe91ae6c7567093bf75a2/av-12.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a7cc709c0c231f282f1b26a76b42d63100a8bc088522cfd06c500ed4b6c660c", size = 33310123 }, @@ -201,36 +132,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/28/fe/8b7ec1008f42942f0cb0db1f700bc4d1e862018677c32f4d47331202302e/av-12.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbe1ace6ebaae1de41f3b0412367eec42188a381fae83669d4b18e1340648839", size = 33060022 }, { url = "https://files.pythonhosted.org/packages/ea/aa/2e74958ebb9dde8b33940fedd7ead406bd52760589cd7bcd9c19dbac3163/av-12.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8280def29f209ce294b0aa5045a66c1027b8ba2ba5b82e1f66e8a910ff1c1120", size = 35549894 }, { url = "https://files.pythonhosted.org/packages/38/cc/437ca48e268120abab9634775d0befecee7ed54327c4df2573f2cf9f9d51/av-12.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:6740ae90ffd7fe6e7439beab6494c966cd46739943d3046ea01021d4bc2b36e6", size = 26829453 }, - { url = "https://files.pythonhosted.org/packages/46/70/20437408a1b80adae3de234f926915d266ab21634ee02f7823d1c2211793/av-12.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7f7248e1d75cf2a154146eae48b8aa18d4b2b4ae5e19d97148a7e494581f7d30", size = 26102022 }, - { url = "https://files.pythonhosted.org/packages/e9/fa/f8b5de56a2693e9f9e44c1caccea6e9b12fb477486253a7e616ff07180a0/av-12.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:dfcd81555b60ab2868cc4e6ef2f0e5d6d0cee13ebe2d5be37d0fd7f10c4c7fc4", size = 20914623 }, - { url = "https://files.pythonhosted.org/packages/3a/42/8d81bddf28d3e208ebd1a827a8039bd2de45288e9c0170409c0be3f7cf15/av-12.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a3e4241f28e125d1a3b3496a0b4e26b8890c71b5e03081bbf3649a34bb9448e", size = 32566194 }, - { url = "https://files.pythonhosted.org/packages/ce/bf/90eab4ebf22d577d7e6c91a1cecf811ea50994dfcd00d0d4f61daaf52e85/av-12.2.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99f2bfa082199e758bf4daea993c134a9109710c92e8f19cd644716577f1171b", size = 32156616 }, - { url = "https://files.pythonhosted.org/packages/e6/16/9a6531f58ca2a23f00d9d2f3447e16df7ca7e052bf7d5141c0c12677bd34/av-12.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0da53f16d7cf936bd631eb91afcf54f092484e08afe7e2bf492afafdf133472", size = 34482095 }, - { url = "https://files.pythonhosted.org/packages/e7/41/6b04e3f9e8742eb81de4908e1ad3a7613a4638200168decfca82ea3e439c/av-12.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:92a7541ade9bd562b598cc6ec17745dff2b4697a7e88bb47e51d22a248f610cb", size = 26860958 }, - { url = "https://files.pythonhosted.org/packages/2d/15/a9d63917ab40f2e15db9d406e9051d41c259e732de1c08b37dc09635d3e0/av-12.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0f61b1d8335c065ba7f03f0bd95f35bef35317a0073a5ded21663f6c664b8127", size = 26091405 }, - { url = "https://files.pythonhosted.org/packages/7c/06/ea2b1e9aed0d08d313b7bc60bfe2dbce914fbe8ef8a300902965fca12346/av-12.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9d88a567f17614605613d9905952baa4281988591a76fd270dc0a54eec6595c7", size = 20904472 }, - { url = "https://files.pythonhosted.org/packages/b5/cb/1d3b07a0ad97d2dd6f260416fd892ff4b5c4570e592b1bc2eeb4beee6f93/av-12.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c263791697a5a60798a67fda10f4ba5f81dc9b541595f82bfdcc2566ee866e32", size = 32509401 }, - { url = "https://files.pythonhosted.org/packages/0d/43/6092305e4f7854969bd3bedfc9750281c42da1ab75d38417ef150dcf87a7/av-12.2.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c9553e2a537d89123589f2b16b82e491968774c5426a11bb95762cd6a0aa384", size = 32091695 }, - { url = "https://files.pythonhosted.org/packages/11/19/61b26e4be23d7db45a40c544d26471876dccf78e03df51b02e29e3db7a28/av-12.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52e31bc61d1036be12400a35f8fd73fe274ef013f3e183e63a6a3786069b26bc", size = 34423395 }, - { url = "https://files.pythonhosted.org/packages/64/ed/7d2cf42dc20c297efd8e2823b4c2c04b112b7a3a66995e73b22a2c22b131/av-12.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:f69b455952d26909cd350dba5967d2e1c2a3c6fa3129e04308fdc59c18e0a6dd", size = 26848471 }, - { url = "https://files.pythonhosted.org/packages/34/b4/0b9c3e396043114400a73b189007c033c67567125883de5922419ab9a3f9/av-12.2.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8a8184c226d887c5fe8512b93ae10838faeca4ee044a61ab4f2bbd69c29c16f1", size = 25642128 }, - { url = "https://files.pythonhosted.org/packages/a2/83/bdce90a2b90e05736a7408c90a07a168179969e7b277eeaa99b28a1b2001/av-12.2.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:42b0e6fe67a449dd78d1e81dda177c0e1985cd76f539e46e819607b68c0a72f3", size = 20524662 }, - { url = "https://files.pythonhosted.org/packages/5e/bd/5f50ddcc7d53a16c5dda4cebef80f65b3f8cec10c99e574dba6edcd49fd3/av-12.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac681467309d292ac0e2364210861875167badfb2b567eb98a9bb5d6ba3d3438", size = 24116630 }, - { url = "https://files.pythonhosted.org/packages/07/04/b620547c756e9186ebe6634526aefe598cf96423731275f3b03a6392917a/av-12.2.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1d8264a2096a84a5b23f0e43f25d4f976f34b6af2939d29c7334bd50f043eb8", size = 24130324 }, - { url = "https://files.pythonhosted.org/packages/c7/78/f2b835610829f752faace09b0d5d330919e3f7ec5ce2e32759aa1dd22f07/av-12.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc78da95e8fd83ff113467807883cef039506ef4fb1a31106cf8ac056dfa9a3f", size = 26009671 }, - { url = "https://files.pythonhosted.org/packages/26/6f/f062c08aa3cc9ce58a9358282d89f6675a7e9b5d4f20fe1206172fb0fb3e/av-12.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0586a5ed90ce4d010fc9884d3e2bac869cb4e0ee85a3ac1e26d5d01280446d87", size = 26611514 }, - { url = "https://files.pythonhosted.org/packages/c8/fe/938460839515ba86c150786ce4208923ff85b139cb516fed8f2051a5e2ab/av-12.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1cd41871196411c1290780f995b427a0dbfbc15ce7c53a729860beb4a29e77d6", size = 25624846 }, - { url = "https://files.pythonhosted.org/packages/22/77/5b8693fc1ea1f2af88f55490f0dbfa8b734e6ce349c568d54b106c878af2/av-12.2.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b4d098eb97c5bcd2d8a8fe4d3ed8b2f33e8a0936372713185b5958831152329c", size = 20493072 }, - { url = "https://files.pythonhosted.org/packages/e5/89/a50addda752a1788c8f713479682c39f468c13e3b593ca82a602a045fb35/av-12.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df2f3620d5ae95f06417a046673d8b3d31f21f38b8ba038c7fc5cbc0e33a158a", size = 24103031 }, - { url = "https://files.pythonhosted.org/packages/75/6b/f3f3885916cb7d38f3104cc91c838f165dbe877ca9fb59b448637e18764a/av-12.2.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfcb66943386175d92700e459cb3295a1cf2c6ef033b83b43b42d904f3839834", size = 24108933 }, - { url = "https://files.pythonhosted.org/packages/1f/0d/af48abbe79d603f06b08d7505e473bf2fd0eed75c55836a4d6c83afd57f4/av-12.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d604718802b1c9644808f5f172d1cf1e45e9769ee7e5710de0afbc9f9f512f08", size = 25993428 }, - { url = "https://files.pythonhosted.org/packages/d0/08/e7d1913356d049478e38acc83b7d669e8eb462519bcb3ca293b00c73d9f0/av-12.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3b49726898439583cf7805fc78563ee491a700ab79f5aae4297da03d5f9ffa62", size = 26598698 }, - { url = "https://files.pythonhosted.org/packages/18/b7/6b691974597973fb2c51ac699ae73b2e0829972f7e8af190ee7f24cfe79c/av-12.2.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8eb2428d56cb5e690b4014e9c39fe8c9fbb909bb5585132327b8c467d1a59c72", size = 25638470 }, - { url = "https://files.pythonhosted.org/packages/29/b4/488c3c8c65693ef53b537347fff8693c4c995f34b9f9fd2bb8041fb19582/av-12.2.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:01eebcdfc9b98cec21d36e43e38fb34f970eec66b47fdec88cd434e1b8e69883", size = 20520781 }, - { url = "https://files.pythonhosted.org/packages/6f/5a/e50667063bb4d9058d2723a369fe30741eb682005c5d523fe19fb5747d8e/av-12.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d913fa71dbb9436798ffbbfedec62db12f50c8483311dfcd9b76ffaaf7383955", size = 24112011 }, - { url = "https://files.pythonhosted.org/packages/1b/d1/2f989e4d482993e0d427a98e881ac7c0499a9e04e816fcadc4394b57f92a/av-12.2.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9995c36a31102901f67f11306af3e972ea2b6290296fd35a6334ea0325bf20", size = 24124904 }, - { url = "https://files.pythonhosted.org/packages/4c/23/8285c82e19531895950a763f862d04bff178ad0f24b4a20762d9cd27b327/av-12.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29c835f4bb89cbb80571ab1e18ad344c4642148626dd133d27a95dbd1e94637b", size = 26005271 }, - { url = "https://files.pythonhosted.org/packages/f2/6b/4e98b6040f33ea63be04c02c90a3da698a523eac70713508c64039fb9e12/av-12.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:909ddd39a9c08d5599560b95bdf610043bc66e9c2943c8230de62c0cc9ac8152", size = 26610683 }, ] [[distribution]] @@ -376,17 +277,6 @@ dependencies = [ { name = "pycparser" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/aa/1c43e48a6f361d1529f9e4602d6992659a0107b5f21cae567e2eddcf8d66/cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", size = 182457 }, - { url = "https://files.pythonhosted.org/packages/c4/01/f5116266fe80c04d4d1cc96c3d355606943f9fb604a810e0b02228a0ce19/cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", size = 176792 }, - { url = "https://files.pythonhosted.org/packages/57/3a/c263cf4d5b02880274866968fa2bf196a02c4486248bc164732319b4a4c0/cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", size = 423848 }, - { url = "https://files.pythonhosted.org/packages/f0/31/a6503a5c4874fb4d4c2053f73f09a957cb427b6943fab5a43b8e156df397/cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", size = 446005 }, - { url = "https://files.pythonhosted.org/packages/22/05/43cfda378da7bb0aa19b3cf34fe54f8867b0d581294216339d87deefd69c/cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", size = 452639 }, - { url = "https://files.pythonhosted.org/packages/54/49/b8875986beef2e74fc668b95f2df010e354f78e009d33d95b375912810c3/cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", size = 434140 }, - { url = "https://files.pythonhosted.org/packages/c9/7c/43d81bdd5a915923c3bad5bb4bff401ea00ccc8e28433fb6083d2e3bf58e/cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", size = 443865 }, - { url = "https://files.pythonhosted.org/packages/eb/de/4f644fc78a1144a897e1f908abfb2058f7be05a8e8e4fe90b7f41e9de36b/cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", size = 436867 }, - { url = "https://files.pythonhosted.org/packages/ee/68/74a2b9f9432b70d97d1184cdabf32d7803124c228adef9481d280864a4a7/cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", size = 465830 }, - { url = "https://files.pythonhosted.org/packages/20/18/76e26bcfa6a7a62f880791122261575b3048ac57dd72f300ba0827629ab8/cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", size = 172955 }, - { url = "https://files.pythonhosted.org/packages/be/3e/0b197d1bfbf386a90786b251dbf2634a15f2ea3d4e4070e99c7d1c7689cf/cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", size = 181616 }, { url = "https://files.pythonhosted.org/packages/95/c8/ce05a6cba2bec12d4b28285e66c53cc88dd7385b102dea7231da3b74cfef/cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", size = 182415 }, { url = "https://files.pythonhosted.org/packages/18/6c/0406611f3d5aadf4c5b08f6c095d874aed8dfc2d3a19892707d72536d5dc/cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", size = 176745 }, { url = "https://files.pythonhosted.org/packages/58/ac/2a3ea436a6cbaa8f75ddcab39010e5e0817a18f26fef5d2fe2e0c7df3425/cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", size = 443787 }, @@ -408,25 +298,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4c/00/e17e2a8df0ff5aca2edd9eeebd93e095dd2515f2dd8d591d84a3233518f6/cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", size = 487099 }, { url = "https://files.pythonhosted.org/packages/c9/6e/751437067affe7ac0944b1ad4856ec11650da77f0dd8f305fae1117ef7bb/cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", size = 173564 }, { url = "https://files.pythonhosted.org/packages/e9/63/e285470a4880a4f36edabe4810057bd4b562c6ddcc165eacf9c3c7210b40/cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", size = 181956 }, - { url = "https://files.pythonhosted.org/packages/39/44/4381b8d26e9cfa3e220e3c5386f443a10c6313a6ade7acb314b2bcc0a6ce/cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", size = 182122 }, - { url = "https://files.pythonhosted.org/packages/7f/5a/39e212f99aa73660a1c523f6b7ddeb4e26f906faaa5088e97b617a89c7ae/cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", size = 423842 }, - { url = "https://files.pythonhosted.org/packages/8b/5c/7f9cd1fb80512c9e16c90b29b26fea52977e9ab268321f64b42f4c8488a3/cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", size = 446183 }, - { url = "https://files.pythonhosted.org/packages/f9/6c/af5f40c66aac38aa70abfa6f26e8296947a79ef373cb81a14c791c3da91d/cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", size = 452938 }, - { url = "https://files.pythonhosted.org/packages/85/3e/a4e4857c2aae635195459679ac9daea296630c1d76351259eb3de3c18ed0/cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", size = 434495 }, - { url = "https://files.pythonhosted.org/packages/f1/c9/326611aa83e16b13b6db4dbb73b5455c668159a003c4c2f0c3bcb2ddabaf/cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", size = 444654 }, - { url = "https://files.pythonhosted.org/packages/40/c9/cfba735d9ed117471e32d7bce435dd49721261ae294277c64aa929ec9c9d/cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", size = 172767 }, - { url = "https://files.pythonhosted.org/packages/4a/56/572f7f728b20e4d51766e63d7de811e45c7cae727dc1f769caad2973fb52/cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", size = 181358 }, - { url = "https://files.pythonhosted.org/packages/9d/da/e6dbf22b66899419e66c501ae5f1cf3d69979d4c75ad30da683f60abba94/cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", size = 182457 }, - { url = "https://files.pythonhosted.org/packages/20/3b/f95e667064141843843df8ca79dd49ba57bb7a7615d6d7d538531e45f002/cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", size = 176810 }, - { url = "https://files.pythonhosted.org/packages/33/14/8398798ab001523f1abb2b4170a01bf2114588f3f1fa1f984b3f3bef107e/cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", size = 422712 }, - { url = "https://files.pythonhosted.org/packages/50/bd/17a8f9ac569d328de304e7318d7707fcdb6f028bcc194d80cfc654902007/cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", size = 444981 }, - { url = "https://files.pythonhosted.org/packages/69/46/8882b0405be4ac7db3fefa5a201f221acb54f27c76e584e23e9c62b68819/cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", size = 451612 }, - { url = "https://files.pythonhosted.org/packages/ae/00/831d01e63288d1654ed3084a6ac8b0940de6dc0ada4ba71b830fff7a0088/cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", size = 433351 }, - { url = "https://files.pythonhosted.org/packages/ea/ac/e9e77bc385729035143e54cc8c4785bd480eaca9df17565963556b0b7a93/cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", size = 443366 }, - { url = "https://files.pythonhosted.org/packages/20/f8/5931cfb7a8cc15d224099cead5e5432efe729bd61abce72d9b3e51e5800b/cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", size = 435991 }, - { url = "https://files.pythonhosted.org/packages/8c/54/82aa3c014760d5a6ddfde3253602f0ac1937dd504621d4139746f230a7b5/cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", size = 465264 }, - { url = "https://files.pythonhosted.org/packages/04/a2/55f290ac034bd98c2a63e83be96925729cb2a70c8c42adc391ec5fbbaffd/cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", size = 172894 }, - { url = "https://files.pythonhosted.org/packages/73/dd/15c6f32166f0c8f97d8aadee9ac8f096557899f4f21448d2feb74cf4f210/cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", size = 181630 }, ] [[distribution]] @@ -444,21 +315,6 @@ version = "3.3.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/63/09/c1bc53dab74b1816a00d8d030de5bf98f724c52c1635e07681d312f20be8/charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", size = 104809 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/61/095a0aa1a84d1481998b534177c8566fdc50bb1233ea9a0478cd3cc075bd/charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", size = 194219 }, - { url = "https://files.pythonhosted.org/packages/cc/94/f7cf5e5134175de79ad2059edf2adce18e0685ebdb9227ff0139975d0e93/charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", size = 122521 }, - { url = "https://files.pythonhosted.org/packages/46/6a/d5c26c41c49b546860cc1acabdddf48b0b3fb2685f4f5617ac59261b44ae/charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", size = 120383 }, - { url = "https://files.pythonhosted.org/packages/b8/60/e2f67915a51be59d4539ed189eb0a2b0d292bf79270410746becb32bc2c3/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", size = 138223 }, - { url = "https://files.pythonhosted.org/packages/05/8c/eb854996d5fef5e4f33ad56927ad053d04dc820e4a3d39023f35cad72617/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", size = 148101 }, - { url = "https://files.pythonhosted.org/packages/f6/93/bb6cbeec3bf9da9b2eba458c15966658d1daa8b982c642f81c93ad9b40e1/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", size = 140699 }, - { url = "https://files.pythonhosted.org/packages/da/f1/3702ba2a7470666a62fd81c58a4c40be00670e5006a67f4d626e57f013ae/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", size = 142065 }, - { url = "https://files.pythonhosted.org/packages/3f/ba/3f5e7be00b215fa10e13d64b1f6237eb6ebea66676a41b2bcdd09fe74323/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", size = 144505 }, - { url = "https://files.pythonhosted.org/packages/33/c3/3b96a435c5109dd5b6adc8a59ba1d678b302a97938f032e3770cc84cd354/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", size = 139425 }, - { url = "https://files.pythonhosted.org/packages/43/05/3bf613e719efe68fb3a77f9c536a389f35b95d75424b96b426a47a45ef1d/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", size = 145287 }, - { url = "https://files.pythonhosted.org/packages/58/78/a0bc646900994df12e07b4ae5c713f2b3e5998f58b9d3720cce2aa45652f/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", size = 149929 }, - { url = "https://files.pythonhosted.org/packages/eb/5c/97d97248af4920bc68687d9c3b3c0f47c910e21a8ff80af4565a576bd2f0/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", size = 141605 }, - { url = "https://files.pythonhosted.org/packages/a8/31/47d018ef89f95b8aded95c589a77c072c55e94b50a41aa99c0a2008a45a4/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", size = 142646 }, - { url = "https://files.pythonhosted.org/packages/ae/d5/4fecf1d58bedb1340a50f165ba1c7ddc0400252d6832ff619c4568b36cc0/charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", size = 92846 }, - { url = "https://files.pythonhosted.org/packages/a2/a0/4af29e22cb5942488cf45630cbdd7cefd908768e69bdd90280842e4e8529/charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", size = 100343 }, { url = "https://files.pythonhosted.org/packages/68/77/02839016f6fbbf808e8b38601df6e0e66c17bbab76dff4613f7511413597/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", size = 191647 }, { url = "https://files.pythonhosted.org/packages/3e/33/21a875a61057165e92227466e54ee076b73af1e21fe1b31f1e292251aa1e/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", size = 121434 }, { url = "https://files.pythonhosted.org/packages/dd/51/68b61b90b24ca35495956b718f35a9756ef7d3dd4b3c1508056fa98d1a1b/charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", size = 118979 }, @@ -489,49 +345,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/ae/ce2c12fcac59cb3860b2e2d76dc405253a4475436b1861d95fe75bdea520/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", size = 142167 }, { url = "https://files.pythonhosted.org/packages/ed/3a/a448bf035dce5da359daf9ae8a16b8a39623cc395a2ffb1620aa1bce62b0/charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", size = 93041 }, { url = "https://files.pythonhosted.org/packages/b6/7c/8debebb4f90174074b827c63242c23851bdf00a532489fba57fef3416e40/charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", size = 100397 }, - { url = "https://files.pythonhosted.org/packages/4f/d1/d547cc26acdb0cc458b152f79b2679d7422f29d41581e6fa907861e88af1/charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c", size = 118254 }, - { url = "https://files.pythonhosted.org/packages/f6/d3/bfc699ab2c4f9245867060744e8136d359412ff1e5ad93be38a46d160f9d/charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5", size = 133657 }, - { url = "https://files.pythonhosted.org/packages/58/a2/0c63d5d7ffac3104b86631b7f2690058c97bf72d3145c0a9cd4fb90c58c2/charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985", size = 142965 }, - { url = "https://files.pythonhosted.org/packages/2e/37/9223632af0872c86d8b851787f0edd3fe66be4a5378f51242b25212f8374/charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6", size = 136078 }, - { url = "https://files.pythonhosted.org/packages/c9/7a/6d8767fac16f2c80c7fa9f14e0f53d4638271635c306921844dc0b5fd8a6/charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714", size = 136822 }, - { url = "https://files.pythonhosted.org/packages/b2/62/5a5dcb9a71390a9511a253bde19c9c89e0b20118e41080185ea69fb2c209/charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786", size = 139545 }, - { url = "https://files.pythonhosted.org/packages/f2/0e/e06bc07ef4673e4d24dc461333c254586bb759fdd075031539bab6514d07/charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5", size = 134128 }, - { url = "https://files.pythonhosted.org/packages/8d/b7/9e95102e9a8cce6654b85770794b582dda2921ec1fd924c10fbcf215ad31/charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c", size = 140017 }, - { url = "https://files.pythonhosted.org/packages/13/f8/eefae0629fa9260f83b826ee3363e311bb03cfdd518dad1bd10d57cb2d84/charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8", size = 144367 }, - { url = "https://files.pythonhosted.org/packages/91/95/e2cfa7ce962e6c4b59a44a6e19e541c3a0317e543f0e0923f844e8d7d21d/charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711", size = 136883 }, - { url = "https://files.pythonhosted.org/packages/a0/b1/4e72ef73d68ebdd4748f2df97130e8428c4625785f2b6ece31f555590c2d/charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811", size = 136977 }, - { url = "https://files.pythonhosted.org/packages/c8/ce/09d6845504246d95c7443b8c17d0d3911ec5fdc838c3213e16c5e47dee44/charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4", size = 91300 }, - { url = "https://files.pythonhosted.org/packages/96/fc/0cae31c0f150cd1205a2a208079de865f69a8fd052a98856c40c99e36b3c/charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99", size = 98127 }, - { url = "https://files.pythonhosted.org/packages/ef/d4/a1d72a8f6aa754fdebe91b848912025d30ab7dced61e9ed8aabbf791ed65/charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a", size = 191415 }, - { url = "https://files.pythonhosted.org/packages/13/82/83c188028b6f38d39538442dd127dc794c602ae6d45d66c469f4063a4c30/charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac", size = 121051 }, - { url = "https://files.pythonhosted.org/packages/16/ea/a9e284aa38cccea06b7056d4cbc7adf37670b1f8a668a312864abf1ff7c6/charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a", size = 119143 }, - { url = "https://files.pythonhosted.org/packages/34/2a/f392457d45e24a0c9bfc012887ed4f3c54bf5d4d05a5deb970ffec4b7fc0/charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33", size = 137506 }, - { url = "https://files.pythonhosted.org/packages/be/4d/9e370f8281cec2fcc9452c4d1ac513324c32957c5f70c73dd2fa8442a21a/charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238", size = 147272 }, - { url = "https://files.pythonhosted.org/packages/33/95/ef68482e4a6adf781fae8d183fb48d6f2be8facb414f49c90ba6a5149cd1/charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a", size = 139734 }, - { url = "https://files.pythonhosted.org/packages/3d/09/d82fe4a34c5f0585f9ea1df090e2a71eb9bb1e469723053e1ee9f57c16f3/charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2", size = 141094 }, - { url = "https://files.pythonhosted.org/packages/81/b2/160893421adfa3c45554fb418e321ed342bb10c0a4549e855b2b2a3699cb/charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8", size = 144113 }, - { url = "https://files.pythonhosted.org/packages/9e/ef/cd47a63d3200b232792e361cd67530173a09eb011813478b1c0fb8aa7226/charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898", size = 138555 }, - { url = "https://files.pythonhosted.org/packages/a8/6f/4ff299b97da2ed6358154b6eb3a2db67da2ae204e53d205aacb18a7e4f34/charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99", size = 144944 }, - { url = "https://files.pythonhosted.org/packages/d1/2f/0d1efd07c74c52b6886c32a3b906fb8afd2fecf448650e73ecb90a5a27f1/charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d", size = 148925 }, - { url = "https://files.pythonhosted.org/packages/bd/28/7ea29e73eea52c7e15b4b9108d0743fc9e4cc2cdb00d275af1df3d46d360/charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04", size = 140732 }, - { url = "https://files.pythonhosted.org/packages/b3/c1/ebca8e87c714a6a561cfee063f0655f742e54b8ae6e78151f60ba8708b3a/charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087", size = 141288 }, - { url = "https://files.pythonhosted.org/packages/74/20/8923a06f15eb3d7f6a306729360bd58f9ead1dc39bc7ea8831f4b407e4ae/charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25", size = 92373 }, - { url = "https://files.pythonhosted.org/packages/db/fb/d29e343e7c57bbf1231275939f6e75eb740cd47a9d7cb2c52ffeb62ef869/charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b", size = 99577 }, - { url = "https://files.pythonhosted.org/packages/f7/9d/bcf4a449a438ed6f19790eee543a86a740c77508fbc5ddab210ab3ba3a9a/charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4", size = 194198 }, - { url = "https://files.pythonhosted.org/packages/66/fe/c7d3da40a66a6bf2920cce0f436fa1f62ee28aaf92f412f0bf3b84c8ad6c/charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d", size = 122494 }, - { url = "https://files.pythonhosted.org/packages/2a/9d/a6d15bd1e3e2914af5955c8eb15f4071997e7078419328fee93dfd497eb7/charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0", size = 120393 }, - { url = "https://files.pythonhosted.org/packages/3d/85/5b7416b349609d20611a64718bed383b9251b5a601044550f0c8983b8900/charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269", size = 138331 }, - { url = "https://files.pythonhosted.org/packages/79/66/8946baa705c588521afe10b2d7967300e49380ded089a62d38537264aece/charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c", size = 148097 }, - { url = "https://files.pythonhosted.org/packages/44/80/b339237b4ce635b4af1c73742459eee5f97201bd92b2371c53e11958392e/charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519", size = 140711 }, - { url = "https://files.pythonhosted.org/packages/98/69/5d8751b4b670d623aa7a47bef061d69c279e9f922f6705147983aa76c3ce/charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796", size = 142251 }, - { url = "https://files.pythonhosted.org/packages/1f/8d/33c860a7032da5b93382cbe2873261f81467e7b37f4ed91e25fed62fd49b/charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185", size = 144636 }, - { url = "https://files.pythonhosted.org/packages/c2/65/52aaf47b3dd616c11a19b1052ce7fa6321250a7a0b975f48d8c366733b9f/charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c", size = 139514 }, - { url = "https://files.pythonhosted.org/packages/51/fd/0ee5b1c2860bb3c60236d05b6e4ac240cf702b67471138571dad91bcfed8/charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458", size = 145528 }, - { url = "https://files.pythonhosted.org/packages/e1/9c/60729bf15dc82e3aaf5f71e81686e42e50715a1399770bcde1a9e43d09db/charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2", size = 149804 }, - { url = "https://files.pythonhosted.org/packages/53/cd/aa4b8a4d82eeceb872f83237b2d27e43e637cac9ffaef19a1321c3bafb67/charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8", size = 141708 }, - { url = "https://files.pythonhosted.org/packages/54/7f/cad0b328759630814fcf9d804bfabaf47776816ad4ef2e9938b7e1123d04/charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561", size = 142708 }, - { url = "https://files.pythonhosted.org/packages/c1/9d/254a2f1bcb0ce9acad838e94ed05ba71a7cb1e27affaa4d9e1ca3958cdb6/charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f", size = 92830 }, - { url = "https://files.pythonhosted.org/packages/2f/0e/d7303ccae9735ff8ff01e36705ad6233ad2002962e8668a970fc000c5e1b/charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d", size = 100376 }, { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, ] @@ -586,16 +399,6 @@ dependencies = [ { name = "numpy" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/64/2a/e389ad2e209db9f9db59598fabd5f4b515eccabef4df71d07c0b77c1b2d7/contourpy-1.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bd7c23df857d488f418439686d3b10ae2fbf9bc256cd045b37a8c16575ea1040", size = 260792 }, - { url = "https://files.pythonhosted.org/packages/d8/d5/f23beca650c8aab67e72f610d65817c68c306e6f6a124ca337fcec7d5d57/contourpy-1.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5b9eb0ca724a241683c9685a484da9d35c872fd42756574a7cfbf58af26677fd", size = 244848 }, - { url = "https://files.pythonhosted.org/packages/1c/72/66e920088a9bebbc2e356626a1763cabbd4e7199ce29e7f89818dc2757bf/contourpy-1.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c75507d0a55378240f781599c30e7776674dbaf883a46d1c90f37e563453480", size = 300760 }, - { url = "https://files.pythonhosted.org/packages/73/a0/a6533b607e5ffce2e1780e94056da8ec034849136747f42e7232fa1a11e2/contourpy-1.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11959f0ce4a6f7b76ec578576a0b61a28bdc0696194b6347ba3f1c53827178b9", size = 336330 }, - { url = "https://files.pythonhosted.org/packages/87/75/a57c116798f34b16154d61bf1d2c00968f2eed8ae9aebe0760f2e2776da2/contourpy-1.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb3315a8a236ee19b6df481fc5f997436e8ade24a9f03dfdc6bd490fea20c6da", size = 310178 }, - { url = "https://files.pythonhosted.org/packages/67/0f/6e5b4879594cd1cbb6a2754d9230937be444f404cf07c360c07a10b36aac/contourpy-1.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39f3ecaf76cd98e802f094e0d4fbc6dc9c45a8d0c4d185f0f6c2234e14e5f75b", size = 305232 }, - { url = "https://files.pythonhosted.org/packages/d3/c3/05e085167bc4fe8f919d6812700fc7738cd6b07f5ac9e904d5ec5bf2cd7a/contourpy-1.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:94b34f32646ca0414237168d68a9157cb3889f06b096612afdd296003fdd32fd", size = 807382 }, - { url = "https://files.pythonhosted.org/packages/21/7f/a5ecf64f0bbb17d9a2b12bf934a2ccbcb35b53a289d41e450927c1eb2690/contourpy-1.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:457499c79fa84593f22454bbd27670227874cd2ff5d6c84e60575c8b50a69619", size = 831069 }, - { url = "https://files.pythonhosted.org/packages/8c/5e/f6ee233fa88b73156e7812f823ea7372a8161beb209a0812801383ffe737/contourpy-1.2.1-cp310-cp310-win32.whl", hash = "sha256:ac58bdee53cbeba2ecad824fa8159493f0bf3b8ea4e93feb06c9a465d6c87da8", size = 166724 }, - { url = "https://files.pythonhosted.org/packages/b6/b2/27c7a0d46c7dceb9083272eb314bef1ed43e5280a4197719656f866b496d/contourpy-1.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9cffe0f850e89d7c0012a1fb8730f75edd4320a0a731ed0c183904fe6ecfc3a9", size = 187455 }, { url = "https://files.pythonhosted.org/packages/33/0e/51ff72fac17e2500baf30b6b2a24be423a8d27e1625e5de99f585b852d74/contourpy-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6022cecf8f44e36af10bd9118ca71f371078b4c168b6e0fab43d4a889985dbb5", size = 262121 }, { url = "https://files.pythonhosted.org/packages/9f/6b/8a1ca4b81d426c104fe42b3cfad9488eaaef0a03fcf98eaecc22b628a013/contourpy-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef5adb9a3b1d0c645ff694f9bca7702ec2c70f4d734f9922ea34de02294fdf72", size = 245940 }, { url = "https://files.pythonhosted.org/packages/98/72/ae1e8518a2fe75980598a2716e392c7642b70b6a5605fc925426007b0f49/contourpy-1.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6150ffa5c767bc6332df27157d95442c379b7dce3a38dff89c0f39b63275696f", size = 302068 }, @@ -616,19 +419,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0a/b2/e51c4d13e79c5150d99e62ca1fc0a08bc550096663f077e04d7e832b42b7/contourpy-1.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:187fa1d4c6acc06adb0fae5544c59898ad781409e61a926ac7e84b8f276dcef4", size = 829368 }, { url = "https://files.pythonhosted.org/packages/01/f8/65fafbc5374920cf6c842f415bb60de4c36c1c194eb45ca6b488ae012cef/contourpy-1.2.1-cp312-cp312-win32.whl", hash = "sha256:c2528d60e398c7c4c799d56f907664673a807635b857df18f7ae64d3e6ce2d9f", size = 167497 }, { url = "https://files.pythonhosted.org/packages/78/38/a046bb0ebce6f530175d434e7364149e338ffe1069ee286ed8ba7f6481ee/contourpy-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:1a07fc092a4088ee952ddae19a2b2a85757b923217b7eed584fdf25f53a6e7ce", size = 189901 }, - { url = "https://files.pythonhosted.org/packages/e9/1e/09f0fdf21d3a71e298cfbc1944eb1f74c1f025ca6193f6c75caa35e27b10/contourpy-1.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb6834cbd983b19f06908b45bfc2dad6ac9479ae04abe923a275b5f48f1a186b", size = 260993 }, - { url = "https://files.pythonhosted.org/packages/1e/f5/8a0e688c3a6098a358fa359da6a09a7b9afd8f3f6c9b83e9898c29e87b95/contourpy-1.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1d59e739ab0e3520e62a26c60707cc3ab0365d2f8fecea74bfe4de72dc56388f", size = 244970 }, - { url = "https://files.pythonhosted.org/packages/61/0e/b0284ac009d9349ffa1f1e5a064ade6122b07c0a500f9a95cb16a9f970d3/contourpy-1.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd3db01f59fdcbce5b22afad19e390260d6d0222f35a1023d9adc5690a889364", size = 300785 }, - { url = "https://files.pythonhosted.org/packages/64/a9/181ec22a3fdc9d14b590b738ed35715f35a2c25d1f2c0c7fbb282046ef24/contourpy-1.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a12a813949e5066148712a0626895c26b2578874e4cc63160bb007e6df3436fe", size = 336922 }, - { url = "https://files.pythonhosted.org/packages/be/fd/62fa44a4db484acffaa21e2e0e931b0c6e5643aabfaeb8435bf65e0788eb/contourpy-1.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe0ccca550bb8e5abc22f530ec0466136379c01321fd94f30a22231e8a48d985", size = 310199 }, - { url = "https://files.pythonhosted.org/packages/31/a2/2f12e3a6e45935ff694654b710961b03310b0e1ec997ee9f416d3c873f87/contourpy-1.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d59258c3c67c865435d8fbeb35f8c59b8bef3d6f46c1f29f6123556af28445", size = 304993 }, - { url = "https://files.pythonhosted.org/packages/9b/f5/d6f4251760bffb3519e5304a0eda3f812738f7d6a62ee0e5df2155269228/contourpy-1.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f32c38afb74bd98ce26de7cc74a67b40afb7b05aae7b42924ea990d51e4dac02", size = 806968 }, - { url = "https://files.pythonhosted.org/packages/60/1b/3d65f9bc0a7e4882429aba9bd96831b6fbac090e45c85f2e8b38df915945/contourpy-1.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d31a63bc6e6d87f77d71e1abbd7387ab817a66733734883d1fc0021ed9bfa083", size = 831384 }, - { url = "https://files.pythonhosted.org/packages/1c/89/b551535d7dd73136339e0ace8ce25111d3a2801bcf36b0bb038a72c328d3/contourpy-1.2.1-cp39-cp39-win32.whl", hash = "sha256:ddcb8581510311e13421b1f544403c16e901c4e8f09083c881fab2be80ee31ba", size = 166886 }, - { url = "https://files.pythonhosted.org/packages/62/5c/08e3a7a35762c8decb6be01c7ec1f4b5f85ef2e2fbb44af87e9caf25a879/contourpy-1.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:10a37ae557aabf2509c79715cd20b62e4c7c28b8cd62dd7d99e5ed3ce28c3fd9", size = 182810 }, - { url = "https://files.pythonhosted.org/packages/8b/ca/2423074f8b1f9ef8d662c5ec36b630e8600bde882b7f41dd19937c51c570/contourpy-1.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a31f94983fecbac95e58388210427d68cd30fe8a36927980fab9c20062645609", size = 259588 }, - { url = "https://files.pythonhosted.org/packages/a1/f4/d1d4d0d933b243669cfa9c0b7d043ae1c6ce35e6d3a40d38c32aabfc7406/contourpy-1.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef2b055471c0eb466033760a521efb9d8a32b99ab907fc8358481a1dd29e3bd3", size = 303337 }, - { url = "https://files.pythonhosted.org/packages/67/73/0e5bfa8e54d65e5e988ba91f40ff71aaf793e09d36a3f1e918006e98b356/contourpy-1.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b33d2bc4f69caedcd0a275329eb2198f560b325605810895627be5d4b876bf7f", size = 186603 }, ] [[distribution]] @@ -651,16 +441,6 @@ version = "7.5.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ef/05/31553dc038667012853d0a248b57987d8d70b2d67ea885605f87bcb1baba/coverage-7.5.4.tar.gz", hash = "sha256:a44963520b069e12789d0faea4e9fdb1e410cdc4aab89d94f7f55cbb7fef0353", size = 793238 } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/3d/9f9469f445789a170cb5bef3ad02ae9084ddd689f938797aa8ee793db404/coverage-7.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6cfb5a4f556bb51aba274588200a46e4dd6b505fb1a5f8c5ae408222eb416f99", size = 205105 }, - { url = "https://files.pythonhosted.org/packages/b0/d8/b7bde23a5e94cfc1a45effad2dd4c45dc111c515f71c522986dd8ded31a1/coverage-7.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2174e7c23e0a454ffe12267a10732c273243b4f2d50d07544a91198f05c48f47", size = 205537 }, - { url = "https://files.pythonhosted.org/packages/99/49/0e8c8e8f9f7ea87ed94ddce70cdfe49224b13857ef3cbdb65a5eb29bba6f/coverage-7.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2214ee920787d85db1b6a0bd9da5f8503ccc8fcd5814d90796c2f2493a2f4d2e", size = 234067 }, - { url = "https://files.pythonhosted.org/packages/a9/9a/79381c5dbc118b5cc0aac637352f65078766527ab0d23031d5421f2fb144/coverage-7.5.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1137f46adb28e3813dec8c01fefadcb8c614f33576f672962e323b5128d9a68d", size = 232015 }, - { url = "https://files.pythonhosted.org/packages/a2/78/d457df19baefbe3d38ef63cddfbda0f443d6546f3f56fa95cd884d612e8e/coverage-7.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b385d49609f8e9efc885790a5a0e89f2e3ae042cdf12958b6034cc442de428d3", size = 233145 }, - { url = "https://files.pythonhosted.org/packages/ef/48/fccbf1b4ab5943e1b5bf5e29892531341b4c2731c448c6970349b0bb2f3b/coverage-7.5.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b4a474f799456e0eb46d78ab07303286a84a3140e9700b9e154cfebc8f527016", size = 232230 }, - { url = "https://files.pythonhosted.org/packages/44/ab/1ce64d6d01486b7e307ce0b25565b2337b9883d409fdb7655c94b0e80ae7/coverage-7.5.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5cd64adedf3be66f8ccee418473c2916492d53cbafbfcff851cbec5a8454b136", size = 230741 }, - { url = "https://files.pythonhosted.org/packages/fd/a2/4db4030508e3f7267151155e2221487e1515eda167262d0aa88bce8d4b57/coverage-7.5.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e564c2cf45d2f44a9da56f4e3a26b2236504a496eb4cb0ca7221cd4cc7a9aca9", size = 231831 }, - { url = "https://files.pythonhosted.org/packages/a6/90/3e1a9e003f3bc35cde1b1082f740e3c0ad90595caf31df0e49473c3f230a/coverage-7.5.4-cp310-cp310-win32.whl", hash = "sha256:7076b4b3a5f6d2b5d7f1185fde25b1e54eb66e647a1dfef0e2c2bfaf9b4c88c8", size = 207727 }, - { url = "https://files.pythonhosted.org/packages/a5/0f/d56b6b9c2e900b9e51b8dae6b46aa15eb43a6a41342c9b0faca2a6c9890a/coverage-7.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:018a12985185038a5b2bcafab04ab833a9a0f2c59995b3cec07e10074c78635f", size = 208519 }, { url = "https://files.pythonhosted.org/packages/48/92/f56bf17b10efdb21311b7aa6853afc39eb962af0f9595a24408f7df3f694/coverage-7.5.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:db14f552ac38f10758ad14dd7b983dbab424e731588d300c7db25b6f89e335b5", size = 205211 }, { url = "https://files.pythonhosted.org/packages/b8/69/a3bdace4d667f592b7730c0d636ac9ff9195f678fb4e61b5469b91e49919/coverage-7.5.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3257fdd8e574805f27bb5342b77bc65578e98cbc004a92232106344053f319ba", size = 205664 }, { url = "https://files.pythonhosted.org/packages/cd/bd/8515e955724baab11e8220a3872dc3d1c895b841b281ac8865834257ae2e/coverage-7.5.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a6612c99081d8d6134005b1354191e103ec9705d7ba2754e848211ac8cacc6b", size = 237695 }, @@ -681,26 +461,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ef/e5/829ddcfb29ad41661ba8e9cac7dc52100fd2c4853bb93d668a3ebde64862/coverage-7.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:581ea96f92bf71a5ec0974001f900db495488434a6928a2ca7f01eee20c23805", size = 237309 }, { url = "https://files.pythonhosted.org/packages/98/f6/f9c96fbf9b36be3f4d8c252ab2b4944420d99425f235f492784498804182/coverage-7.5.4-cp312-cp312-win32.whl", hash = "sha256:73ca8fbc5bc622e54627314c1a6f1dfdd8db69788f3443e752c215f29fa87a0b", size = 207988 }, { url = "https://files.pythonhosted.org/packages/0e/c1/2b7c7dcf4c273aac7676f12fb2b5524b133671d731ab91bd9a41c21675b9/coverage-7.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:cef4649ec906ea7ea5e9e796e68b987f83fa9a718514fe147f538cfeda76d7a7", size = 208756 }, - { url = "https://files.pythonhosted.org/packages/f2/82/5ddb436de663abe2ec566461fa106f9f344afae339f0f56963f020fd94b4/coverage-7.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdd31315fc20868c194130de9ee6bfd99755cc9565edff98ecc12585b90be882", size = 205088 }, - { url = "https://files.pythonhosted.org/packages/71/d3/751c6dc673211a5cad695a59f782013e3f0f466d16ecaf9a34f0167f5e98/coverage-7.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:02ff6e898197cc1e9fa375581382b72498eb2e6d5fc0b53f03e496cfee3fac6d", size = 205510 }, - { url = "https://files.pythonhosted.org/packages/83/46/5020dadddbcef1c8f0bf7869a117c4558ff59b2a163b008868a5fb78fc68/coverage-7.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d05c16cf4b4c2fc880cb12ba4c9b526e9e5d5bb1d81313d4d732a5b9fe2b9d53", size = 234970 }, - { url = "https://files.pythonhosted.org/packages/e4/9d/6f415813b10ca2927da0b4c948d25fcbd3559f8cd2c04b1aac49ca223131/coverage-7.5.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5986ee7ea0795a4095ac4d113cbb3448601efca7f158ec7f7087a6c705304e4", size = 232860 }, - { url = "https://files.pythonhosted.org/packages/35/b3/27fbdf02d2e561d68a4e53522c83f4f2756aea5886c73880a96b8afdeaae/coverage-7.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5df54843b88901fdc2f598ac06737f03d71168fd1175728054c8f5a2739ac3e4", size = 234305 }, - { url = "https://files.pythonhosted.org/packages/d1/dd/b29cc90e643af35acd9ddc99c520b7bcd34ec5c13830f5ef956dd6d6b6a2/coverage-7.5.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ab73b35e8d109bffbda9a3e91c64e29fe26e03e49addf5b43d85fc426dde11f9", size = 233563 }, - { url = "https://files.pythonhosted.org/packages/8a/da/a3dbe8d7bfa6da354ed63691d2a1c3ec3afb058125ed578647fdf8396aa5/coverage-7.5.4-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:aea072a941b033813f5e4814541fc265a5c12ed9720daef11ca516aeacd3bd7f", size = 232224 }, - { url = "https://files.pythonhosted.org/packages/86/d4/b3863e938d1b95b3f34bcf7fa9772b66f40fff0819193749e92a528ebfba/coverage-7.5.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:16852febd96acd953b0d55fc842ce2dac1710f26729b31c80b940b9afcd9896f", size = 233071 }, - { url = "https://files.pythonhosted.org/packages/c3/65/4a3ae9bfb1eaec6898e34a8b283c7cc36d07c034f9abf40e494db616a090/coverage-7.5.4-cp38-cp38-win32.whl", hash = "sha256:8f894208794b164e6bd4bba61fc98bf6b06be4d390cf2daacfa6eca0a6d2bb4f", size = 207683 }, - { url = "https://files.pythonhosted.org/packages/ec/55/f38b087d950693b90034abfeefe825f9fda142d3c7469750d5141ab28a9b/coverage-7.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:e2afe743289273209c992075a5a4913e8d007d569a406ffed0bd080ea02b0633", size = 208521 }, - { url = "https://files.pythonhosted.org/packages/57/1f/b6c0725454c49b88c0229cdbb22435a90e94521149ea1d068da1d17906d7/coverage-7.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b95c3a8cb0463ba9f77383d0fa8c9194cf91f64445a63fc26fb2327e1e1eb088", size = 205100 }, - { url = "https://files.pythonhosted.org/packages/13/f5/3e13e18a4e42fbb7734c1919255841b7fda188babc57e0fcad3c2e5a080e/coverage-7.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d7564cc09dd91b5a6001754a5b3c6ecc4aba6323baf33a12bd751036c998be4", size = 205536 }, - { url = "https://files.pythonhosted.org/packages/c6/1c/bd6d46e44ddb2affc73271d22cba263d9e5d8a0afd593a5de62dbd1380cd/coverage-7.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44da56a2589b684813f86d07597fdf8a9c6ce77f58976727329272f5a01f99f7", size = 233667 }, - { url = "https://files.pythonhosted.org/packages/01/ee/87e1285608cb69c44a0da9864434818fc53a0a95ec45f112f623a6578ee9/coverage-7.5.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e16f3d6b491c48c5ae726308e6ab1e18ee830b4cdd6913f2d7f77354b33f91c8", size = 231650 }, - { url = "https://files.pythonhosted.org/packages/c4/b4/0cbc18998613f8caaec793ad5878d2450382dfac80e65d352fb7cd9cc1dc/coverage-7.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbc5958cb471e5a5af41b0ddaea96a37e74ed289535e8deca404811f6cb0bc3d", size = 232731 }, - { url = "https://files.pythonhosted.org/packages/41/03/3968f2d60208c4332bb12c2d25fdfdbbd9a5c7a2a64b4ed1050b20a9dc3f/coverage-7.5.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a04e990a2a41740b02d6182b498ee9796cf60eefe40cf859b016650147908029", size = 231874 }, - { url = "https://files.pythonhosted.org/packages/68/d0/1e2bae9d17c7c8757b75a9b9c7bf35083a84fcf5361802bb6da911aa7089/coverage-7.5.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ddbd2f9713a79e8e7242d7c51f1929611e991d855f414ca9996c20e44a895f7c", size = 230372 }, - { url = "https://files.pythonhosted.org/packages/0d/93/9eabf10ab089b9b9dcb026d84e70a3114054b75f2d37fd7e61642da775a1/coverage-7.5.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b1ccf5e728ccf83acd313c89f07c22d70d6c375a9c6f339233dcf792094bcbf7", size = 231359 }, - { url = "https://files.pythonhosted.org/packages/9d/f9/8a6cf39d151765f6adaa2808032fda07f57fe4ba658deed11bf1b6c65f11/coverage-7.5.4-cp39-cp39-win32.whl", hash = "sha256:56b4eafa21c6c175b3ede004ca12c653a88b6f922494b023aeb1e836df953ace", size = 207741 }, - { url = "https://files.pythonhosted.org/packages/a0/3a/e75878173e3f5ef21c04b96c535b5e0d10195e5fa28a842b781d339c3df9/coverage-7.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:65e528e2e921ba8fd67d9055e6b9f9e34b21ebd6768ae1c1723f4ea6ace1234d", size = 208542 }, { url = "https://files.pythonhosted.org/packages/7a/c3/a5b06a07b68795018f47b5d69b523ad473ac9ee66be3c22c4d3e5eadd91e/coverage-7.5.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:79b356f3dd5b26f3ad23b35c75dbdaf1f9e2450b6bcefc6d0825ea0aa3f86ca5", size = 197342 }, ] @@ -742,14 +502,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fd/2b/be327b580645927bb1a1f32d5a175b897a9b956bc085b095e15c40bac9ed/cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14", size = 3938751 }, { url = "https://files.pythonhosted.org/packages/3c/d5/c6a78ffccdbe4516711ebaa9ed2c7eb6ac5dfa3dc920f2c7e920af2418b0/cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c", size = 2439281 }, { url = "https://files.pythonhosted.org/packages/a2/7b/b0d330852dd5953daee6b15f742f15d9f18e9c0154eb4cfcc8718f0436da/cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a", size = 2886038 }, - { url = "https://files.pythonhosted.org/packages/a3/fe/1e21699f0a7904e8a30d4fc6db262958f1edf5e505a02e7d97a5b419e482/cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe", size = 3014449 }, - { url = "https://files.pythonhosted.org/packages/d5/f3/61b398b5ec61f4b6ffbf746227df7ebb421696458d9625d634043f236a13/cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c", size = 3558533 }, - { url = "https://files.pythonhosted.org/packages/c1/e2/60b05e720766e185ef097d07068bd878a51d613ef91e4c241750f9c9192b/cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71", size = 3759330 }, - { url = "https://files.pythonhosted.org/packages/10/38/2c8dae407d301eaf942e377a5b2b30485cfa0df03c6c2dcc2ac044054ed9/cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d", size = 2801764 }, - { url = "https://files.pythonhosted.org/packages/fc/4d/55718454ee7a5b7da07f9892afae34004f211b29f0679869ddc838d78873/cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c", size = 3014446 }, - { url = "https://files.pythonhosted.org/packages/a2/31/7cb5750b1b85a3b2adbfb40eeb283623077e606a3c950f78012c7ff455fd/cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842", size = 3558644 }, - { url = "https://files.pythonhosted.org/packages/92/db/cea4ec90a8730449dd5c42ce361749bb62de2bec5bed37ea84d98eff0d8b/cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648", size = 3759539 }, - { url = "https://files.pythonhosted.org/packages/21/a7/b88d4f80396488c442c39c588302a71ad7b1c1f03179b4a770bcddc2af77/cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad", size = 2801728 }, ] [[distribution]] @@ -767,14 +519,6 @@ version = "3.0.10" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d5/f7/2fdd9205a2eedee7d9b0abbf15944a1151eb943001dbdc5233b1d1cfc34e/Cython-3.0.10.tar.gz", hash = "sha256:dcc96739331fb854dcf503f94607576cfe8488066c61ca50dfd55836f132de99", size = 2751764 } wheels = [ - { url = "https://files.pythonhosted.org/packages/31/e7/d1bc7b8139808a08efde19cade7e45cbfdc5c5978ba819983162b33af3ff/Cython-3.0.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e876272548d73583e90babda94c1299537006cad7a34e515a06c51b41f8657aa", size = 3107259 }, - { url = "https://files.pythonhosted.org/packages/88/1c/ad65940b3bf45e275302aabaee7b32e741bdecdf55bd573e23dc1767a2a7/Cython-3.0.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:adc377aa33c3309191e617bf675fdbb51ca727acb9dc1aa23fc698d8121f7e23", size = 3461626 }, - { url = "https://files.pythonhosted.org/packages/2d/bc/3246e32829c8c823032dfb7b8e0f5f4818e28c74748c46766ae342e078b0/Cython-3.0.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:401aba1869a57aba2922ccb656a6320447e55ace42709b504c2f8e8b166f46e1", size = 3627560 }, - { url = "https://files.pythonhosted.org/packages/3c/51/7185dc4a2987dcd6bccea24184a0b5b74536e5dff45d79c035d3d5c96a6c/Cython-3.0.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:541fbe725d6534a90b93f8c577eb70924d664b227a4631b90a6e0506d1469591", size = 3680326 }, - { url = "https://files.pythonhosted.org/packages/7b/4e/064b5b7230737404700905f909e86ce7b856fcb36fe12dc49452bd45b69a/Cython-3.0.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:86998b01f6a6d48398df8467292c7637e57f7e3a2ca68655367f13f66fed7734", size = 3466760 }, - { url = "https://files.pythonhosted.org/packages/b7/cc/389543a3d91826423468501da5ebeaa1e9d091e6db73aeb5a8db7208a660/Cython-3.0.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d092c0ddba7e9e530a5c5be4ac06db8360258acc27675d1fc86294a5dc8994c5", size = 3623768 }, - { url = "https://files.pythonhosted.org/packages/83/5b/5746455e739f771b4bfaefd37e6157f6f6702b8222c42264a8d37dd2f8c4/Cython-3.0.10-cp310-cp310-win32.whl", hash = "sha256:3cffb666e649dba23810732497442fb339ee67ba4e0be1f0579991e83fcc2436", size = 2575212 }, - { url = "https://files.pythonhosted.org/packages/83/42/9537a513d7d83196ab5973d911056eb22a639e04162fd649cf74b4dac3f1/Cython-3.0.10-cp310-cp310-win_amd64.whl", hash = "sha256:9ea31184c7b3a728ef1f81fccb161d8948c05aa86c79f63b74fb6f3ddec860ec", size = 2780248 }, { url = "https://files.pythonhosted.org/packages/05/69/198e26fb362a35460cbc72596352228fb8bddb15d11a787acfd7fa30aec4/Cython-3.0.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:051069638abfb076900b0c2bcb6facf545655b3f429e80dd14365192074af5a4", size = 3120551 }, { url = "https://files.pythonhosted.org/packages/8e/30/947edd67f2ca21da1b88cba9c7f24fd27923a068138e0077095927dbee9e/Cython-3.0.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:712760879600907189c7d0d346851525545484e13cd8b787e94bfd293da8ccf0", size = 3441040 }, { url = "https://files.pythonhosted.org/packages/45/82/077c13035d6f45d8b8b74d67e9f73f2bfc54ef8d1f79572790f6f7d2b4f5/Cython-3.0.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38d40fa1324ac47c04483d151f5e092406a147eac88a18aec789cf01c089c3f2", size = 3596464 }, @@ -791,38 +535,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/00/79/bd4ce9b16aee79f801c62beaac106fba09b110e00a4e257ec8826f6c3b81/Cython-3.0.10-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f8a2b8fa0fd8358bccb5f3304be563c4750aae175100463d212d5ea0ec74cbe0", size = 3527265 }, { url = "https://files.pythonhosted.org/packages/5d/6b/7c3a198ba733b63c4e61b6d5385da3c172b90bc0cde57ebddd95f6eea44a/Cython-3.0.10-cp312-cp312-win32.whl", hash = "sha256:2d29e617fd23cf4b83afe8f93f2966566c9f565918ad1e86a4502fe825cc0a79", size = 2607261 }, { url = "https://files.pythonhosted.org/packages/2f/59/6669edfd1fad83ee18d698b897f25871b5296e258f74964a003d50d003fe/Cython-3.0.10-cp312-cp312-win_amd64.whl", hash = "sha256:6c5af936940a38c300977b81598d9c0901158f220a58c177820e17e1774f1cf1", size = 2795667 }, - { url = "https://files.pythonhosted.org/packages/15/7a/2c9eb11c78b3f99a6151edc1f971859eb1a0a785e38a19c753d1a1e01ca5/Cython-3.0.10-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:5f465443917d5c0f69825fca3b52b64c74ac3de0143b1fff6db8ba5b48c9fb4a", size = 2981971 }, - { url = "https://files.pythonhosted.org/packages/2d/3d/7d3526c5ad9318df1387c0d13e8e2a29986f69ad2b7647927e741c1e1762/Cython-3.0.10-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fadb84193c25641973666e583df8df4e27c52cdc05ddce7c6f6510d690ba34a", size = 3317560 }, - { url = "https://files.pythonhosted.org/packages/94/12/3006eec0c5c4efd98c37dd196fdcffbeb584e8aa5daae15c58636893c18c/Cython-3.0.10-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fa9e7786083b6aa61594c16979d621b62e61fcd9c2edd4761641b95c7fb34b2", size = 3458030 }, - { url = "https://files.pythonhosted.org/packages/48/c1/cad29c9fecfcd6eaa7f22ce7247d46ae87b671db2b662b0b67fb22cb2880/Cython-3.0.10-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4780d0f98ce28191c4d841c4358b5d5e79d96520650910cd59904123821c52d", size = 3537897 }, - { url = "https://files.pythonhosted.org/packages/95/f3/cf2071c67a2bfe2181403cd7a68c13f884c66bea1b33c6e40b900a445cf9/Cython-3.0.10-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:32fbad02d1189be75eb96456d9c73f5548078e5338d8fa153ecb0115b6ee279f", size = 3352527 }, - { url = "https://files.pythonhosted.org/packages/60/83/de77351653c8a3fe508576e605fd846cfd5d3e907adb0e7ea2796c7f1635/Cython-3.0.10-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:90e2f514fc753b55245351305a399463103ec18666150bb1c36779b9862388e9", size = 3475310 }, - { url = "https://files.pythonhosted.org/packages/4b/03/88ce37debab57a7e111186c37466645ec5755116c9bc0ece3a6095e98dba/Cython-3.0.10-cp36-cp36m-win32.whl", hash = "sha256:a9c976e9ec429539a4367cb4b24d15a1e46b925976f4341143f49f5f161171f5", size = 2606152 }, - { url = "https://files.pythonhosted.org/packages/e1/82/4e95bd3b1c639a85573fbcee52b4768a49e315dfad740caaa73683ca9f7f/Cython-3.0.10-cp36-cp36m-win_amd64.whl", hash = "sha256:a9bb402674788a7f4061aeef8057632ec440123e74ed0fb425308a59afdfa10e", size = 2836057 }, - { url = "https://files.pythonhosted.org/packages/71/e9/5a273075825fca0d1b567a10b07c260b6083bec8e61b5998cb737ca5a164/Cython-3.0.10-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:206e803598010ecc3813db8748ed685f7beeca6c413f982df9f8a505fce56563", size = 3031546 }, - { url = "https://files.pythonhosted.org/packages/f6/ca/6beddd6728c9848f21f8313550013be75bdac53b29380e7a346c0961c58c/Cython-3.0.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15b6d397f4ee5ad54e373589522af37935a32863f1b23fa8c6922adf833e28e2", size = 3415903 }, - { url = "https://files.pythonhosted.org/packages/5b/29/7f69c9e9bcc570908531a52390dfae37a8bbd6db48e1a11a16d826556140/Cython-3.0.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a181144c2f893ed8e6a994d43d0b96300bc99873f21e3b7334ca26c61c37b680", size = 3562153 }, - { url = "https://files.pythonhosted.org/packages/d0/de/0f9266708da1be4b7098123b6a845e238a537da188e984fc66b59512dca7/Cython-3.0.10-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b74b700d6a793113d03fb54b63bdbadba6365379424bac7c0470605672769260", size = 3642555 }, - { url = "https://files.pythonhosted.org/packages/0e/ed/01800eecd9fd3b7911a39cf6ebe2a16e80b4b3c55a09bd5c91bf4159fc29/Cython-3.0.10-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:076e9fd4e0ca33c5fa00a7479180dbfb62f17fe928e2909f82da814536e96d2b", size = 3454330 }, - { url = "https://files.pythonhosted.org/packages/75/40/f6d414edc9740c1cc6b257fdd596d397bc7c7cbf07132dadfdac71d83de1/Cython-3.0.10-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:269f06e6961e8591d56e30b46e1a51b6ccb42cab04c29fa3b30d3e8723485fb4", size = 3583998 }, - { url = "https://files.pythonhosted.org/packages/c8/77/1fe39cf1cfbed6bf5d9a02df05058d9f021832334fe3b2333520edb9c070/Cython-3.0.10-cp37-cp37m-win32.whl", hash = "sha256:d4e83a8ceff7af60064da4ccfce0ac82372544dd5392f1b350c34f1b04d0fae6", size = 2544775 }, - { url = "https://files.pythonhosted.org/packages/a6/5a/fecd57c009bc0be42a91ba19507ee886ec2012ad90b01359b6e16d1a2d69/Cython-3.0.10-cp37-cp37m-win_amd64.whl", hash = "sha256:40fac59c3a7fbcd9c25aea64c342c890a5e2270ce64a1525e840807800167799", size = 2728440 }, - { url = "https://files.pythonhosted.org/packages/7a/3e/640c616b6bed48a7eb92d30adce31c560faa7df7af576c20a19df19b07dc/Cython-3.0.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f43a58bf2434870d2fc42ac2e9ff8138c9e00c6251468de279d93fa279e9ba3b", size = 3086520 }, - { url = "https://files.pythonhosted.org/packages/a8/b9/e01e8f09ccb91884eac5ee865edd24e62b36743d2b4bd04191e6d8c53f49/Cython-3.0.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e9a885ec63d3955a08cefc4eec39fefa9fe14989c6e5e2382bd4aeb6bdb9bc3", size = 3470271 }, - { url = "https://files.pythonhosted.org/packages/3a/6f/8a79707ac83cf4dc79903077b856c7c31dc08675b9fbde77a38ca79814b4/Cython-3.0.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acfbe0fff364d54906058fc61f2393f38cd7fa07d344d80923937b87e339adcf", size = 3640653 }, - { url = "https://files.pythonhosted.org/packages/8d/8e/54275ba256352285e76098a9130cf134810e432ee6fde4cbbdbd47be5df6/Cython-3.0.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8adcde00a8a88fab27509b558cd8c2959ab0c70c65d3814cfea8c68b83fa6dcd", size = 3688586 }, - { url = "https://files.pythonhosted.org/packages/10/88/de394dd1ab01433b63bd5588977ca62e3044452336d3ff61ffd93a89fe5d/Cython-3.0.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2c9c1e3e78909488f3b16fabae02308423fa6369ed96ab1e250807d344cfffd7", size = 3499569 }, - { url = "https://files.pythonhosted.org/packages/6e/56/1fc1290a9fb86dc3cbaccfdcf7415259ff4e4d8585df9c6bf7e7a4db4fe9/Cython-3.0.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fc6e0faf5b57523b073f0cdefadcaef3a51235d519a0594865925cadb3aeadf0", size = 3652920 }, - { url = "https://files.pythonhosted.org/packages/4d/e3/93a4a3bc8ea7f7f61c70a88078d6ddd6927e994822a624e984a7857eecc3/Cython-3.0.10-cp38-cp38-win32.whl", hash = "sha256:35f6ede7c74024ed1982832ae61c9fad7cf60cc3f5b8c6a63bb34e38bc291936", size = 2587301 }, - { url = "https://files.pythonhosted.org/packages/3a/ac/18d413580ac61a88f3725c5b6eb73c651495f1b6a5631be211514ac8aa0c/Cython-3.0.10-cp38-cp38-win_amd64.whl", hash = "sha256:950c0c7b770d2a7cec74fb6f5ccc321d0b51d151f48c075c0d0db635a60ba1b5", size = 2793921 }, - { url = "https://files.pythonhosted.org/packages/95/c1/c7ebf23958c8c225206204ca47582c71a35ee9b3a09c45af4a5706c6b7e0/Cython-3.0.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:077b61ee789e48700e25d4a16daa4258b8e65167136e457174df400cf9b4feab", size = 3114763 }, - { url = "https://files.pythonhosted.org/packages/95/87/beb17707b21a89dce293e3c35a685ec35b2010584c5d8a62c7a22950ff47/Cython-3.0.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64f1f8bba9d8f37c0cffc934792b4ac7c42d0891077127c11deebe9fa0a0f7e4", size = 3468065 }, - { url = "https://files.pythonhosted.org/packages/a7/f5/3dde4d96076888ceaa981827b098274c2b45ddd4b20d75a8cfaa92b91eec/Cython-3.0.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:651a15a8534ebfb9b58cb0b87c269c70984b6f9c88bfe65e4f635f0e3f07dfcd", size = 3633236 }, - { url = "https://files.pythonhosted.org/packages/5b/20/4afaa8d51830cab70c1749bcc67839c3ed26fb0893b7943578a3e086a9dc/Cython-3.0.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d10fc9aa82e5e53a0b7fd118f9771199cddac8feb4a6d8350b7d4109085aa775", size = 3687463 }, - { url = "https://files.pythonhosted.org/packages/85/23/0cb865d1c633e0b8eee62c775690843526fe7c01bae077e0ffb2333f8ba2/Cython-3.0.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4f610964ab252a83e573a427e28b103e2f1dd3c23bee54f32319f9e73c3c5499", size = 3473035 }, - { url = "https://files.pythonhosted.org/packages/ac/63/2ccf2d991c67065ea4b464a34616055b8b01015e3d634d6a6e4071a7f1fa/Cython-3.0.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8c9c4c4f3ab8f8c02817b0e16e8fa7b8cc880f76e9b63fe9c010e60c1a6c2b13", size = 3630868 }, - { url = "https://files.pythonhosted.org/packages/b1/8e/228a169ef207ada48a0a651f24d40d42a715769ce3a330ba0909b5fe9181/Cython-3.0.10-cp39-cp39-win32.whl", hash = "sha256:0bac3ccdd4e03924028220c62ae3529e17efa8ca7e9df9330de95de02f582b26", size = 2580208 }, - { url = "https://files.pythonhosted.org/packages/ba/a4/457fdf9a6cb89fbb3a9c51a3cfb5fb6ecd36eabae6abe077784be95fc121/Cython-3.0.10-cp39-cp39-win_amd64.whl", hash = "sha256:81f356c1c8c0885b8435bfc468025f545c5d764aa9c75ab662616dd1193c331e", size = 2785089 }, { url = "https://files.pythonhosted.org/packages/b6/83/b0a63fc7b315edd46821a1a381d18765c1353d201246da44558175cddd56/Cython-3.0.10-py2.py3-none-any.whl", hash = "sha256:fcbb679c0b43514d591577fd0d20021c55c240ca9ccafbdb82d3fb95e5edfee2", size = 1170278 }, ] @@ -925,14 +637,6 @@ version = "4.53.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c6/cb/cd80a0da995adde8ade6044a8744aee0da5efea01301cadf770f7fbe7dcc/fonttools-4.53.1.tar.gz", hash = "sha256:e128778a8e9bc11159ce5447f76766cefbd876f44bd79aff030287254e4752c4", size = 3452797 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/3b/4db0513b71eb21bf73cd9fcff47ac5cebcf0146be5f3a42263eaafabdc33/fonttools-4.53.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0679a30b59d74b6242909945429dbddb08496935b82f91ea9bf6ad240ec23397", size = 2761563 }, - { url = "https://files.pythonhosted.org/packages/49/79/3976d0913db440644d14bc85ba697da7dc0847663acd6c96b0dff797f592/fonttools-4.53.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8bf06b94694251861ba7fdeea15c8ec0967f84c3d4143ae9daf42bbc7717fe3", size = 2247768 }, - { url = "https://files.pythonhosted.org/packages/b5/c8/815092e63534257469afb7dcc90a588b0bba60df5de2a06795af4d64ea8e/fonttools-4.53.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b96cd370a61f4d083c9c0053bf634279b094308d52fdc2dd9a22d8372fdd590d", size = 4568312 }, - { url = "https://files.pythonhosted.org/packages/56/61/ad19cad430aacbc3418be503e1f6daed9375c997a4e32b78a91195b3054a/fonttools-4.53.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1c7c5aa18dd3b17995898b4a9b5929d69ef6ae2af5b96d585ff4005033d82f0", size = 4624347 }, - { url = "https://files.pythonhosted.org/packages/af/a0/e8b6a6e9dc3861afb76bc449876907de4c126f817f15b21a9e44c129fdfc/fonttools-4.53.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e013aae589c1c12505da64a7d8d023e584987e51e62006e1bb30d72f26522c41", size = 4564284 }, - { url = "https://files.pythonhosted.org/packages/84/63/4ade973eb583024a50f223d0d66f6f469bfe6095cc76c4bab86385faca4d/fonttools-4.53.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9efd176f874cb6402e607e4cc9b4a9cd584d82fc34a4b0c811970b32ba62501f", size = 4735828 }, - { url = "https://files.pythonhosted.org/packages/f5/a8/e01479b8e2b7c838b67c38b98f4efd6b7edb8baa433a108164186dd1c171/fonttools-4.53.1-cp310-cp310-win32.whl", hash = "sha256:c8696544c964500aa9439efb6761947393b70b17ef4e82d73277413f291260a4", size = 2159775 }, - { url = "https://files.pythonhosted.org/packages/70/11/7b81b12a5614b5d237ab70c38bdc268de3eb3880ce7bb1269122e0a415ea/fonttools-4.53.1-cp310-cp310-win_amd64.whl", hash = "sha256:8959a59de5af6d2bec27489e98ef25a397cfa1774b375d5787509c06659b3671", size = 2203850 }, { url = "https://files.pythonhosted.org/packages/8b/6a/206391c869ab22d1374e2575cad7cab36b93b9e3d37f48f4696eed2c6e9e/fonttools-4.53.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:da33440b1413bad53a8674393c5d29ce64d8c1a15ef8a77c642ffd900d07bfe1", size = 2762654 }, { url = "https://files.pythonhosted.org/packages/f5/7e/4060d88dbfaf446e1c9f0fe9cf13dba36ba47c4da85ce5c1df084ce47e7d/fonttools-4.53.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ff7e5e9bad94e3a70c5cd2fa27f20b9bb9385e10cddab567b85ce5d306ea923", size = 2247865 }, { url = "https://files.pythonhosted.org/packages/e1/67/fff766817e17d67208f8a1e72de15066149485acb5e4ff0816b11fd5fca3/fonttools-4.53.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6e7170d675d12eac12ad1a981d90f118c06cf680b42a2d74c6c931e54b50719", size = 4873046 }, @@ -949,22 +653,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ac/9f/27135ac0328e22cca1ba23ee6a1a1f971c13e9f0387adc5598d4635c501d/fonttools-4.53.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9e6ceba2a01b448e36754983d376064730690401da1dd104ddb543519470a15f", size = 5023568 }, { url = "https://files.pythonhosted.org/packages/04/40/44d6a94e52e91fe104f9ca95944466af34828992cbc66b666f541de137f1/fonttools-4.53.1-cp312-cp312-win32.whl", hash = "sha256:791b31ebbc05197d7aa096bbc7bd76d591f05905d2fd908bf103af4488e60670", size = 2147572 }, { url = "https://files.pythonhosted.org/packages/6d/9a/b695930e1b4e6929cc60e294489421632a05c105ac8c56ee63ef56a47872/fonttools-4.53.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ed170b5e17da0264b9f6fae86073be3db15fa1bd74061c8331022bca6d09bab", size = 2193313 }, - { url = "https://files.pythonhosted.org/packages/88/cf/3d0c40471d38ce081b9744216b22360ed9048ab165d15a95c4848a745aee/fonttools-4.53.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c818c058404eb2bba05e728d38049438afd649e3c409796723dfc17cd3f08749", size = 2759786 }, - { url = "https://files.pythonhosted.org/packages/cc/a8/5f9e8664708e90acb1c8e625beab78bca4ef69abd45cdd1c14be84d23906/fonttools-4.53.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:651390c3b26b0c7d1f4407cad281ee7a5a85a31a110cbac5269de72a51551ba2", size = 2247323 }, - { url = "https://files.pythonhosted.org/packages/d9/e2/9f23d610ad557cd717f9b4f2744dc76038edd39d6fd4bb8ca58c8f417333/fonttools-4.53.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e54f1bba2f655924c1138bbc7fa91abd61f45c68bd65ab5ed985942712864bbb", size = 4651283 }, - { url = "https://files.pythonhosted.org/packages/f1/d1/8a596e41e4df480e186de3cd0e90a461a01b7e4f20b5443a5c2a87567e18/fonttools-4.53.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9cd19cf4fe0595ebdd1d4915882b9440c3a6d30b008f3cc7587c1da7b95be5f", size = 4716577 }, - { url = "https://files.pythonhosted.org/packages/a4/bc/e1729257506ecc5f0a064475847c05e8eacdf1f4097f7aeb76aaa83349e4/fonttools-4.53.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2af40ae9cdcb204fc1d8f26b190aa16534fcd4f0df756268df674a270eab575d", size = 4669151 }, - { url = "https://files.pythonhosted.org/packages/fc/6f/32c94dfad17483b4820d924067ecfdb28f998fa29747af7de3b2c5d19f13/fonttools-4.53.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:35250099b0cfb32d799fb5d6c651220a642fe2e3c7d2560490e6f1d3f9ae9169", size = 4844635 }, - { url = "https://files.pythonhosted.org/packages/2e/e8/c0a1386660a1897078eef5c6787624ab0e61b3625085c51df4a48493c356/fonttools-4.53.1-cp38-cp38-win32.whl", hash = "sha256:f08df60fbd8d289152079a65da4e66a447efc1d5d5a4d3f299cdd39e3b2e4a7d", size = 1483234 }, - { url = "https://files.pythonhosted.org/packages/66/5e/ef1ada47adeccce7ced24240b6502a2527a98076d8b386cb76f12fa8d42e/fonttools-4.53.1-cp38-cp38-win_amd64.whl", hash = "sha256:7b6b35e52ddc8fb0db562133894e6ef5b4e54e1283dff606fda3eed938c36fc8", size = 1527699 }, - { url = "https://files.pythonhosted.org/packages/c4/88/86aba816dc6cc4a296df93fb00f6b1dc1ba495c235ccb4241f14cc1a5872/fonttools-4.53.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75a157d8d26c06e64ace9df037ee93a4938a4606a38cb7ffaf6635e60e253b7a", size = 2764568 }, - { url = "https://files.pythonhosted.org/packages/f3/d5/bff14bc918cb2f407e336de41f4dc85aa79888c5954a0d9e4ff4c29aebd9/fonttools-4.53.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4824c198f714ab5559c5be10fd1adf876712aa7989882a4ec887bf1ef3e00e31", size = 2249254 }, - { url = "https://files.pythonhosted.org/packages/6b/0f/2b61b7c48640c20005f75ec0565b5b96ce0f579baffff610f3f6034afc04/fonttools-4.53.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:becc5d7cb89c7b7afa8321b6bb3dbee0eec2b57855c90b3e9bf5fb816671fa7c", size = 4573976 }, - { url = "https://files.pythonhosted.org/packages/7b/30/ad4483dfc5a1999f26b7bc5edc311576f433a3e00dd8aea01f2099c3a29f/fonttools-4.53.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84ec3fb43befb54be490147b4a922b5314e16372a643004f182babee9f9c3407", size = 4632564 }, - { url = "https://files.pythonhosted.org/packages/21/be/a602ba37b1213a6b07eb6b9b4134aae79cbed6b5db4a6bd2efeaeaf18196/fonttools-4.53.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:73379d3ffdeecb376640cd8ed03e9d2d0e568c9d1a4e9b16504a834ebadc2dfb", size = 4567848 }, - { url = "https://files.pythonhosted.org/packages/02/d9/d539010191d99ef8c8403138a9bec272d74b83b99aa2f3bb9c3753bdfc59/fonttools-4.53.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:02569e9a810f9d11f4ae82c391ebc6fb5730d95a0657d24d754ed7763fb2d122", size = 4739315 }, - { url = "https://files.pythonhosted.org/packages/41/4b/b4b7d04a7b3ee9cc9fea48dcf38f3c18804d8b0446eaf0f5b77e6fddc043/fonttools-4.53.1-cp39-cp39-win32.whl", hash = "sha256:aae7bd54187e8bf7fd69f8ab87b2885253d3575163ad4d669a262fe97f0136cb", size = 2160338 }, - { url = "https://files.pythonhosted.org/packages/f2/d5/f7d2122140848fb7a7bd1d59881b822dd514c19b7648984b7565d9f39d56/fonttools-4.53.1-cp39-cp39-win_amd64.whl", hash = "sha256:e5b708073ea3d684235648786f5f6153a48dc8762cdfe5563c57e80787c29fbb", size = 2204286 }, { url = "https://files.pythonhosted.org/packages/e4/b9/0394d67056d4ad36a3807b439571934b318f1df925593a95e9ec0516b1a7/fonttools-4.53.1-py3-none-any.whl", hash = "sha256:f1f8758a2ad110bd6432203a344269f445a2907dc24ef6bccfd0ac4e14e0d71d", size = 1090472 }, ] @@ -974,21 +662,6 @@ version = "1.4.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/cf/3d/2102257e7acad73efc4a0c306ad3953f68c504c16982bbdfee3ad75d8085/frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b", size = 37820 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/35/1328c7b0f780d34f8afc1d87ebdc2bb065a123b24766a0b475f0d67da637/frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac", size = 94315 }, - { url = "https://files.pythonhosted.org/packages/f4/d6/ca016b0adcf8327714ccef969740688808c86e0287bf3a639ff582f24e82/frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868", size = 53805 }, - { url = "https://files.pythonhosted.org/packages/ae/83/bcdaa437a9bd693ba658a0310f8cdccff26bd78e45fccf8e49897904a5cd/frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776", size = 52163 }, - { url = "https://files.pythonhosted.org/packages/d4/e9/759043ab7d169b74fe05ebfbfa9ee5c881c303ebc838e308346204309cd0/frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a", size = 238595 }, - { url = "https://files.pythonhosted.org/packages/f8/ce/b9de7dc61e753dc318cf0de862181b484178210c5361eae6eaf06792264d/frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad", size = 262428 }, - { url = "https://files.pythonhosted.org/packages/36/ce/dc6f29e0352fa34ebe45421960c8e7352ca63b31630a576e8ffb381e9c08/frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c", size = 258867 }, - { url = "https://files.pythonhosted.org/packages/51/47/159ac53faf8a11ae5ee8bb9db10327575557504e549cfd76f447b969aa91/frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe", size = 229412 }, - { url = "https://files.pythonhosted.org/packages/ec/25/0c87df2e53c0c5d90f7517ca0ff7aca78d050a8ec4d32c4278e8c0e52e51/frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a", size = 239539 }, - { url = "https://files.pythonhosted.org/packages/97/94/a1305fa4716726ae0abf3b1069c2d922fcfd442538cb850f1be543f58766/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98", size = 253379 }, - { url = "https://files.pythonhosted.org/packages/53/82/274e19f122e124aee6d113188615f63b0736b4242a875f482a81f91e07e2/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75", size = 245901 }, - { url = "https://files.pythonhosted.org/packages/b8/28/899931015b8cffbe155392fe9ca663f981a17e1adc69589ee0e1e7cdc9a2/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5", size = 263797 }, - { url = "https://files.pythonhosted.org/packages/6e/4f/b8a5a2f10c4a58c52a52a40cf6cf1ffcdbf3a3b64f276f41dab989bf3ab5/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950", size = 264415 }, - { url = "https://files.pythonhosted.org/packages/b0/2c/7be3bdc59dbae444864dbd9cde82790314390ec54636baf6b9ce212627ad/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc", size = 253964 }, - { url = "https://files.pythonhosted.org/packages/2e/ec/4fb5a88f6b9a352aed45ab824dd7ce4801b7bcd379adcb927c17a8f0a1a8/frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1", size = 44559 }, - { url = "https://files.pythonhosted.org/packages/61/15/2b5d644d81282f00b61e54f7b00a96f9c40224107282efe4cd9d2bf1433a/frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439", size = 50434 }, { url = "https://files.pythonhosted.org/packages/01/bc/8d33f2d84b9368da83e69e42720cff01c5e199b5a868ba4486189a4d8fa9/frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0", size = 97060 }, { url = "https://files.pythonhosted.org/packages/af/b2/904500d6a162b98a70e510e743e7ea992241b4f9add2c8063bf666ca21df/frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49", size = 55347 }, { url = "https://files.pythonhosted.org/packages/5b/9c/f12b69997d3891ddc0d7895999a00b0c6a67f66f79498c0e30f27876435d/frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced", size = 53374 }, @@ -1019,36 +692,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a5/c2/e42ad54bae8bcffee22d1e12a8ee6c7717f7d5b5019261a8c861854f4776/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8", size = 282602 }, { url = "https://files.pythonhosted.org/packages/b6/61/56bad8cb94f0357c4bc134acc30822e90e203b5cb8ff82179947de90c17f/frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89", size = 44063 }, { url = "https://files.pythonhosted.org/packages/3e/dc/96647994a013bc72f3d453abab18340b7f5e222b7b7291e3697ca1fcfbd5/frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5", size = 50452 }, - { url = "https://files.pythonhosted.org/packages/32/c7/cc0db0d69ee0dbd85fb453650ce86436f15c39a8cde4d2b432fddc77a80e/frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d", size = 97416 }, - { url = "https://files.pythonhosted.org/packages/07/eb/71b5531dfb71eb6272b6e2281139d7d46b6adaf43c59850bc8ff64ac1860/frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826", size = 55248 }, - { url = "https://files.pythonhosted.org/packages/a0/9f/255b4d34a4f8ff7f31db79406917c403032aa19b39a651ad0a0d6b467317/frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb", size = 53797 }, - { url = "https://files.pythonhosted.org/packages/3b/75/30ff63c92b4c561803662bb7e75b5a6863a2af434e6ff05be8a514a41dd2/frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6", size = 239543 }, - { url = "https://files.pythonhosted.org/packages/43/ec/362807e1682bb0f6a5f34d15994125d72fc7e52fb9b8e4953b13384dcc94/frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d", size = 256966 }, - { url = "https://files.pythonhosted.org/packages/b8/d5/35bba11c3f32283996611dbd88c5357b3ff7bcea63509f8e35b62fa9525a/frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887", size = 252874 }, - { url = "https://files.pythonhosted.org/packages/90/e4/d205655ac3db4dc1bb96ccb1dd59c0d38d54349408ad840bea85a3dd66e9/frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a", size = 231439 }, - { url = "https://files.pythonhosted.org/packages/45/4d/175b16d42daae8013bb1872f6d0870abd87da93e0a36706da4c9ba655d19/frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b", size = 240857 }, - { url = "https://files.pythonhosted.org/packages/0c/fa/ef6a96b7757c969b3d7be55c3e70951409509464f5177624d62c894656b6/frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701", size = 246935 }, - { url = "https://files.pythonhosted.org/packages/44/7e/f3177ed74571eb55779bc3c9ac486505ffc4306852f48c6ee5bd82baecb0/frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0", size = 239742 }, - { url = "https://files.pythonhosted.org/packages/eb/59/e4d3a794b2d9b7ca86a266b61a949f5cccec7a88d818f3b6ad8b80b3ad65/frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11", size = 257417 }, - { url = "https://files.pythonhosted.org/packages/31/fb/d6dc05b56cc30bf6abef2f2100ff6d6d417c33b956a642d768d5e11b5fdf/frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09", size = 255624 }, - { url = "https://files.pythonhosted.org/packages/dc/c9/21abed93eddf089dd0ddd7e09203f2f3dad5d2b784674603a319b0f0c02c/frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7", size = 248001 }, - { url = "https://files.pythonhosted.org/packages/05/6b/e76e740c826acc2ebb5ad5eb06bac15269cd950fc51bd86bbcdbbc04a863/frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497", size = 44799 }, - { url = "https://files.pythonhosted.org/packages/57/0e/63fba1e3a50f2e55d980aa633b8b58062ec7777333aabf0cc3a07a13eb5e/frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09", size = 50820 }, - { url = "https://files.pythonhosted.org/packages/d3/fb/6f2a22086065bc16797f77168728f0e59d5b89be76dd184e06b404f1e43b/frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e", size = 97291 }, - { url = "https://files.pythonhosted.org/packages/4d/23/7f01123d0e5adcc65cbbde5731378237dea7db467abd19e391f1ddd4130d/frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d", size = 55249 }, - { url = "https://files.pythonhosted.org/packages/8b/c9/a81e9af48291954a883d35686f32308238dc968043143133b8ac9e2772af/frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8", size = 53676 }, - { url = "https://files.pythonhosted.org/packages/57/15/172af60c7e150a1d88ecc832f2590721166ae41eab582172fe1e9844eab4/frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0", size = 239365 }, - { url = "https://files.pythonhosted.org/packages/8c/a4/3dc43e259960ad268ef8f2bf92912c2d2cd2e5275a4838804e03fd6f085f/frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b", size = 265592 }, - { url = "https://files.pythonhosted.org/packages/a0/c1/458cf031fc8cd29a751e305b1ec773785ce486106451c93986562c62a21e/frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0", size = 261274 }, - { url = "https://files.pythonhosted.org/packages/4a/32/21329084b61a119ecce0b2942d30312a34a7a0dccd01dcf7b40bda80f22c/frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897", size = 230787 }, - { url = "https://files.pythonhosted.org/packages/70/b0/6f1ebdabfb604e39a0f84428986b89ab55f246b64cddaa495f2c953e1f6b/frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7", size = 240674 }, - { url = "https://files.pythonhosted.org/packages/a3/05/50c53f1cdbfdf3d2cb9582a4ea5e12cd939ce33bd84403e6d07744563486/frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742", size = 255712 }, - { url = "https://files.pythonhosted.org/packages/b8/3d/cbc6f057f7d10efb7f1f410e458ac090f30526fd110ed2b29bb56ec38fe1/frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea", size = 247618 }, - { url = "https://files.pythonhosted.org/packages/96/86/d5e9cd583aed98c9ee35a3aac2ce4d022ce9de93518e963aadf34a18143b/frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5", size = 266868 }, - { url = "https://files.pythonhosted.org/packages/0f/6e/542af762beb9113f13614a590cafe661e0e060cddddee6107c8833605776/frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9", size = 266439 }, - { url = "https://files.pythonhosted.org/packages/ea/db/8b611e23fda75da5311b698730a598df54cfe6236678001f449b1dedb241/frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6", size = 256677 }, - { url = "https://files.pythonhosted.org/packages/eb/06/732cefc0c46c638e4426a859a372a50e4c9d62e65dbfa7ddcf0b13e6a4f2/frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932", size = 44825 }, - { url = "https://files.pythonhosted.org/packages/29/eb/2110c4be2f622e87864e433efd7c4ee6e4f8a59ff2a93c1aa426ee50a8b8/frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0", size = 50652 }, { url = "https://files.pythonhosted.org/packages/83/10/466fe96dae1bff622021ee687f68e5524d6392b0a2f80d05001cd3a451ba/frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7", size = 11552 }, ] @@ -1096,16 +739,6 @@ version = "1.5.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d3/a5/4bb58448fffd36ede39684044df93a396c13d1ea3516f585767f9f960352/google-crc32c-1.5.0.tar.gz", hash = "sha256:89284716bc6a5a415d4eaa11b1726d2d60a0cd12aadf5439828353662ede9dd7", size = 12689 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/9a/a9bc2603a17d4fda1827d7ab0bb18d1eb5b9df80b9e11955ed9f727ace09/google_crc32c-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:596d1f98fc70232fcb6590c439f43b350cb762fb5d61ce7b0e9db4539654cc13", size = 32090 }, - { url = "https://files.pythonhosted.org/packages/f8/b3/59b49d9c5f15172a35f5560b67048eae02a54927e60c370f3b91743b79f6/google_crc32c-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:be82c3c8cfb15b30f36768797a640e800513793d6ae1724aaaafe5bf86f8f346", size = 30073 }, - { url = "https://files.pythonhosted.org/packages/34/c6/27be6fc6cbfebff08f63c2017fe885932b3387b45a0013b772f9beac7c01/google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:461665ff58895f508e2866824a47bdee72497b091c730071f2b7575d5762ab65", size = 32681 }, - { url = "https://files.pythonhosted.org/packages/b7/53/0170614ccaf34ac602c877929998dbca4923f0c401f0bea6f0d5a38a3e57/google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2096eddb4e7c7bdae4bd69ad364e55e07b8316653234a56552d9c988bd2d61b", size = 30022 }, - { url = "https://files.pythonhosted.org/packages/a9/d0/04f2846f0af1c683eb3b664c9de9543da1e66a791397456a65073b6054a2/google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:116a7c3c616dd14a3de8c64a965828b197e5f2d121fedd2f8c5585c547e87b02", size = 32288 }, - { url = "https://files.pythonhosted.org/packages/f9/c2/eb43b40e799a9f85a43b358f2b4a2b4d60f8c22a7867aca5d6eb1b88b565/google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5829b792bf5822fd0a6f6eb34c5f81dd074f01d570ed7f36aa101d6fc7a0a6e4", size = 569180 }, - { url = "https://files.pythonhosted.org/packages/b9/14/e9ba87ccc931323d79574924bf582633cc467e196bb63a49bc5a75c1dd58/google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:64e52e2b3970bd891309c113b54cf0e4384762c934d5ae56e283f9a0afcd953e", size = 35236 }, - { url = "https://files.pythonhosted.org/packages/3f/a7/d9709429d1eae1c4907b3b9aab866de26acc5ca42c4237d216acf0b7033a/google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:02ebb8bf46c13e36998aeaad1de9b48f4caf545e91d14041270d9dca767b780c", size = 581671 }, - { url = "https://files.pythonhosted.org/packages/5a/6b/882314bb535e44bb5578d60859497c5b9d82103960f3b6ecdaf42d3fab34/google_crc32c-1.5.0-cp310-cp310-win32.whl", hash = "sha256:2e920d506ec85eb4ba50cd4228c2bec05642894d4c73c59b3a2fe20346bd00ee", size = 23927 }, - { url = "https://files.pythonhosted.org/packages/1f/6b/fcd4744a020fa7bfb1a451b0be22b3e5a4cb28bafaaf01467d2e9402b96b/google_crc32c-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:07eb3c611ce363c51a933bf6bd7f8e3878a51d124acfc89452a75120bc436289", size = 27318 }, { url = "https://files.pythonhosted.org/packages/69/0f/7f89ae2b22c55273110a44a7ed55a2948bc213fb58983093fbefcdfd2d13/google_crc32c-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cae0274952c079886567f3f4f685bcaf5708f0a23a5f5216fdab71f81a6c0273", size = 32093 }, { url = "https://files.pythonhosted.org/packages/41/3f/8141b03ad127fc569c3efda2bfe31d64665e02e2b8b7fbf7b25ea914c27a/google_crc32c-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1034d91442ead5a95b5aaef90dbfaca8633b0247d1e41621d1e9f9db88c36298", size = 30071 }, { url = "https://files.pythonhosted.org/packages/fc/76/3ef124b893aa280e45e95d2346160f1d1d5c0ffc89d3f6e446c83116fb91/google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c42c70cd1d362284289c6273adda4c6af8039a8ae12dc451dcd61cdabb8ab57", size = 32702 }, @@ -1116,53 +749,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/02/94/d2ea867760d5a27b3e9eb40ff31faf7f03f949e51d4e3b3ae24f759b5963/google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:72218785ce41b9cfd2fc1d6a017dc1ff7acfc4c17d01053265c41a2c0cc39b8c", size = 582541 }, { url = "https://files.pythonhosted.org/packages/b7/09/768d2ca0c10a0765f83c6d06a5e40f3083cb75b8e7718ac22edff997aefc/google_crc32c-1.5.0-cp311-cp311-win32.whl", hash = "sha256:66741ef4ee08ea0b2cc3c86916ab66b6aef03768525627fd6a1b34968b4e3709", size = 23928 }, { url = "https://files.pythonhosted.org/packages/ce/8b/02bf4765c487901c8660290ade9929d65a6151c367ba32e75d136ef2d0eb/google_crc32c-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba1eb1843304b1e5537e1fca632fa894d6f6deca8d6389636ee5b4797affb968", size = 27318 }, - { url = "https://files.pythonhosted.org/packages/a5/25/c5bb4769b1ef0d74af968c1e24a234066cf0558126dcfa92b0ffd7e21a9a/google_crc32c-1.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:98cb4d057f285bd80d8778ebc4fde6b4d509ac3f331758fb1528b733215443ae", size = 30067 }, - { url = "https://files.pythonhosted.org/packages/97/8e/e8ebb46a7ec0b995746fc995a2f625c7b34777a40e4e5728db0055d0b072/google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd8536e902db7e365f49e7d9029283403974ccf29b13fc7028b97e2295b33556", size = 33104 }, - { url = "https://files.pythonhosted.org/packages/d7/24/b989665f0a17355461bc34b25a5e95376b3e1c0a044e8cb1f37f7b57b8a9/google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19e0a019d2c4dcc5e598cd4a4bc7b008546b0358bd322537c74ad47a5386884f", size = 30452 }, - { url = "https://files.pythonhosted.org/packages/2c/8d/8eb582e052b2c588111f1d697847cf2409bb6e6d8eed8e5b6e3a70db0218/google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02c65b9817512edc6a4ae7c7e987fea799d2e0ee40c53ec573a692bee24de876", size = 32697 }, - { url = "https://files.pythonhosted.org/packages/77/1a/cb80480e05bc5f8710be7a7ca2e2ce266006ee5aef42190749beffc65a21/google_crc32c-1.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6ac08d24c1f16bd2bf5eca8eaf8304812f44af5cfe5062006ec676e7e1d50afc", size = 32855 }, - { url = "https://files.pythonhosted.org/packages/24/f0/1ef67cfe874a569d309d5aa8bf4004e22257034fc00d7657a9dac0370373/google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3359fc442a743e870f4588fcf5dcbc1bf929df1fad8fb9905cd94e5edb02e84c", size = 570264 }, - { url = "https://files.pythonhosted.org/packages/fc/7f/b8fc0644c6eea688532a58a0d872d28ea9ffc2fdf93956ce03aa07f19c6b/google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e986b206dae4476f41bcec1faa057851f3889503a70e1bdb2378d406223994a", size = 36296 }, - { url = "https://files.pythonhosted.org/packages/58/50/f8f0a69f129473018e19de86d599781b863ce5017b325a554013a87f5522/google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:de06adc872bcd8c2a4e0dc51250e9e65ef2ca91be023b9d13ebd67c2ba552e1e", size = 582789 }, - { url = "https://files.pythonhosted.org/packages/13/6f/3ac9e55162d6f40b5893afc796b44624cf76c64aea63bea4ba52ff4f5f39/google_crc32c-1.5.0-cp37-cp37m-win32.whl", hash = "sha256:d3515f198eaa2f0ed49f8819d5732d70698c3fa37384146079b3799b97667a94", size = 23922 }, - { url = "https://files.pythonhosted.org/packages/f0/24/6d6ad7630637fc79c0036635ec11f7707f7b14fed5b2d09b8878bf1c7e00/google_crc32c-1.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:67b741654b851abafb7bc625b6d1cdd520a379074e64b6a128e3b688c3c04740", size = 27318 }, - { url = "https://files.pythonhosted.org/packages/b3/86/0621b9b3a454e53cf4a7ec29bee8fb7bf6927d11bb544d66344fc9e460c3/google_crc32c-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c02ec1c5856179f171e032a31d6f8bf84e5a75c45c33b2e20a3de353b266ebd8", size = 32093 }, - { url = "https://files.pythonhosted.org/packages/7c/5e/964aee31aa04921a13fb923a07d30ffde5a2bc9151273203eb4407607e84/google_crc32c-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:edfedb64740750e1a3b16152620220f51d58ff1b4abceb339ca92e934775c27a", size = 30063 }, - { url = "https://files.pythonhosted.org/packages/1e/48/f06dd28f26bf7b0b33aeca91a6d7379953e2692081e63351cb4c6ac5fdda/google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84e6e8cd997930fc66d5bb4fde61e2b62ba19d62b7abd7a69920406f9ecca946", size = 33100 }, - { url = "https://files.pythonhosted.org/packages/c5/2b/03ed959db876bff7d28aaca36cce8dc1b82e1c9a3e3fc05fea67dd382a8f/google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:024894d9d3cfbc5943f8f230e23950cd4906b2fe004c72e29b209420a1e6b05a", size = 30449 }, - { url = "https://files.pythonhosted.org/packages/bc/53/488ed34d5e461d5e868a44e1326ef1408f8da5a998a38d896b299b48b7c4/google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:998679bf62b7fb599d2878aa3ed06b9ce688b8974893e7223c60db155f26bd8d", size = 32708 }, - { url = "https://files.pythonhosted.org/packages/94/c9/b0563fe4b331f89b2da88906aaaa3aac125766bd8a7d2ea606b4c2ec337e/google_crc32c-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:83c681c526a3439b5cf94f7420471705bbf96262f49a6fe546a6db5f687a3d4a", size = 33032 }, - { url = "https://files.pythonhosted.org/packages/1d/f2/d2933d57f31a637af3e9e3c9671aed25b888991335bac8db2d492422f1c2/google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4c6fdd4fccbec90cc8a01fc00773fcd5fa28db683c116ee3cb35cd5da9ef6c37", size = 569215 }, - { url = "https://files.pythonhosted.org/packages/56/4f/cfde2048fffdfe63ef35b3acb2e463c341e186d697e798883833bcd0cfdb/google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5ae44e10a8e3407dbe138984f21e536583f2bba1be9491239f942c2464ac0894", size = 35245 }, - { url = "https://files.pythonhosted.org/packages/ab/e1/6cd2fbffabc28ba0b611f3c84ae25cf146cf4683852d84737b6256ed2c10/google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:37933ec6e693e51a5b07505bd05de57eee12f3e8c32b07da7e73669398e6630a", size = 581722 }, - { url = "https://files.pythonhosted.org/packages/ab/ef/48efc65af146635b66e883e3b7cf5a0eafe6e01cfbb1f94bd5e5b73ed2be/google_crc32c-1.5.0-cp38-cp38-win32.whl", hash = "sha256:fe70e325aa68fa4b5edf7d1a4b6f691eb04bbccac0ace68e34820d283b5f80d4", size = 23923 }, - { url = "https://files.pythonhosted.org/packages/ad/42/f8d35568ae119d7485ab5d3838c0aff0739f175d38e319004203e39805b8/google_crc32c-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:74dea7751d98034887dbd821b7aae3e1d36eda111d6ca36c206c44478035709c", size = 27318 }, - { url = "https://files.pythonhosted.org/packages/23/f8/a6e6304484d72a53c80bbcbe2225c29dfe5cbe17aa1d45ed5c906929025b/google_crc32c-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c6c777a480337ac14f38564ac88ae82d4cd238bf293f0a22295b66eb89ffced7", size = 32092 }, - { url = "https://files.pythonhosted.org/packages/a6/ba/9826da8b2e4778e963339aed1cff6dfd7efe938011d8eff804b32f5e3e12/google_crc32c-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:759ce4851a4bb15ecabae28f4d2e18983c244eddd767f560165563bf9aefbc8d", size = 30066 }, - { url = "https://files.pythonhosted.org/packages/69/59/08ef90c8c0ad56e1903895dd419749dc9cd77617b4c05f513c205de8f1fd/google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f13cae8cc389a440def0c8c52057f37359014ccbc9dc1f0827936bcd367c6100", size = 32526 }, - { url = "https://files.pythonhosted.org/packages/4a/1f/2182df8cbd52dca8a54957ebb979f3844e244be1a9eeef69c36c9ea74e70/google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e560628513ed34759456a416bf86b54b2476c59144a9138165c9a1575801d0d9", size = 29869 }, - { url = "https://files.pythonhosted.org/packages/1e/a2/b1de9a4f22fdd4ad34e084555a4a34da430ee69a47b71fff23f3309d6abf/google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1674e4307fa3024fc897ca774e9c7562c957af85df55efe2988ed9056dc4e57", size = 32131 }, - { url = "https://files.pythonhosted.org/packages/4b/9d/25cfb36f8e6fb0dd47e0ce368762a3ce371ed84d888acd8865a182f8169a/google_crc32c-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:278d2ed7c16cfc075c91378c4f47924c0625f5fc84b2d50d921b18b7975bd210", size = 32853 }, - { url = "https://files.pythonhosted.org/packages/d2/b1/e85646501adbc960f9e4695b058286d2fcfd890c9aad3ae73832fdb73911/google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d5280312b9af0976231f9e317c20e4a61cd2f9629b7bfea6a693d1878a264ebd", size = 569001 }, - { url = "https://files.pythonhosted.org/packages/1c/8f/f3c495b77d8c50e4d1926c50844d36f46216973694f795b0d73bbc322f97/google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8b87e1a59c38f275c0e3676fc2ab6d59eccecfd460be267ac360cc31f7bcde96", size = 35039 }, - { url = "https://files.pythonhosted.org/packages/82/d8/ee36a80de9f381ce267adcc9b8c252d3f7f15fecff164389217a3e515774/google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7c074fece789b5034b9b1404a1f8208fc2d4c6ce9decdd16e8220c5a793e6f61", size = 581507 }, - { url = "https://files.pythonhosted.org/packages/b0/70/1497215cf1d234be473af3b7b8ec0239bcff810b4e00a12fff31240390e4/google_crc32c-1.5.0-cp39-cp39-win32.whl", hash = "sha256:7f57f14606cd1dd0f0de396e1e53824c371e9544a822648cd76c034d209b559c", size = 23923 }, - { url = "https://files.pythonhosted.org/packages/29/93/0934093fbd214ac9d45dce8306e8a1d4b1da83b1d8392caa3e52d3e4c90b/google_crc32c-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:a2355cba1f4ad8b6988a4ca3feed5bff33f6af2d7f134852cf279c2aebfde541", size = 27316 }, - { url = "https://files.pythonhosted.org/packages/42/28/1eb1aba5afaf7c8f668c7d493eff003ae8613d47b71e15a60ab65e25c997/google_crc32c-1.5.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f314013e7dcd5cf45ab1945d92e713eec788166262ae8deb2cfacd53def27325", size = 29985 }, - { url = "https://files.pythonhosted.org/packages/98/75/c208efbd782d8816eee355671e38c5e4684d7536b6633e47a5233e902533/google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b747a674c20a67343cb61d43fdd9207ce5da6a99f629c6e2541aa0e89215bcd", size = 27910 }, - { url = "https://files.pythonhosted.org/packages/f4/44/6af2ffd9584f424fddd0711cd86f498d42dc5ad3a1f26a339c8535bd6486/google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f24ed114432de109aa9fd317278518a5af2d31ac2ea6b952b2f7782b43da091", size = 25647 }, - { url = "https://files.pythonhosted.org/packages/08/05/f143e453787b05958a53b226f4f0e1d11ee2d6765c15b24b9ab9d0271875/google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8667b48e7a7ef66afba2c81e1094ef526388d35b873966d8a9a447974ed9178", size = 27697 }, - { url = "https://files.pythonhosted.org/packages/7e/ee/998646a47a747c099acd236f77100728fc9dc8e712e3c3d10583e14361e5/google_crc32c-1.5.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1c7abdac90433b09bad6c43a43af253e688c9cfc1c86d332aed13f9a7c7f65e2", size = 27350 }, - { url = "https://files.pythonhosted.org/packages/5b/28/38353a232bdd1b3bca3732cd0a87dc2ee5bec2ce149cbacadfd47066c97e/google_crc32c-1.5.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6f998db4e71b645350b9ac28a2167e6632c239963ca9da411523bb439c5c514d", size = 29981 }, - { url = "https://files.pythonhosted.org/packages/bb/47/3dd904821181dbd20a8a72732592bf6ad5fb8a9d6b81d118eaf209089c48/google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c99616c853bb585301df6de07ca2cadad344fd1ada6d62bb30aec05219c45d2", size = 27910 }, - { url = "https://files.pythonhosted.org/packages/8b/08/7d4e899a866df7217a3bed6de436139ae789f651dda3b9f6e84d31f0989f/google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ad40e31093a4af319dadf503b2467ccdc8f67c72e4bcba97f8c10cb078207b5", size = 25646 }, - { url = "https://files.pythonhosted.org/packages/45/b8/e8de2b6d45d9ca777469ebf6f66137fe393c61175e9717805f924ee81e88/google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd67cf24a553339d5062eff51013780a00d6f97a39ca062781d06b3a73b15462", size = 27697 }, - { url = "https://files.pythonhosted.org/packages/5a/4a/999197b83bb5d24928a3cba2e59d3830910df5bd5f3c7a5253e623d8f9c3/google_crc32c-1.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:398af5e3ba9cf768787eef45c803ff9614cc3e22a5b2f7d7ae116df8b11e3314", size = 27350 }, - { url = "https://files.pythonhosted.org/packages/58/47/5374e1e82d2337a02506a339b1769a5af5f56abaa41bdc0a38885b7c014a/google_crc32c-1.5.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b1f8133c9a275df5613a451e73f36c2aea4fe13c5c8997e22cf355ebd7bd0728", size = 29989 }, - { url = "https://files.pythonhosted.org/packages/0c/1d/5e1eda168f85452609873fc8c0c4e85e0b8a19958e81e5b4bfc681ca3879/google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ba053c5f50430a3fcfd36f75aff9caeba0440b2d076afdb79a318d6ca245f88", size = 27910 }, - { url = "https://files.pythonhosted.org/packages/08/08/ee1c27ac7120c599bb51e09c5bfc3be618cedf34f73b21d0a6455f81f236/google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:272d3892a1e1a2dbc39cc5cde96834c236d5327e2122d3aaa19f6614531bb6eb", size = 25648 }, - { url = "https://files.pythonhosted.org/packages/9f/f2/f7f130a11bac632287659c1df246400350c2554fb3c4a800d7d83b75b769/google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:635f5d4dd18758a1fbd1049a8e8d2fee4ffed124462d837d1a02a0e009c3ab31", size = 27699 }, - { url = "https://files.pythonhosted.org/packages/0e/9a/c43c9e80d65c5e004569047e3cc5e851c9e283c47381e8472028bf025590/google_crc32c-1.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c672d99a345849301784604bfeaeba4db0c7aae50b95be04dd651fd2a7310b93", size = 27349 }, ] [[distribution]] @@ -1207,11 +793,11 @@ wheels = [ [[distribution]] name = "identify" -version = "2.5.36" +version = "2.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/9a/83775a4e09de8b9d774a2217bfe03038c488778e58561e6970daa39b4801/identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d", size = 99049 } +sdist = { url = "https://files.pythonhosted.org/packages/32/f4/8e8f7db397a7ce20fbdeac5f25adaf567fc362472432938d25556008e03a/identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf", size = 99116 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/d3/d31b7fe744a3b2e6c51ea04af6575d1583deb09eb33cecfc99fa7644a725/identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa", size = 98970 }, + { url = "https://files.pythonhosted.org/packages/24/6c/a4f39abe7f19600b74528d0c717b52fff0b300bb0161081510d39c53cb00/identify-2.6.0-py2.py3-none-any.whl", hash = "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0", size = 98962 }, ] [[distribution]] @@ -1310,21 +896,6 @@ version = "1.4.5" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b9/2d/226779e405724344fc678fcc025b812587617ea1a48b9442628b688e85ea/kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec", size = 97552 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/56/cb02dcefdaab40df636b91e703b172966b444605a0ea313549f3ffc05bd3/kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af", size = 127397 }, - { url = "https://files.pythonhosted.org/packages/0e/c1/d084f8edb26533a191415d5173157080837341f9a06af9dd1a75f727abb4/kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3", size = 68125 }, - { url = "https://files.pythonhosted.org/packages/23/11/6fb190bae4b279d712a834e7b1da89f6dcff6791132f7399aa28a57c3565/kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4", size = 66211 }, - { url = "https://files.pythonhosted.org/packages/b3/13/5e9e52feb33e9e063f76b2c5eb09cb977f5bba622df3210081bfb26ec9a3/kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1", size = 1637145 }, - { url = "https://files.pythonhosted.org/packages/6f/40/4ab1fdb57fced80ce5903f04ae1aed7c1d5939dda4fd0c0aa526c12fe28a/kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff", size = 1617849 }, - { url = "https://files.pythonhosted.org/packages/49/ca/61ef43bd0832c7253b370735b0c38972c140c8774889b884372a629a8189/kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a", size = 1400921 }, - { url = "https://files.pythonhosted.org/packages/68/6f/854f6a845c00b4257482468e08d8bc386f4929ee499206142378ba234419/kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa", size = 1513009 }, - { url = "https://files.pythonhosted.org/packages/50/65/76f303377167d12eb7a9b423d6771b39fe5c4373e4a42f075805b1f581ae/kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c", size = 1444819 }, - { url = "https://files.pythonhosted.org/packages/7e/ee/98cdf9dde129551467138b6e18cc1cc901e75ecc7ffb898c6f49609f33b1/kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b", size = 1817054 }, - { url = "https://files.pythonhosted.org/packages/e6/5b/ab569016ec4abc7b496f6cb8a3ab511372c99feb6a23d948cda97e0db6da/kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770", size = 1918613 }, - { url = "https://files.pythonhosted.org/packages/93/ac/39b9f99d2474b1ac7af1ddfe5756ddf9b6a8f24c5f3a32cd4c010317fc6b/kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0", size = 1872650 }, - { url = "https://files.pythonhosted.org/packages/40/5b/be568548266516b114d1776120281ea9236c732fb6032a1f8f3b1e5e921c/kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525", size = 1827415 }, - { url = "https://files.pythonhosted.org/packages/d4/80/c0c13d2a17a12937a19ef378bf35e94399fd171ed6ec05bcee0f038e1eaf/kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b", size = 1838094 }, - { url = "https://files.pythonhosted.org/packages/70/d1/5ab93ee00ca5af708929cc12fbe665b6f1ed4ad58088e70dc00e87e0d107/kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238", size = 46585 }, - { url = "https://files.pythonhosted.org/packages/4a/a1/8a9c9be45c642fa12954855d8b3a02d9fd8551165a558835a19508fec2e6/kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276", size = 56095 }, { url = "https://files.pythonhosted.org/packages/2a/eb/9e099ad7c47c279995d2d20474e1821100a5f10f847739bd65b1c1f02442/kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5", size = 127403 }, { url = "https://files.pythonhosted.org/packages/a6/94/695922e71288855fc7cace3bdb52edda9d7e50edba77abb0c9d7abb51e96/kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90", size = 68156 }, { url = "https://files.pythonhosted.org/packages/4a/fe/23d7fa78f7c66086d196406beb1fb2eaf629dd7adc01c3453033303d17fa/kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797", size = 66166 }, @@ -1355,64 +926,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4f/e9/9c0de8e45fef3d63f85eed3b1757f9aa511065942866331ef8b99421f433/kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a", size = 1908464 }, { url = "https://files.pythonhosted.org/packages/a3/60/4f0fd50b08f5be536ea0cef518ac7255d9dab43ca40f3b93b60e3ddf80dd/kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20", size = 46473 }, { url = "https://files.pythonhosted.org/packages/63/50/2746566bdf4a6a842d117367d05c90cfb87ac04e9e2845aa1fa21f071362/kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9", size = 56004 }, - { url = "https://files.pythonhosted.org/packages/90/54/d173ef7c814476f23471781768804356494363a824e312a1bd0fef50344c/kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130", size = 67465 }, - { url = "https://files.pythonhosted.org/packages/5e/37/d7753af11a6b4b8d22585525db06c1c01166a22c33afc43166d497c45f32/kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898", size = 1398679 }, - { url = "https://files.pythonhosted.org/packages/fe/65/73ac820664dd1e71276d8eff0d60f5a150d45d241cd1d88aed05a7754b17/kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709", size = 1509715 }, - { url = "https://files.pythonhosted.org/packages/ff/f2/1c442ed10b35846b152c66ac7b7a71ba71034c398b606181c4c0cc8cbffc/kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b", size = 1442772 }, - { url = "https://files.pythonhosted.org/packages/a1/38/2aedab05bd1e5b38dd470b5aeb0789f9e2f8f4bac47ee2c5beaea0ef8478/kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89", size = 1108140 }, - { url = "https://files.pythonhosted.org/packages/f9/77/e3046bf19720b22e3e0b7c12e28f6f2c0c18a213fb91a56cea640862270f/kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985", size = 1148389 }, - { url = "https://files.pythonhosted.org/packages/7f/e8/91989c0f30ffe4f94f8b8667740b8af66363229c08d43246f3c97761eb2e/kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265", size = 1828589 }, - { url = "https://files.pythonhosted.org/packages/a9/45/1934f450a68fd3daaa4741d57fd11f6bceda20c4433ff2f6d8fa70c74182/kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a", size = 1934260 }, - { url = "https://files.pythonhosted.org/packages/5e/51/806f3db7094c39e8fe44b2a725392f70e7601eee7ac93c72dd20421bbe72/kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205", size = 1883323 }, - { url = "https://files.pythonhosted.org/packages/2b/70/63df980a3cbf125919353cfcce094e34426867464ea387abb7102c38f9ec/kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb", size = 1838388 }, - { url = "https://files.pythonhosted.org/packages/47/52/75489f9fee2f01b81ea1975fd92c20f58e1cc964b78d2b9e493e077faf5e/kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f", size = 1844428 }, - { url = "https://files.pythonhosted.org/packages/a6/fc/d036c3832de1b30fbf27ca61b483f737b02d6f1f85b1fcedb3861fd96efa/kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3", size = 47910 }, - { url = "https://files.pythonhosted.org/packages/27/b5/c548a1f1cef3fb9af3f59d6fc4259aa17c48403680c33435ca675aae2b30/kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a", size = 55797 }, - { url = "https://files.pythonhosted.org/packages/e0/39/ba38e5634e4e21c5f738d55879fbc7eee91a70d7cc52903e15e9168296bc/kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71", size = 127208 }, - { url = "https://files.pythonhosted.org/packages/ca/78/2bff6dbedc619a614871005c32f106f24c3366e1025afff0fdfc2b56b7c8/kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93", size = 68043 }, - { url = "https://files.pythonhosted.org/packages/2e/db/501d8e0452e025e3ae7140439efab43789eb251e5cd8ed962297d565a301/kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29", size = 66043 }, - { url = "https://files.pythonhosted.org/packages/10/15/0c225864a00eb3dbd3d04b6465f331dc12a6e80673449166457b9566036d/kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712", size = 1387275 }, - { url = "https://files.pythonhosted.org/packages/58/23/58fc9e035eeac6c9e2ad7a2965e178aaf75a274193face124632c42e206f/kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6", size = 1500591 }, - { url = "https://files.pythonhosted.org/packages/91/7f/bffd5437533de5cc95c384413cb210a026038908e209fed73e0dd3ba4363/kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb", size = 1431728 }, - { url = "https://files.pythonhosted.org/packages/39/65/3341d1ba7d357985732b04d676e72206b231afa8f6318cf851dc5b35447e/kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18", size = 1125852 }, - { url = "https://files.pythonhosted.org/packages/d2/55/7021ffcc8cb26a520bb051aa0a3d08daf200cde945e5863d5768161e2d3d/kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333", size = 1180026 }, - { url = "https://files.pythonhosted.org/packages/c2/e3/de457b232f8d2a1bf22aceb9fb6ac44e4461719ecdfedcfb851824b09b49/kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da", size = 1814216 }, - { url = "https://files.pythonhosted.org/packages/19/8e/6390f247f83b2b4b9598c41ff81eb2356be627c72988bac7dc389e717b0c/kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b", size = 1913943 }, - { url = "https://files.pythonhosted.org/packages/70/6b/3713b38105dd071bec0c69221baf3e493b335f7157bef7743312f1b5e4cf/kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c", size = 1870507 }, - { url = "https://files.pythonhosted.org/packages/17/2b/aa1499f50c9d36b31663a3605e9888c662631a1e37c6f2501ae174e0950a/kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc", size = 1824249 }, - { url = "https://files.pythonhosted.org/packages/64/62/193cd7b7c2e26300857d3661697fd4e599858e21434cf6e35369e7884c94/kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250", size = 1834838 }, - { url = "https://files.pythonhosted.org/packages/1c/e1/597068727a76cbaf6aadb28882eb4d0ac48fed2e00a37e9f6cbbca5c24df/kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e", size = 46886 }, - { url = "https://files.pythonhosted.org/packages/1e/93/9dc4ca136063707f12eb56f4c8c294a940dd23f8512834573b201df83f88/kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced", size = 56197 }, - { url = "https://files.pythonhosted.org/packages/d5/2b/f0b6f9e8c657e493b5d9f43e9e786e2d4b3665f4f24e8b575044d6de33b9/kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d", size = 127375 }, - { url = "https://files.pythonhosted.org/packages/ef/da/e887802f34afb5806f139c71e6d5f20a9f33b2fccd7f9de771094f66ca5e/kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9", size = 68124 }, - { url = "https://files.pythonhosted.org/packages/89/a8/3b7e14121bea4438b87630557645bb7648b17b54acaa39b93f4bf7f8d33e/kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046", size = 66167 }, - { url = "https://files.pythonhosted.org/packages/ae/ca/5fdda20d677a19a789b490b9aa4542a6ce1842acb92e6e24ba2294cc9ffa/kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0", size = 1627002 }, - { url = "https://files.pythonhosted.org/packages/c0/a8/841594f11d0b88d8aeb26991bc4dac38baa909dc58d0c4262a4f7893bcbf/kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff", size = 1607093 }, - { url = "https://files.pythonhosted.org/packages/a8/04/b16d356c54db98d6f1002e7485997d47e8bfd416fe60c3a4139d256e1617/kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54", size = 1391911 }, - { url = "https://files.pythonhosted.org/packages/0b/59/e8b4264849c57fc823ddfbd2a029c9e1ca9f24fad82ea874b7a767132653/kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958", size = 1504791 }, - { url = "https://files.pythonhosted.org/packages/d7/4c/c1c861e7b4c6b4a67312942e155368aa228e7fd692fc217d92b0f6d388ff/kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3", size = 1437028 }, - { url = "https://files.pythonhosted.org/packages/85/de/f3230420b9995ddd389139ac250f73954b098e85300eac79decdd2c72b97/kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf", size = 1808774 }, - { url = "https://files.pythonhosted.org/packages/57/5c/6fe2f73eec0040031abd172a45af2471f4c3bd880ed4461b6d6e721d790f/kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901", size = 1909458 }, - { url = "https://files.pythonhosted.org/packages/71/8f/3030eb363dc1b1f64d5411544c95d86079817cda39f4e973247615161660/kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9", size = 1864345 }, - { url = "https://files.pythonhosted.org/packages/bb/24/c3616cc9078f2e3b6bfccb51afb8fa8ae0a4796c646cd2756c00a93b652c/kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342", size = 1820451 }, - { url = "https://files.pythonhosted.org/packages/08/b0/a818e5376b5718d3571412e2e0381e68df8bd88f12cab2418cc9122f6d1f/kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77", size = 1830580 }, - { url = "https://files.pythonhosted.org/packages/33/2a/3e559e086890220dcb6fc5e7812e94353a6ebc94470df6b3c02ce812a151/kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f", size = 46896 }, - { url = "https://files.pythonhosted.org/packages/ca/c1/1f986c8119c0c57c2bd71d1941da23332c38ee2c90117e46dff4358b70f7/kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635", size = 56201 }, - { url = "https://files.pythonhosted.org/packages/c9/b6/aad80b6e1e9640743ef2c8b6d2e10135692365176909f33f5e1400ec3a52/kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920", size = 58249 }, - { url = "https://files.pythonhosted.org/packages/65/1b/e498d7850c94f8690087295a81959bce1c5ac4807f19da7cbef921630c77/kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390", size = 103601 }, - { url = "https://files.pythonhosted.org/packages/9c/dd/c72f9b75ed53a3293366990a90a9dd597f33e18b15fde0d78ca12939a84a/kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d", size = 95306 }, - { url = "https://files.pythonhosted.org/packages/07/ad/d586def32f28baf92e66abb31fb409390f692f286cb1f01058517b8fa152/kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523", size = 78531 }, - { url = "https://files.pythonhosted.org/packages/63/61/3646d578ebf8550ae381cf965786beeedc1bb7ea092cdfbee2c489fd68a5/kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4", size = 56153 }, - { url = "https://files.pythonhosted.org/packages/d5/ec/43f8ce87157cf7f38de2fef6451f38fc6dc452a072721d6e8f6650962c88/kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892", size = 58978 }, - { url = "https://files.pythonhosted.org/packages/51/95/9e875695f51531ecf07a8a744f619d24fc1e5e78d0a6f31422bb1cc34f7a/kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544", size = 103602 }, - { url = "https://files.pythonhosted.org/packages/67/aa/8db40b241238c4d58bafc5a0be2ad2a8f5c9060ae887165ae53920c8e617/kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126", size = 95304 }, - { url = "https://files.pythonhosted.org/packages/56/0c/c7ebefc36b064d1ed08b3bb42e1aea85f75bcddcde903372c245f26990fc/kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd", size = 78235 }, - { url = "https://files.pythonhosted.org/packages/9c/ce/3d3f4df2702a188107fd47a960a4671720b0cb3b68e7382217687ec9551a/kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929", size = 56414 }, - { url = "https://files.pythonhosted.org/packages/31/57/a12b06f802834b0baee6d50a77cb7e73b730b8aa6f4794898cd53a4a80d7/kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09", size = 58285 }, - { url = "https://files.pythonhosted.org/packages/c7/47/19b88813ad3377cf25a42e83459fc36160da24ec788fa37f1f0a8776d171/kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7", size = 84358 }, - { url = "https://files.pythonhosted.org/packages/83/5b/799c1b0b12ad72b9bc17ba304f090385cc113e4e99816efae163b7d8b6c6/kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad", size = 80817 }, - { url = "https://files.pythonhosted.org/packages/2d/bc/b34ba1b2525c3f2380b21fcf72ad2b7468a998544e48da1a175e0b4bd031/kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea", size = 80022 }, - { url = "https://files.pythonhosted.org/packages/9b/9e/976aaa9a957e2bdcbd7cfd63dba83d8f422ee709c2d2314206e8b64555ee/kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee", size = 56008 }, ] [[distribution]] @@ -1432,19 +945,6 @@ version = "1.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/96/e3/42c87871920602a3c8300915bd0292f76eccc66c38f782397acbf8a62088/lru-dict-1.3.0.tar.gz", hash = "sha256:54fd1966d6bd1fcde781596cb86068214edeebff1db13a2cea11079e3fd07b6b", size = 13123 } wheels = [ - { url = "https://files.pythonhosted.org/packages/36/fc/d0de12343c9f132b10c7efe40951dfb6c3cfba328941ecf4c198e6bfdd78/lru_dict-1.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4073333894db9840f066226d50e6f914a2240711c87d60885d8c940b69a6673f", size = 17708 }, - { url = "https://files.pythonhosted.org/packages/75/56/af1cae207a5c4f1ada20a9bde92d7d953404274f499dd8fe3f4ece91eefe/lru_dict-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0ad6361e4dd63b47b2fc8eab344198f37387e1da3dcfacfee19bafac3ec9f1eb", size = 11017 }, - { url = "https://files.pythonhosted.org/packages/e9/d1/1dcaf052b4d039b85af8a8df9090c10923acc4bed448051ce791376313f3/lru_dict-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c637ab54b8cd9802fe19b260261e38820d748adf7606e34045d3c799b6dde813", size = 11322 }, - { url = "https://files.pythonhosted.org/packages/14/d4/77553cb43a2e50c3a5bb6338fe4ba3415638a99a5c8404a4ec13ab7cec52/lru_dict-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fce5f95489ca1fc158cc9fe0f4866db9cec82c2be0470926a9080570392beaf", size = 30597 }, - { url = "https://files.pythonhosted.org/packages/14/28/184d94fcd121a0dc775fa423bf05b886ae42fc081cbd693540068cf06ece/lru_dict-1.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2bf2e24cf5f19c3ff69bf639306e83dced273e6fa775b04e190d7f5cd16f794", size = 31871 }, - { url = "https://files.pythonhosted.org/packages/da/0e/6b49fa5fccc7b2d28fe254c48c64323741c98334e4fe41e4694fa049c208/lru_dict-1.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e90059f7701bef3c4da073d6e0434a9c7dc551d5adce30e6b99ef86b186f4b4a", size = 28651 }, - { url = "https://files.pythonhosted.org/packages/41/52/c3a4922421c8e5eb6fa1fdf5f56a7e01270a141a4f5f645d5ed6931b490f/lru_dict-1.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ecb7ae557239c64077e9b26a142eb88e63cddb104111a5122de7bebbbd00098", size = 30277 }, - { url = "https://files.pythonhosted.org/packages/f9/10/a15f70c5c36d46adba72850e64b075c6a118d2a9ee1ce7f2af2f4a419401/lru_dict-1.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6af36166d22dba851e06a13e35bbf33845d3dd88872e6aebbc8e3e7db70f4682", size = 34793 }, - { url = "https://files.pythonhosted.org/packages/56/e3/9901f9165a8c2d650bb84ae6ba371fa635e35e8b1dfb1aff2bd7be4cfd3a/lru_dict-1.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ee38d420c77eed548df47b7d74b5169a98e71c9e975596e31ab808e76d11f09", size = 33414 }, - { url = "https://files.pythonhosted.org/packages/be/27/6323b27dd42914c3ee511631d976d49247699ef0ec6fd468a5d4eef3930e/lru_dict-1.3.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0e1845024c31e6ff246c9eb5e6f6f1a8bb564c06f8a7d6d031220044c081090b", size = 36345 }, - { url = "https://files.pythonhosted.org/packages/76/14/b7d9009acf698e6f5d656e35776cedd3fd09755db5b09ff372d4e2667c4e/lru_dict-1.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3ca5474b1649555d014be1104e5558a92497509021a5ba5ea6e9b492303eb66b", size = 34619 }, - { url = "https://files.pythonhosted.org/packages/96/8d/ec1813a2618b152b845e782f8bf071e3d8cd5029fd725c8248c9db0109b6/lru_dict-1.3.0-cp310-cp310-win32.whl", hash = "sha256:ebb03a9bd50c2ed86d4f72a54e0aae156d35a14075485b2127c4b01a3f4a63fa", size = 12538 }, - { url = "https://files.pythonhosted.org/packages/dc/f4/463045af7fd4cf3840029ac75174bbff7240021daa9624bdd7a47265daf6/lru_dict-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:04cda617f4e4c27009005d0a8185ef02829b14b776d2791f5c994cc9d668bc24", size = 13652 }, { url = "https://files.pythonhosted.org/packages/a8/c9/6fac0cb67160f0efa3cc76a6a7d04d5e21a516eeb991ebba08f4f8f01ec5/lru_dict-1.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:20c595764695d20bdc3ab9b582e0cc99814da183544afb83783a36d6741a0dac", size = 17750 }, { url = "https://files.pythonhosted.org/packages/61/14/f90dee4bc547ae266dbeffd4e11611234bb6af511dea48f3bc8dac1de478/lru_dict-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d9b30a8f50c3fa72a494eca6be5810a1b5c89e4f0fda89374f0d1c5ad8d37d51", size = 11055 }, { url = "https://files.pythonhosted.org/packages/4e/63/a0ae20525f9d52f62ac0def47935f8a2b3b6fcd2c145218b9a27fc1fb910/lru_dict-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9710737584650a4251b9a566cbb1a86f83437adb209c9ba43a4e756d12faf0d7", size = 11330 }, @@ -1471,47 +971,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5a/0b/e30236aafe31b4247aa9ae61ba8aac6dde75c3ea0e47a8fb7eef53f6d5ce/lru_dict-1.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0e88dba16695f17f41701269fa046197a3fd7b34a8dba744c8749303ddaa18df", size = 37143 }, { url = "https://files.pythonhosted.org/packages/1c/28/b59bcebb8d76ba8147a784a8be7eab6a4ad3395b9236e73740ff675a5a52/lru_dict-1.3.0-cp312-cp312-win32.whl", hash = "sha256:6ffaf595e625b388babc8e7d79b40f26c7485f61f16efe76764e32dce9ea17fc", size = 12653 }, { url = "https://files.pythonhosted.org/packages/bd/18/06d9710cb0a0d3634f8501e4bdcc07abe64a32e404d82895a6a36fab97f6/lru_dict-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf9da32ef2582434842ab6ba6e67290debfae72771255a8e8ab16f3e006de0aa", size = 13811 }, - { url = "https://files.pythonhosted.org/packages/d1/2b/cc1d6f6371c7508843616b520f93031d8c7ad05e442db9b5080161380e78/lru_dict-1.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c265f16c936a8ff3bb4b8a4bda0be94c15ec28b63e99fdb1439c1ffe4cd437db", size = 17730 }, - { url = "https://files.pythonhosted.org/packages/38/13/93d8d4149fbf9974e49edcb27107a2f053294c76ad0465789a0bc223e64f/lru_dict-1.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:784ca9d3b0730b3ec199c0a58f66264c63dd5d438119c739c349a6a9be8e5f6e", size = 11001 }, - { url = "https://files.pythonhosted.org/packages/55/1a/d201a2018b45b95983b3afba0ac64847eded7e45e0a28bd0a5b68c9ce6aa/lru_dict-1.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e13b2f58f647178470adaa14603bb64cc02eeed32601772ccea30e198252883c", size = 11357 }, - { url = "https://files.pythonhosted.org/packages/ee/57/d1e616f1cefa1b57acfcf71c57c288d6e638d144cb14373bbd66f583ac56/lru_dict-1.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ffbce5c2e80f57937679553c8f27e61ec327c962bf7ea0b15f1d74277fd5363", size = 31192 }, - { url = "https://files.pythonhosted.org/packages/5a/ba/b4cadefbdd82ac2f8e68b1add9ccddbd919a7e7f714addfc3f7288cb2d73/lru_dict-1.3.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7969cb034b3ccc707aff877c73c225c32d7e2a7981baa8f92f5dd4d468fe8c33", size = 32525 }, - { url = "https://files.pythonhosted.org/packages/69/07/ed55d79d64c0a71787c6e57963205e5f1e58152856562fd1b5514f2e0eb3/lru_dict-1.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca9ab676609cce85dd65d91c275e47da676d13d77faa72de286fbea30fbaa596", size = 29270 }, - { url = "https://files.pythonhosted.org/packages/06/3e/1dbc3a4e46614744e4754d31106ad02b6d776b5706120f4ea29008cfd49b/lru_dict-1.3.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f27c078b5d75989952acbf9b77e14c3dadc468a4aafe85174d548afbc5efc38b", size = 30811 }, - { url = "https://files.pythonhosted.org/packages/c2/25/ab3cf40f7a114baad14a79243107e3a56aa8122409bafbea4838b3ea9ab3/lru_dict-1.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6123aefe97762ad74215d05320a7f389f196f0594c8813534284d4eafeca1a96", size = 35016 }, - { url = "https://files.pythonhosted.org/packages/19/18/72ff558501d7e68d7d38c0aeb230b8ef56bff6f1feb431494ffcf634a83f/lru_dict-1.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cd869cadba9a63e1e7fe2dced4a5747d735135b86016b0a63e8c9e324ab629ac", size = 33693 }, - { url = "https://files.pythonhosted.org/packages/ee/e6/ae18f50d422bc11e6980f67895c51c6316a64edddeda8d8c819d40599118/lru_dict-1.3.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:40a8daddc29c7edb09dfe44292cf111f1e93a8344349778721d430d336b50505", size = 36636 }, - { url = "https://files.pythonhosted.org/packages/e4/14/57e8bcdd13bd9a3623d15fc94c2902aa8d4281a0d8b2b998170092ad10c1/lru_dict-1.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a03170e4152836987a88dcebde61aaeb73ab7099a00bb86509d45b3fe424230", size = 34913 }, - { url = "https://files.pythonhosted.org/packages/33/f8/e720f6f070a998e7cc5df0cc0e243a6d1c3952d9805e6ca18ab066f0fe5d/lru_dict-1.3.0-cp38-cp38-win32.whl", hash = "sha256:3b4f121afe10f5a82b8e317626eb1e1c325b3f104af56c9756064cd833b1950b", size = 12588 }, - { url = "https://files.pythonhosted.org/packages/44/64/2bf4f469c821d07557f7f384c1d642baccce71d66ed678194677c4d5fdce/lru_dict-1.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:1470f5828c7410e16c24b5150eb649647986e78924816e6fb0264049dea14a2b", size = 13749 }, - { url = "https://files.pythonhosted.org/packages/2a/fe/7f7fe14b680c8605bf73087a985b859f3bf4ca52a5c40b23e691bd39f95c/lru_dict-1.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a3c9f746a9917e784fffcedeac4c8c47a3dbd90cbe13b69e9140182ad97ce4b7", size = 17720 }, - { url = "https://files.pythonhosted.org/packages/2d/73/b5bb1e97566791fa83ab851e4426887817e03f0404ef079007dd0c83eb52/lru_dict-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2789296819525a1f3204072dfcf3df6db8bcf69a8fc740ffd3de43a684ea7002", size = 11024 }, - { url = "https://files.pythonhosted.org/packages/72/31/5252dcf464f6f39abfc3f1b38dd0e42e6ea2b41c0b867227ee13568b32f7/lru_dict-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:170b66d29945391460351588a7bd8210a95407ae82efe0b855e945398a1d24ea", size = 11323 }, - { url = "https://files.pythonhosted.org/packages/2e/af/dad7f54ad9713829c7a98aa64981d14fdadfebac7e04fc6471c70932d88f/lru_dict-1.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:774ca88501a9effe8797c3db5a6685cf20978c9cb0fe836b6813cfe1ca60d8c9", size = 30257 }, - { url = "https://files.pythonhosted.org/packages/f2/f7/49b0d40262af0ea275a9bf169d26c59e8ba4ccc84bf21a039712c60841ea/lru_dict-1.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:df2e119c6ae412d2fd641a55f8a1e2e51f45a3de3449c18b1b86c319ab79e0c4", size = 31494 }, - { url = "https://files.pythonhosted.org/packages/37/2f/89bf5f6eb08f8661eb1704bfe82abbb839b6aa6a7bb04da397b8b32c6856/lru_dict-1.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28aa1ea42a7e48174bf513dc2416fea7511a547961e678dc6f5670ca987c18cb", size = 28253 }, - { url = "https://files.pythonhosted.org/packages/d4/7a/0245feb3a7d8216b8415520f8530516fc7b6ce0d33ea154ffce0bd45db40/lru_dict-1.3.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9537e1cee6fa582cb68f2fb9ce82d51faf2ccc0a638b275d033fdcb1478eb80b", size = 29847 }, - { url = "https://files.pythonhosted.org/packages/60/c7/494b0938443891a456260502465544f7a2781111857d7e018e7f2abf95d4/lru_dict-1.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:64545fca797fe2c68c5168efb5f976c6e1459e058cab02445207a079180a3557", size = 34376 }, - { url = "https://files.pythonhosted.org/packages/59/1a/5d6219520274eced5327fe3590d0c7c8c6352d996f3507f277beb49b6293/lru_dict-1.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a193a14c66cfc0c259d05dddc5e566a4b09e8f1765e941503d065008feebea9d", size = 33006 }, - { url = "https://files.pythonhosted.org/packages/05/8c/4664d41111032b829db77d87cef0530078bf6a6c6c20f0e09e64ee6fb1b5/lru_dict-1.3.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:3cb1de0ce4137b060abaafed8474cc0ebd12cedd88aaa7f7b3ebb1ddfba86ae0", size = 35933 }, - { url = "https://files.pythonhosted.org/packages/58/e6/dc37372228567c7cfb4bc21096f031249047f269b307c692e3917a038a4d/lru_dict-1.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8551ccab1349d4bebedab333dfc8693c74ff728f4b565fe15a6bf7d296bd7ea9", size = 34193 }, - { url = "https://files.pythonhosted.org/packages/97/03/53e3e566b633d853a751d79a8073a2554ab5cd87b2c6dae52492ac8a38ff/lru_dict-1.3.0-cp39-cp39-win32.whl", hash = "sha256:6cb0be5e79c3f34d69b90d8559f0221e374b974b809a22377122c4b1a610ff67", size = 12567 }, - { url = "https://files.pythonhosted.org/packages/2b/a6/bfebae2154dd666cccf282d37a54a3142855796209c70dd9ff862343bde8/lru_dict-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9f725f2a0bdf1c18735372d5807af4ea3b77888208590394d4660e3d07971f21", size = 13718 }, - { url = "https://files.pythonhosted.org/packages/78/8b/4b7af0793512af8b0d814b3b08ccecb08f313594866cfe9aabf77f642934/lru_dict-1.3.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f8f7824db5a64581180ab9d09842e6dd9fcdc46aac9cb592a0807cd37ea55680", size = 10060 }, - { url = "https://files.pythonhosted.org/packages/47/04/e310269b8bbb5718025d0375d8189551f10f1ef057df2b21e4bc5714fb56/lru_dict-1.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:acd04b7e7b0c0c192d738df9c317093335e7282c64c9d1bb6b7ebb54674b4e24", size = 13299 }, - { url = "https://files.pythonhosted.org/packages/e2/d2/246d375c89a71637fe193f260c500537e5dc11cf3a2b5144669bfef69295/lru_dict-1.3.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5c20f236f27551e3f0adbf1a987673fb1e9c38d6d284502cd38f5a3845ef681", size = 13142 }, - { url = "https://files.pythonhosted.org/packages/8a/10/56fead7639a41d507eac5163a81f18c7f47a8c1feb3046d20a9c8bb56e56/lru_dict-1.3.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca3703ff03b03a1848c563bc2663d0ad813c1cd42c4d9cf75b623716d4415d9a", size = 12839 }, - { url = "https://files.pythonhosted.org/packages/fe/a4/0d68bc4007aac962386185f625d0d5180cf574e72b5279f840abde1a0e4e/lru_dict-1.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a9fb71ba262c6058a0017ce83d343370d0a0dbe2ae62c2eef38241ec13219330", size = 13768 }, - { url = "https://files.pythonhosted.org/packages/fe/bd/beb9bf8bdd21d67d0079ce3bbd2cfcd49fc2ae3f7030943ba8a92afb925c/lru_dict-1.3.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f5b88a7c39e307739a3701194993455968fcffe437d1facab93546b1b8a334c1", size = 10057 }, - { url = "https://files.pythonhosted.org/packages/ec/c2/2a45c9c39dbb4207a584187bb321085699bd7736dabe08b4e60edbe58353/lru_dict-1.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2682bfca24656fb7a643621520d57b7fe684ed5fa7be008704c1235d38e16a32", size = 13260 }, - { url = "https://files.pythonhosted.org/packages/64/d9/7ea3b571b3113069b34f8fd5a2155bf45630c3a71640f544901ec3be409a/lru_dict-1.3.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96fc87ddf569181827458ec5ad8fa446c4690cffacda66667de780f9fcefd44d", size = 13133 }, - { url = "https://files.pythonhosted.org/packages/93/fc/73a5dfd2d4846b629aecfd07e2a7fb79632b2525906112bd4120daefc013/lru_dict-1.3.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcec98e2c7da7631f0811730303abc4bdfe70d013f7a11e174a2ccd5612a7c59", size = 12859 }, - { url = "https://files.pythonhosted.org/packages/e1/19/b56e1b445a3ffefdcce221fd09f683897257fab11a78b5b007a01974bf63/lru_dict-1.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:6bba2863060caeaedd8386b0c8ee9a7ce4d57a7cb80ceeddf440b4eff2d013ba", size = 13674 }, - { url = "https://files.pythonhosted.org/packages/2f/cc/1167c2d28c09b8491ea23eb5429f9372569376ee3df18aae8053beef457b/lru_dict-1.3.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3c497fb60279f1e1d7dfbe150b1b069eaa43f7e172dab03f206282f4994676c5", size = 10055 }, - { url = "https://files.pythonhosted.org/packages/59/ce/f8d122c90f724900aede0251f11352ba37915d55433fe6896e218ef23cd4/lru_dict-1.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d9509d817a47597988615c1a322580c10100acad10c98dfcf3abb41e0e5877f", size = 13294 }, - { url = "https://files.pythonhosted.org/packages/e6/47/8071b4689ed54f6d6ecf89f5ab30906d3ff26253ce89d5ba3cdeb15d3f5f/lru_dict-1.3.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0213ab4e3d9a8d386c18e485ad7b14b615cb6f05df6ef44fb2a0746c6ea9278b", size = 13140 }, - { url = "https://files.pythonhosted.org/packages/f8/15/70915c50fe4afd59493aa0391fab52769ecbcb1b79c5ce00a8e3bd9622d6/lru_dict-1.3.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b50fbd69cd3287196796ab4d50e4cc741eb5b5a01f89d8e930df08da3010c385", size = 12840 }, - { url = "https://files.pythonhosted.org/packages/03/79/4cefb7cc8387da16480e8aba8c5483cd692460ea29fe7114d6057ed4e0d4/lru_dict-1.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5247d1f011f92666010942434020ddc5a60951fefd5d12a594f0e5d9f43e3b3b", size = 13779 }, ] [[distribution]] @@ -1520,27 +979,6 @@ version = "5.2.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/63/f7/ffbb6d2eb67b80a45b8a0834baa5557a14a5ffce0979439e7cd7f0c4055b/lxml-5.2.2.tar.gz", hash = "sha256:bb2dc4898180bea79863d5487e5f9c7c34297414bad54bcd0f0852aee9cfdb87", size = 3678631 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/e9/73c7e6f9a933ee82cd68599d6291c875379cbce2c47717b811744cfd2256/lxml-5.2.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:364d03207f3e603922d0d3932ef363d55bbf48e3647395765f9bfcbdf6d23632", size = 8124248 }, - { url = "https://files.pythonhosted.org/packages/f2/1e/364a7e4afe9d27cef4f7a684ace409a379c953fe0881b0f2ff67380ed9ea/lxml-5.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:50127c186f191b8917ea2fb8b206fbebe87fd414a6084d15568c27d0a21d60db", size = 4412062 }, - { url = "https://files.pythonhosted.org/packages/06/0f/fd5d42f906eff843c9080fba7fdd005cdf1be697e19517013938c0581eed/lxml-5.2.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74e4f025ef3db1c6da4460dd27c118d8cd136d0391da4e387a15e48e5c975147", size = 5138539 }, - { url = "https://files.pythonhosted.org/packages/06/53/6994084d29251e9ee0e8486d82416836a9d009208853e8216cbc4c924c8c/lxml-5.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:981a06a3076997adf7c743dcd0d7a0415582661e2517c7d961493572e909aa1d", size = 4839289 }, - { url = "https://files.pythonhosted.org/packages/68/ad/3cbe5b7005722cae504f3cc2879f444f6407fb1a8a1f53050f03ca784c46/lxml-5.2.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aef5474d913d3b05e613906ba4090433c515e13ea49c837aca18bde190853dff", size = 5420758 }, - { url = "https://files.pythonhosted.org/packages/6b/2d/ea82f53acc12e7245a1927de78093654d140e6ef12bd2fcae41436c936da/lxml-5.2.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e275ea572389e41e8b039ac076a46cb87ee6b8542df3fff26f5baab43713bca", size = 4874778 }, - { url = "https://files.pythonhosted.org/packages/98/59/3877fd55ebc6d0f426583137bedeee21c9f6d5d5c829664a14103f5279a7/lxml-5.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5b65529bb2f21ac7861a0e94fdbf5dc0daab41497d18223b46ee8515e5ad297", size = 5013017 }, - { url = "https://files.pythonhosted.org/packages/84/2e/dac726231781599429ea0b3faf018c081334a68c68708e7381077f447033/lxml-5.2.2-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:bcc98f911f10278d1daf14b87d65325851a1d29153caaf146877ec37031d5f36", size = 4816824 }, - { url = "https://files.pythonhosted.org/packages/54/4d/47eb532c0472bb5495efe899740e3d928ddb79599e73d156d4cfa8e126a3/lxml-5.2.2-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:b47633251727c8fe279f34025844b3b3a3e40cd1b198356d003aa146258d13a2", size = 5468541 }, - { url = "https://files.pythonhosted.org/packages/78/73/82a00717a29330cf56a4a7f3077aa7ee4d5171e79fcdd7d161d90df53122/lxml-5.2.2-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:fbc9d316552f9ef7bba39f4edfad4a734d3d6f93341232a9dddadec4f15d425f", size = 4977853 }, - { url = "https://files.pythonhosted.org/packages/c6/24/8ddb86ab14428d4d222a383a5260eea93728192359a1fff5de8f7fa13374/lxml-5.2.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:13e69be35391ce72712184f69000cda04fc89689429179bc4c0ae5f0b7a8c21b", size = 5030426 }, - { url = "https://files.pythonhosted.org/packages/1f/fb/510777421d0231b3f601d7d6a9a494717bac3a206eca1518b38a869f5289/lxml-5.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3b6a30a9ab040b3f545b697cb3adbf3696c05a3a68aad172e3fd7ca73ab3c835", size = 4865825 }, - { url = "https://files.pythonhosted.org/packages/27/0a/82b3f5b375d3252a76e73efb56857424804f5dabce62712e256f96d0fa69/lxml-5.2.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a233bb68625a85126ac9f1fc66d24337d6e8a0f9207b688eec2e7c880f012ec0", size = 5417133 }, - { url = "https://files.pythonhosted.org/packages/03/f4/73ea84c176aaff04ca10093fc7ac3912c4aa4793ef1c3f5a963a40db0a6f/lxml-5.2.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:dfa7c241073d8f2b8e8dbc7803c434f57dbb83ae2a3d7892dd068d99e96efe2c", size = 4838827 }, - { url = "https://files.pythonhosted.org/packages/38/bc/e9269ba955b66ef2af8559d405514d8c055b5dfa58cec71f78f0bc4d7493/lxml-5.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a7aca7964ac4bb07680d5c9d63b9d7028cace3e2d43175cb50bba8c5ad33316", size = 5004832 }, - { url = "https://files.pythonhosted.org/packages/0a/99/a3abdfcde8f2a171a9e5f63b97bf2a6a6612c2356af151fb2bdc949e77ba/lxml-5.2.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ae4073a60ab98529ab8a72ebf429f2a8cc612619a8c04e08bed27450d52103c0", size = 4860569 }, - { url = "https://files.pythonhosted.org/packages/1e/3c/ba4aa85a49a7bb9fef7062cd7f584b3da59d4bba82cef375164b95f60834/lxml-5.2.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ffb2be176fed4457e445fe540617f0252a72a8bc56208fd65a690fdb1f57660b", size = 5506124 }, - { url = "https://files.pythonhosted.org/packages/5c/5d/faebbdaae16a40eb559b3e1bf0548e23ad43716f1c5e781c1d2f9ac900ec/lxml-5.2.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e290d79a4107d7d794634ce3e985b9ae4f920380a813717adf61804904dc4393", size = 4946883 }, - { url = "https://files.pythonhosted.org/packages/31/47/64914d8e752c9dd13b7da69ca7b9f645983412206936058b5261c2c9e093/lxml-5.2.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:96e85aa09274955bb6bd483eaf5b12abadade01010478154b0ec70284c1b1526", size = 5046267 }, - { url = "https://files.pythonhosted.org/packages/54/c2/cc28433f429a6767e0de7b9f908ed0c88dc5c60195330d15686d6ba623a4/lxml-5.2.2-cp310-cp310-win32.whl", hash = "sha256:f956196ef61369f1685d14dad80611488d8dc1ef00be57c0c5a03064005b0f30", size = 3478736 }, - { url = "https://files.pythonhosted.org/packages/5b/bc/51530ee31e3ce25634ed790e38a62ffaea6507befd73b51926e19ce794f9/lxml-5.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:875a3f90d7eb5c5d77e529080d95140eacb3c6d13ad5b616ee8095447b1d22e7", size = 3807856 }, { url = "https://files.pythonhosted.org/packages/da/6a/24e9f77d17668dd4ac0a6c2a56113fd3e0db07cee51e3a67afcd47c597e5/lxml-5.2.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:45f9494613160d0405682f9eee781c7e6d1bf45f819654eb249f8f46a2c22545", size = 8137962 }, { url = "https://files.pythonhosted.org/packages/4e/42/3bfe92749715c819763d2205370ecc7f586b44e277f38839e27cce7d6bb8/lxml-5.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b0b3f2df149efb242cee2ffdeb6674b7f30d23c9a7af26595099afaf46ef4e88", size = 4424403 }, { url = "https://files.pythonhosted.org/packages/d5/fd/4899215277e3ef1767019fab178fad8a149081f80cf886a73dc0ba1badae/lxml-5.2.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d28cb356f119a437cc58a13f8135ab8a4c8ece18159eb9194b0d269ec4e28083", size = 5099309 }, @@ -1583,84 +1021,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3e/fa/b361d670ffa8f477504b7fc0e5734a7878815c7e0b6769f3a5a903a94aee/lxml-5.2.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f11ae142f3a322d44513de1018b50f474f8f736bc3cd91d969f464b5bfef8836", size = 4972719 }, { url = "https://files.pythonhosted.org/packages/fc/43/70e469a190a8f39ca5829b4ef4f2f7299ce65243abe46ba4a73dc58c1365/lxml-5.2.2-cp312-cp312-win32.whl", hash = "sha256:16a8326e51fcdffc886294c1e70b11ddccec836516a343f9ed0f82aac043c24a", size = 3487299 }, { url = "https://files.pythonhosted.org/packages/58/16/99b03974974537c8c786fb98183d7c213ceb16e71205174a29ae869ca988/lxml-5.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:bbc4b80af581e18568ff07f6395c02114d05f4865c2812a1f02f2eaecf0bfd48", size = 3817779 }, - { url = "https://files.pythonhosted.org/packages/4a/a2/b58dcc43a4fee4cc87c1c2ff1c73abed338ebef75c930f7327c52067fff3/lxml-5.2.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e3d9d13603410b72787579769469af730c38f2f25505573a5888a94b62b920f8", size = 4391065 }, - { url = "https://files.pythonhosted.org/packages/fc/44/eb43b3913660f5740beaab422b159b90e4cfccc95f660151bbed6bbb1c9d/lxml-5.2.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38b67afb0a06b8575948641c1d6d68e41b83a3abeae2ca9eed2ac59892b36706", size = 4949724 }, - { url = "https://files.pythonhosted.org/packages/ca/88/8e0aedee5f2282c5f663c2dbde79fc257943330c75dc104d335d6d429a4d/lxml-5.2.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c689d0d5381f56de7bd6966a4541bff6e08bf8d3871bbd89a0c6ab18aa699573", size = 4818956 }, - { url = "https://files.pythonhosted.org/packages/27/08/54bec8bfcab42b54859e1b94d0f1860e7430e3770ef0085e357ccd6f384c/lxml-5.2.2-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:cf2a978c795b54c539f47964ec05e35c05bd045db5ca1e8366988c7f2fe6b3ce", size = 4850018 }, - { url = "https://files.pythonhosted.org/packages/fa/c8/44ff095bd4e7ad49cf34daa68727afd7d03cfbea364e8578e039c4208611/lxml-5.2.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:739e36ef7412b2bd940f75b278749106e6d025e40027c0b94a17ef7968d55d56", size = 4976726 }, - { url = "https://files.pythonhosted.org/packages/8f/c7/64b65404d108dbbc54c536cd35f13a88996467d966684522c7c69be71ed4/lxml-5.2.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d8bbcd21769594dbba9c37d3c819e2d5847656ca99c747ddb31ac1701d0c0ed9", size = 4837453 }, - { url = "https://files.pythonhosted.org/packages/bd/8a/cf8577620d9cfffe1cf9997203b46834508b149e87f54f0376a86444a271/lxml-5.2.2-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:2304d3c93f2258ccf2cf7a6ba8c761d76ef84948d87bf9664e14d203da2cd264", size = 4866442 }, - { url = "https://files.pythonhosted.org/packages/81/7b/ef49abe8fb09fa7dc728c6d51aa05981dbf3415f6d768790d48e04a7c623/lxml-5.2.2-cp36-cp36m-win32.whl", hash = "sha256:02437fb7308386867c8b7b0e5bc4cd4b04548b1c5d089ffb8e7b31009b961dc3", size = 3519110 }, - { url = "https://files.pythonhosted.org/packages/0c/26/f7615f8b45367cc0958631980251ae74c278a3df45ff9271cb5cdd93e1e9/lxml-5.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:edcfa83e03370032a489430215c1e7783128808fd3e2e0a3225deee278585196", size = 3859255 }, - { url = "https://files.pythonhosted.org/packages/1a/9e/91d0477379aa28bc8102c0359d28ec19f40d7102232d68f6ab9b1c1f5f55/lxml-5.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:28bf95177400066596cdbcfc933312493799382879da504633d16cf60bba735b", size = 4432286 }, - { url = "https://files.pythonhosted.org/packages/bf/a1/86a0b3aecf60e8d4795bb005e0235e6666f4631b7b03eecf634f5de2af53/lxml-5.2.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a745cc98d504d5bd2c19b10c79c61c7c3df9222629f1b6210c0368177589fb8", size = 5070460 }, - { url = "https://files.pythonhosted.org/packages/bd/5c/09e9cfbc959e1e122ba35927ab05d431a857c24717a74151bf6df46fc4ca/lxml-5.2.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b590b39ef90c6b22ec0be925b211298e810b4856909c8ca60d27ffbca6c12e6", size = 4784507 }, - { url = "https://files.pythonhosted.org/packages/6f/7f/75f64f3520d16d7af1221327c3a4991f2dca6d1a9a69aeb79b7d18ddad20/lxml-5.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b336b0416828022bfd5a2e3083e7f5ba54b96242159f83c7e3eebaec752f1716", size = 4939964 }, - { url = "https://files.pythonhosted.org/packages/a7/67/0b6288b409aafad2e4281341a94a5e4fde4184ccad9a8d1de7cce744ff59/lxml-5.2.2-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:c2faf60c583af0d135e853c86ac2735ce178f0e338a3c7f9ae8f622fd2eb788c", size = 4773461 }, - { url = "https://files.pythonhosted.org/packages/d8/53/51c82d3dc16ea3e060c317acb2e44286a2a0b69d301a45515c26ae2addeb/lxml-5.2.2-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:4bc6cb140a7a0ad1f7bc37e018d0ed690b7b6520ade518285dc3171f7a117905", size = 4979706 }, - { url = "https://files.pythonhosted.org/packages/a9/56/854c2af278132ee3adc10216c67c106178708dde57115d0d090ab105db4d/lxml-5.2.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7ff762670cada8e05b32bf1e4dc50b140790909caa8303cfddc4d702b71ea184", size = 4835274 }, - { url = "https://files.pythonhosted.org/packages/f2/d6/e042d399030b0d0f24a5c11b762babc990c599cbe48e849cb99473230227/lxml-5.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:57f0a0bbc9868e10ebe874e9f129d2917750adf008fe7b9c1598c0fbbfdde6a6", size = 4968706 }, - { url = "https://files.pythonhosted.org/packages/d5/01/12e750cb9bb7306dbd7638fb1c03a54da80401381bbb746e0d82a4ddfc92/lxml-5.2.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:a6d2092797b388342c1bc932077ad232f914351932353e2e8706851c870bca1f", size = 4815323 }, - { url = "https://files.pythonhosted.org/packages/d5/22/c75dcff88d6b152d6c02199bffc7d724e67a3a0a3832fd779fe3a5c08b80/lxml-5.2.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:60499fe961b21264e17a471ec296dcbf4365fbea611bf9e303ab69db7159ce61", size = 5000567 }, - { url = "https://files.pythonhosted.org/packages/f1/d5/f2f03d60bc46f81182fd7015580e1f16bc8958dd828589f09d3440e238ef/lxml-5.2.2-cp37-cp37m-win32.whl", hash = "sha256:d9b342c76003c6b9336a80efcc766748a333573abf9350f4094ee46b006ec18f", size = 3457991 }, - { url = "https://files.pythonhosted.org/packages/9a/05/8ef2856a0d47450e52ebe9f63137f3ad228f902458659143f5be3c3c546f/lxml-5.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b16db2770517b8799c79aa80f4053cd6f8b716f21f8aca962725a9565ce3ee40", size = 3774971 }, - { url = "https://files.pythonhosted.org/packages/c1/cd/fffcb438ce26bb6cb439cba9fc2f7a80b81f65415f2d6ec20c50512db391/lxml-5.2.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7ed07b3062b055d7a7f9d6557a251cc655eed0b3152b76de619516621c56f5d3", size = 4456989 }, - { url = "https://files.pythonhosted.org/packages/2b/8f/81f26f7a6248920ede179d51259ed7d25dd08f8c081a7ede9aacd5fb3b7a/lxml-5.2.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f60fdd125d85bf9c279ffb8e94c78c51b3b6a37711464e1f5f31078b45002421", size = 5136876 }, - { url = "https://files.pythonhosted.org/packages/82/28/0262488edce330c629ab8fcfa51d94ffd40413ce12d11d336a08c9a8a645/lxml-5.2.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a7e24cb69ee5f32e003f50e016d5fde438010c1022c96738b04fc2423e61706", size = 4844441 }, - { url = "https://files.pythonhosted.org/packages/13/ad/e1cc7fe23da35866cf8d8453cdb7a6c550f9bc3faf2d7a3640dc1b6c6eba/lxml-5.2.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23cfafd56887eaed93d07bc4547abd5e09d837a002b791e9767765492a75883f", size = 5021413 }, - { url = "https://files.pythonhosted.org/packages/4d/72/f118145d85f02a76d3f31955c044cb913419c57413b11cd44c00359903dc/lxml-5.2.2-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:19b4e485cd07b7d83e3fe3b72132e7df70bfac22b14fe4bf7a23822c3a35bff5", size = 4837342 }, - { url = "https://files.pythonhosted.org/packages/1f/d7/459d1393f71c1f9781b05b39ef9d5f99a052e7476212d285929565d49adb/lxml-5.2.2-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7ce7ad8abebe737ad6143d9d3bf94b88b93365ea30a5b81f6877ec9c0dee0a48", size = 5062883 }, - { url = "https://files.pythonhosted.org/packages/d1/7b/769e3aa58bb34d18212495bec03b0b81471bdba5348b914a4eaef90b3798/lxml-5.2.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e49b052b768bb74f58c7dda4e0bdf7b79d43a9204ca584ffe1fb48a6f3c84c66", size = 4890395 }, - { url = "https://files.pythonhosted.org/packages/7c/db/f0090d54d26aa801307b2229520b10d47a290e717a8538562b6a1bff417d/lxml-5.2.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d14a0d029a4e176795cef99c056d58067c06195e0c7e2dbb293bf95c08f772a3", size = 5034282 }, - { url = "https://files.pythonhosted.org/packages/f5/5c/5351861cc904359e2fb79a189167a9c51a525cac4b2271e37dfb103f5df1/lxml-5.2.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:be49ad33819d7dcc28a309b86d4ed98e1a65f3075c6acd3cd4fe32103235222b", size = 4875796 }, - { url = "https://files.pythonhosted.org/packages/48/8d/6b694185f9b5d5ae076948c2df9e82e707987bdf6769854adef4a661a4e7/lxml-5.2.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a6d17e0370d2516d5bb9062c7b4cb731cff921fc875644c3d751ad857ba9c5b1", size = 5077787 }, - { url = "https://files.pythonhosted.org/packages/d1/67/d9c0e1fc12fce10ddb1aa4a912935799d4a708bba2d874e32269f9878897/lxml-5.2.2-cp38-cp38-win32.whl", hash = "sha256:5b8c041b6265e08eac8a724b74b655404070b636a8dd6d7a13c3adc07882ef30", size = 3485262 }, - { url = "https://files.pythonhosted.org/packages/be/4b/6ca2d2e16a1b78a8a3ec18f5e586044c3903c3967411e7a9e37cb4727c6d/lxml-5.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:f61efaf4bed1cc0860e567d2ecb2363974d414f7f1f124b1df368bbf183453a6", size = 3816804 }, - { url = "https://files.pythonhosted.org/packages/51/79/9f7d249850c9f8357538055359bffa91cc9f0606fcea72b6881fdea9ee39/lxml-5.2.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fb91819461b1b56d06fa4bcf86617fac795f6a99d12239fb0c68dbeba41a0a30", size = 8129295 }, - { url = "https://files.pythonhosted.org/packages/40/94/cc5a570ae1dcd337a6b63330d8fd6ff81dc27310574157129faca3ddbfe7/lxml-5.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d4ed0c7cbecde7194cd3228c044e86bf73e30a23505af852857c09c24e77ec5d", size = 4415097 }, - { url = "https://files.pythonhosted.org/packages/bc/41/38d7e67e72f87fea0d9f2fd37e394484eb32b102d3a0520611a65e992602/lxml-5.2.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54401c77a63cc7d6dc4b4e173bb484f28a5607f3df71484709fe037c92d4f0ed", size = 5139658 }, - { url = "https://files.pythonhosted.org/packages/6f/3f/66f7869f12bf6f21af6b24b0b29e4bccc162efa276ee46a58e6993b63f5a/lxml-5.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:625e3ef310e7fa3a761d48ca7ea1f9d8718a32b1542e727d584d82f4453d5eeb", size = 4839453 }, - { url = "https://files.pythonhosted.org/packages/f5/67/5dd78932c10e49f5fd3d0cd63d27bcaa801fae8f64c643a931e0391c56e2/lxml-5.2.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:519895c99c815a1a24a926d5b60627ce5ea48e9f639a5cd328bda0515ea0f10c", size = 5422704 }, - { url = "https://files.pythonhosted.org/packages/0f/e8/c0dd37abb15dd982e348c666ae02a7767d7a70acf143d5e24a906de2b29f/lxml-5.2.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c7079d5eb1c1315a858bbf180000757db8ad904a89476653232db835c3114001", size = 4875536 }, - { url = "https://files.pythonhosted.org/packages/e5/43/d60da0fe90a9a48198a23268dd2dafeac46f880adda6739b4cbbcec65a02/lxml-5.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:343ab62e9ca78094f2306aefed67dcfad61c4683f87eee48ff2fd74902447726", size = 5013656 }, - { url = "https://files.pythonhosted.org/packages/f6/59/74549a8c486d60c24c8cae942325e60916fb2699b1cbec89025ceeb49e51/lxml-5.2.2-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:cd9e78285da6c9ba2d5c769628f43ef66d96ac3085e59b10ad4f3707980710d3", size = 4818873 }, - { url = "https://files.pythonhosted.org/packages/9b/d5/469cc5b87f704d951d558ab8dcf4a6a1e339dbfd4cf82788d6c5f76daa55/lxml-5.2.2-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:546cf886f6242dff9ec206331209db9c8e1643ae642dea5fdbecae2453cb50fd", size = 5470990 }, - { url = "https://files.pythonhosted.org/packages/0d/89/d2f6f90e30cf7eb4477554a13f8a7b8aadaf762d595c76a434eb26d0947c/lxml-5.2.2-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:02f6a8eb6512fdc2fd4ca10a49c341c4e109aa6e9448cc4859af5b949622715a", size = 4979955 }, - { url = "https://files.pythonhosted.org/packages/c4/34/11d8b7bacec6b9af6305a266cc5a2695f81427dba9a4c2d59791b5b156e5/lxml-5.2.2-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:339ee4a4704bc724757cd5dd9dc8cf4d00980f5d3e6e06d5847c1b594ace68ab", size = 5028329 }, - { url = "https://files.pythonhosted.org/packages/2b/40/9a1782445756e1c3b028a26d8ce1864042d13ba8c7e5aa1eeb12a6b3b410/lxml-5.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0a028b61a2e357ace98b1615fc03f76eb517cc028993964fe08ad514b1e8892d", size = 4866331 }, - { url = "https://files.pythonhosted.org/packages/b4/10/741b8edfacede7a3bcec3f0f781fcc9270efe276b0fe73aa0330217c41fa/lxml-5.2.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f90e552ecbad426eab352e7b2933091f2be77115bb16f09f78404861c8322981", size = 5420205 }, - { url = "https://files.pythonhosted.org/packages/88/8f/320abad6e805b6bff2920ce99fea4e818598bee771e10744a2a173402a4d/lxml-5.2.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d83e2d94b69bf31ead2fa45f0acdef0757fa0458a129734f59f67f3d2eb7ef32", size = 4841182 }, - { url = "https://files.pythonhosted.org/packages/2b/94/fc50d1b8b8dcd75e3020b420339d650657fc2f6fcdeadbfcd39f63ee4292/lxml-5.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a02d3c48f9bb1e10c7788d92c0c7db6f2002d024ab6e74d6f45ae33e3d0288a3", size = 5006820 }, - { url = "https://files.pythonhosted.org/packages/21/83/46e40a901e00105a3520d57d6726ac1e5c8a9276f5972ef26b4be54789f1/lxml-5.2.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6d68ce8e7b2075390e8ac1e1d3a99e8b6372c694bbe612632606d1d546794207", size = 4861349 }, - { url = "https://files.pythonhosted.org/packages/ee/92/a5a02b2b556b8736061532588a07dafdd0fa3bd34c515d600790ff931a5b/lxml-5.2.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:453d037e09a5176d92ec0fd282e934ed26d806331a8b70ab431a81e2fbabf56d", size = 5507842 }, - { url = "https://files.pythonhosted.org/packages/ab/a1/4c25151d56943c76937a976d5f5cc5047e4e60322e3af189d76d1a09e021/lxml-5.2.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:3b019d4ee84b683342af793b56bb35034bd749e4cbdd3d33f7d1107790f8c472", size = 4949210 }, - { url = "https://files.pythonhosted.org/packages/bc/7a/6b40c5bca97a9b685d1db5217cd51f829c5ed16fe797b0c40eb6e33f7cb5/lxml-5.2.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cb3942960f0beb9f46e2a71a3aca220d1ca32feb5a398656be934320804c0df9", size = 5047392 }, - { url = "https://files.pythonhosted.org/packages/fb/53/7b3959a5d41c696db8cf7e4481bf1ac630f7a882215b332e795107d10d19/lxml-5.2.2-cp39-cp39-win32.whl", hash = "sha256:ac6540c9fff6e3813d29d0403ee7a81897f1d8ecc09a8ff84d2eea70ede1cdbf", size = 3479661 }, - { url = "https://files.pythonhosted.org/packages/78/c7/0479936ae05ec99a855cea94fcedfa6b3b2d642689e52122722811f54afe/lxml-5.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:610b5c77428a50269f38a534057444c249976433f40f53e3b47e68349cca1425", size = 3809160 }, - { url = "https://files.pythonhosted.org/packages/00/68/cd5637510441ab4556f087b342000e4ae2d0cf3bea67b073a4327f31020c/lxml-5.2.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b537bd04d7ccd7c6350cdaaaad911f6312cbd61e6e6045542f781c7f8b2e99d2", size = 3927145 }, - { url = "https://files.pythonhosted.org/packages/f6/e0/1122d5b6a10eb71fac4276a0d3b1f5cf1ef0a29f774601d4740e80a70e1a/lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4820c02195d6dfb7b8508ff276752f6b2ff8b64ae5d13ebe02e7667e035000b9", size = 4215917 }, - { url = "https://files.pythonhosted.org/packages/95/d1/ff0c68a61a385f6dffd4c099bc9720cb127bb94f0df8e71f52fe539f85b7/lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a09f6184f17a80897172863a655467da2b11151ec98ba8d7af89f17bf63dae", size = 4326313 }, - { url = "https://files.pythonhosted.org/packages/a8/3c/c9ce5ba91764aaea8944b8e90543ba2e8fc2610d4c5c052160e83ac100b6/lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:76acba4c66c47d27c8365e7c10b3d8016a7da83d3191d053a58382311a8bf4e1", size = 4218518 }, - { url = "https://files.pythonhosted.org/packages/59/03/df1fc5b9f1db8502863ebef8f6a6f37131d7e7c432e997724689221052d9/lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b128092c927eaf485928cec0c28f6b8bead277e28acf56800e972aa2c2abd7a2", size = 4351481 }, - { url = "https://files.pythonhosted.org/packages/f0/ca/8f3b5500119f2651e45d261506e2246b960691239aa499411b763aa79a61/lxml-5.2.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ae791f6bd43305aade8c0e22f816b34f3b72b6c820477aab4d18473a37e8090b", size = 3488498 }, - { url = "https://files.pythonhosted.org/packages/8d/4d/41798bea944db84e2bd89dcd80202caca6e2564df9cd295101deae0df27a/lxml-5.2.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a2f6a1bc2460e643785a2cde17293bd7a8f990884b822f7bca47bee0a82fc66b", size = 3931309 }, - { url = "https://files.pythonhosted.org/packages/0d/45/93bb70897852fbc823ad96275e39c91cccee572f7128e8c5727a2cae0c96/lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e8d351ff44c1638cb6e980623d517abd9f580d2e53bfcd18d8941c052a5a009", size = 4243181 }, - { url = "https://files.pythonhosted.org/packages/fc/d4/090d9827ea5ab04823a713e294b0896ca6b0cb4f6de789a49787bfd76599/lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bec4bd9133420c5c52d562469c754f27c5c9e36ee06abc169612c959bd7dbb07", size = 4368537 }, - { url = "https://files.pythonhosted.org/packages/82/2f/8e2fc1ef352103ea3e7d946707104135b8141a4cf5a5548c9db36ae09eeb/lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:55ce6b6d803890bd3cc89975fca9de1dff39729b43b73cb15ddd933b8bc20484", size = 4243449 }, - { url = "https://files.pythonhosted.org/packages/68/79/759dde4cc03709c33d65a754c9691746e080a93419af02731702276a6ebf/lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8ab6a358d1286498d80fe67bd3d69fcbc7d1359b45b41e74c4a26964ca99c3f8", size = 4387353 }, - { url = "https://files.pythonhosted.org/packages/cb/98/a7214510d5fe4f10a471c5acc87f2c77f15814c5d961123766716cd4bb74/lxml-5.2.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:06668e39e1f3c065349c51ac27ae430719d7806c026fec462e5693b08b95696b", size = 3489410 }, - { url = "https://files.pythonhosted.org/packages/f4/9c/f7d1dc9806cd4cd900c14f36d997ff071eea10bcafb1b556856979e3e25b/lxml-5.2.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9cd5323344d8ebb9fb5e96da5de5ad4ebab993bbf51674259dbe9d7a18049525", size = 3931611 }, - { url = "https://files.pythonhosted.org/packages/1c/d3/36567855dc9abf4562725242401c670ff12001202c6dd0f48d3b47a32201/lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89feb82ca055af0fe797a2323ec9043b26bc371365847dbe83c7fd2e2f181c34", size = 4229409 }, - { url = "https://files.pythonhosted.org/packages/bb/5c/0880631419c1d8481323f7e803ea09fe98748f46a5b4d848a726f95431c3/lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e481bba1e11ba585fb06db666bfc23dbe181dbafc7b25776156120bf12e0d5a6", size = 4339170 }, - { url = "https://files.pythonhosted.org/packages/f7/50/b9f056368a85d62f126eb119495d37be56a3198e06a41ec93dd47271a301/lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d6c6ea6a11ca0ff9cd0390b885984ed31157c168565702959c25e2191674a14", size = 4231259 }, - { url = "https://files.pythonhosted.org/packages/f3/39/1aa9e576ad377c0f96f900532cc847dd71c3ffefcc365bddde1a37656c83/lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3d98de734abee23e61f6b8c2e08a88453ada7d6486dc7cdc82922a03968928db", size = 4362427 }, - { url = "https://files.pythonhosted.org/packages/a1/49/a041bcb1fa87edcf22384f11ad281c8925cb0145f5bb6b770a93d77dc401/lxml-5.2.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:69ab77a1373f1e7563e0fb5a29a8440367dec051da6c7405333699d07444f511", size = 3489677 }, - { url = "https://files.pythonhosted.org/packages/37/ee/4e2c2d6b86c448a39f4d8bfdce5fa65a116c716dc6bfb257f404ebf5f222/lxml-5.2.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:34e17913c431f5ae01d8658dbf792fdc457073dcdfbb31dc0cc6ab256e664a8d", size = 3924281 }, - { url = "https://files.pythonhosted.org/packages/76/51/0e53d8b7dfce944b6f9136ec4346f910c507ced0b16b520b61f2e98cbc55/lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05f8757b03208c3f50097761be2dea0aba02e94f0dc7023ed73a7bb14ff11eb0", size = 4214485 }, - { url = "https://files.pythonhosted.org/packages/b1/d9/7a3aebdf5eb50b8a1e3b70c8b693fdc314b5e41b289d31c9c6d383b1aa44/lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a520b4f9974b0a0a6ed73c2154de57cdfd0c8800f4f15ab2b73238ffed0b36e", size = 4324516 }, - { url = "https://files.pythonhosted.org/packages/a0/f9/c079a1690bfab601122e9355f34a71c17e2d7c74b0ea460c42288b68f96c/lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5e097646944b66207023bc3c634827de858aebc226d5d4d6d16f0b77566ea182", size = 4215143 }, - { url = "https://files.pythonhosted.org/packages/c6/63/27d3d039276e87ac956cb1c3ddc3a2f949512630de6ecf202a9780588927/lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b5e4ef22ff25bfd4ede5f8fb30f7b24446345f3e79d9b7455aef2836437bc38a", size = 4347095 }, - { url = "https://files.pythonhosted.org/packages/2a/a6/86ef80e010cb757107ff079990b0e07d41b0b60c9eae20423be809877355/lxml-5.2.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ff69a9a0b4b17d78170c73abe2ab12084bdf1691550c5629ad1fe7849433f324", size = 3487478 }, ] [[distribution]] @@ -1690,16 +1050,6 @@ version = "2.1.5" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/87/5b/aae44c6655f3801e81aa3eef09dbbf012431987ba564d7231722f68df02d/MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", size = 19384 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/54/ad5eb37bf9d51800010a74e4665425831a9db4e7c4e0fde4352e391e808e/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", size = 18206 }, - { url = "https://files.pythonhosted.org/packages/6a/4a/a4d49415e600bacae038c67f9fecc1d5433b9d3c71a4de6f33537b89654c/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", size = 14079 }, - { url = "https://files.pythonhosted.org/packages/0a/7b/85681ae3c33c385b10ac0f8dd025c30af83c78cec1c37a6aa3b55e67f5ec/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", size = 26620 }, - { url = "https://files.pythonhosted.org/packages/7c/52/2b1b570f6b8b803cef5ac28fdf78c0da318916c7d2fe9402a84d591b394c/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", size = 25818 }, - { url = "https://files.pythonhosted.org/packages/29/fe/a36ba8c7ca55621620b2d7c585313efd10729e63ef81e4e61f52330da781/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", size = 25493 }, - { url = "https://files.pythonhosted.org/packages/60/ae/9c60231cdfda003434e8bd27282b1f4e197ad5a710c14bee8bea8a9ca4f0/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", size = 30630 }, - { url = "https://files.pythonhosted.org/packages/65/dc/1510be4d179869f5dafe071aecb3f1f41b45d37c02329dfba01ff59e5ac5/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", size = 29745 }, - { url = "https://files.pythonhosted.org/packages/30/39/8d845dd7d0b0613d86e0ef89549bfb5f61ed781f59af45fc96496e897f3a/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", size = 30021 }, - { url = "https://files.pythonhosted.org/packages/c7/5c/356a6f62e4f3c5fbf2602b4771376af22a3b16efa74eb8716fb4e328e01e/MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", size = 16659 }, - { url = "https://files.pythonhosted.org/packages/69/48/acbf292615c65f0604a0c6fc402ce6d8c991276e16c80c46a8f758fbd30c/MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", size = 17213 }, { url = "https://files.pythonhosted.org/packages/11/e7/291e55127bb2ae67c64d66cef01432b5933859dfb7d6949daa721b89d0b3/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", size = 18219 }, { url = "https://files.pythonhosted.org/packages/6b/cb/aed7a284c00dfa7c0682d14df85ad4955a350a21d2e3b06d8240497359bf/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", size = 14098 }, { url = "https://files.pythonhosted.org/packages/1c/cf/35fe557e53709e93feb65575c93927942087e9b97213eabc3fe9d5b25a55/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", size = 29014 }, @@ -1720,35 +1070,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/07/2dc76aa51b481eb96a4c3198894f38b480490e834479611a4053fbf08623/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", size = 33038 }, { url = "https://files.pythonhosted.org/packages/96/0c/620c1fb3661858c0e37eb3cbffd8c6f732a67cd97296f725789679801b31/MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", size = 16572 }, { url = "https://files.pythonhosted.org/packages/3f/14/c3554d512d5f9100a95e737502f4a2323a1959f6d0d01e0d0997b35f7b10/MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", size = 17127 }, - { url = "https://files.pythonhosted.org/packages/a7/88/a940e11827ea1c136a34eca862486178294ae841164475b9ab216b80eb8e/MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f", size = 13982 }, - { url = "https://files.pythonhosted.org/packages/cb/06/0d28bd178db529c5ac762a625c335a9168a7a23f280b4db9c95e97046145/MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf", size = 26335 }, - { url = "https://files.pythonhosted.org/packages/4a/1d/c4f5016f87ced614eacc7d5fb85b25bcc0ff53e8f058d069fc8cbfdc3c7a/MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a", size = 25557 }, - { url = "https://files.pythonhosted.org/packages/b3/fb/c18b8c9fbe69e347fdbf782c6478f1bc77f19a830588daa224236678339b/MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52", size = 25245 }, - { url = "https://files.pythonhosted.org/packages/2f/69/30d29adcf9d1d931c75001dd85001adad7374381c9c2086154d9f6445be6/MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9", size = 31013 }, - { url = "https://files.pythonhosted.org/packages/3a/03/63498d05bd54278b6ca340099e5b52ffb9cdf2ee4f2d9b98246337e21689/MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df", size = 30178 }, - { url = "https://files.pythonhosted.org/packages/68/79/11b4fe15124692f8673b603433e47abca199a08ecd2a4851bfbdc97dc62d/MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50", size = 30429 }, - { url = "https://files.pythonhosted.org/packages/ed/88/408bdbf292eb86f03201c17489acafae8358ba4e120d92358308c15cea7c/MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371", size = 16633 }, - { url = "https://files.pythonhosted.org/packages/6c/4c/3577a52eea1880538c435176bc85e5b3379b7ab442327ccd82118550758f/MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2", size = 17215 }, - { url = "https://files.pythonhosted.org/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", size = 18192 }, - { url = "https://files.pythonhosted.org/packages/4f/14/6f294b9c4f969d0c801a4615e221c1e084722ea6114ab2114189c5b8cbe0/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", size = 14072 }, - { url = "https://files.pythonhosted.org/packages/81/d4/fd74714ed30a1dedd0b82427c02fa4deec64f173831ec716da11c51a50aa/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", size = 26928 }, - { url = "https://files.pythonhosted.org/packages/c7/bd/50319665ce81bb10e90d1cf76f9e1aa269ea6f7fa30ab4521f14d122a3df/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", size = 26106 }, - { url = "https://files.pythonhosted.org/packages/4c/6f/f2b0f675635b05f6afd5ea03c094557bdb8622fa8e673387444fe8d8e787/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68", size = 25781 }, - { url = "https://files.pythonhosted.org/packages/51/e0/393467cf899b34a9d3678e78961c2c8cdf49fb902a959ba54ece01273fb1/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", size = 30518 }, - { url = "https://files.pythonhosted.org/packages/f6/02/5437e2ad33047290dafced9df741d9efc3e716b75583bbd73a9984f1b6f7/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", size = 29669 }, - { url = "https://files.pythonhosted.org/packages/0e/7d/968284145ffd9d726183ed6237c77938c021abacde4e073020f920e060b2/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", size = 29933 }, - { url = "https://files.pythonhosted.org/packages/bf/f3/ecb00fc8ab02b7beae8699f34db9357ae49d9f21d4d3de6f305f34fa949e/MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", size = 16656 }, - { url = "https://files.pythonhosted.org/packages/92/21/357205f03514a49b293e214ac39de01fadd0970a6e05e4bf1ddd0ffd0881/MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", size = 17206 }, - { url = "https://files.pythonhosted.org/packages/0f/31/780bb297db036ba7b7bbede5e1d7f1e14d704ad4beb3ce53fb495d22bc62/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", size = 18193 }, - { url = "https://files.pythonhosted.org/packages/6c/77/d77701bbef72892affe060cdacb7a2ed7fd68dae3b477a8642f15ad3b132/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", size = 14073 }, - { url = "https://files.pythonhosted.org/packages/d9/a7/1e558b4f78454c8a3a0199292d96159eb4d091f983bc35ef258314fe7269/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", size = 26486 }, - { url = "https://files.pythonhosted.org/packages/5f/5a/360da85076688755ea0cceb92472923086993e86b5613bbae9fbc14136b0/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", size = 25685 }, - { url = "https://files.pythonhosted.org/packages/6a/18/ae5a258e3401f9b8312f92b028c54d7026a97ec3ab20bfaddbdfa7d8cce8/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", size = 25338 }, - { url = "https://files.pythonhosted.org/packages/0b/cc/48206bd61c5b9d0129f4d75243b156929b04c94c09041321456fd06a876d/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", size = 30439 }, - { url = "https://files.pythonhosted.org/packages/d1/06/a41c112ab9ffdeeb5f77bc3e331fdadf97fa65e52e44ba31880f4e7f983c/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", size = 29531 }, - { url = "https://files.pythonhosted.org/packages/02/8c/ab9a463301a50dab04d5472e998acbd4080597abc048166ded5c7aa768c8/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", size = 29823 }, - { url = "https://files.pythonhosted.org/packages/bc/29/9bc18da763496b055d8e98ce476c8e718dcfd78157e17f555ce6dd7d0895/MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", size = 16658 }, - { url = "https://files.pythonhosted.org/packages/f6/f8/4da07de16f10551ca1f640c92b5f316f9394088b183c6a57183df6de5ae4/MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", size = 17211 }, ] [[distribution]] @@ -1768,12 +1089,6 @@ dependencies = [ { name = "python-dateutil" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/42/ba/0016c92366f93f77cd22c4fb030ac1d5924fcc2320bdaa17c5b0768afd67/matplotlib-3.9.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7ccd6270066feb9a9d8e0705aa027f1ff39f354c72a87efe8fa07632f30fc6bb", size = 7893085 }, - { url = "https://files.pythonhosted.org/packages/fe/f9/df790297f1981c81b8c6af92769535c2e4fa889c9aab7134b8d7f171fde6/matplotlib-3.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:591d3a88903a30a6d23b040c1e44d1afdd0d778758d07110eb7596f811f31842", size = 7773136 }, - { url = "https://files.pythonhosted.org/packages/0b/53/96e98ba8ab163c3a56b993e08625a48efe47744a53ec221974dcddaff7c7/matplotlib-3.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd2a59ff4b83d33bca3b5ec58203cc65985367812cb8c257f3e101632be86d92", size = 8192140 }, - { url = "https://files.pythonhosted.org/packages/32/ad/58902b481f5a294101a53ed964d68a2c2355d55622a8e9cb09fc3f517385/matplotlib-3.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fc001516ffcf1a221beb51198b194d9230199d6842c540108e4ce109ac05cc0", size = 8303732 }, - { url = "https://files.pythonhosted.org/packages/ce/29/479fe8b057a4580fb0f476b0b83e0ba7ea08bc0f55081e045d3794e830a4/matplotlib-3.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:83c6a792f1465d174c86d06f3ae85a8fe36e6f5964633ae8106312ec0921fdf5", size = 9083082 }, - { url = "https://files.pythonhosted.org/packages/be/f6/4ac7f10c1e8d51f42e320a0890ee7c8e45fb5b1178ed147f374a37900924/matplotlib-3.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:421851f4f57350bcf0811edd754a708d2275533e84f52f6760b740766c6747a7", size = 7961172 }, { url = "https://files.pythonhosted.org/packages/ce/f5/22d0f294a76cc65c431fb7f2146a96a4e12233c09cbce6285f74bb75db96/matplotlib-3.9.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b3fce58971b465e01b5c538f9d44915640c20ec5ff31346e963c9e1cd66fa812", size = 7902698 }, { url = "https://files.pythonhosted.org/packages/46/81/38bc95cf20ce6ed9dd5e7aec805bf1efc931e3fdeb9c5b593d00634a4747/matplotlib-3.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a973c53ad0668c53e0ed76b27d2eeeae8799836fd0d0caaa4ecc66bf4e6676c0", size = 7781109 }, { url = "https://files.pythonhosted.org/packages/54/7e/4f8f44fcc65a8cfa6303d3469d8973d6a2ba019a9627af9a9ae545f718d6/matplotlib-3.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cd5acf8f3ef43f7532c2f230249720f5dc5dd40ecafaf1c60ac8200d46d7eb", size = 8202150 }, @@ -1786,16 +1101,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0d/cb/78283ec2ded91fb74a2ae9ae93f91a897fa578fa78c8c271a7c147f6b8d6/matplotlib-3.9.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d12cb1837cffaac087ad6b44399d5e22b78c729de3cdae4629e252067b705e2b", size = 8306066 }, { url = "https://files.pythonhosted.org/packages/e8/6a/d26801848d5a61b2caf9cd9bf2dc1747520bb8dc074376177c9372779e83/matplotlib-3.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0e835c6988edc3d2d08794f73c323cc62483e13df0194719ecb0723b564e0b5c", size = 9086483 }, { url = "https://files.pythonhosted.org/packages/e3/31/aeab8a3db1fb22a7d04c5215f872b92451baf7f6595ffd59004aeead0b2c/matplotlib-3.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:44a21d922f78ce40435cb35b43dd7d573cf2a30138d5c4b709d19f00e3907fd7", size = 7974774 }, - { url = "https://files.pythonhosted.org/packages/e5/8a/7ee266d4d45588529b04be1e52626c708314f559252c863c6dab46b55cdd/matplotlib-3.9.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:0c584210c755ae921283d21d01f03a49ef46d1afa184134dd0f95b0202ee6f03", size = 7894019 }, - { url = "https://files.pythonhosted.org/packages/c5/34/ad49016a943305cf44eb8f42fb6c001c3d54c6ba5781d842aea9c60e3f31/matplotlib-3.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11fed08f34fa682c2b792942f8902e7aefeed400da71f9e5816bea40a7ce28fe", size = 7773937 }, - { url = "https://files.pythonhosted.org/packages/7b/88/68ee52339a9fefb2cdaceab09e38ec157882e3d1f814a525ddf1724d5a46/matplotlib-3.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0000354e32efcfd86bda75729716b92f5c2edd5b947200be9881f0a671565c33", size = 8193851 }, - { url = "https://files.pythonhosted.org/packages/8e/67/e75134cb83d2e533e46d72e2033a413772efdc18291beb981f5d574a829f/matplotlib-3.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4db17fea0ae3aceb8e9ac69c7e3051bae0b3d083bfec932240f9bf5d0197a049", size = 8306053 }, - { url = "https://files.pythonhosted.org/packages/eb/22/3e320ab5a74670d4a3b31d1f56eba007cf357cb35d9e47fd5c0f52ccb23f/matplotlib-3.9.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:208cbce658b72bf6a8e675058fbbf59f67814057ae78165d8a2f87c45b48d0ff", size = 9085292 }, - { url = "https://files.pythonhosted.org/packages/0c/dd/8270a3114b46831b0faa7fa28e6c78f5e1264eefe2908f0c8869dce4dfbb/matplotlib-3.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:dc23f48ab630474264276be156d0d7710ac6c5a09648ccdf49fef9200d8cbe80", size = 7956580 }, - { url = "https://files.pythonhosted.org/packages/ba/af/c657eb22e5d3d455545825b80469b7d56fe2e1e05d88e0a3c2d4955ba448/matplotlib-3.9.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3fda72d4d472e2ccd1be0e9ccb6bf0d2eaf635e7f8f51d737ed7e465ac020cb3", size = 7885084 }, - { url = "https://files.pythonhosted.org/packages/75/e3/8e966205e415d17762f5715a3f5bd09ca1dbc07df38768980464df561dda/matplotlib-3.9.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:84b3ba8429935a444f1fdc80ed930babbe06725bcf09fbeb5c8757a2cd74af04", size = 7762826 }, - { url = "https://files.pythonhosted.org/packages/1e/42/273966d8150b98abf62cded0f236f6a75418ac2d35db8c36b6db1499b320/matplotlib-3.9.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b918770bf3e07845408716e5bbda17eadfc3fcbd9307dc67f37d6cf834bb3d98", size = 8305461 }, - { url = "https://files.pythonhosted.org/packages/fe/00/2eb1b5216709b9aec5ff3b1e1c84adf57ca2cb160460e946d2d43a7937ea/matplotlib-3.9.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f1f2e5d29e9435c97ad4c36fb6668e89aee13d48c75893e25cef064675038ac9", size = 7982116 }, ] [[distribution]] @@ -1978,21 +1283,6 @@ version = "6.0.5" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f9/79/722ca999a3a09a63b35aac12ec27dfa8e5bb3a38b0f857f7a1a209a88836/multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da", size = 59867 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/36/48097b96135017ed1b806c5ea27b6cdc2ed3a6861c5372b793563206c586/multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9", size = 50955 }, - { url = "https://files.pythonhosted.org/packages/d9/48/037440edb5d4a1c65e002925b2f24071d6c27754e6f4734f63037e3169d6/multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604", size = 30361 }, - { url = "https://files.pythonhosted.org/packages/a4/eb/d8e7693c9064554a1585698d1902839440c6c695b0f53c9a8be5d9d4a3b8/multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600", size = 30508 }, - { url = "https://files.pythonhosted.org/packages/f3/7d/fe7648d4b2f200f8854066ce6e56bf51889abfaf859814c62160dd0e32a9/multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c", size = 126318 }, - { url = "https://files.pythonhosted.org/packages/8d/ea/0230b6faa9a5bc10650fd50afcc4a86e6c37af2fe05bc679b74d79253732/multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5", size = 133998 }, - { url = "https://files.pythonhosted.org/packages/36/6d/d2f982fb485175727a193b4900b5f929d461e7aa87d6fb5a91a377fcc9c0/multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f", size = 129150 }, - { url = "https://files.pythonhosted.org/packages/33/62/2c9085e571318d51212a6914566fe41dd0e33d7f268f7e2f23dcd3f06c56/multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae", size = 124266 }, - { url = "https://files.pythonhosted.org/packages/ce/e2/88cdfeaf03eab3498f688a19b62ca704d371cd904cb74b682541ca7b20a7/multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182", size = 116637 }, - { url = "https://files.pythonhosted.org/packages/12/4d/99dfc36872dcc53956879f5da80a6505bbd29214cce90ce792a86e15fddf/multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf", size = 155908 }, - { url = "https://files.pythonhosted.org/packages/c2/5c/1e76b2c742cb9e0248d1e8c4ed420817879230c833fa27d890b5fd22290b/multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442", size = 147111 }, - { url = "https://files.pythonhosted.org/packages/bc/84/9579004267e1cc5968ef2ef8718dab9d8950d99354d85b739dd67b09c273/multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a", size = 160502 }, - { url = "https://files.pythonhosted.org/packages/11/b7/bef33e84e3722bc42531af020d7ae8c31235ce8846bacaa852b6484cf868/multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef", size = 156587 }, - { url = "https://files.pythonhosted.org/packages/26/ce/f745a2d6104e56f7fa0d7d0756bb9ed27b771dd7b8d9d7348cd7f0f7b9de/multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc", size = 151948 }, - { url = "https://files.pythonhosted.org/packages/f1/50/714da64281d2b2b3b4068e84f115e1ef3bd3ed3715b39503ff3c59e8d30d/multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319", size = 25734 }, - { url = "https://files.pythonhosted.org/packages/ef/3d/ba0dc18e96c5d83731c54129819d5892389e180f54ebb045c6124b2e8b87/multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8", size = 28182 }, { url = "https://files.pythonhosted.org/packages/5f/da/b10ea65b850b54f44a6479177c6987f456bc2d38f8dc73009b78afcf0ede/multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba", size = 50815 }, { url = "https://files.pythonhosted.org/packages/21/db/3403263f158b0bc7b0d4653766d71cb39498973f2042eead27b2e9758782/multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e", size = 30269 }, { url = "https://files.pythonhosted.org/packages/02/c1/b15ecceb6ffa5081ed2ed450aea58d65b0e0358001f2b426705f9f41f4c2/multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd", size = 30500 }, @@ -2023,49 +1313,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/60/47/9a0f43470c70bbf6e148311f78ef5a3d4996b0226b6d295bdd50fdcfe387/multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda", size = 166229 }, { url = "https://files.pythonhosted.org/packages/1d/23/c1b7ae7a0b8a3e08225284ef3ecbcf014b292a3ee821bc4ed2185fd4ce7d/multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5", size = 25840 }, { url = "https://files.pythonhosted.org/packages/4a/68/66fceb758ad7a88993940dbdf3ac59911ba9dc46d7798bf6c8652f89f853/multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556", size = 27905 }, - { url = "https://files.pythonhosted.org/packages/21/d2/8faec69b04237385c760d0c481ba032e46cdecb6bf47bdbf672a60f19d75/multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3", size = 28541 }, - { url = "https://files.pythonhosted.org/packages/e0/fa/517294e7f7a1d070a03a16bd28f10997d4b90846ca52f390833365d15048/multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5", size = 101199 }, - { url = "https://files.pythonhosted.org/packages/93/4b/fc9f393fbae0e9ebd7728b06a79f60325f6307ee4fc433cfa39995f307ee/multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd", size = 105644 }, - { url = "https://files.pythonhosted.org/packages/ab/f7/6d5f45c0cc8bcb2e510a8c17c51c74b42c2dcd6636bd048217d4336c342f/multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e", size = 102379 }, - { url = "https://files.pythonhosted.org/packages/0a/f0/b256648385dfda067688570b10e7b90eacd3711c26635763560cbad0a447/multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626", size = 99846 }, - { url = "https://files.pythonhosted.org/packages/41/34/16237d404dc204a90c94d5974ae8aaaa6dd4604b6ff808883262a5759c0d/multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83", size = 92908 }, - { url = "https://files.pythonhosted.org/packages/62/34/829b3a0857ae46e502cb9c6699541107aa2d077501004c1148909465b6c7/multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a", size = 138546 }, - { url = "https://files.pythonhosted.org/packages/33/2e/b37eaa5541d29847dfdfb6dbe3ac514d31dab186c78b0156cdb585616b13/multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c", size = 128775 }, - { url = "https://files.pythonhosted.org/packages/6b/97/08c6a79ef52b2764ae9f7abb7463e7e1e6ddcb17125494654f00cb343380/multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5", size = 141346 }, - { url = "https://files.pythonhosted.org/packages/fc/3a/308c8bcdffe345cf4e2682543311a67aabb3c85492ce896d0a07d5105443/multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3", size = 134203 }, - { url = "https://files.pythonhosted.org/packages/eb/1c/bc0d59aeb216f3fce21333632f72843bf2dfd5d045e32a13615477cd7d7c/multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc", size = 135421 }, - { url = "https://files.pythonhosted.org/packages/e8/ae/b0e7cdfb513b297cf46c9b229f1bff082ed8497d0c800d640c697111cef4/multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee", size = 24337 }, - { url = "https://files.pythonhosted.org/packages/66/f9/f016a8963b4784a4a013c0c0dac717add7146bb47d51e93a23b8205dfdce/multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423", size = 26637 }, - { url = "https://files.pythonhosted.org/packages/a2/82/2641816aa81288a2ead7b982e3805ef8bc494619f574b72edf271bc3a8af/multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54", size = 50607 }, - { url = "https://files.pythonhosted.org/packages/6c/13/97f4a2e0e26b7c6e2469de03f1efc255ce2f984a537c301d957762a23eba/multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d", size = 30209 }, - { url = "https://files.pythonhosted.org/packages/7b/0a/c5a12e908f32ec3844772a8a52322594bfc7ea5786ffdfd4efc70eead079/multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7", size = 30343 }, - { url = "https://files.pythonhosted.org/packages/7d/b6/fd8dd4a1ce1d129a1870143133f449b769ae236e9435ed8d74a8d45acb8e/multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93", size = 130659 }, - { url = "https://files.pythonhosted.org/packages/6a/43/d753dbaa498d42e8e292889cc9a9def30b32631573ae86c9911889977049/multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8", size = 136375 }, - { url = "https://files.pythonhosted.org/packages/e8/4e/51130700c255597ac8e15ceac2e492117ffad44c75610381652b7d2e96a1/multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b", size = 131294 }, - { url = "https://files.pythonhosted.org/packages/61/a3/c307d4af64e695d13e8587d3f996a51b134156c0e8e2e26f4135bb2bf517/multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50", size = 129342 }, - { url = "https://files.pythonhosted.org/packages/dc/04/0dcb48358f8217ae6839075287ce5d4be124e68d4ef7696b23e3f0981b51/multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e", size = 121538 }, - { url = "https://files.pythonhosted.org/packages/fd/e2/8b98715478dc4a3cdf0230886680f33f4eacbc2ab2a4c1604b027e9540eb/multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89", size = 160932 }, - { url = "https://files.pythonhosted.org/packages/c7/72/3f696c93d03f19f8fbefe82e8f415dea8c574fa58ffdb4bc04ebafbd4a05/multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386", size = 151332 }, - { url = "https://files.pythonhosted.org/packages/03/a6/b13e10db5357695645748fae401c94674f612e04e2262c99032ddc638864/multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453", size = 165893 }, - { url = "https://files.pythonhosted.org/packages/eb/da/519f691131f42a25555a903cd6d150285b530786a0d10751ff286aa0e326/multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461", size = 161519 }, - { url = "https://files.pythonhosted.org/packages/3a/85/2d0162c949f7ce7876498d854cba8ce3ae45b1e2212e7a80e0d6ef602a19/multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44", size = 156612 }, - { url = "https://files.pythonhosted.org/packages/ce/7b/7f68ee7e21cf8a7e43fbea41508f9cc0698c497ea54525a5a5a99b4574ef/multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241", size = 25640 }, - { url = "https://files.pythonhosted.org/packages/f7/d6/26f82e3f45802a826c8220af7305ca3b06ad8f25ef2fcdbf1899c7bc01d3/multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c", size = 28138 }, - { url = "https://files.pythonhosted.org/packages/c6/7c/c8f4445389c0bbc5ea85d1e737233c257f314d0f836a6644e097a5ef512f/multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929", size = 50828 }, - { url = "https://files.pythonhosted.org/packages/7d/5c/c364a77b37f580cc28da4194b77ed04286c7631933d3e64fdae40f1972e2/multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9", size = 30315 }, - { url = "https://files.pythonhosted.org/packages/1a/25/f4b60a34dde70c475f4dcaeb4796c256db80d2e03198052d0c3cee5d5fbb/multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a", size = 30451 }, - { url = "https://files.pythonhosted.org/packages/d0/10/2ff646c471e84af25fe8111985ffb8ec85a3f6e1ade8643bfcfcc0f4d2b1/multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1", size = 125880 }, - { url = "https://files.pythonhosted.org/packages/c9/ee/a4775297550dfb127641bd335d00d6d896e4ba5cf0216f78654e5ad6ac80/multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e", size = 133606 }, - { url = "https://files.pythonhosted.org/packages/7d/e9/95746d0c7c40bb0f43fc5424b7d7cf783e8638ce67f05fa677fff9ad76bb/multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046", size = 128720 }, - { url = "https://files.pythonhosted.org/packages/39/a9/1f8d42c8103bcb1da6bb719f1bc018594b5acc8eae56b3fec4720ebee225/multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c", size = 123750 }, - { url = "https://files.pythonhosted.org/packages/b5/f8/c8abbe7c425497d8bf997b1fffd9650ca175325ff397fadc9d63ae5dc027/multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40", size = 116213 }, - { url = "https://files.pythonhosted.org/packages/c2/bb/242664de860cd1201f4d207f0bd2011c1a730877e1dbffbe5d6ec4089e2d/multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527", size = 155410 }, - { url = "https://files.pythonhosted.org/packages/f6/5b/35d20c85b8ccd0c9afc47b8dd46e028b6650ad9660a4b6ad191301d220f5/multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9", size = 146668 }, - { url = "https://files.pythonhosted.org/packages/1b/52/6e984685d048f6728807c3fd9b8a6e3e3d51a06a4d6665d6e0102115455d/multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38", size = 160140 }, - { url = "https://files.pythonhosted.org/packages/76/c0/3aa6238557ed1d235be70d9c3f86d63a835c421b76073b8ce06bf32725e8/multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479", size = 156185 }, - { url = "https://files.pythonhosted.org/packages/85/82/02ed81023b5812582bf7c46e8e2868ffd6a29f8c313af1dd76e82e243c39/multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c", size = 151518 }, - { url = "https://files.pythonhosted.org/packages/d8/00/fd6eef9830046c063939cbf119c101898cbb611ea20301ae911b74caca19/multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b", size = 25732 }, - { url = "https://files.pythonhosted.org/packages/58/a3/4d2c1b4d1859c89d9ce48a4ae410ee019485e324e484b0160afdba8cc42b/multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755", size = 28181 }, { url = "https://files.pythonhosted.org/packages/fa/a2/17e1e23c6be0a916219c5292f509360c345b5fa6beeb50d743203c27532c/multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7", size = 9729 }, ] @@ -2079,11 +1326,6 @@ dependencies = [ { name = "typing-extensions" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/56/24/8a179de3ed98e1882f640d431db25a17fc5813258fded79674e475501f87/mypy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e36f229acfe250dc660790840916eb49726c928e8ce10fbdf90715090fe4ae02", size = 10817694 }, - { url = "https://files.pythonhosted.org/packages/f3/80/1675d07cfb4cc12bedcb5bb426f256d8c8da3668cbf300121e39333f0c96/mypy-1.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:51a46974340baaa4145363b9e051812a2446cf583dfaeba124af966fa44593f7", size = 9975362 }, - { url = "https://files.pythonhosted.org/packages/d5/a0/684ebd636f258bdd263b12be46dd4e1ed33ac73a76d590b209c026e3c65f/mypy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:901c89c2d67bba57aaaca91ccdb659aa3a312de67f23b9dfb059727cce2e2e0a", size = 12728032 }, - { url = "https://files.pythonhosted.org/packages/f3/c8/1f881f08e93ea8165113ab0fad490262b0466d0c2616c13c1bb85741ff87/mypy-1.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0cd62192a4a32b77ceb31272d9e74d23cd88c8060c34d1d3622db3267679a5d9", size = 12797751 }, - { url = "https://files.pythonhosted.org/packages/4a/d3/46c81d90576e2e766144c0e436fa397a7387092fe29c6ef964f91d92778d/mypy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a2cbc68cb9e943ac0814c13e2452d2046c2f2b23ff0278e26599224cf164e78d", size = 9398835 }, { url = "https://files.pythonhosted.org/packages/38/cf/0645128c6edf70eb9b9687ad42fcb61ea344a7927ed2b78ce2275282fe87/mypy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd6f629b67bb43dc0d9211ee98b96d8dabc97b1ad38b9b25f5e4c4d7569a0c6a", size = 10740526 }, { url = "https://files.pythonhosted.org/packages/19/c9/10842953066265e6063c41a85bbee3b877501947c970ea84a1db5f11d32e/mypy-1.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1bbb3a6f5ff319d2b9d40b4080d46cd639abe3516d5a62c070cf0114a457d84", size = 9898375 }, { url = "https://files.pythonhosted.org/packages/e4/9e/551e897f67c5d67aa1976bc3b4951f297d1daf07250c421bb045b2613350/mypy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8edd4e9bbbc9d7b79502eb9592cab808585516ae1bcc1446eb9122656c6066f", size = 12602338 }, @@ -2094,16 +1336,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ff/b5/cbccba4dca9703c4c467171e7f61ea6a1a75eae991208aa5bc7d49807f91/mypy-1.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bacf8f3a3d7d849f40ca6caea5c055122efe70e81480c8328ad29c55c69e93e", size = 12647633 }, { url = "https://files.pythonhosted.org/packages/02/3c/1f5e57c8cfab4299f7189821ae8bb4896e8e623a04d293fd32e32eb0e617/mypy-1.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:701b5f71413f1e9855566a34d6e9d12624e9e0a8818a5704d74d6b0402e66c04", size = 12730251 }, { url = "https://files.pythonhosted.org/packages/f9/20/d33608e8dc3bc0f5966fc1f6c2d16671f0725dcca279beec47c3e19afd9d/mypy-1.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c4c2992f6ea46ff7fce0072642cfb62af7a2484efe69017ed8b095f7b39ef31", size = 9491734 }, - { url = "https://files.pythonhosted.org/packages/da/ae/00a39c2226e1a6bd34fcaec5d120a514d2a8fc78c3c49bc0f017a41349fc/mypy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:604282c886497645ffb87b8f35a57ec773a4a2721161e709a4422c1636ddde5c", size = 10754845 }, - { url = "https://files.pythonhosted.org/packages/d2/b2/d8d2a59300a2a60055f82c9990a0b491d5b7223634849381f65a824318d6/mypy-1.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37fd87cab83f09842653f08de066ee68f1182b9b5282e4634cdb4b407266bade", size = 9928644 }, - { url = "https://files.pythonhosted.org/packages/67/1c/c99c7b18ef187cbc9aaaa962f5c62e3308a2ff61cf67cd9187ef13eb09a7/mypy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8addf6313777dbb92e9564c5d32ec122bf2c6c39d683ea64de6a1fd98b90fe37", size = 12677231 }, - { url = "https://files.pythonhosted.org/packages/12/58/406fdd1d026c7a5f8ceadc833b990243c0290dff90f36da1206323963056/mypy-1.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cc3ca0a244eb9a5249c7c583ad9a7e881aa5d7b73c35652296ddcdb33b2b9c7", size = 12739164 }, - { url = "https://files.pythonhosted.org/packages/67/43/a40fa843df69f614ad33f3e3307604505fbad6784a8bf285977bb16768d4/mypy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:1b3a2ffce52cc4dbaeee4df762f20a2905aa171ef157b82192f2e2f368eec05d", size = 9384395 }, - { url = "https://files.pythonhosted.org/packages/50/00/86bb2f6c5b58fc6f360dd4cb5c0666dc67c05007c2cddcc694528a59a604/mypy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe85ed6836165d52ae8b88f99527d3d1b2362e0cb90b005409b8bed90e9059b3", size = 10813338 }, - { url = "https://files.pythonhosted.org/packages/33/b0/20c9f6dcbfb312d1804a81f4a39e0b401fe614dc0de580249b6deb07d053/mypy-1.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2ae450d60d7d020d67ab440c6e3fae375809988119817214440033f26ddf7bf", size = 9968141 }, - { url = "https://files.pythonhosted.org/packages/aa/87/ec65c45b2e5160203a680b0f79e459fbe9c192f9eff501c3fec82bef3be5/mypy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6be84c06e6abd72f960ba9a71561c14137a583093ffcf9bbfaf5e613d63fa531", size = 12724186 }, - { url = "https://files.pythonhosted.org/packages/c5/5c/f61c876647036d572a1434f0251257a04f2a7bd038c718b28fa5ca699515/mypy-1.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2189ff1e39db399f08205e22a797383613ce1cb0cb3b13d8bcf0170e45b96cc3", size = 12796640 }, - { url = "https://files.pythonhosted.org/packages/69/09/5cd3609d18cf27ec84f380a92b3da695f84781de119d68db69d274c3d1ee/mypy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:97a131ee36ac37ce9581f4220311247ab6cba896b4395b9c87af0675a13a755f", size = 9396105 }, { url = "https://files.pythonhosted.org/packages/2b/ee/d53a3d4792a09b6cd757978951d6dcf8b10825a8b8522b68e9b5eb53b9a1/mypy-1.10.1-py3-none-any.whl", hash = "sha256:71d8ac0b906354ebda8ef1673e5fde785936ac1f29ff6987c7483cfbd5a4235a", size = 2580108 }, ] @@ -2157,14 +1389,6 @@ version = "1.26.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468 }, - { url = "https://files.pythonhosted.org/packages/20/f7/b24208eba89f9d1b58c1668bc6c8c4fd472b20c45573cb767f59d49fb0f6/numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", size = 13966411 }, - { url = "https://files.pythonhosted.org/packages/fc/a5/4beee6488160798683eed5bdb7eead455892c3b4e1f78d79d8d3f3b084ac/numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", size = 14219016 }, - { url = "https://files.pythonhosted.org/packages/4b/d7/ecf66c1cd12dc28b4040b15ab4d17b773b87fa9d29ca16125de01adb36cd/numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f", size = 18240889 }, - { url = "https://files.pythonhosted.org/packages/24/03/6f229fe3187546435c4f6f89f6d26c129d4f5bed40552899fcf1f0bf9e50/numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", size = 13876746 }, - { url = "https://files.pythonhosted.org/packages/39/fe/39ada9b094f01f5a35486577c848fe274e374bbf8d8f472e1423a0bbd26d/numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", size = 18078620 }, - { url = "https://files.pythonhosted.org/packages/d5/ef/6ad11d51197aad206a9ad2286dc1aac6a378059e06e8cf22cd08ed4f20dc/numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", size = 5972659 }, - { url = "https://files.pythonhosted.org/packages/19/77/538f202862b9183f54108557bfda67e17603fc560c384559e769321c9d92/numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", size = 15808905 }, { url = "https://files.pythonhosted.org/packages/11/57/baae43d14fe163fa0e4c47f307b6b2511ab8d7d30177c491960504252053/numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71", size = 20630554 }, { url = "https://files.pythonhosted.org/packages/1a/2e/151484f49fd03944c4a3ad9c418ed193cfd02724e138ac8a9505d056c582/numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef", size = 13997127 }, { url = "https://files.pythonhosted.org/packages/79/ae/7e5b85136806f9dadf4878bf73cf223fe5c2636818ba3ab1c585d0403164/numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e", size = 14222994 }, @@ -2181,17 +1405,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/76/8c/2ba3902e1a0fc1c74962ea9bb33a534bb05984ad7ff9515bf8d07527cadd/numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", size = 17786643 }, { url = "https://files.pythonhosted.org/packages/28/4a/46d9e65106879492374999e76eb85f87b15328e06bd1550668f79f7b18c6/numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", size = 5677803 }, { url = "https://files.pythonhosted.org/packages/16/2e/86f24451c2d530c88daf997cb8d6ac622c1d40d19f5a031ed68a4b73a374/numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", size = 15517754 }, - { url = "https://files.pythonhosted.org/packages/7d/24/ce71dc08f06534269f66e73c04f5709ee024a1afe92a7b6e1d73f158e1f8/numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c", size = 20636301 }, - { url = "https://files.pythonhosted.org/packages/ae/8c/ab03a7c25741f9ebc92684a20125fbc9fc1b8e1e700beb9197d750fdff88/numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be", size = 13971216 }, - { url = "https://files.pythonhosted.org/packages/6d/64/c3bcdf822269421d85fe0d64ba972003f9bb4aa9a419da64b86856c9961f/numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764", size = 14226281 }, - { url = "https://files.pythonhosted.org/packages/54/30/c2a907b9443cf42b90c17ad10c1e8fa801975f01cb9764f3f8eb8aea638b/numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3", size = 18249516 }, - { url = "https://files.pythonhosted.org/packages/43/12/01a563fc44c07095996d0129b8899daf89e4742146f7044cdbdb3101c57f/numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd", size = 13882132 }, - { url = "https://files.pythonhosted.org/packages/16/ee/9df80b06680aaa23fc6c31211387e0db349e0e36d6a63ba3bd78c5acdf11/numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c", size = 18084181 }, - { url = "https://files.pythonhosted.org/packages/28/7d/4b92e2fe20b214ffca36107f1a3e75ef4c488430e64de2d9af5db3a4637d/numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6", size = 5976360 }, - { url = "https://files.pythonhosted.org/packages/b5/42/054082bd8220bbf6f297f982f0a8f5479fcbc55c8b511d928df07b965869/numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea", size = 15814633 }, - { url = "https://files.pythonhosted.org/packages/3f/72/3df6c1c06fc83d9cfe381cccb4be2532bbd38bf93fbc9fad087b6687f1c0/numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30", size = 20455961 }, - { url = "https://files.pythonhosted.org/packages/8e/02/570545bac308b58ffb21adda0f4e220ba716fb658a63c151daecc3293350/numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c", size = 18061071 }, - { url = "https://files.pythonhosted.org/packages/f4/5f/fafd8c51235f60d49f7a88e2275e13971e90555b67da52dd6416caec32fe/numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0", size = 15709730 }, ] [[distribution]] @@ -2204,11 +1417,6 @@ dependencies = [ { name = "protobuf" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/bf/810fe3215735ff55a2b65d0430ba9782b70916d67554d9c2c58cebeace45/onnx-1.16.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:bb2d392e5b7060082c2fb38eb5c44f67eb34ff5f0681bd6f45beff9abc6f7094", size = 16503944 }, - { url = "https://files.pythonhosted.org/packages/36/16/07a819f1139a75e67b0b31e1474e5770d1e7c93b69744c6f7434415a9f65/onnx-1.16.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15abf94a7868eed6db15a8b5024ba570c891cae77ca4d0e7258dabdad76980df", size = 15793552 }, - { url = "https://files.pythonhosted.org/packages/c6/7e/5031717c0636e6074764a2f61a459a3ecd46c20d8b83a1f1cd2513a76160/onnx-1.16.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6251910e554f811fdd070164b0bc76d76b067b95576cb9dad4d52ae64fe014b5", size = 15924038 }, - { url = "https://files.pythonhosted.org/packages/b7/4b/4133ef16259384123389286afa2db8111495e8c93d3379c61e7491826047/onnx-1.16.1-cp310-cp310-win32.whl", hash = "sha256:c11e3b15eee46cd20767e505cc3ba97457ef5ac93c3e459cdfb77943ff8fe9a7", size = 14337055 }, - { url = "https://files.pythonhosted.org/packages/9c/7c/40fbebcb30f0fb6a773ca36e3a9dd4bdccd4b15455ef6c21a335781db78f/onnx-1.16.1-cp310-cp310-win_amd64.whl", hash = "sha256:b3d10405706807ec2ef493b2a78519fa0264cf190363e89478585aac1179b596", size = 14436356 }, { url = "https://files.pythonhosted.org/packages/17/ab/cea6c47f05b51046f4e7b523b817a99c736f9569c60613b53c03f5fff355/onnx-1.16.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:006ba5059c85ce43e89a1486cc0276d0f1a8ec9c6efd1a9334fd3fa0f6e33b64", size = 16504005 }, { url = "https://files.pythonhosted.org/packages/55/f8/fd7078f3c976209ff19e027eaabf1d1b0e35ffcdd48e37f9148767480bd1/onnx-1.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1521ea7cd3497ecaf57d3b5e72d637ca5ebca632122a0806a9df99bedbeecdf8", size = 15793779 }, { url = "https://files.pythonhosted.org/packages/e8/e3/2eba2167d36a845af16255fe9c2a0a22a7034f3765109790cab91038c167/onnx-1.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45cf20421aeac03872bea5fd6ebf92abe15c4d1461a2572eb839add5059e2a09", size = 15924158 }, @@ -2219,16 +1427,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/14/a9/bb3a9aedbdc6a5ab8423d3d246a8e6d14f527de0d992fefa55d5b23fd7f0/onnx-1.16.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595b2830093f81361961295f7b0ebb6000423bcd04123d516d081c306002e387", size = 15924056 }, { url = "https://files.pythonhosted.org/packages/80/b8/2fe98bc5802e6cfe878acd8f2c5d193c081434aa27dc9ce34f157e1132d5/onnx-1.16.1-cp312-cp312-win32.whl", hash = "sha256:2fde4dd5bc278b3fc8148f460bce8807b2874c66f48529df9444cdbc9ecf456b", size = 14337703 }, { url = "https://files.pythonhosted.org/packages/85/53/09fed1c26b53a0b07791badaea96ffc46734b2251fc0d651bfda1163c159/onnx-1.16.1-cp312-cp312-win_amd64.whl", hash = "sha256:e69ad8c110d8c37d759cad019d498fdf3fd24e0bfaeb960e52fed0469a5d2974", size = 14438296 }, - { url = "https://files.pythonhosted.org/packages/34/1b/cc43f49c7f8a85f3c8049c4ad99994e62a08047d54af7fb828d1e7038a22/onnx-1.16.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:0fc189195a40b5862fb77d97410c89823197fe19c1088ce150444eec72f200c1", size = 16503397 }, - { url = "https://files.pythonhosted.org/packages/1a/b1/4e6822e70923107425fdadb032aa01fa61cf0abfbfa4a05029a660608bf6/onnx-1.16.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:496ba17b16a74711081772e1b03f3207959972e351298e51abdc600051027a22", size = 15793329 }, - { url = "https://files.pythonhosted.org/packages/32/d0/0b6d9a30bda9374355ae0254f2d192ed7b398b39c8dfe54014fb05709d7a/onnx-1.16.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3faf239b48418b3ea6fe73bd4d86807b903d0b2ebd20b8b8c84f83741b0f18", size = 15924318 }, - { url = "https://files.pythonhosted.org/packages/fa/ce/8440fa53d00bf1f4ae0210551970e49456125eabd86d752a13dfd2408359/onnx-1.16.1-cp38-cp38-win32.whl", hash = "sha256:18b22143836838591f6551b089196e69f60c47fabce52b4b72b4cb37522645aa", size = 14337203 }, - { url = "https://files.pythonhosted.org/packages/5c/8d/7efe8c1f489cab37d45e7676d8c371c67d404dcad9e3b22ed5499e3a9ffb/onnx-1.16.1-cp38-cp38-win_amd64.whl", hash = "sha256:8c2b70d602acfb90056fbdc60ef26f4658f964591212a4e9dbbda922ff43061b", size = 14436437 }, - { url = "https://files.pythonhosted.org/packages/87/98/03e94c62f835121a647e4516368acd3ae1ae7d1a83481f0475a2f5975555/onnx-1.16.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:2bed6fe05905b073206cabbb4463c58050cf8d544192303c09927b229f93ac14", size = 16504276 }, - { url = "https://files.pythonhosted.org/packages/6d/aa/ffdce5f0459849c401a2d3b37d35491e444a95e3127f93d2f044f16d8127/onnx-1.16.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5798414332534a41404a7ff83677d49ced01d70160e1541484cce647f2295051", size = 15794162 }, - { url = "https://files.pythonhosted.org/packages/8f/23/ab9e0586873a9cba8d1127528255205620092c66d77203919c372f19dfe7/onnx-1.16.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa7518d6d27f357261a4014079dec364cad6fef827d0b3fe1d3ff59939a68394", size = 15924923 }, - { url = "https://files.pythonhosted.org/packages/59/fa/af73c5d1d542e5967bb0ebe48195c6cdf7367f7be5bfcbf96a6fb0aba4f1/onnx-1.16.1-cp39-cp39-win32.whl", hash = "sha256:67f372db4fe8fe61e00b762af5b0833aa72b5baa37e7e2f47d8668964ebff411", size = 14337204 }, - { url = "https://files.pythonhosted.org/packages/9d/14/56a14765f9e544a511dbd8e6abfa42b7413a65fdd771a0e637811599023f/onnx-1.16.1-cp39-cp39-win_amd64.whl", hash = "sha256:1c059fea6229c44d2d39c8f6e2f2f0d676d587c97f4c854c86f3e7bc97e0b31c", size = 14432270 }, ] [[distribution]] @@ -2244,11 +1442,6 @@ dependencies = [ { name = "sympy" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/02/83/b72ef2d6cc8f8b4d60bc6b41641eaa8975c5f968a49bc69ff3c5e9b28b7f/onnxruntime-1.18.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:29ef7683312393d4ba04252f1b287d964bd67d5e6048b94d2da3643986c74d80", size = 15892232 }, - { url = "https://files.pythonhosted.org/packages/cd/ef/4f4e45d49c2587080f0252dba644620a9808e2d19591bb0b327650ace6b6/onnxruntime-1.18.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fc706eb1df06ddf55776e15a30519fb15dda7697f987a2bbda4962845e3cec05", size = 6013528 }, - { url = "https://files.pythonhosted.org/packages/04/da/cd671caf4231942c4f68bf0dc1a959303df91dfd0e1d55c556b924d8e68e/onnxruntime-1.18.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7de69f5ced2a263531923fa68bbec52a56e793b802fcd81a03487b5e292bc3a", size = 6788962 }, - { url = "https://files.pythonhosted.org/packages/63/ea/7f1396f7279073e1288e1d39874f39999ee7ea5b2f3f5ad838214b4a3620/onnxruntime-1.18.1-cp310-cp310-win32.whl", hash = "sha256:221e5b16173926e6c7de2cd437764492aa12b6811f45abd37024e7cf2ae5d7e3", size = 5069833 }, - { url = "https://files.pythonhosted.org/packages/74/8e/0db236760a60ba59fac48e253c2c645bfd7d6ade58d4ce796b645d73e2de/onnxruntime-1.18.1-cp310-cp310-win_amd64.whl", hash = "sha256:75211b619275199c861ee94d317243b8a0fcde6032e5a80e1aa9ded8ab4c6060", size = 5581426 }, { url = "https://files.pythonhosted.org/packages/d7/ae/e257a5ffa4ef84e51255a38b62b4fdb538d92455e1f0f0ad056074f89c94/onnxruntime-1.18.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:f26582882f2dc581b809cfa41a125ba71ad9e715738ec6402418df356969774a", size = 15892594 }, { url = "https://files.pythonhosted.org/packages/54/4b/f4c52a6b5e62f98f852a946fefc48f12d5838652eb7da5c300dc27a80ba4/onnxruntime-1.18.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef36f3a8b768506d02be349ac303fd95d92813ba3ba70304d40c3cd5c25d6a4c", size = 6010462 }, { url = "https://files.pythonhosted.org/packages/dd/ae/163375ec2b6aee385c26889b4a0bd4546133b1da7c66285ef8db180781c5/onnxruntime-1.18.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:170e711393e0618efa8ed27b59b9de0ee2383bd2a1f93622a97006a5ad48e434", size = 6794885 }, @@ -2259,16 +1452,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a3/0a/89bc7acdf7b311ec5cdf6c01983e8ecb23f7b1ba7a1b2d2fd10d33dfd24a/onnxruntime-1.18.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:781aa9873640f5df24524f96f6070b8c550c66cb6af35710fd9f92a20b4bfbf6", size = 6793752 }, { url = "https://files.pythonhosted.org/packages/b7/ea/8eac166b5903b1f0e6e08ff8c64986654b1b21e410b1f18c45e97a225a88/onnxruntime-1.18.1-cp312-cp312-win32.whl", hash = "sha256:3a2d9ab6254ca62adbb448222e630dc6883210f718065063518c8f93a32432be", size = 5070749 }, { url = "https://files.pythonhosted.org/packages/80/62/3f54fd70511e004869a2bc5c4ba4303a5b51b625ff81bd989c35d1d8086a/onnxruntime-1.18.1-cp312-cp312-win_amd64.whl", hash = "sha256:ad93c560b1c38c27c0275ffd15cd7f45b3ad3fc96653c09ce2931179982ff204", size = 5584630 }, - { url = "https://files.pythonhosted.org/packages/ac/0d/c0d05c901117acdfdb6828c002abd36ae4d19d266fbe72a73197f14fe17b/onnxruntime-1.18.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:3b55dc9d3c67626388958a3eb7ad87eb7c70f75cb0f7ff4908d27b8b42f2475c", size = 15892380 }, - { url = "https://files.pythonhosted.org/packages/92/00/d838931f8bc2fc3b7e74a97ac17320c643b48f4c4cc5ce10d9c26318fb19/onnxruntime-1.18.1-cp38-cp38-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f80dbcfb6763cc0177a31168b29b4bd7662545b99a19e211de8c734b657e0669", size = 6010633 }, - { url = "https://files.pythonhosted.org/packages/66/5c/de6bb89e99ae158f1cbc475f16ac9543243c83e6984ca5cc79bf9ddb9dee/onnxruntime-1.18.1-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f1ff2c61a16d6c8631796c54139bafea41ee7736077a0fc64ee8ae59432f5c58", size = 6788827 }, - { url = "https://files.pythonhosted.org/packages/0d/36/1f4f1227e0409de4b241fb564640e20d7cdd46d3f550456c62eb92c8acb2/onnxruntime-1.18.1-cp38-cp38-win32.whl", hash = "sha256:219855bd272fe0c667b850bf1a1a5a02499269a70d59c48e6f27f9c8bcb25d02", size = 5069289 }, - { url = "https://files.pythonhosted.org/packages/a9/82/c98b28ded95bec2f389282fd9be1544149441a4c310a9f1f8f07a0532cd4/onnxruntime-1.18.1-cp38-cp38-win_amd64.whl", hash = "sha256:afdf16aa607eb9a2c60d5ca2d5abf9f448e90c345b6b94c3ed14f4fb7e6a2d07", size = 5581702 }, - { url = "https://files.pythonhosted.org/packages/9c/95/b581d7e2134ef49d9f4d63bfd0aa7ad91e6c8fecf8ce71a229306a78857c/onnxruntime-1.18.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:128df253ade673e60cea0955ec9d0e89617443a6d9ce47c2d79eb3f72a3be3de", size = 15893504 }, - { url = "https://files.pythonhosted.org/packages/5f/66/8a1deac3f16fad5fab4aedeea8d4a0baaafef0e16f7c5ae2e162f6af6d34/onnxruntime-1.18.1-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9839491e77e5c5a175cab3621e184d5a88925ee297ff4c311b68897197f4cde9", size = 5995471 }, - { url = "https://files.pythonhosted.org/packages/10/f5/67bd1b947bc4055ea62efd4b974cef51a8a6819ac4e8c61ca014901dbfd0/onnxruntime-1.18.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ad3187c1faff3ac15f7f0e7373ef4788c582cafa655a80fdbb33eaec88976c66", size = 6793994 }, - { url = "https://files.pythonhosted.org/packages/50/ea/4fb07d2a82d6b2782c98adcaea7d3e6b057b8e85c219f8d21e5ec72bc423/onnxruntime-1.18.1-cp39-cp39-win32.whl", hash = "sha256:34657c78aa4e0b5145f9188b550ded3af626651b15017bf43d280d7e23dbf195", size = 5070149 }, - { url = "https://files.pythonhosted.org/packages/da/5b/60dd8b3acf1230eb7093122f4fa621784ec4a7deaaf246456a4e2f0f0a25/onnxruntime-1.18.1-cp39-cp39-win_amd64.whl", hash = "sha256:9c14fd97c3ddfa97da5feef595e2c73f14c2d0ec1d4ecbea99c8d96603c89589", size = 5584248 }, ] [[distribution]] @@ -2284,16 +1467,10 @@ dependencies = [ { name = "sympy" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/52/fa9ba5a69cfed82ba1765882f50664b05c26982f55fec6edd1bda700195f/onnxruntime_gpu-1.18.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e9de7b8c7c975f7830d1e9323daca2090408df821f2adc10ea267b4f469b59e0", size = 200801022 }, - { url = "https://files.pythonhosted.org/packages/39/9b/665165a418bc45f1bc54561e19063a24b7fc2814ff5cd56e7601321e183d/onnxruntime_gpu-1.18.1-cp310-cp310-win_amd64.whl", hash = "sha256:7622a5979bb64a6631f888439b6ac8b11fbdd47da980425c697b82d4dd04b427", size = 157670940 }, { url = "https://files.pythonhosted.org/packages/92/2e/5c6a3c94a8e4794a0ad1ba00f5b86c89673f271f43c77f537a90db4472c0/onnxruntime_gpu-1.18.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:af2d3ee6fba72b57abf6f379b8aca30ee773959d4346271e7d92557dd5cf2901", size = 200794895 }, { url = "https://files.pythonhosted.org/packages/7d/78/ec2a3948600b1d3297d055d5a52175d71f45f1b2b41da749cf39973036b1/onnxruntime_gpu-1.18.1-cp311-cp311-win_amd64.whl", hash = "sha256:e40ba43771043fe286fea38b2c6549d1cc4b2b5b424624163c923163a8dc27ac", size = 157666628 }, { url = "https://files.pythonhosted.org/packages/a3/81/c364ca9c0b2260a38c7bc026b8a74e6bb8caa9e4fcc9f20438558b942b0f/onnxruntime_gpu-1.18.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:87d1884523f485f40d3a126677a9f93fc15569dd817fc753ee7fc519142a4425", size = 200797176 }, { url = "https://files.pythonhosted.org/packages/31/f0/84034a7592937f02ca3c671e50b767f86a721959619635fe40ffa14031e0/onnxruntime_gpu-1.18.1-cp312-cp312-win_amd64.whl", hash = "sha256:3f2ab38a62350965f5007111728410b3ef25213104dd1e7d61ecc158002ea3f5", size = 157671367 }, - { url = "https://files.pythonhosted.org/packages/ae/53/d065090e5f0727bf892313f0fdd005eb0cc9942486cfec38f6ad6e03d8fc/onnxruntime_gpu-1.18.1-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:96e665393934cd6a2d7f5c4a8449815fc88e6afaeafc0b1da795545fabc7624f", size = 200802339 }, - { url = "https://files.pythonhosted.org/packages/9d/bd/e61e9a3ad7f9e3c53eed938ca45938dfe511287d3c77b86b2bc69d6496b3/onnxruntime_gpu-1.18.1-cp38-cp38-win_amd64.whl", hash = "sha256:5ba076faa5c6fdccf99a607ea0910f066ad4f53c472269ac9f5768c5193aa6c7", size = 157671449 }, - { url = "https://files.pythonhosted.org/packages/cc/cd/ea25a9a3180bd158467d0eed30111e080873188f76d98d1ebfdd0713d10f/onnxruntime_gpu-1.18.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d39d3ff85eaa70d85401bd81f675b44959a135fdfb2a21383f424d1f8f290c32", size = 200800975 }, - { url = "https://files.pythonhosted.org/packages/3a/2e/1e254840ceda53e75a69f05d5e0f7937652f3b59346a1f0b19dd44c3b9c7/onnxruntime_gpu-1.18.1-cp39-cp39-win_amd64.whl", hash = "sha256:126035cd623445f9922ca0f277cf18ffc83d7e073c0c5c8057eee37f22e24440", size = 157671220 }, ] [[distribution]] @@ -2417,20 +1594,6 @@ name = "panda3d" version = "1.10.14" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/da/d8/2ea7dc056353d2444c003fe11caca542f82a8fa1831885669428dc0011bd/panda3d-1.10.14-cp27-cp27m-macosx_10_6_i386.whl", hash = "sha256:cf47bcbe5d6270107e80f5f18b88186cc40de83e4e90c86e7e516d2289a68dd1", size = 58788186 }, - { url = "https://files.pythonhosted.org/packages/5d/97/12c052a92a6cb9924dc2bcc4d84c2147125c72d09fd2aa21d9bcc8ac1f33/panda3d-1.10.14-cp27-cp27m-macosx_10_6_x86_64.whl", hash = "sha256:c371a3df183b2e382cb6dbf07efb744b05bdb0d89101457f350ea9a7a9a481f1", size = 61022056 }, - { url = "https://files.pythonhosted.org/packages/b6/08/c27d9e109580136f559d9d4104deb65739d7b6ebf05231bafdddb24f3f77/panda3d-1.10.14-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ba49c6f213a5f0287e4cbdb66714cdf3b4aa5bdbe4e1a55034e74d0dda9f0250", size = 65649880 }, - { url = "https://files.pythonhosted.org/packages/f6/6d/c8b4905f42e5f3930ee0cd98fa7f595e0cb4baaed902dd3c42538c4f0778/panda3d-1.10.14-cp27-cp27m-win32.whl", hash = "sha256:adb54216a9234f3736693d49032783d7fb8952a15510f1397f992a5c94cdf897", size = 51249102 }, - { url = "https://files.pythonhosted.org/packages/7d/c4/b67a332fc8e870a76919cfa1313a8a62ce49643ba7c157c9dcbcae6a1cc8/panda3d-1.10.14-cp27-cp27m-win_amd64.whl", hash = "sha256:f94dd5f557166b6571969883bd2ffd3a555e8ac720f0f3e347d2081222bc0997", size = 62288779 }, - { url = "https://files.pythonhosted.org/packages/44/17/1016890f1667e834289c0468abb69003f0137135c7400eefd10a2c45e7ad/panda3d-1.10.14-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:c98d2143755e52d4be3b474b932207c830e473aa0e10052831bc82784f1dd17c", size = 49888419 }, - { url = "https://files.pythonhosted.org/packages/35/3d/dcb2b1f8c56d483e97068338151c88cfb68eaa46ec685e18a16b4ef7ccc8/panda3d-1.10.14-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:b7f8c6524e1381bd28a15e5e2ed7aaba8ed3b6fa29d4ea5a4b215c4639b49438", size = 52391433 }, - { url = "https://files.pythonhosted.org/packages/3c/a9/8d702b0e5537586728329841efbc066458b7f7919a7f537af9fb12fb5dcf/panda3d-1.10.14-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b0e2aacb148b7033c08929bbf89bb497c2bed1811aa9f7e5efc167dbf57c90ae", size = 66656539 }, - { url = "https://files.pythonhosted.org/packages/0f/03/119699a167166ad58dffcba8ef82e1cc3a7d89d04800d0a063d6ad71c9fc/panda3d-1.10.14-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:2c60139139654a51dab213ce1c9f67abd73153fc9e0a0514c0758741b2d2bd96", size = 116957978 }, - { url = "https://files.pythonhosted.org/packages/7e/fd/500423904aed94e8937dee33183ef5d5dc963a4ed8877341dcfedf9b8919/panda3d-1.10.14-cp310-cp310-manylinux2010_i686.whl", hash = "sha256:f5da02fb5735294193eb1794ecbe619f20f87712f1b2c5d6e4d1a269f652ebeb", size = 55299406 }, - { url = "https://files.pythonhosted.org/packages/06/2e/4cfa35d3687bb8a97ba4fbda6aea6387502c59c2830667edb8f43e1bb41f/panda3d-1.10.14-cp310-cp310-manylinux2010_x86_64.whl", hash = "sha256:d6a65b1930e144d5901cdd20d2779dc157897a730f0c9674692d61ad50e31213", size = 54612440 }, - { url = "https://files.pythonhosted.org/packages/68/69/4c25038988413532dea3637b32bb871dbd0181c9eaeb922d46e1610e3b10/panda3d-1.10.14-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:182a309537cd76c514b9f4d0dfd54bc9cb35d06a32234084bab6f3f0b0db3985", size = 54882414 }, - { url = "https://files.pythonhosted.org/packages/83/7c/e0c7a5e7f4d6896ac0d1ebc7b4654be0f977a15a77a5754e15fecc966ab1/panda3d-1.10.14-cp310-cp310-win32.whl", hash = "sha256:2a2b872a180ed84ff337147d6d46c14aceccbcfd1149135ba57e15136350d87f", size = 52360963 }, - { url = "https://files.pythonhosted.org/packages/c8/de/faf0b5a6a4e32c8e292394a06479f44829395c7a68527e497e5ef538354c/panda3d-1.10.14-cp310-cp310-win_amd64.whl", hash = "sha256:385d12a1f0924e91a39ebd6053104712a1acd91e089638d292b533e36f402c48", size = 63538238 }, { url = "https://files.pythonhosted.org/packages/f5/9a/31d07e3d7c1b40335e8418c540d63f4d33c571648ed8d69896ab778e65c3/panda3d-1.10.14-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:54b8ef9fe3684960a2c7d47b0d63c0354c17bc516795e59db6c1e5bda8c16c1c", size = 67700752 }, { url = "https://files.pythonhosted.org/packages/61/05/fce327535d8907ac01f43813c980f30ea86d37db62c340847519ea2ab222/panda3d-1.10.14-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:93414675894b18eea8d27edc1bbd1dc719eae207d45ec263d47195504bc4705f", size = 118966179 }, { url = "https://files.pythonhosted.org/packages/8a/54/24e205231e7b1bced58ba9620fbec7114673d821fc7ad9ed1804cab556b4/panda3d-1.10.14-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:d1bc0d926f90c8fa14a1587fa9dbe5f89a4eda8c9684fa183a8eaa35fc8e891a", size = 55145295 }, @@ -2442,49 +1605,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/11/69/806dcdbaee3e8deee1956abeea0d3d3e504315d2e9814de82a44809a8617/panda3d-1.10.14-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:3c4399a286a142de7ff86f9356d7e526bbbd38892d7f7d39fecb5c33064972bc", size = 55539594 }, { url = "https://files.pythonhosted.org/packages/ad/25/005de5e2b6d0acd546f8b3f2b547cd29e308cdd04a397f0ea68046e26571/panda3d-1.10.14-cp312-cp312-win32.whl", hash = "sha256:e92e0dd907e2af33085a2c31ca2263dc8023b1b7bc70ce1b9fbc84631e130e51", size = 53479813 }, { url = "https://files.pythonhosted.org/packages/74/bb/cb57563855da994614a33f57bd5691fbcd69f12e5ccddd30d387d0be287f/panda3d-1.10.14-cp312-cp312-win_amd64.whl", hash = "sha256:a5f2defd822d38848f8ae1956115adcb6cc7f464f03a67e73681cc72df125ef4", size = 64893222 }, - { url = "https://files.pythonhosted.org/packages/9b/37/786758da5c5f51f48744ac4e914198df7e9b9aceac8e226b6416e0c05ebb/panda3d-1.10.14-cp34-cp34m-macosx_10_6_i386.whl", hash = "sha256:84ca5855e03173f521a2b4edc84e62ad5ffb31e9454bd809efb8e71a5c32df4f", size = 56961319 }, - { url = "https://files.pythonhosted.org/packages/e8/4a/9d565f3a5eb1bad6e607f67df14f8dd0d8fc8aa0f0e4024a38732200303d/panda3d-1.10.14-cp34-cp34m-macosx_10_6_x86_64.whl", hash = "sha256:9082e3d66a653589ffab7c5bd7a50eb46ab168104e08a86c77b58bbd77030d50", size = 59180473 }, - { url = "https://files.pythonhosted.org/packages/70/63/70de0bd09b15bf555435426efbfdafe6b6e74b52f7317314a3a704e7db22/panda3d-1.10.14-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:f1a46ca8427ffb9267b3951af81f6774b7259b7e8f89210af6366b208e5762e6", size = 49724699 }, - { url = "https://files.pythonhosted.org/packages/b5/88/5dc7027d7d8dc78ffc9d1b54ef9b80a84c2de68d0a7231da760b82bf3e84/panda3d-1.10.14-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:c23694788696d7bfe291ced98dd87e57532a23f821e71f7b2d0c2004a4648c8f", size = 52223275 }, - { url = "https://files.pythonhosted.org/packages/8a/e0/0d2c948bb87eb4b4aac0b533f0cfd100dbb7af821bc81dd325c93e04da9b/panda3d-1.10.14-cp34-cp34m-win32.whl", hash = "sha256:f14455c459730f396e524d8b9e62875438481e1dc7dfd2083e9522a3bad45f28", size = 50984680 }, - { url = "https://files.pythonhosted.org/packages/56/4c/e79e461f6df774aafeb32b1137bbcb02c6e97df66558c44ad915d0d70074/panda3d-1.10.14-cp34-cp34m-win_amd64.whl", hash = "sha256:110a33b20f15aa6333c8e72e30bcf0dc9afaef809a325d247bb7470de3942dae", size = 61984918 }, - { url = "https://files.pythonhosted.org/packages/ed/f2/c7c529be9a0bd949a6481db3a582ead69d255159f094129574da1f59226f/panda3d-1.10.14-cp35-cp35m-macosx_10_6_i386.whl", hash = "sha256:d91e37d43242d5132886c3850aa4a2f3ee7401de2360cb8313616b45ab78ecba", size = 57102302 }, - { url = "https://files.pythonhosted.org/packages/69/b1/8782d1fd0760b860646c3af6490b9f8a1386435d69e8e291b4820012c687/panda3d-1.10.14-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:f4bcf78223df3c13e9a627a25856c91bdbf28f75b021630e5ca37a961eeabb27", size = 59317903 }, - { url = "https://files.pythonhosted.org/packages/6f/ab/42d37301d01ff7e5bf5d6feb13af0e4aed15a371682b573b5d919bd37ca4/panda3d-1.10.14-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:e0a7a1d7cbe10474cad720898b384d642dcd3d7a07b3dbe09154107a5651be49", size = 63259045 }, - { url = "https://files.pythonhosted.org/packages/db/b1/3954c90a04af005e3f2adeae3b13caa1624d041bf0a07732b88e6f81a8f1/panda3d-1.10.14-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:78404da82a5d93641b0f2a89790cad235b087e7e2e37bbe83c995e99495635cd", size = 49875273 }, - { url = "https://files.pythonhosted.org/packages/a8/8a/4e97a8363c5ce70c3b103b8739174adb06ae1e21b1c270a7cfe4ea7aa42f/panda3d-1.10.14-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aa1381f4c06b789b8a725185773397b0c7a2508eeb8156874537c07171e5cb99", size = 52355141 }, - { url = "https://files.pythonhosted.org/packages/e4/41/cf791611448a40dbdbebc4b6058d1d3a03c4853de06f7d32f7a543dfd0b2/panda3d-1.10.14-cp35-cp35m-win32.whl", hash = "sha256:8a497dd7401b50fa372664c724f1cb949b8d8bc3ed6d9b6433af19086bcf9325", size = 51357116 }, - { url = "https://files.pythonhosted.org/packages/f5/2c/f4cba383b423b2e091d104f329beb09cdd29e8033b9cae2003279d682e96/panda3d-1.10.14-cp35-cp35m-win_amd64.whl", hash = "sha256:293c5441e4f2720da480abdb3c99e55e96a7616d8867ac9c7b94526694a5812e", size = 62300039 }, - { url = "https://files.pythonhosted.org/packages/5b/68/0f7bd034764193391cee638baa81fd54ee6f884f740982de8084f7c9aa91/panda3d-1.10.14-cp36-cp36m-macosx_10_6_i386.whl", hash = "sha256:15083e9c82d884c279bca897576ed91848323f951617f7bbb43d2dba32e6d662", size = 58200988 }, - { url = "https://files.pythonhosted.org/packages/2d/8b/319efa9de2e2e5b6b4336bfdcfab6da4e4e88b7e6d4f3f235d0e3b46730b/panda3d-1.10.14-cp36-cp36m-macosx_10_6_x86_64.whl", hash = "sha256:b8a20828a45a9215f7ecb59baec18a79adda56ad1b25eb99b9958d26d8ab2a40", size = 60715754 }, - { url = "https://files.pythonhosted.org/packages/f2/36/9f7bfc6ad00aacfb347a4b74f659d0d997d2327962d7c4575dfbb5b2ebac/panda3d-1.10.14-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d4c555a5c47ffcaaed518c52b3bb9d5729a5dc4492f51e8a46b076ca54adcae0", size = 64556656 }, - { url = "https://files.pythonhosted.org/packages/0e/a1/d767bca6e7b0be98e6b0a4d6a41bd084c1b6fc123c500cd9eb4e24ece4cb/panda3d-1.10.14-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0c43a4dfd6b12323359439ea7c60e8fbf84ff0aa75abaccd5179cc6b27baa2b7", size = 50027455 }, - { url = "https://files.pythonhosted.org/packages/e3/4a/32fbd23d9b7dd9f8dd006cfdae395d67d6f8a3f0737934f7a6cb53662962/panda3d-1.10.14-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:06a4595f1737170d316829b451cbfb01a130918a04481b1f217212c485c64586", size = 52564251 }, - { url = "https://files.pythonhosted.org/packages/78/05/944d153f9058d56f1bc7f118e1370d1669e1f0ba3c5442ac0105adf8d70b/panda3d-1.10.14-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:24d2a38f9068f868ac23101a8601d88f3c137ededed2be222d5e711a4b114467", size = 54313467 }, - { url = "https://files.pythonhosted.org/packages/dd/07/fc48ca674a1e1403780228afc84a6a2555786cd4b308031eb59580c07610/panda3d-1.10.14-cp36-cp36m-win32.whl", hash = "sha256:d7d722fb5a62531e62f6b98db2b3e399deddde945f84c954aefac73989c75e4c", size = 51853501 }, - { url = "https://files.pythonhosted.org/packages/b9/04/806438046e958b9f63e070d2983be6edc889a870129c2b60cf31dd74e608/panda3d-1.10.14-cp36-cp36m-win_amd64.whl", hash = "sha256:7d17fe989aaed3f35a7992742a4c4536936fb0a70a87d4625b92f185f0318c45", size = 62678880 }, - { url = "https://files.pythonhosted.org/packages/22/cd/93bde5898dde0ac349ecd725dfe6f5d651e9685f556256dec014f3103f03/panda3d-1.10.14-cp37-cp37m-macosx_10_6_i386.whl", hash = "sha256:0ab75f828daef54678e9f2a15bccfe4e7b090991ee025689be324194266fd82e", size = 58867183 }, - { url = "https://files.pythonhosted.org/packages/36/4a/5a9b269219ff49fab305f87a0a539de06d6e1372b16293985f8bef2e5735/panda3d-1.10.14-cp37-cp37m-macosx_10_6_x86_64.whl", hash = "sha256:f04af7a7becaf30c0c256a0177a7493ab91247ea5a2798345b2df2ec71aeff23", size = 61151869 }, - { url = "https://files.pythonhosted.org/packages/37/67/45514d1358bd518178a5ea4a2bfc63a943d3849c871ad112e313579238dc/panda3d-1.10.14-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d41579867cb2998f4273bdece282c641dac6f40ca2e713dafa3fb9ce3ef12162", size = 65564365 }, - { url = "https://files.pythonhosted.org/packages/5e/59/b846f3e6dc5b59b86d22b43f8e05436dfc62579bbe4ae1f28382361f9d04/panda3d-1.10.14-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4db1b920d501d3524e92467a21ecb08cc0063566a681991cc683f2070068f128", size = 50180821 }, - { url = "https://files.pythonhosted.org/packages/86/60/4134b23c544e880f9b52f7d606739c8a8103e0bf4f6925be4b972003901a/panda3d-1.10.14-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:db28161d1f40adf0b0998f7064ac784e49a2f2ec3bb04810c2757ba938c7d2cf", size = 52708608 }, - { url = "https://files.pythonhosted.org/packages/27/7e/a0902f7e2cec74ecb00669f9f25602d05ff19b513a9d4b5d63bbd1dd1cff/panda3d-1.10.14-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:0cbdbc41229fa7d075925a716477e7a8d1a17a2523fc88e97fa010c4e0706442", size = 54454771 }, - { url = "https://files.pythonhosted.org/packages/23/c4/2a3dd5f3187dbf09fdc84d5331c179ccc62e4e761f62ed02f8da3b5ce879/panda3d-1.10.14-cp37-cp37m-win32.whl", hash = "sha256:145cd28de41261e0ac2bc24323417f8b21623f48de0bb7a9e0d70ff386c34c84", size = 51737248 }, - { url = "https://files.pythonhosted.org/packages/af/c6/b508249aa931470c432153cf2af1f07eeff4addbfddee432cdeea3a6f743/panda3d-1.10.14-cp37-cp37m-win_amd64.whl", hash = "sha256:fadb6eb4106dc3fecea81a1e81186b3cc3ee0019d0b5435273113a18aec2352c", size = 62788200 }, - { url = "https://files.pythonhosted.org/packages/f5/fd/85538d72d2af1221e75d5f6d0f28ba4f0b1d2c41404026f182284b48cdb7/panda3d-1.10.14-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a61c973d8d58305a502d05a82dc3ec6cf2b5e01ada7151a83415c51a959ff774", size = 65849139 }, - { url = "https://files.pythonhosted.org/packages/92/45/c84b5c195401147b22f4eae1df67e2681cf6ae272ea8356c3c450562b20b/panda3d-1.10.14-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:3e82b2f904efb9f7f78dbf6d88bc5ebc83c5c0fbc9e477a8ef2b154bd7935591", size = 115469586 }, - { url = "https://files.pythonhosted.org/packages/05/a2/461f66ab78fc7d57b4448cb9ccad109bbc8f0c20430412313a5045199cbd/panda3d-1.10.14-cp38-cp38-manylinux1_i686.whl", hash = "sha256:96d1ce3483a51ec5aebc43f3e30e552deacb660606d2b36e86ed3a9756e3eccf", size = 50412970 }, - { url = "https://files.pythonhosted.org/packages/ab/e7/088201b2927c5ac3de20e0f55198103a852b53b4b99c5c774e423550da79/panda3d-1.10.14-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b658d75a5342ff175703ce780e8b383da438ff68ea941d0e5dff68c5189d38ec", size = 52960612 }, - { url = "https://files.pythonhosted.org/packages/14/a3/9a93fe08fa7311653bee6940f9781c42222d312c7e17b37c2a74b06f4ea4/panda3d-1.10.14-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:3e564c44d879b01d01a7fcdc03977affcf3b1dabcf2d6e5c678e06b9de8855ac", size = 54711042 }, - { url = "https://files.pythonhosted.org/packages/8a/03/e66b1d64a426cdbfb6f4a762e6b36730eae1cae7eecb0c755122dd1c7da0/panda3d-1.10.14-cp38-cp38-win32.whl", hash = "sha256:06007592951730b52852771e98b306b3c1de9dc51abf0bab183c3ec3ac404131", size = 52208838 }, - { url = "https://files.pythonhosted.org/packages/65/fd/69187c77e40373f345c5718d9cf3cf0abbaa1409184c386ae2e549f1d937/panda3d-1.10.14-cp38-cp38-win_amd64.whl", hash = "sha256:b05713b5acfcfcbf1dc87c19b1d5babf926d21f83b3772180e7a5de83f45b454", size = 63239878 }, - { url = "https://files.pythonhosted.org/packages/29/87/032644031f586ec9ecd7f28d9475e27a11c431792e63b3a861bad9c18ac6/panda3d-1.10.14-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d55c7d52bd07e54a16219bb88a7cf34a5b9e7c720dce585e9de8427cc54d9dd2", size = 66008285 }, - { url = "https://files.pythonhosted.org/packages/f2/4c/322b69b5dad82949f4e1a4b8ed4bd945863ae67970ea973391ebdbc1b751/panda3d-1.10.14-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:39abf9330ebcfcff07c29ebcf397cf43c2e5be6c148cf45a0a025d3297c43289", size = 115924203 }, - { url = "https://files.pythonhosted.org/packages/64/f2/0f81e1f77a6db8eb63321ed7148eb79d1c92dc4418d5c998acf9e292c4cf/panda3d-1.10.14-cp39-cp39-manylinux1_i686.whl", hash = "sha256:0f69c7232713f50a552b00ada4cbb03780bb97ec1ddb640e5162df61d1b26a2b", size = 50543371 }, - { url = "https://files.pythonhosted.org/packages/48/71/60df1aa81b628856786085b39f2cf5576282a2c725cd96c5a851ce0b3497/panda3d-1.10.14-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:9dda6736e8c180fa9caab70aa9461d7042b74764f73e4d2c59fe560751989341", size = 53092313 }, - { url = "https://files.pythonhosted.org/packages/70/cd/51738569e3c2b780c7791199b2d36aa3787d57f8c9628b3d2d3d41f6bc73/panda3d-1.10.14-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:a91ab520fa8bd206460f0b7acfa6329440d72669048bac3eab4bb4d8dcd09991", size = 54843772 }, - { url = "https://files.pythonhosted.org/packages/f4/b4/0779b3a422fdfe829530f56454961eb64badbccf1c0c9c21d39258964538/panda3d-1.10.14-cp39-cp39-win32.whl", hash = "sha256:2de074b0a3e0f243e4c1fba0376a26489d585cc71fd79986de274e282e3913d8", size = 52580779 }, - { url = "https://files.pythonhosted.org/packages/13/5a/6e7420c6c7499bf724f172808e252726b57a05877c19b11cf9acdfb5f6e0/panda3d-1.10.14-cp39-cp39-win_amd64.whl", hash = "sha256:356c55c25c2227bb2cf20a9613410c470f4e9de887543ec8b3765c848af4bff0", size = 63624709 }, ] [[distribution]] @@ -2525,13 +1645,6 @@ dependencies = [ { name = "tzdata" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/2d/39600d073ea70b9cafdc51fab91d69c72b49dd92810f24cb5ac6631f387f/pandas-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce", size = 12551798 }, - { url = "https://files.pythonhosted.org/packages/fd/4b/0cd38e68ab690b9df8ef90cba625bf3f93b82d1c719703b8e1b333b2c72d/pandas-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238", size = 11287392 }, - { url = "https://files.pythonhosted.org/packages/01/c6/d3d2612aea9b9f28e79a30b864835dad8f542dcf474eee09afeee5d15d75/pandas-2.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08", size = 15634823 }, - { url = "https://files.pythonhosted.org/packages/89/1b/12521efcbc6058e2673583bb096c2b5046a9df39bd73eca392c1efed24e5/pandas-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0", size = 13032214 }, - { url = "https://files.pythonhosted.org/packages/e4/d7/303dba73f1c3a9ef067d23e5afbb6175aa25e8121be79be354dcc740921a/pandas-2.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51", size = 16278302 }, - { url = "https://files.pythonhosted.org/packages/ba/df/8ff7c5ed1cc4da8c6ab674dc8e4860a4310c3880df1283e01bac27a4333d/pandas-2.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e5a0b00e1e56a842f922e7fae8ae4077aee4af0acb5ae3622bd4b4c30aedf99", size = 13892866 }, - { url = "https://files.pythonhosted.org/packages/69/a6/81d5dc9a612cf0c1810c2ebc4f2afddb900382276522b18d128213faeae3/pandas-2.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:ddf818e4e6c7c6f4f7c8a12709696d193976b591cc7dc50588d3d1a6b5dc8772", size = 11621592 }, { url = "https://files.pythonhosted.org/packages/1b/70/61704497903d43043e288017cb2b82155c0d41e15f5c17807920877b45c2/pandas-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288", size = 12574808 }, { url = "https://files.pythonhosted.org/packages/16/c6/75231fd47afd6b3f89011e7077f1a3958441264aca7ae9ff596e3276a5d0/pandas-2.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151", size = 11304876 }, { url = "https://files.pythonhosted.org/packages/97/2d/7b54f80b93379ff94afb3bd9b0cd1d17b48183a0d6f98045bc01ce1e06a7/pandas-2.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b", size = 15602548 }, @@ -2546,13 +1659,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/35/9d/208febf8c4eb5c1d9ea3314d52d8bd415fd0ef0dd66bb24cc5bdbc8fa71a/pandas-2.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76", size = 15858913 }, { url = "https://files.pythonhosted.org/packages/99/d1/2d9bd05def7a9e08a92ec929b5a4c8d5556ec76fae22b0fa486cbf33ea63/pandas-2.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32", size = 13417786 }, { url = "https://files.pythonhosted.org/packages/22/a5/a0b255295406ed54269814bc93723cfd1a0da63fb9aaf99e1364f07923e5/pandas-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23", size = 11498828 }, - { url = "https://files.pythonhosted.org/packages/1b/cc/eb6ce83667131667c6561e009823e72aa5c76698e75552724bdfc8d1ef0b/pandas-2.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2", size = 12566406 }, - { url = "https://files.pythonhosted.org/packages/96/08/9ad65176f854fd5eb806a27da6e8b6c12d5ddae7ef3bd80d8b3009099333/pandas-2.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd", size = 11304008 }, - { url = "https://files.pythonhosted.org/packages/aa/30/5987c82fea318ac7d6bcd083c5b5259d4000e99dd29ae7a9357c65a1b17a/pandas-2.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863", size = 15662279 }, - { url = "https://files.pythonhosted.org/packages/bb/30/f6f1f1ac36250f50c421b1b6af08c35e5a8b5a84385ef928625336b93e6f/pandas-2.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921", size = 13069490 }, - { url = "https://files.pythonhosted.org/packages/b5/27/76c1509f505d1f4cb65839352d099c90a13019371e90347166811aa6a075/pandas-2.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a", size = 16299412 }, - { url = "https://files.pythonhosted.org/packages/5d/11/a5a2f52936fba3afc42de35b19cae941284d973649cb6949bc41cc2e5901/pandas-2.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92fd6b027924a7e178ac202cfbe25e53368db90d56872d20ffae94b96c7acc57", size = 13920884 }, - { url = "https://files.pythonhosted.org/packages/bf/2c/a0cee9c392a4c9227b835af27f9260582b994f9a2b5ec23993b596e5deb7/pandas-2.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:640cef9aa381b60e296db324337a554aeeb883ead99dc8f6c18e81a93942f5f4", size = 11637580 }, ] [[distribution]] @@ -2579,17 +1685,6 @@ version = "10.4.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/cd/74/ad3d526f3bf7b6d3f408b73fde271ec69dfac8b81341a318ce825f2b3812/pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", size = 46555059 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/69/a31cccd538ca0b5272be2a38347f8839b97a14be104ea08b0db92f749c74/pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", size = 3509271 }, - { url = "https://files.pythonhosted.org/packages/9a/9e/4143b907be8ea0bce215f2ae4f7480027473f8b61fcedfda9d851082a5d2/pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", size = 3375658 }, - { url = "https://files.pythonhosted.org/packages/8a/25/1fc45761955f9359b1169aa75e241551e74ac01a09f487adaaf4c3472d11/pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", size = 4332075 }, - { url = "https://files.pythonhosted.org/packages/5e/dd/425b95d0151e1d6c951f45051112394f130df3da67363b6bc75dc4c27aba/pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", size = 4444808 }, - { url = "https://files.pythonhosted.org/packages/b1/84/9a15cc5726cbbfe7f9f90bfb11f5d028586595907cd093815ca6644932e3/pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", size = 4356290 }, - { url = "https://files.pythonhosted.org/packages/b5/5b/6651c288b08df3b8c1e2f8c1152201e0b25d240e22ddade0f1e242fc9fa0/pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", size = 4525163 }, - { url = "https://files.pythonhosted.org/packages/07/8b/34854bf11a83c248505c8cb0fcf8d3d0b459a2246c8809b967963b6b12ae/pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", size = 4463100 }, - { url = "https://files.pythonhosted.org/packages/78/63/0632aee4e82476d9cbe5200c0cdf9ba41ee04ed77887432845264d81116d/pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", size = 4592880 }, - { url = "https://files.pythonhosted.org/packages/df/56/b8663d7520671b4398b9d97e1ed9f583d4afcbefbda3c6188325e8c297bd/pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", size = 2235218 }, - { url = "https://files.pythonhosted.org/packages/f4/72/0203e94a91ddb4a9d5238434ae6c1ca10e610e8487036132ea9bf806ca2a/pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", size = 2554487 }, - { url = "https://files.pythonhosted.org/packages/bd/52/7e7e93d7a6e4290543f17dc6f7d3af4bd0b3dd9926e2e8a35ac2282bc5f4/pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1", size = 2243219 }, { url = "https://files.pythonhosted.org/packages/a7/62/c9449f9c3043c37f73e7487ec4ef0c03eb9c9afc91a92b977a67b3c0bbc5/pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c", size = 3509265 }, { url = "https://files.pythonhosted.org/packages/f4/5f/491dafc7bbf5a3cc1845dc0430872e8096eb9e2b6f8161509d124594ec2d/pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be", size = 3375655 }, { url = "https://files.pythonhosted.org/packages/73/d5/c4011a76f4207a3c151134cd22a1415741e42fa5ddecec7c0182887deb3d/pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3", size = 4340304 }, @@ -2623,41 +1718,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/f9/cfaa5082ca9bc4a6de66ffe1c12c2d90bf09c309a5f52b27759a596900e7/pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060", size = 2235603 }, { url = "https://files.pythonhosted.org/packages/01/6a/30ff0eef6e0c0e71e55ded56a38d4859bf9d3634a94a88743897b5f96936/pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea", size = 2554972 }, { url = "https://files.pythonhosted.org/packages/48/2c/2e0a52890f269435eee38b21c8218e102c621fe8d8df8b9dd06fabf879ba/pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d", size = 2243375 }, - { url = "https://files.pythonhosted.org/packages/56/70/f40009702a477ce87d8d9faaa4de51d6562b3445d7a314accd06e4ffb01d/pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736", size = 3509213 }, - { url = "https://files.pythonhosted.org/packages/10/43/105823d233c5e5d31cea13428f4474ded9d961652307800979a59d6a4276/pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b", size = 3375883 }, - { url = "https://files.pythonhosted.org/packages/3c/ad/7850c10bac468a20c918f6a5dbba9ecd106ea1cdc5db3c35e33a60570408/pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2", size = 4330810 }, - { url = "https://files.pythonhosted.org/packages/84/4c/69bbed9e436ac22f9ed193a2b64f64d68fcfbc9f4106249dc7ed4889907b/pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680", size = 4444341 }, - { url = "https://files.pythonhosted.org/packages/8f/4f/c183c63828a3f37bf09644ce94cbf72d4929b033b109160a5379c2885932/pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b", size = 4356005 }, - { url = "https://files.pythonhosted.org/packages/fb/ad/435fe29865f98a8fbdc64add8875a6e4f8c97749a93577a8919ec6f32c64/pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd", size = 4525201 }, - { url = "https://files.pythonhosted.org/packages/80/74/be8bf8acdfd70e91f905a12ae13cfb2e17c0f1da745c40141e26d0971ff5/pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84", size = 4460635 }, - { url = "https://files.pythonhosted.org/packages/e4/90/763616e66dc9ad59c9b7fb58f863755e7934ef122e52349f62c7742b82d3/pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0", size = 4590283 }, - { url = "https://files.pythonhosted.org/packages/69/66/03002cb5b2c27bb519cba63b9f9aa3709c6f7a5d3b285406c01f03fb77e5/pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e", size = 2235185 }, - { url = "https://files.pythonhosted.org/packages/f2/75/3cb820b2812405fc7feb3d0deb701ef0c3de93dc02597115e00704591bc9/pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab", size = 2554594 }, - { url = "https://files.pythonhosted.org/packages/31/85/955fa5400fa8039921f630372cfe5056eed6e1b8e0430ee4507d7de48832/pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d", size = 3509283 }, - { url = "https://files.pythonhosted.org/packages/23/9c/343827267eb28d41cd82b4180d33b10d868af9077abcec0af9793aa77d2d/pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b", size = 3375691 }, - { url = "https://files.pythonhosted.org/packages/60/a3/7ebbeabcd341eab722896d1a5b59a3df98c4b4d26cf4b0385f8aa94296f7/pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd", size = 4328295 }, - { url = "https://files.pythonhosted.org/packages/32/3f/c02268d0c6fb6b3958bdda673c17b315c821d97df29ae6969f20fb49388a/pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126", size = 4440810 }, - { url = "https://files.pythonhosted.org/packages/67/5d/1c93c8cc35f2fdd3d6cc7e4ad72d203902859a2867de6ad957d9b708eb8d/pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b", size = 4352283 }, - { url = "https://files.pythonhosted.org/packages/bc/a8/8655557c9c7202b8abbd001f61ff36711cefaf750debcaa1c24d154ef602/pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c", size = 4521800 }, - { url = "https://files.pythonhosted.org/packages/58/78/6f95797af64d137124f68af1bdaa13b5332da282b86031f6fa70cf368261/pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1", size = 4459177 }, - { url = "https://files.pythonhosted.org/packages/8a/6d/2b3ce34f1c4266d79a78c9a51d1289a33c3c02833fe294ef0dcbb9cba4ed/pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df", size = 4589079 }, - { url = "https://files.pythonhosted.org/packages/e3/e0/456258c74da1ff5bf8ef1eab06a95ca994d8b9ed44c01d45c3f8cbd1db7e/pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef", size = 2235247 }, - { url = "https://files.pythonhosted.org/packages/37/f8/bef952bdb32aa53741f58bf21798642209e994edc3f6598f337f23d5400a/pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5", size = 2554479 }, - { url = "https://files.pythonhosted.org/packages/bb/8e/805201619cad6651eef5fc1fdef913804baf00053461522fabbc5588ea12/pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e", size = 2243226 }, - { url = "https://files.pythonhosted.org/packages/38/30/095d4f55f3a053392f75e2eae45eba3228452783bab3d9a920b951ac495c/pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", size = 3493889 }, - { url = "https://files.pythonhosted.org/packages/f3/e8/4ff79788803a5fcd5dc35efdc9386af153569853767bff74540725b45863/pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", size = 3346160 }, - { url = "https://files.pythonhosted.org/packages/d7/ac/4184edd511b14f760c73f5bb8a5d6fd85c591c8aff7c2229677a355c4179/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", size = 3435020 }, - { url = "https://files.pythonhosted.org/packages/da/21/1749cd09160149c0a246a81d646e05f35041619ce76f6493d6a96e8d1103/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", size = 3490539 }, - { url = "https://files.pythonhosted.org/packages/b6/f5/f71fe1888b96083b3f6dfa0709101f61fc9e972c0c8d04e9d93ccef2a045/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", size = 3476125 }, - { url = "https://files.pythonhosted.org/packages/96/b9/c0362c54290a31866c3526848583a2f45a535aa9d725fd31e25d318c805f/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", size = 3579373 }, - { url = "https://files.pythonhosted.org/packages/52/3b/ce7a01026a7cf46e5452afa86f97a5e88ca97f562cafa76570178ab56d8d/pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", size = 2554661 }, - { url = "https://files.pythonhosted.org/packages/e1/1f/5a9fcd6ced51633c22481417e11b1b47d723f64fb536dfd67c015eb7f0ab/pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b", size = 3493850 }, - { url = "https://files.pythonhosted.org/packages/cb/e6/3ea4755ed5320cb62aa6be2f6de47b058c6550f752dd050e86f694c59798/pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908", size = 3346118 }, - { url = "https://files.pythonhosted.org/packages/0a/22/492f9f61e4648422b6ca39268ec8139277a5b34648d28f400faac14e0f48/pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b", size = 3434958 }, - { url = "https://files.pythonhosted.org/packages/f9/19/559a48ad4045704bb0547965b9a9345f5cd461347d977a56d178db28819e/pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8", size = 3490340 }, - { url = "https://files.pythonhosted.org/packages/d9/de/cebaca6fb79905b3a1aa0281d238769df3fb2ede34fd7c0caa286575915a/pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a", size = 3476048 }, - { url = "https://files.pythonhosted.org/packages/71/f0/86d5b2f04693b0116a01d75302b0a307800a90d6c351a8aa4f8ae76cd499/pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27", size = 3579366 }, - { url = "https://files.pythonhosted.org/packages/37/ae/2dbfc38cc4fd14aceea14bc440d5151b21f64c4c3ba3f6f4191610b7ee5d/pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3", size = 2554652 }, ] [[distribution]] @@ -2723,10 +1783,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/75/44/6ae304790fad936bb4cf09907a05d669b7600458a02b6c960fdaaeeab06e/protobuf-5.27.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a109916aaac42bff84702fb5187f3edadbc7c97fc2c99c5ff81dd15dcce0d1e5", size = 412246 }, { url = "https://files.pythonhosted.org/packages/cd/c7/a534268f9c3780be1ba50f5ed96243fa9cf6224a445de662c34e91ce0e61/protobuf-5.27.2-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:176c12b1f1c880bf7a76d9f7c75822b6a2bc3db2d28baa4d300e8ce4cde7409b", size = 307143 }, { url = "https://files.pythonhosted.org/packages/27/e4/8dc4546be46873f8950cb44cdfe19b79d66d26e53c4ee5e3440406257fcd/protobuf-5.27.2-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:b848dbe1d57ed7c191dfc4ea64b8b004a3f9ece4bf4d0d80a367b76df20bf36e", size = 309259 }, - { url = "https://files.pythonhosted.org/packages/51/a7/82ae09a8b84bd55d77ba84929a6d1fec5ecfc9f7388d75b3438f3c7b0a3d/protobuf-5.27.2-cp38-cp38-win32.whl", hash = "sha256:4fadd8d83e1992eed0248bc50a4a6361dc31bcccc84388c54c86e530b7f58863", size = 405849 }, - { url = "https://files.pythonhosted.org/packages/5d/2e/ea551dcc5c8a19241f0ae15cb1f285228f99f41feefb5cd1d2cadd5d745e/protobuf-5.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:610e700f02469c4a997e58e328cac6f305f649826853813177e6290416e846c6", size = 426928 }, - { url = "https://files.pythonhosted.org/packages/20/99/845cd306286d939f3c4c4c27774208f720a1962108fe781031a5c9c31931/protobuf-5.27.2-cp39-cp39-win32.whl", hash = "sha256:9e8f199bf7f97bd7ecebffcae45ebf9527603549b2b562df0fbc6d4d688f14ca", size = 405935 }, - { url = "https://files.pythonhosted.org/packages/af/dd/262fc7c88db9f7444f8ce33124e4ea7f421ec51f223ac28c9f1788bf7a5e/protobuf-5.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:7fc3add9e6003e026da5fc9e59b131b8f22b428b991ccd53e2af8071687b4fce", size = 426916 }, { url = "https://files.pythonhosted.org/packages/3a/fa/4c3ac5527ed2e5f3577167ecd5f8180ffcdc8bdd59c9f143409c19706456/protobuf-5.27.2-py3-none-any.whl", hash = "sha256:54330f07e4949d09614707c48b06d1a22f8ffb5763c159efd5c0928326a91470", size = 164772 }, ] @@ -2736,19 +1792,12 @@ version = "6.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/18/c7/8c6872f7372eb6a6b2e4708b88419fb46b857f7a2e1892966b851cc79fc9/psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2", size = 508067 } wheels = [ - { url = "https://files.pythonhosted.org/packages/13/e5/35ebd7169008752be5561cafdba3f1634be98193b85fe3d22e883f9fe2e1/psutil-6.0.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6", size = 250527 }, - { url = "https://files.pythonhosted.org/packages/92/a7/083388ef0964a6d74df51c677b3d761e0866d823d37e3a8823551c0d375d/psutil-6.0.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:1287c2b95f1c0a364d23bc6f2ea2365a8d4d9b726a3be7294296ff7ba97c17f0", size = 316838 }, - { url = "https://files.pythonhosted.org/packages/52/2f/44b7005f306ea8bfd24aa662b5d0ba6ea1daf29dbd0b6c7bbcd3606373ad/psutil-6.0.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a9a3dbfb4de4f18174528d87cc352d1f788b7496991cca33c6996f40c9e3c92c", size = 317493 }, - { url = "https://files.pythonhosted.org/packages/81/c9/8cb36769b6636d817be3414ebbb27a9ab3fbe6d13835d00f31e77e1fccce/psutil-6.0.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6ec7588fb3ddaec7344a825afe298db83fe01bfaaab39155fa84cf1c0d6b13c3", size = 316855 }, - { url = "https://files.pythonhosted.org/packages/14/c0/024ac5369ca160e9ed45ed09247d9d779c460017fbd9aa801fd6eb0f060c/psutil-6.0.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1e7c870afcb7d91fdea2b37c24aeb08f98b6d67257a5cb0a8bc3ac68d0f1a68c", size = 317519 }, { url = "https://files.pythonhosted.org/packages/c5/66/78c9c3020f573c58101dc43a44f6855d01bbbd747e24da2f0c4491200ea3/psutil-6.0.0-cp27-none-win32.whl", hash = "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35", size = 249766 }, { url = "https://files.pythonhosted.org/packages/e1/3f/2403aa9558bea4d3854b0e5e567bc3dd8e9fbc1fc4453c0aa9aafeb75467/psutil-6.0.0-cp27-none-win_amd64.whl", hash = "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1", size = 253024 }, { url = "https://files.pythonhosted.org/packages/0b/37/f8da2fbd29690b3557cca414c1949f92162981920699cd62095a984983bf/psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0", size = 250961 }, { url = "https://files.pythonhosted.org/packages/35/56/72f86175e81c656a01c4401cd3b1c923f891b31fbcebe98985894176d7c9/psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0", size = 287478 }, { url = "https://files.pythonhosted.org/packages/19/74/f59e7e0d392bc1070e9a70e2f9190d652487ac115bb16e2eff6b22ad1d24/psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd", size = 290455 }, { url = "https://files.pythonhosted.org/packages/cd/5f/60038e277ff0a9cc8f0c9ea3d0c5eb6ee1d2470ea3f9389d776432888e47/psutil-6.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132", size = 292046 }, - { url = "https://files.pythonhosted.org/packages/cd/ff/39c38910cdb8f02fc9965afb520967a1e9307d53d14879dddd0a4f41f6f8/psutil-6.0.0-cp36-cp36m-win32.whl", hash = "sha256:fc8c9510cde0146432bbdb433322861ee8c3efbf8589865c8bf8d21cb30c4d14", size = 255537 }, - { url = "https://files.pythonhosted.org/packages/08/88/16dd53af4a84e719e27a5ad7db040231415d8caeb48f019bacafbb4d0002/psutil-6.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:34859b8d8f423b86e4385ff3665d3f4d94be3cdf48221fbe476e883514fdb71c", size = 260973 }, { url = "https://files.pythonhosted.org/packages/8b/20/2ff69ad9c35c3df1858ac4e094f20bd2374d33c8643cf41da8fd7cdcb78b/psutil-6.0.0-cp37-abi3-win32.whl", hash = "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d", size = 253560 }, { url = "https://files.pythonhosted.org/packages/73/44/561092313ae925f3acfaace6f9ddc4f6a9c748704317bad9c8c8f8a36a79/psutil-6.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3", size = 257399 }, { url = "https://files.pythonhosted.org/packages/7c/06/63872a64c312a24fb9b4af123ee7007a306617da63ff13bcc1432386ead7/psutil-6.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0", size = 251988 }, @@ -2763,13 +1812,6 @@ dependencies = [ { name = "numpy" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/84/8a80b9ed7f595073ee920c2eafaecaeda4b8adffee8dcb88275fce4609d8/pyarrow-16.1.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:17e23b9a65a70cc733d8b738baa6ad3722298fa0c81d88f63ff94bf25eaa77b9", size = 28348792 }, - { url = "https://files.pythonhosted.org/packages/dc/5c/4d5c43361ee36b8bca29a3a7afaa9d651aa8d5dc05d87ab507e6b2e4e2f8/pyarrow-16.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4740cc41e2ba5d641071d0ab5e9ef9b5e6e8c7611351a5cb7c1d175eaf43674a", size = 26012856 }, - { url = "https://files.pythonhosted.org/packages/8d/4b/82f67b58a4e0ac4ebaa0e04d7a17b59ed4fbd63094f62893160f606350a0/pyarrow-16.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98100e0268d04e0eec47b73f20b39c45b4006f3c4233719c3848aa27a03c1aef", size = 38663112 }, - { url = "https://files.pythonhosted.org/packages/91/83/57572c088ec185582f04b607d545a4a6ef7599c0a3c1e60d397743b0d609/pyarrow-16.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68f409e7b283c085f2da014f9ef81e885d90dcd733bd648cfba3ef265961848", size = 40949054 }, - { url = "https://files.pythonhosted.org/packages/a4/53/3446907cced548d8beaf1be9dfa9d52b7ec38fa44f25d292d7999e6bf509/pyarrow-16.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:a8914cd176f448e09746037b0c6b3a9d7688cef451ec5735094055116857580c", size = 38060550 }, - { url = "https://files.pythonhosted.org/packages/b0/54/eb7fcfc0e1ec6a8404cadd11ac957b3ee4fd0774225cafe3ffe6287861cb/pyarrow-16.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:48be160782c0556156d91adbdd5a4a7e719f8d407cb46ae3bb4eaee09b3111bd", size = 40806957 }, - { url = "https://files.pythonhosted.org/packages/48/16/23218e1e965123e70defb1c9603305ef4616e9f1bfbcd735280f36ec28d3/pyarrow-16.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:9cf389d444b0f41d9fe1444b70650fea31e9d52cfcb5f818b7888b91b586efff", size = 25883914 }, { url = "https://files.pythonhosted.org/packages/28/17/a12aaddb818b7b73d17f3304afc22bce32ccb26723b507cc9c267aa809f3/pyarrow-16.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:d0ebea336b535b37eee9eee31761813086d33ed06de9ab6fc6aaa0bace7b250c", size = 28380406 }, { url = "https://files.pythonhosted.org/packages/f3/94/4e2a579bbac1adb19e63b054b300f6f7fa04f32f212ce86c18727bdda698/pyarrow-16.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e73cfc4a99e796727919c5541c65bb88b973377501e39b9842ea71401ca6c1c", size = 26040531 }, { url = "https://files.pythonhosted.org/packages/7e/34/d5b6eb5066553533dd6eb9782d50f353f8c6451ee2e49e0ea54d0e67bc34/pyarrow-16.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf9251264247ecfe93e5f5a0cd43b8ae834f1e61d1abca22da55b20c788417f6", size = 38666685 }, @@ -2784,20 +1826,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f7/8f/a51a290a855172514b8496c8a74f0e0b98e5e0582d44ae7547cf68dd033b/pyarrow-16.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8785bb10d5d6fd5e15d718ee1d1f914fe768bf8b4d1e5e9bf253de8a26cb1628", size = 38060675 }, { url = "https://files.pythonhosted.org/packages/25/7b/8da91f8de0b40b760dd748031973b6ac2aa3d4f85c67f45b7e58577ca22e/pyarrow-16.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e1369af39587b794873b8a307cc6623a3b1194e69399af0efd05bb202195a5a7", size = 40826735 }, { url = "https://files.pythonhosted.org/packages/fa/2b/a0053f1304586f2976cb2c37ddb0e52cf4114220e805ebba272a1e231ccc/pyarrow-16.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:febde33305f1498f6df85e8020bca496d0e9ebf2093bab9e0f65e2b4ae2b3444", size = 25838156 }, - { url = "https://files.pythonhosted.org/packages/63/62/f3346d26d0c1706e19e05155c3159689095519fe67065f52b325f0a26215/pyarrow-16.1.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b5f5705ab977947a43ac83b52ade3b881eb6e95fcc02d76f501d549a210ba77f", size = 28349635 }, - { url = "https://files.pythonhosted.org/packages/eb/f3/5413ac69a1c3443bc397e1adab09db69b8ddd2468e1505241aa3d10baf47/pyarrow-16.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0d27bf89dfc2576f6206e9cd6cf7a107c9c06dc13d53bbc25b0bd4556f19cf5f", size = 26017282 }, - { url = "https://files.pythonhosted.org/packages/d4/bb/3236773fb52dd263b22adf2e6e4637cdb965778b0c06315737468d614b80/pyarrow-16.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d07de3ee730647a600037bc1d7b7994067ed64d0eba797ac74b2bc77384f4c2", size = 38763463 }, - { url = "https://files.pythonhosted.org/packages/6e/e8/ae66b4aa457143329e5677149afe552e3e0d1062582ef688b9cce444e7c7/pyarrow-16.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbef391b63f708e103df99fbaa3acf9f671d77a183a07546ba2f2c297b361e83", size = 41047771 }, - { url = "https://files.pythonhosted.org/packages/28/5e/89746311740c0bfcfc8fe4e6cb51e5d78d3145b3d86eeba17e750adc2782/pyarrow-16.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:19741c4dbbbc986d38856ee7ddfdd6a00fc3b0fc2d928795b95410d38bb97d15", size = 38134848 }, - { url = "https://files.pythonhosted.org/packages/95/96/3fc14bb56d118a1ac2284c3066281339fd86ab83d28f493e5c8f983f7614/pyarrow-16.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f2c5fb249caa17b94e2b9278b36a05ce03d3180e6da0c4c3b3ce5b2788f30eed", size = 40897618 }, - { url = "https://files.pythonhosted.org/packages/1e/e1/068a97b80968f50ad969c11be1a12e0979b282d57afe0a13899399ccfefd/pyarrow-16.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:e6b6d3cd35fbb93b70ade1336022cc1147b95ec6af7d36906ca7fe432eb09710", size = 25906779 }, - { url = "https://files.pythonhosted.org/packages/6b/5b/7b1c11872ddd2fd0ca472d0beaf2a3aa2e6cc168a933985e79498d79b71d/pyarrow-16.1.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:18da9b76a36a954665ccca8aa6bd9f46c1145f79c0bb8f4f244f5f8e799bca55", size = 28362255 }, - { url = "https://files.pythonhosted.org/packages/e3/12/635c509b84c50cd92fa35a2dee8bc9c1f6fc042da86276ca726f24c5d87f/pyarrow-16.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:99f7549779b6e434467d2aa43ab2b7224dd9e41bdde486020bae198978c9e05e", size = 26023963 }, - { url = "https://files.pythonhosted.org/packages/10/0f/ccfee8b6260888fe5e08d962af28a4b9115d5d245d4e61f8938a8b69f981/pyarrow-16.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f07fdffe4fd5b15f5ec15c8b64584868d063bc22b86b46c9695624ca3505b7b4", size = 38673686 }, - { url = "https://files.pythonhosted.org/packages/df/3e/9cfa78ad9744c77e4f3c183d919de3649505e50663d3715151a094c27769/pyarrow-16.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddfe389a08ea374972bd4065d5f25d14e36b43ebc22fc75f7b951f24378bf0b5", size = 40961694 }, - { url = "https://files.pythonhosted.org/packages/87/60/cc0645eb4ef73f88847e40a7f9d238bae6b7409d6c1f6a5d200d8ade1f09/pyarrow-16.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3b20bd67c94b3a2ea0a749d2a5712fc845a69cb5d52e78e6449bbd295611f3aa", size = 38073487 }, - { url = "https://files.pythonhosted.org/packages/4a/0e/ca72b2e27d8d7a23e9866c819436ebeb518f934ac2b8b871fab373f9c859/pyarrow-16.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:ba8ac20693c0bb0bf4b238751d4409e62852004a8cf031c73b0e0962b03e45e3", size = 40818747 }, - { url = "https://files.pythonhosted.org/packages/5e/1b/d59f6ee8f55a233b85299d0b93fb24ac487571849f8ca93807dcd182d614/pyarrow-16.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:31a1851751433d89a986616015841977e0a188662fcffd1a5677453f1df2de0a", size = 25893294 }, ] [[distribution]] @@ -2806,16 +1834,10 @@ version = "0.2.14" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/26/1d/8878c7752febb0f6716a7e1a52cb92ac98871c5aa522cba181878091607c/PyAudio-0.2.14.tar.gz", hash = "sha256:78dfff3879b4994d1f4fc6485646a57755c6ee3c19647a491f790a0895bd2f87", size = 47066 } wheels = [ - { url = "https://files.pythonhosted.org/packages/90/90/1553487277e6aa25c0b7c2c38709cdd2b49e11c66c0b25c6e8b7b6638c72/PyAudio-0.2.14-cp310-cp310-win32.whl", hash = "sha256:126065b5e82a1c03ba16e7c0404d8f54e17368836e7d2d92427358ad44fefe61", size = 144624 }, - { url = "https://files.pythonhosted.org/packages/27/bc/719d140ee63cf4b0725016531d36743a797ffdbab85e8536922902c9349a/PyAudio-0.2.14-cp310-cp310-win_amd64.whl", hash = "sha256:2a166fc88d435a2779810dd2678354adc33499e9d4d7f937f28b20cc55893e83", size = 164069 }, { url = "https://files.pythonhosted.org/packages/7b/f0/b0eab89eafa70a86b7b566a4df2f94c7880a2d483aa8de1c77d335335b5b/PyAudio-0.2.14-cp311-cp311-win32.whl", hash = "sha256:506b32a595f8693811682ab4b127602d404df7dfc453b499c91a80d0f7bad289", size = 144624 }, { url = "https://files.pythonhosted.org/packages/82/d8/f043c854aad450a76e476b0cf9cda1956419e1dacf1062eb9df3c0055abe/PyAudio-0.2.14-cp311-cp311-win_amd64.whl", hash = "sha256:bbeb01d36a2f472ae5ee5e1451cacc42112986abe622f735bb870a5db77cf903", size = 164070 }, { url = "https://files.pythonhosted.org/packages/8d/45/8d2b76e8f6db783f9326c1305f3f816d4a12c8eda5edc6a2e1d03c097c3b/PyAudio-0.2.14-cp312-cp312-win32.whl", hash = "sha256:5fce4bcdd2e0e8c063d835dbe2860dac46437506af509353c7f8114d4bacbd5b", size = 144750 }, { url = "https://files.pythonhosted.org/packages/b0/6a/d25812e5f79f06285767ec607b39149d02aa3b31d50c2269768f48768930/PyAudio-0.2.14-cp312-cp312-win_amd64.whl", hash = "sha256:12f2f1ba04e06ff95d80700a78967897a489c05e093e3bffa05a84ed9c0a7fa3", size = 164126 }, - { url = "https://files.pythonhosted.org/packages/31/33/91d2294eec57699ac4d511f65480b097b89af38635cf1af90321e366d828/PyAudio-0.2.14-cp38-cp38-win32.whl", hash = "sha256:858caf35b05c26d8fc62f1efa2e8f53d5fa1a01164842bd622f70ddc41f55000", size = 144619 }, - { url = "https://files.pythonhosted.org/packages/72/d7/06eb308310281200e113910a675ea63483eeafcb1d851db8ef98393a3e33/PyAudio-0.2.14-cp38-cp38-win_amd64.whl", hash = "sha256:2dac0d6d675fe7e181ba88f2de88d321059b69abd52e3f4934a8878e03a7a074", size = 164066 }, - { url = "https://files.pythonhosted.org/packages/05/4d/8e96cb4e350870b4c8b73f18903804dd9c2d99792beeddf7e7f7c74ed1bd/PyAudio-0.2.14-cp39-cp39-win32.whl", hash = "sha256:f745109634a7c19fa4d6b8b7d6967c3123d988c9ade0cd35d4295ee1acdb53e9", size = 144621 }, - { url = "https://files.pythonhosted.org/packages/ac/9e/cb59be3b49a6c1ee6350f27ca1abae2be2c7e643eac63cf10c399c4d6f71/PyAudio-0.2.14-cp39-cp39-win_amd64.whl", hash = "sha256:009f357ee5aa6bc8eb19d69921cd30e98c42cddd34210615d592a71d09c4bd57", size = 164066 }, ] [[distribution]] @@ -2840,20 +1862,6 @@ version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/9b/fb/54b46b52c1fa2acd9afd81bd05810c61bb1b05c6084c9625b64bc6d41843/pycapnp-2.0.0.tar.gz", hash = "sha256:503ab9b7b16773590ee226f2460408972c6b1c2cb2d819037115b919bef682be", size = 574848 } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/da/562114ce916f139a16018c43a9e0a4ff707fde6a91983ee815141b0f2333/pycapnp-2.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12fc023da9acd062884c9b394113457908b3c5e26aeb85f668b59c0e84b7b150", size = 1679335 }, - { url = "https://files.pythonhosted.org/packages/c3/f7/fd1db2306dc45bf49cc5ceb0c162a247e123cf2b9ae3eaed45f14e7fdc17/pycapnp-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c8f5e4e68a1b59ae73cd77550b95f8719aea624aa424cd77aa193c6d45ea97ab", size = 1523005 }, - { url = "https://files.pythonhosted.org/packages/37/b4/22aa3c822826f8fb4955053033a6ab398cae1593d35de7b8e8814690a748/pycapnp-2.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50ff7f45d77dc2ef0c44a0aef41f37433a0c395b6a1db99b7e6f45e0e9237bd4", size = 4699521 }, - { url = "https://files.pythonhosted.org/packages/39/3d/b0da69a3021f64111edbed6ff91077658b294f50a6dde5a6ad572a3a2e3e/pycapnp-2.0.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc68ef3d80d9e7e9b96ba2077d8e2effd42f936bda1024f1aedc05022c9401bb", size = 4818053 }, - { url = "https://files.pythonhosted.org/packages/67/0d/e668033c6d2d63a661822645ad5112308d6e81d36f0881bfb55e58685518/pycapnp-2.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74a75e5c190e4d722aa0d2702bd04fedc2cb8e0a893031813e7a50cc067a054a", size = 4973514 }, - { url = "https://files.pythonhosted.org/packages/b5/1d/60b8ac6ea0aab7b6649993f46daafc08f559e9377fa19933e27ee676d311/pycapnp-2.0.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db1bc53cbe5222f4fd0748ba6b53da9ec58e8f7b2219dc9cd50d15266a3fa85c", size = 4839079 }, - { url = "https://files.pythonhosted.org/packages/1e/b4/7185210aab0ca0f458db5807c3d7f3bcd6e3642bcc306d5f93027900eca6/pycapnp-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a0509ef856239634be21375cbad73dc7cf7fdfb32c03c312ad41e994f0674f7", size = 4859945 }, - { url = "https://files.pythonhosted.org/packages/88/19/fc82fe79538d36a9cda3c2c172415b05f770e61de2a3315505d18fa3c956/pycapnp-2.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:48372a19b59e8d533768c12988a92af4ea6c2daa1a8ba1c42202cd0dd24a1d24", size = 5258129 }, - { url = "https://files.pythonhosted.org/packages/c0/f7/b6a784268f306e2e67ebff0f7b0b0ee1fd0eefde87a53644ffb6a8bcc71d/pycapnp-2.0.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:46c16a98cec9ae6dce5ebf488bb0c8425484d7710eed1ee008a26b60470ee755", size = 5452125 }, - { url = "https://files.pythonhosted.org/packages/79/29/af2ea1f89d7493e6f3dac74d2924fd40e6aaaaefd24fc609e1fa65621396/pycapnp-2.0.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:be91cdb7895c4e2f1e1cd6b701ed66050c285d2c228f476a775bfd76bbd697f1", size = 5551321 }, - { url = "https://files.pythonhosted.org/packages/8d/ce/1034d8e30ac5b10e945517ed795470e7f3b1cf67d691eb4a31d6b760ec34/pycapnp-2.0.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:21db83e5f0c3a944b567cd20e4df47dba023e936a45d7057f2a615b8c19356f8", size = 5438794 }, - { url = "https://files.pythonhosted.org/packages/6d/61/dc476eb0a2889ec0babc55af7392f8bc1534656a98d241ee54145704215a/pycapnp-2.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:825a8a86e034d66d8df8d82b7bf9fdd3f344bd84ff43a838ec08f08fe7461be0", size = 5425971 }, - { url = "https://files.pythonhosted.org/packages/da/2b/fdcfd06e7a804d2f5e80db3f03d8cb879d48a45df7ae74337bcc49c6728c/pycapnp-2.0.0-cp310-cp310-win32.whl", hash = "sha256:13ff9dca5741079d7bbe4e2512634b8ce859b709a1b126481eed404bda0b3d4a", size = 1044616 }, - { url = "https://files.pythonhosted.org/packages/e9/b1/30a3ff0e5930a5fdd323fe66d398cc4b21bfaa79355ba3941950d1984295/pycapnp-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:279d9f7c34527d15a62dde0dfc82cb918ed0a900dfa9713960d64bed3f9236a4", size = 1145453 }, { url = "https://files.pythonhosted.org/packages/cb/82/cf311b1a9800b605759a38a0c337a55a639b685427364294e98a0f9b7306/pycapnp-2.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:829c7eb4e5f23dbcac25466110faf72a691035cf87c5d46e5053da15790e428d", size = 1673673 }, { url = "https://files.pythonhosted.org/packages/ae/55/4c03ca95c568776a1f637db9ffdcf302fb63f46e4d2a4f13edd8cb1a5f90/pycapnp-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dab60fbe3e4eaf99ec97918a0a776216c6c149b6d49261383d91c2201adb475d", size = 1513351 }, { url = "https://files.pythonhosted.org/packages/55/98/e4b2dea076f8a2575abc45cd879a91bc9aa975c69ae2ac1cab61d83c5087/pycapnp-2.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c48a0582078bb74d7326d28571db0b8e6919563365537a5a13e8f5360c12bfc", size = 4910666 }, @@ -2882,34 +1890,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e7/b0/63f2b0327853ae08158de61b4dfc7fa43ae5a5c00f1d28f769e7c30cdf55/pycapnp-2.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8a20b7dc55ef83a1fa446bf12680bce25caeb8f81788b623b072c3ec820db50d", size = 5405076 }, { url = "https://files.pythonhosted.org/packages/7d/24/e025dd95f1abf34e373fbab8841ac8e5fa62afe3af4a4b0c61bd01354400/pycapnp-2.0.0-cp312-cp312-win32.whl", hash = "sha256:145eea66233fb5ac9152cd1c06b999ddb691815126f87f5cc37b9cda5d569f8a", size = 1030361 }, { url = "https://files.pythonhosted.org/packages/3f/70/a71108ee9d4db9a027b665a2c383202407207174f1956195d5be45aca705/pycapnp-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:b8b03000769b29b36a8810f458b931f0f706f42027ee6676821eff28092d7734", size = 1135121 }, - { url = "https://files.pythonhosted.org/packages/cc/33/f624af4c87e1b59e28933ec91d191054b87725ece6f02c9e6d4f2557a8fe/pycapnp-2.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6b1d547af10ecf4a3da25143c71ce64a3b0817bf229c560c9f9729d355c3b48d", size = 1696883 }, - { url = "https://files.pythonhosted.org/packages/60/21/12d2bf6f88a13c7f12dd393d95364d636f831c405edec47f45e8c0a21428/pycapnp-2.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ecbbdbc2251d5e9d16148601e224ffaf9612d07751af72496472a3e285a1baed", size = 1534078 }, - { url = "https://files.pythonhosted.org/packages/ed/12/b21f1506c258a06e1b4f82bf226bb6975ad25bc2c0aed7b84a9ff3af94e2/pycapnp-2.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8158ebb967f7b103d2d5514d6a8cc643b1744cc8e14e14a5c19697507719de7b", size = 4741636 }, - { url = "https://files.pythonhosted.org/packages/35/77/9ab2a639efe2ee632f46525e3d4c2e588fffab8d100f8fecacf262114f9c/pycapnp-2.0.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:999068b371fd4f21dddfff97640609f325cd8498c2a9d6a6c253164466628ba0", size = 4849287 }, - { url = "https://files.pythonhosted.org/packages/e0/1b/3b6947a5a83af99597d0f4a8e494ec0e0ea3757285e8377a5b84dfb5b905/pycapnp-2.0.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb46a9191a64ce532f82800e6885abe61e63ae4f612ed1d98c7a493dd6ee6d2b", size = 5018337 }, - { url = "https://files.pythonhosted.org/packages/86/1a/5bd982916edd27e2850ea208c84a0f2915e68c9c3531be553bf688045ec4/pycapnp-2.0.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fe49a1be55fb01f794434bab42643de7b4e37e774c3d63635f4a9ca9064437e", size = 4882453 }, - { url = "https://files.pythonhosted.org/packages/ca/9e/8864f0818d465a9246620a0a5c1bb1b9a1e2cfe0371b67b1953f5f217059/pycapnp-2.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ab6c94687908003fced23ce8c415d85e521e923b0bcbcc5323bac66d14911d5", size = 4896970 }, - { url = "https://files.pythonhosted.org/packages/53/95/2edf785b707e6f665b7f967ef0f1c17824cbd8c2ada5402cb5d6dd66461f/pycapnp-2.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a5b814578f4f29c787deef30226c54f11188caef9b375776e8b1d73649e4119", size = 5451586 }, - { url = "https://files.pythonhosted.org/packages/ab/57/3ace7e0f11105579d57cd13690dfc753b98d645b771f3f2290379550bbe0/pycapnp-2.0.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f169bdc0a683f1cb716c1ab83c5028e75d7bf34674c00b302ca1ebf66e0d27ca", size = 5615382 }, - { url = "https://files.pythonhosted.org/packages/fd/b5/1e06d00be733167f70cbd491a8f7f0f4e256dbe258339ed5101276ede6a4/pycapnp-2.0.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:5f348f8487df6a67891684e3c9c6476930fbb09258fe33f96c9bbdc4c51e6d4e", size = 5746617 }, - { url = "https://files.pythonhosted.org/packages/73/4e/feb54b18cdfc8a2b71f81d877f1cd1f27a8c803e48e92081ddd0407f2d37/pycapnp-2.0.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:57940b9898d8b2565671bdf8d8aa67e6b91c3ba879594b58287134ee20b242c7", size = 5635680 }, - { url = "https://files.pythonhosted.org/packages/ef/b9/39c682b0e79d41cfafee41b119dc0b73120117fc0b72686850f75b3889e9/pycapnp-2.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:68a8d2ae0c078df11a5dbf2d2b5b5d48c3893584fe9bb6fa9b88dd6eadf65dda", size = 5612817 }, - { url = "https://files.pythonhosted.org/packages/0e/a8/a5f1cbf8a1cd2c237eb5394a0795ba14bf9ca30cd760c0f134aa71458bbf/pycapnp-2.0.0-cp38-cp38-win32.whl", hash = "sha256:81bbaf65c70dfbe8bc67ea715778bd764f4b1126fd905c0778ab6fd4e358f8f4", size = 1054625 }, - { url = "https://files.pythonhosted.org/packages/1d/10/adce5c74be47fd6464b070e3fbc730d0878b297a418ca02e0546c543377d/pycapnp-2.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:34acb733c3a4a2a13607f0d905f776d4567d0c9697e5a9865035d38d3b4fb53b", size = 1152877 }, - { url = "https://files.pythonhosted.org/packages/4c/e6/c1629e98b05a442e042253753fa1cda1e0dc00a362de35d2d178624f7be7/pycapnp-2.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:87931c9322679c733bd522a0d73704d804d6531a8a5258fd8ec65930bf89f2dd", size = 1691193 }, - { url = "https://files.pythonhosted.org/packages/05/a5/6a05da82d34c9c61fb37ee68a372660e5ebab509e353826eaeee9f60729c/pycapnp-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7d08748e55f0f49c86f0a1e2c0f96c4e6880c1c8fd5df98c12c3eae557aa441", size = 1530310 }, - { url = "https://files.pythonhosted.org/packages/ba/be/a18d35add098fb1d6ac14377871e427f55a9864e24bfddf1ef954a4f3e06/pycapnp-2.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ffd25a63c92f0ef85bccabc7c2c13fe6da7eadf5525025d49206d967afb670d", size = 4729220 }, - { url = "https://files.pythonhosted.org/packages/0c/50/e84a64316cea31342c56ee929c768c94483b59b6d953801fa18c54b60121/pycapnp-2.0.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c8b9b9ea78df282f5ce63ccd435b83b83aabb931807066e84d967444ea005571", size = 4830034 }, - { url = "https://files.pythonhosted.org/packages/f0/5e/08b144d4dcb1a0391d50ef977686f8bddf24b72f055363f6450fee1c5998/pycapnp-2.0.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:829b071216ae51c2ea55fd41476adaf3044a303038399276bdba6144b58157c0", size = 5003996 }, - { url = "https://files.pythonhosted.org/packages/48/e1/ab0671bafa26f4c18c8867dc290db28e8f97d890d427a824683c56848d31/pycapnp-2.0.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16b78b58969924dd499c7c24627cf392368a3354fcc900667fcabda2621d8250", size = 4867638 }, - { url = "https://files.pythonhosted.org/packages/c2/7b/9514799a66b75a6450aa7c90c1a174425da08b3367fbe49e4a18f464d6d1/pycapnp-2.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a365a7dff8cb05145616aecc04ea73ed493cd630c10d7ef67d833347ba264b6", size = 4885425 }, - { url = "https://files.pythonhosted.org/packages/9f/c6/262ad17e252fd79bea2c5842f25c336303e080193811ae511427837cb089/pycapnp-2.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:82ebe35487dcb8061e2f80403d29c20686d1d539562162f1658d36ef43e38cfa", size = 5284082 }, - { url = "https://files.pythonhosted.org/packages/4f/ae/d8b3b842ac5eb61381d8633758604e20f852d997143d7057e0c72eb0d45e/pycapnp-2.0.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f496c59face3195f32a50df141a7a042cd3504bd4da123c5dced096eae76699d", size = 5460673 }, - { url = "https://files.pythonhosted.org/packages/05/20/c610db47bb419a06f744d0c9768efef7dd9d8af0abd0eb0e00230e2d8e1e/pycapnp-2.0.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f2ed0033b56b1836a8b99de11b939d93aa93d01f5d52650da65447f4f3c03e21", size = 5575099 }, - { url = "https://files.pythonhosted.org/packages/4e/56/34a27f16b3c3da1aba7f7967acaaabcfeca3a918392ebc9abc35f250aaee/pycapnp-2.0.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d66097f70b0a0bff5d9431b117d359a0abe46c73ac0eb3b64ad252cf7e99d780", size = 5472640 }, - { url = "https://files.pythonhosted.org/packages/ab/04/2ef5a290625d3de72fb10ed576a4840e476750a94cf20287b8bd4c9da930/pycapnp-2.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:245942fe441d5e7a6511110ddea44ea91f0544385ef8afbef7155bec4aaa266f", size = 5449555 }, - { url = "https://files.pythonhosted.org/packages/99/e9/11cfcebd14a52dbd61e7c4daf03375125c5a60eb6dc0c47ef2cdbb1c65c8/pycapnp-2.0.0-cp39-cp39-win32.whl", hash = "sha256:1bcbb55fc12ff41d5e456991e9d4d368ca26ba11c65c41bd384f4edf1307b6f7", size = 1053980 }, - { url = "https://files.pythonhosted.org/packages/f3/f2/d6ec520029e007d865c94955004c3a830b158327792eca6480f81d084870/pycapnp-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:d4bee40372c02bcce647084faa6a831d9884a80033f77c7aacbaac697c4bbe46", size = 1152622 }, ] [[distribution]] @@ -2927,17 +1907,6 @@ version = "3.20.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b9/ed/19223a0a0186b8a91ebbdd2852865839237a21c74f1fbc4b8d5b62965239/pycryptodome-3.20.0.tar.gz", hash = "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7", size = 4794232 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ac/1e/d0fbf9c82e49c0e0c5ceebf4e9c3acdbdad21fe47b2a7cc5db2284140401/pycryptodome-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f0e6d631bae3f231d3634f91ae4da7a960f7ff87f2865b2d2b831af1dfb04e9a", size = 1589544 }, - { url = "https://files.pythonhosted.org/packages/ef/50/090be8ca0ea560037bf515c5b2f27547777e2175244f168555ecccc23c54/pycryptodome-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:baee115a9ba6c5d2709a1e88ffe62b73ecc044852a925dcb67713a288c4ec70f", size = 2331812 }, - { url = "https://files.pythonhosted.org/packages/dd/20/b4b6bd07bfb6f6826b147131dcea9fea99559077842ad7e304a7464353c5/pycryptodome-3.20.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:417a276aaa9cb3be91f9014e9d18d10e840a7a9b9a9be64a42f553c5b50b4d1d", size = 2309021 }, - { url = "https://files.pythonhosted.org/packages/68/31/d444cbb52f348ea89f90e2aff4804e03b42671c784719ee7c75d51db2913/pycryptodome-3.20.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a1250b7ea809f752b68e3e6f3fd946b5939a52eaeea18c73bdab53e9ba3c2dd", size = 2059709 }, - { url = "https://files.pythonhosted.org/packages/fb/0b/eb6bfe34a9b7a265e103084a3cfc0dbb2a102d04a6239ce91434b03641c0/pycryptodome-3.20.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:d5954acfe9e00bc83ed9f5cb082ed22c592fbbef86dc48b907238be64ead5c33", size = 2052744 }, - { url = "https://files.pythonhosted.org/packages/9a/6a/ccfc4b1c7eee616dd9b3a663a26ec1ba2a13319dd51876f64867b4ab3d27/pycryptodome-3.20.0-cp27-cp27m-win32.whl", hash = "sha256:06d6de87c19f967f03b4cf9b34e538ef46e99a337e9a61a77dbe44b2cbcf0690", size = 1707428 }, - { url = "https://files.pythonhosted.org/packages/42/4c/706ef0c97ef61598d6b3745cfdae57c09b10b61fd60700d69443173bd430/pycryptodome-3.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ec0bb1188c1d13426039af8ffcb4dbe3aad1d7680c35a62d8eaf2a529b5d3d4f", size = 1719433 }, - { url = "https://files.pythonhosted.org/packages/24/0a/9e0791833984305a8ee7cb8b1feaabffdbe1607f79f6890b38259befacc4/pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5601c934c498cd267640b57569e73793cb9a83506f7c73a8ec57a516f5b0b091", size = 2331787 }, - { url = "https://files.pythonhosted.org/packages/80/fc/bc18a2951ab3104caa67cae290d42d9cd230884f0d27bf0891f821636f32/pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d29daa681517f4bc318cd8a23af87e1f2a7bad2fe361e8aa29c77d652a065de4", size = 2309064 }, - { url = "https://files.pythonhosted.org/packages/f0/65/6cb997318100aa9f7dfc2753a611c4728a84825990645a0391859deeaa6f/pycryptodome-3.20.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3427d9e5310af6680678f4cce149f54e0bb4af60101c7f2c16fdf878b39ccccc", size = 2059714 }, - { url = "https://files.pythonhosted.org/packages/75/00/744661e96afcb5016c10ee821fe6ff6962f5feb020d7286d082c004a36dd/pycryptodome-3.20.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:3cd3ef3aee1079ae44afaeee13393cf68b1058f70576b11439483e34f93cf818", size = 2052797 }, { url = "https://files.pythonhosted.org/packages/ff/96/b0d494defb3346378086848a8ece5ddfd138a66c4a05e038fca873b2518c/pycryptodome-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac1c7c0624a862f2e53438a15c9259d1655325fc2ec4392e66dc46cdae24d044", size = 2427142 }, { url = "https://files.pythonhosted.org/packages/24/80/56a04e2ae622d7f38c1c01aef46a26c6b73a2ad15c9705a8e008b5befb03/pycryptodome-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76658f0d942051d12a9bd08ca1b6b34fd762a8ee4240984f7c06ddfb55eaf15a", size = 1590045 }, { url = "https://files.pythonhosted.org/packages/ea/94/82ebfa5c83d980907ceebf79b00909a569d258bdfd9b0264d621fa752cfd/pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f35d6cee81fa145333137009d9c8ba90951d7d77b67c79cbe5f03c7eb74d8fe2", size = 2061748 }, @@ -2950,14 +1919,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1f/90/d131c0eb643290230dfa4108b7c2d135122d88b714ad241d77beb4782a76/pycryptodome-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:9b3ae153c89a480a0ec402e23db8d8d84a3833b65fa4b15b81b83be9d637aab9", size = 1759588 }, { url = "https://files.pythonhosted.org/packages/17/87/c7153fcd400df0f4a67d7d92cdb6b5e43f309c22434374b8a61849dfb280/pycryptodome-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4401564ebf37dfde45d096974c7a159b52eeabd9969135f0426907db367a652a", size = 1639310 }, { url = "https://files.pythonhosted.org/packages/68/9a/88d984405b087e8c8dd9a9d4c81a6fa675454e5fcf2ae01d9553b3128637/pycryptodome-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:ec1f93feb3bb93380ab0ebf8b859e8e5678c0f010d2d78367cf6bc30bfeb148e", size = 1708332 }, - { url = "https://files.pythonhosted.org/packages/c7/10/88fb67d2fa545ce2ac61cfda70947bcbb1769f1956315c4b919d79774897/pycryptodome-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:acae12b9ede49f38eb0ef76fdec2df2e94aad85ae46ec85be3648a57f0a7db04", size = 1565619 }, - { url = "https://files.pythonhosted.org/packages/a2/40/63dff38fa4f7888f812263494d4a745eeed180ff09dd7b8350a81eb09d21/pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f47888542a0633baff535a04726948e876bf1ed880fddb7c10a736fa99146ab3", size = 1606403 }, - { url = "https://files.pythonhosted.org/packages/8b/61/522235ca81d9dcfcf8b4cbc253b3a8a1f2231603d486369a8a02eb998f31/pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e0e4a987d38cfc2e71b4a1b591bae4891eeabe5fa0f56154f576e26287bfdea", size = 1637284 }, - { url = "https://files.pythonhosted.org/packages/e9/a7/5aa0596f7fc710fd55b4e6bbb025fedacfec929465a618f20e61ebf7df76/pycryptodome-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c18b381553638414b38705f07d1ef0a7cf301bc78a5f9bc17a957eb19446834b", size = 1741193 }, - { url = "https://files.pythonhosted.org/packages/53/a3/1345f914963d7d668a5423dc563deafae02479bd1c69b39180724475584f/pycryptodome-3.20.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a60fedd2b37b4cb11ccb5d0399efe26db9e0dd149016c1cc6c8161974ceac2d6", size = 1565490 }, - { url = "https://files.pythonhosted.org/packages/6a/3d/ba3905a0ae6dd4e8686dbde85c71ce38e27f5ad3587424891238ad520aaf/pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:405002eafad114a2f9a930f5db65feef7b53c4784495dd8758069b89baf68eab", size = 1606310 }, - { url = "https://files.pythonhosted.org/packages/5d/c3/5530f270c4ec87953fbed203e4f1f4a2fa002bc43efdc1b3cf9ab442e741/pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab6ab0cb755154ad14e507d1df72de9897e99fd2d4922851a276ccc14f4f1a5", size = 1637201 }, - { url = "https://files.pythonhosted.org/packages/09/12/34eb6587adcee5d676533e4c217a6385a2f4d90086198a3b1ade5dcdf684/pycryptodome-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acf6e43fa75aca2d33e93409f2dafe386fe051818ee79ee8a3e21de9caa2ac9e", size = 1741088 }, ] [[distribution]] @@ -2978,13 +1939,6 @@ version = "2.6.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/72/49/bd2fcbadb6a55bb24284bad4f530189401c99ffc234d51ba54756a776eb2/pygame-2.6.0.tar.gz", hash = "sha256:722d33ae676aa8533c1f955eded966411298831346b8d51a77dad22e46ba3e35", size = 15787643 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/1c/e515c10196aed75dbef75b41ff3069897c9405f568169694a3b3f8fc0f4c/pygame-2.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e5707aa9d029752495b3eddc1edff62e0e390a02f699b0f1ce77fe0b8c70ea4f", size = 13108654 }, - { url = "https://files.pythonhosted.org/packages/cc/2f/270b3a9c5f1567d91255af15e9f9685d412461115fd96f393777be04b339/pygame-2.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3ed0547368733b854c0d9981c982a3cdfabfa01b477d095c57bf47f2199da44", size = 12375930 }, - { url = "https://files.pythonhosted.org/packages/7c/c8/be72ca148131b3eef3851245e2f081abadf634feffe33edea3c9f619f1ef/pygame-2.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6050f3e95f1f16602153d616b52619c6a2041cee7040eb529f65689e9633fc3e", size = 13608180 }, - { url = "https://files.pythonhosted.org/packages/4b/aa/2e9c10266df048f186ad86ec543fc788e13f99f1b8ccf6d47658f26d0b79/pygame-2.6.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89be55b7e9e22e0eea08af9d6cfb97aed5da780f0b3a035803437d481a16d972", size = 14300992 }, - { url = "https://files.pythonhosted.org/packages/83/59/5b05cb1bff0c2341e01733b9c341eea8f1cc9cc893c8c429437bd90ee8bd/pygame-2.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d65fb222eea1294cfc8206d9e5754d476a1673eb2783c03c4f70e0455320274", size = 13975567 }, - { url = "https://files.pythonhosted.org/packages/d0/0e/068482e06f9a3a5fce3291e55a0bf75e7087b80e9a464680f3226a2f7359/pygame-2.6.0-cp310-cp310-win32.whl", hash = "sha256:71eebb9803cb350298de188fb7cdd3ebf13299f78d59a71c7e81efc649aae348", size = 10379703 }, - { url = "https://files.pythonhosted.org/packages/07/ef/da1c0efe66d15c11138e4e2b616e2fb3d027c4cbf7cd325c0f961671ea88/pygame-2.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:1551852a2cd5b4139a752888f6cbeeb4a96fc0fe6e6f3f8b9d9784eb8fceab13", size = 10746038 }, { url = "https://files.pythonhosted.org/packages/f7/b2/fd8930d12d5a3b13b30ddfe165c1b7fad749c252d6a0b36e2ae4de935061/pygame-2.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f6e5e6c010b1bf429388acf4d41d7ab2f7ad8fbf241d0db822102d35c9a2eb84", size = 13113344 }, { url = "https://files.pythonhosted.org/packages/6b/37/6c03fadba5af47d7144bbe517488b0f5b0072ad01f093318db1e37a9f34f/pygame-2.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:99902f4a2f6a338057200d99b5120a600c27a9f629ca012a9b0087c045508d08", size = 12378489 }, { url = "https://files.pythonhosted.org/packages/46/38/76ff6e2aea68d1111885055557f67722f5747753e795fdd7089af0e385d1/pygame-2.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a284664978a1989c1e31a0888b2f70cfbcbafdfa3bb310e750b0d3366416225", size = 13612062 }, @@ -2999,41 +1953,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/70/da/5c71f05e2d76e0d28153a2d8a52f324908849bf02d70958e5b403ca3ab73/pygame-2.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:315e7b3c1c573984f549ac5da9778ac4709b3b4e3a4061050d94eab63fa4fe31", size = 13956091 }, { url = "https://files.pythonhosted.org/packages/2a/16/ec73fd2350df6620f3471c1a7df06bcd392d7ad99823cabe5b82d54b7df8/pygame-2.6.0-cp312-cp312-win32.whl", hash = "sha256:e44bde0840cc21a91c9d368846ac538d106cf0668be1a6030f48df139609d1e8", size = 10383625 }, { url = "https://files.pythonhosted.org/packages/c2/a2/7a4e02e5833e7391ca4e4e08bdda0bdab6672d8ce3ddee433d50297135ec/pygame-2.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:1c429824b1f881a7a5ce3b5c2014d3d182aa45a22cea33c8347a3971a5446907", size = 10754182 }, - { url = "https://files.pythonhosted.org/packages/72/84/2f129efd1360d2d70207493a95f25251e932794128d4cb7d5ed64e51ae15/pygame-2.6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b832200bd8b6fc485e087bf3ef7ec1a21437258536413a5386088f5dcd3a9870", size = 13081613 }, - { url = "https://files.pythonhosted.org/packages/9d/14/383722198de8e9ac8d8dd1f4381dc74118526159721a88ef85400f4489fc/pygame-2.6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:098029d01a46ea4e30620dfb7c28a577070b456c8fc96350dde05f85c0bf51b5", size = 13581420 }, - { url = "https://files.pythonhosted.org/packages/8c/32/17f807b6a89516d6a77cbb664429e6a23c50ba12e5e9f3187c53ca872cff/pygame-2.6.0-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a858bbdeac5ec473ec9e726c55fb8fbdc2f4aad7c55110e899883738071c7c9b", size = 14271002 }, - { url = "https://files.pythonhosted.org/packages/87/35/429a8156c01b8b0e47fdcd84ea1581232da80ed8e8f7ef3e5f58c5adb609/pygame-2.6.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f908762941fd99e1f66d1211d26383184f6045c45673443138b214bf48a89aa", size = 13943053 }, - { url = "https://files.pythonhosted.org/packages/77/8e/1e79db7739da1806b4a4f2854f8ba94354b64e9ab7cf009b200eb4b94d5e/pygame-2.6.0-cp36-cp36m-win32.whl", hash = "sha256:4a63daee99d050f47d6ec7fa7dbd1c6597b8f082cdd58b6918d382d2bc31262d", size = 10366077 }, - { url = "https://files.pythonhosted.org/packages/cd/60/97b60267b8d4d5edc4b1528d79b7d867e01f512310ae9830d0bc32d543bb/pygame-2.6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:ace471b3849d68968e5427fc01166ef5afaf552a5c442fc2c28d3b7226786f55", size = 10734080 }, - { url = "https://files.pythonhosted.org/packages/86/c8/fe1041d564e82d2d1029f21fe8ad43ec89d513ec566fa7153453ade1dbfd/pygame-2.6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fea019713d0c89dfd5909225aa933010100035d1cd30e6c936e8b6f00529fb80", size = 13099706 }, - { url = "https://files.pythonhosted.org/packages/49/ed/8753e8a9ac4b9de749834f34639df0d2f1bbe2d8742ddc861d811bdd1a9d/pygame-2.6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:249dbf2d51d9f0266009a380ccf0532e1a57614a1528bb2f89a802b01d61f93e", size = 13605998 }, - { url = "https://files.pythonhosted.org/packages/af/49/73b906a0a4f30ab81e6a2e39fdf6463913e961f9d83a6bd3b37378f56022/pygame-2.6.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb51533ee3204e8160600b0de34eaad70eb913a182c94a7777b6051e8fc52f1", size = 14298166 }, - { url = "https://files.pythonhosted.org/packages/14/56/14f3b70f417f4276a9317e210285b9145d8e4fefa99425c1e63dcc881331/pygame-2.6.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f637636a44712e94e5601ec69160a080214626471983dfb0b5b68aa0c61563d", size = 13967534 }, - { url = "https://files.pythonhosted.org/packages/10/b6/cf7108a1fa28ac9c802d1b917fa68aa0f04022ba5e7bf529a5cc20c26057/pygame-2.6.0-cp37-cp37m-win32.whl", hash = "sha256:e432156b6f346f4cc6cab03ce9657600093390f4c9b10bf458716b25beebfe33", size = 10374448 }, - { url = "https://files.pythonhosted.org/packages/0d/d3/7651aae39e85506181cfa6785161f636c7afc2605c470085984e0bf9f954/pygame-2.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a0194652db7874bdde7dfc69d659ca954544c012e04ae527151325bfb970f423", size = 10741252 }, - { url = "https://files.pythonhosted.org/packages/2e/5c/e00213b67377f36b2da733b4339c386f2d6e154ec5b0069729e12d7bc67f/pygame-2.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eae3ee62cc172e268121d5bd9dc406a67094d33517de3a91de3323d6ae23eb02", size = 12967924 }, - { url = "https://files.pythonhosted.org/packages/70/7a/ae9c60669e969c9becbd7591fb9feac2795ce18b135d7f51f73a17aee227/pygame-2.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f6a58b0a5a8740a3c2cf6fc5366888bd4514561253437f093c12a9ab4fb3ecae", size = 12381221 }, - { url = "https://files.pythonhosted.org/packages/e0/a2/c868302c65a8eb2909b58130342e717f95b3455e76a0dad8305c2d3e7da9/pygame-2.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c71da36997dc7b9b4ee973fa3a5d4a6cfb2149161b5b1c08b712d2f13a63ccfe", size = 13614379 }, - { url = "https://files.pythonhosted.org/packages/0b/d4/2265c2af408b5d7f6257b722a02137b15a62639d79a0581f4438886fa47b/pygame-2.6.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b86771801a7fc10d9a62218f27f1d5c13341c3a27394aa25578443a9cd199830", size = 14305916 }, - { url = "https://files.pythonhosted.org/packages/45/f1/f72f422eaabae6574a5b7877765d1e0bb2d2c4f4b5e6db1e55b9c163df8e/pygame-2.6.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4928f3acf5a9ce5fbab384c21f1245304535ffd5fb167ae92a6b4d3cdb55a3b6", size = 13980050 }, - { url = "https://files.pythonhosted.org/packages/47/0e/c900c1ef2425e8b0a95499db18010d1f7fbad8dc0f9d195f9accd86fc57f/pygame-2.6.0-cp38-cp38-win32.whl", hash = "sha256:4faab2df9926c4d31215986536b112f0d76f711cf02f395805f1ff5df8fd55fc", size = 10383438 }, - { url = "https://files.pythonhosted.org/packages/4a/80/5557d2e8a28c9d7d3cc413bb93909c9bbf0af46d483ae8ffb57f2d329f3a/pygame-2.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:afbb8d97aed93dfb116fe105603dacb68f8dab05b978a40a9e4ab1b6c1f683fd", size = 10749333 }, - { url = "https://files.pythonhosted.org/packages/6d/aa/dac464eba5950cfbdc7fbd8e30ab87f7b66808e7eb83589f98aa8d028549/pygame-2.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d11f3646b53819892f4a731e80b8589a9140343d0d4b86b826802191b241228c", size = 12966432 }, - { url = "https://files.pythonhosted.org/packages/65/e8/6bbaf3a7a09685d075d77ab107eccff2d13c82a99b627dcf7f7f226641c7/pygame-2.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5ef92ed93c354eabff4b85e457d4d6980115004ec7ff52a19fd38b929c3b80fb", size = 12378852 }, - { url = "https://files.pythonhosted.org/packages/aa/8c/dd9225864bc5e5e1492074b363271ccea4d9b34127d89085f54224aba54d/pygame-2.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bc1795f2e36302882546faacd5a0191463c4f4ae2b90e7c334a7733aa4190d2", size = 13612616 }, - { url = "https://files.pythonhosted.org/packages/e5/33/59c19e18a1c9098b12ff2d09266b089ca86768549311d4bf1f714e4d063b/pygame-2.6.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e92294fcc85c4955fe5bc6a0404e4cc870808005dc8f359e881544e3cc214108", size = 14304869 }, - { url = "https://files.pythonhosted.org/packages/56/51/58cdc9605498e09075c87dd527e20496627b299be1da2529527259a455f2/pygame-2.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0cb7bdf3ee0233a3ac02ef777c01dfe315e6d4670f1312c83b91c1ef124359a", size = 13978491 }, - { url = "https://files.pythonhosted.org/packages/c0/44/529c34e7616015271a44502d9a8164d3913014714924dd6eac904e2409e1/pygame-2.6.0-cp39-cp39-win32.whl", hash = "sha256:ac906478ae489bb837bf6d2ae1eb9261d658aa2c34fa5b283027a04149bda81a", size = 10382720 }, - { url = "https://files.pythonhosted.org/packages/69/42/03732fa7106c029ba4d4b8380123a9ef8763a58837b8e0e7fd4daf788100/pygame-2.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:92cf12a9722f6f0bdc5520d8925a8f085cff9c054a2ea462fc409cba3781be27", size = 10749496 }, - { url = "https://files.pythonhosted.org/packages/97/9f/0098f5e1c9f3be5844184a4ef48c737497e5386e0ce135baa81184b8d652/pygame-2.6.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:a6636f452fdaddf604a060849feb84c056930b6a3c036214f607741f16aac942", size = 10324551 }, - { url = "https://files.pythonhosted.org/packages/c0/1a/1718a203b8f973d7a6760ed9553f96f8f0c94df2912eeb5ff644b4a10729/pygame-2.6.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dc242dc15d067d10f25c5b12a1da48ca9436d8e2d72353eaf757e83612fba2f", size = 14169107 }, - { url = "https://files.pythonhosted.org/packages/5d/d5/bfba7dc569bcb95504b9dbeeae1e6451f55e89e0ef9f50afb127831462dc/pygame-2.6.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f82df23598a281c8c342d3c90be213c8fe762a26c15815511f60d0aac6e03a70", size = 13859004 }, - { url = "https://files.pythonhosted.org/packages/a8/7a/637973d284e02b1ba8a8e4265d095444d7deec5ec9df3c68e761abfaa105/pygame-2.6.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2ed2539bb6bd211fc570b1169dc4a64a74ec5cd95741e62a0ab46bd18fe08e0d", size = 12769067 }, - { url = "https://files.pythonhosted.org/packages/73/1a/698d7df959b6fb49edb47d4001d9fa085e2802920f9847139f63e362a672/pygame-2.6.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:904aaf29710c6b03a7e1a65b198f5467ed6525e8e60bdcc5e90ff8584c1d54ea", size = 14164530 }, - { url = "https://files.pythonhosted.org/packages/bc/9a/73cd158e0f66e92e6114e343de191c52a27d9d5528cdda22630ae8bc4119/pygame-2.6.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcd28f96f0fffd28e71a98773843074597e10d7f55a098e2e5bcb2bef1bdcbf5", size = 13854278 }, - { url = "https://files.pythonhosted.org/packages/52/d6/54cdf9951a3a87ba2fb97a5cb2c7974d3dc22eb120ae3697ebfdf6d0e66d/pygame-2.6.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4fad1ab33443ecd4f958dbbb67fc09fcdc7a37e26c34054e3296fb7e26ad641e", size = 12774754 }, - { url = "https://files.pythonhosted.org/packages/87/26/825b8968e742973d5c17456f7cb13447ca1cbd87495fc3a2f12c9ae23694/pygame-2.6.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e909186d4d512add39b662904f0f79b73028fbfc4fbfdaf6f9412aed4e500e9c", size = 14171575 }, - { url = "https://files.pythonhosted.org/packages/83/f3/8e1383c4c3b4131fcaa98522cd27775ee6b1ff873cbd5470b6d10775b453/pygame-2.6.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79abcbf6d12fce51a955a0652ccd50b6d0a355baa27799535eaf21efb43433dd", size = 13860407 }, ] [[distribution]] @@ -3084,21 +2003,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/16/78/9ea0c88490ad4fe9683ddf3bbee702c7a2331e83a333bb3aa52e8d7d909b/pylibsrtp-0.10.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b2ef1c32d1145239dd0fe7b7fbe083334d345df6b4597fc66faf914a32682d9", size = 2134898 }, { url = "https://files.pythonhosted.org/packages/00/f6/c76fa5401f9d95c14db70de0cf4fad922ad61686843bc3e7411178a64bc8/pylibsrtp-0.10.0-cp38-abi3-win32.whl", hash = "sha256:8c6fe2576b2ab13942b47db6c2ffe71f5eb1edc1dc3bdd7283169fecd5249e74", size = 1130881 }, { url = "https://files.pythonhosted.org/packages/4c/31/85a58625edc0b6967fe0904c9d89d019bcece3f3e3bf775b9151a8cf9d0d/pylibsrtp-0.10.0-cp38-abi3-win_amd64.whl", hash = "sha256:cd965d4b0e9a77b362526cab119f4d9ce39b83f1f20f46c6af8e694b86fa19a7", size = 1448840 }, - { url = "https://files.pythonhosted.org/packages/66/b5/30b57cac6adf93dfee20cceba6cd91e216c81b723df2bc9dcfe781456263/pylibsrtp-0.10.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:582e9771be7ffd060faea215cb4248afdad1356da473df1b8f35c7e382ca3871", size = 1699981 }, - { url = "https://files.pythonhosted.org/packages/16/e8/3846ac56ae4a2de91e9b3e67dff5363b2b07148616d283416fd8dd8c6ca6/pylibsrtp-0.10.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70111eeb87e5d3ffb9623e1ea036329dc81fed1282aa93c1f32377862ca0a0d8", size = 2441012 }, - { url = "https://files.pythonhosted.org/packages/b1/9f/c611fc47ef5d84dfffca0292bcfb2d78ee5fc1a98d50cf22dfcda3eee171/pylibsrtp-0.10.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eda06947ab42fd3737f01a7b98537a5d5908434d37c70488d10e7bd2ff0d520c", size = 2019497 }, - { url = "https://files.pythonhosted.org/packages/d8/38/90c897fc2f2929290ada1032fa3e0bd39eca9190503250f6724a7bc22b5b/pylibsrtp-0.10.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:511158499309c3f7e97e1ebeffbf3dd939e641ea553de43cfc02d3576aad5c15", size = 2074919 }, - { url = "https://files.pythonhosted.org/packages/2c/46/e92f8a8d7cb5c1d68ec85254a8535aad922efa15646c7ba0c7746b42c4ea/pylibsrtp-0.10.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:4033481f332331bf14b9705dca69efd09d3809ba4a2ff69914c53dddf39c20c1", size = 1446426 }, - { url = "https://files.pythonhosted.org/packages/ed/cb/5f3f7b7370b052bc67735162942be67ee9ee32220051251505b4f7cd4de1/pylibsrtp-0.10.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1990afa3b1acc2ded0bcb015e38d28eb707af32b4bb0a08ba4bc187148f36a9e", size = 1699979 }, - { url = "https://files.pythonhosted.org/packages/93/55/b84bb10861c1818c0a403c45b68e8c67cf32c824f995c0c8eff38a1f53b6/pylibsrtp-0.10.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2115f91e39cf3718591fac3202df76d606441cabc9057e4a1b97b7e7a3328d9", size = 2441007 }, - { url = "https://files.pythonhosted.org/packages/3d/74/3bbb6a270b45d4c8f60b6d1e480376327011a0aa491d82f7fb37907ab53b/pylibsrtp-0.10.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5f971f1f9e4849c5ce38671628b3d1558763941cb4b54a74497026e82b5f68a", size = 2019491 }, - { url = "https://files.pythonhosted.org/packages/f5/e6/6fa59a41b6183b320bbd9a01912d0ad669c180d033729af03658d92d6dbd/pylibsrtp-0.10.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ca0e351c15d2d085665a1103d967fc90c9074d4ba60a0b3ed529ef075fd6e9e", size = 2074914 }, - { url = "https://files.pythonhosted.org/packages/24/7f/ca581c7900a9229783e8d39ddcdec0dae7189d30a6a70472505afdc67573/pylibsrtp-0.10.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:fea95747ce124f7a476fb71e0929d122ce6ddf35ae7d6f4eb372707a078c4b40", size = 1446423 }, - { url = "https://files.pythonhosted.org/packages/86/c4/0789dfe34aad121eaf1dbf763d2c093e3cd29c1dc76e6a68bb23be7753e9/pylibsrtp-0.10.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ba342e60035dcdbb04368c95cea7ed2c9639ea34efb68db42cde3cfd6c489e71", size = 1699977 }, - { url = "https://files.pythonhosted.org/packages/72/b2/91d143f1ea55b95811c4e7385a706ec74748068a9f9702adaeef397456a5/pylibsrtp-0.10.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95a31a776d993cdc486a6435268a6facac8c92cff560b0b53ccc3a1fd4714f6a", size = 2441008 }, - { url = "https://files.pythonhosted.org/packages/18/ab/5bb02ac9e8f4b3323e472735cd954ebf9788dcb1e7576544431e3b019cb9/pylibsrtp-0.10.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e519f9f73cd89404db9008bf7e628f8be4957000f61cee2841b62fcffe267c5", size = 2019491 }, - { url = "https://files.pythonhosted.org/packages/f9/0f/ca0f47f96c5a540148324a015eb382dfb84b95562b6ae8bb216864309ea1/pylibsrtp-0.10.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f33dced976a0039b4873d2468fb864795df0b79cdecf9b9a4286fe76099dfb1b", size = 2074915 }, - { url = "https://files.pythonhosted.org/packages/9e/c1/c8d2be418b63b1651219b8cc733a775657844afeb7ffd0012258e04c0307/pylibsrtp-0.10.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e4d9625a9667d2c0843bf9cfa731f815d8b9a04ed9ffe5b98442483b8b236f13", size = 1446423 }, ] [[distribution]] @@ -3306,13 +2210,9 @@ version = "10.3.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b7/40/a38d78627bd882d86c447db5a195ff307001ae02c1892962c656f2fd6b83/pyobjc_core-10.3.1.tar.gz", hash = "sha256:b204a80ccc070f9ab3f8af423a3a25a6fd787e228508d00c4c30f8ac538ba720", size = 935027 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/2d/355a7042ecbf839515e0caa67819bac62d9ee0a0452281f89f95dddd3066/pyobjc_core-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ea46d2cda17921e417085ac6286d43ae448113158afcf39e0abe484c58fb3d78", size = 774309 }, { url = "https://files.pythonhosted.org/packages/ba/69/e782f176bb5ac71473563f4e5cf825c48b1d7d1fbe1fadde201027804e45/pyobjc_core-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:899d3c84d2933d292c808f385dc881a140cf08632907845043a333a9d7c899f9", size = 775224 }, { url = "https://files.pythonhosted.org/packages/cd/4d/d5d552b209fbca644cf9e0115a4cef8bc5f6726a44303eb7ae8d8a920a9e/pyobjc_core-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:6ff5823d13d0a534cdc17fa4ad47cf5bee4846ce0fd27fc40012e12b46db571b", size = 825968 }, { url = "https://files.pythonhosted.org/packages/2e/8b/341571ac5d625968083cbd718e1af7eac54197ed3d404dfff9467c3a8c88/pyobjc_core-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2581e8e68885bcb0e11ec619e81ef28e08ee3fac4de20d8cc83bc5af5bcf4a90", size = 827410 }, - { url = "https://files.pythonhosted.org/packages/d9/3e/9dd4ad3518a501dc650b22a248af6c18789c94563c245557518b715b51f2/pyobjc_core-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ea98d4c2ec39ca29e62e0327db21418696161fb138ee6278daf2acbedf7ce504", size = 432434 }, - { url = "https://files.pythonhosted.org/packages/09/2d/63dc294430709c4804400465938e7e2f59e68d0f68b5ad075a52ccd57193/pyobjc_core-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:4c179c26ee2123d0aabffb9dbc60324b62b6f8614fb2c2328b09386ef59ef6d8", size = 772193 }, - { url = "https://files.pythonhosted.org/packages/b5/60/219460b689b10a8bdc0699e6512165b050545fbfc76c1ba5bc7f33c18bbd/pyobjc_core-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cb901fce65c9be420c40d8a6ee6fff5ff27c6945f44fd7191989b982baa66dea", size = 780333 }, ] [[distribution]] @@ -3425,13 +2325,9 @@ dependencies = [ { name = "pyobjc-framework-quartz" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/06/c9/f2d92e183345268541315cac065244a117ea13d8872da5a994517fb9b9d2/pyobjc_framework_ApplicationServices-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b694260d423c470cb90c3a7009cfde93e332ea6fb4b9b9526ad3acbd33460e3d", size = 31031 }, { url = "https://files.pythonhosted.org/packages/78/24/31fdd15f88d3a0a88ba88b27d1f134c7819221886bf56644af12fe672c6d/pyobjc_framework_ApplicationServices-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d886ba1f65df47b77ff7546f3fc9bc7d08cfb6b3c04433b719f6b0689a2c0d1f", size = 31029 }, { url = "https://files.pythonhosted.org/packages/af/01/bf2d335e3f176227a142f466419a9400dd752e7f02f03674a276f39c1d78/pyobjc_framework_ApplicationServices-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:be157f2c3ffb254064ef38249670af8cada5e519a714d2aa5da3740934d89bc8", size = 31072 }, { url = "https://files.pythonhosted.org/packages/a5/44/44821633fb0a94e5072997eb56496a72c071ed22a1c93e53915b5a14dbb5/pyobjc_framework_ApplicationServices-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:57737f41731661e4a3b78793ec9173f61242a32fa560c3e4e58484465d049c32", size = 30950 }, - { url = "https://files.pythonhosted.org/packages/52/61/193f07e6a183c4c024c2c4ab7f840e7683e1fb525ff2c51d4b973415f483/pyobjc_framework_ApplicationServices-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c429eca69ee675e781e4e55f79e939196b47f02560ad865b1ba9ac753b90bd77", size = 26045 }, - { url = "https://files.pythonhosted.org/packages/3d/54/f0380189ee56320a3d18f909ea86bdb1a97cc86efd2e9724a205a34a04d8/pyobjc_framework_ApplicationServices-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:4f1814a17041a20adca454044080b52e39a4ebc567ad2c6a48866dd4beaa192a", size = 31723 }, - { url = "https://files.pythonhosted.org/packages/f3/51/4666a71d21e2ca7aff59da9096fa9b72564713dd48130a85e3a5ebcfdf78/pyobjc_framework_ApplicationServices-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1252f1137f83eb2c6b9968d8c591363e8859dd2484bc9441d8f365bcfb43a0e4", size = 31006 }, ] [[distribution]] @@ -3457,13 +2353,9 @@ dependencies = [ { name = "pyobjc-framework-cocoa" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/d7/bfa5cb1118475073414bf69548ad9517864dc314c1ba46e9c47f60957fe7/pyobjc_framework_AudioVideoBridging-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8accf87f136a6aa71d89d3a2204127b48e64ec25d3e1159f0f23ede0c4d70e59", size = 11125 }, { url = "https://files.pythonhosted.org/packages/82/ec/da418b96f03e5dd7d0bf0974843292756d89dd9e2604384e5da802332ffd/pyobjc_framework_AudioVideoBridging-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4f6067b2f50fb48c9ecb521b8865d93dfbd46510a4322cc2041b1e917678f39b", size = 11124 }, { url = "https://files.pythonhosted.org/packages/2f/5b/f03579fb2c77b72981beab1cbb58d9f02ea6a7d0309a9fb4e859a6ede73b/pyobjc_framework_AudioVideoBridging-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1aebc6c1aafb3cdfc5f9fad2dfe2dfccfbab159dc8dbfe54cfea777108e80e44", size = 11152 }, { url = "https://files.pythonhosted.org/packages/a7/3f/cd2f1187295ba9824129823911bdbd984bb49d9c86336c08d77a8f19bccb/pyobjc_framework_AudioVideoBridging-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:b1fb0af1df78800205cd7a7cd90e58b640513bbb944fe6a8d89df43e626a27a8", size = 11094 }, - { url = "https://files.pythonhosted.org/packages/9e/71/0eab68f2c73b5452a7913d213d0a5462a7d63f6065c490fe77c63d0cb145/pyobjc_framework_AudioVideoBridging-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2cc18c005c72a74654a000a1d6d405b6cb12b1d6c09be9bd6b58502ae06035e7", size = 9028 }, - { url = "https://files.pythonhosted.org/packages/7d/53/693fca229708bf739cbf746da76821971bbd404f5510f78ed6d0723e1fd4/pyobjc_framework_AudioVideoBridging-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:b61dc632c31875cb090521b0139d61f528e5fe5fedf4055524522c0aa808a77d", size = 11308 }, - { url = "https://files.pythonhosted.org/packages/bf/8c/43862ebb29a5c2e39aadf281730acd5e50b8fe67f45b0d0953b36497ecee/pyobjc_framework_AudioVideoBridging-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8de78207e617d4d89c66b4a66ff4ff49b60822249d2a68fc9356dd09475f0103", size = 11120 }, ] [[distribution]] @@ -3713,13 +2605,9 @@ dependencies = [ { name = "pyobjc-core" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/03/2f925a8cde4506c021a073c16c08a5b824ed8652bce6e16280353c3c0a3d/pyobjc_framework_Cocoa-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4cb4f8491ab4d9b59f5187e42383f819f7a46306a4fa25b84f126776305291d1", size = 396166 }, { url = "https://files.pythonhosted.org/packages/d4/ad/436c3619d1a84f83d55ff9c709b122e4d1ac2ee9af467b68fcb60e5ad3a6/pyobjc_framework_Cocoa-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5f31021f4f8fdf873b57a97ee1f3c1620dbe285e0b4eaed73dd0005eb72fd773", size = 396142 }, { url = "https://files.pythonhosted.org/packages/29/73/9a913537d6d63758243f76a3d3acbae8eb77705c278eceaf37198e58dcf5/pyobjc_framework_Cocoa-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:11b4e0bad4bbb44a4edda128612f03cdeab38644bbf174de0c13129715497296", size = 396183 }, { url = "https://files.pythonhosted.org/packages/93/1f/b203c35ac17ff50b101433783988b527c1b7d7386c175c9aec1c89da5426/pyobjc_framework_Cocoa-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:de5e62e5ccf2871a94acf3bf79646b20ea893cc9db78afa8d1fe1b0d0f7cbdb0", size = 395004 }, - { url = "https://files.pythonhosted.org/packages/60/4e/8e06eb8a30a192d6b133cb56ff56585e085948e7c6d637f0d29510b942d5/pyobjc_framework_Cocoa-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c5af24610ab639bd1f521ce4500484b40787f898f691b7a23da3339e6bc8b90", size = 291122 }, - { url = "https://files.pythonhosted.org/packages/96/f0/52a63fdad379f05b804683383c3db5fc8ed07b77b7aae7bddd7fcd35812b/pyobjc_framework_Cocoa-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:a7151186bb7805deea434fae9a4423335e6371d105f29e73cc2036c6779a9dbc", size = 395280 }, - { url = "https://files.pythonhosted.org/packages/70/52/0376b7548a73c724dfcf38623e6ec843dd3bf164ca6193c7ed145e60dded/pyobjc_framework_Cocoa-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:743d2a1ac08027fd09eab65814c79002a1d0421d7c0074ffd1217b6560889744", size = 396110 }, ] [[distribution]] @@ -3791,13 +2679,9 @@ dependencies = [ { name = "pyobjc-framework-cocoa" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/07/01/080cff601f8204ed373fdf871992b74f1c09aa720b5e4e4b6e423176920f/pyobjc_framework_CoreAudio-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:76a37e27cfdd67e4dcf27f57b680a881c4a2f3bf44ce3b31d7cdb32596e1e269", size = 35661 }, { url = "https://files.pythonhosted.org/packages/6f/dd/e4be148694e5e73885aaf00a92720293674fd510d87369cf5ba300f24660/pyobjc_framework_CoreAudio-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bd58e69cabbc987d0c2854ab2d13516889cfe4a2094b80296591ad7df0f30e40", size = 35672 }, { url = "https://files.pythonhosted.org/packages/21/1c/af5e88a24dc7f437852a9605949c5eeaedb7bba9883b2c3cd275dea3729b/pyobjc_framework_CoreAudio-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e0aeca61a425d846afc92350ffba970e1e503469182f5f0ea436de98cfd00d96", size = 36444 }, { url = "https://files.pythonhosted.org/packages/31/50/3917e5190b65e4f29a5977c9713651c779f48753042d2fdc3f8dbda12353/pyobjc_framework_CoreAudio-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:21cecd1b023b6960d1071c106345656de45a399196701b07c7e5c076321f25ad", size = 36199 }, - { url = "https://files.pythonhosted.org/packages/95/3c/b067deb8998719eba17a9e499a9902e656741a59698a0b7ad3ddc7021cc4/pyobjc_framework_CoreAudio-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:443b14cc6e64e09e6fb4eae61f6ac1ce19618d9074ae1627d75754fa434ef87f", size = 25594 }, - { url = "https://files.pythonhosted.org/packages/c0/ad/0b40a48a1fd2097e7b60b9d8cd9f9371743709454906500ad2c75e5e357c/pyobjc_framework_CoreAudio-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:4f8d4c4c4fa0529f178ef6d3676cfe08c9e8ae20c3cdbfe067b562d7395debfa", size = 36111 }, - { url = "https://files.pythonhosted.org/packages/43/50/d3096fe386c9620c01ffcce59f5973278875f05e66dbacdaa3f4a4fa4409/pyobjc_framework_CoreAudio-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b93cc6f670feea29f8f4cd2a9511d2220aefde41a89912d5ab8eb06a198e344b", size = 35633 }, ] [[distribution]] @@ -3888,13 +2772,9 @@ dependencies = [ { name = "pyobjc-framework-cocoa" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/54/57/f93b97b4e55e6aa5a6ca79c9def2f6d99350087f7399d726a255fd29969e/pyobjc_framework_CoreMedia-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ef02d87f12ba54e6182ea72fd5732cf6d348982c4263dc9c0b11e4163fbb877", size = 29039 }, { url = "https://files.pythonhosted.org/packages/3b/99/5ca053be93f30cb8420b72a1e7eefb778677e072f86ea2525dd6d848ae88/pyobjc_framework_CoreMedia-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e63b002cf5e34540cba3f3a1704603ea0fb076ffc1ea42c2393a0679f40846de", size = 29040 }, { url = "https://files.pythonhosted.org/packages/9e/2f/2b118b5f3c8fe955efd466398d519ffeb2e02e2957ae61953f8f4df0c798/pyobjc_framework_CoreMedia-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c6eaf48f202becab10679e3b5dd62607ddec2739495db45882524592cabf3997", size = 29052 }, { url = "https://files.pythonhosted.org/packages/cc/47/2af2541dcd14c7d2891a10b31d6b285099963be2a67d3778ce92458592fd/pyobjc_framework_CoreMedia-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:98b8ab02e6ec979007b706e05166e16bd61121e47fbc6e449f4b2de2c58f3cb6", size = 28679 }, - { url = "https://files.pythonhosted.org/packages/08/17/cf23e83df51b74d74754eb9a5f9eace40d81afc90372baa3ecc348104b91/pyobjc_framework_CoreMedia-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:77ca460cc35e39b9f820d9f20e93bfa89439b23dfb350ba201448b1ee958902c", size = 23597 }, - { url = "https://files.pythonhosted.org/packages/b6/18/4b3ea0f3a72d85e6868584875cab6e6e1515ac8fb9ca09eb4e23f556aebe/pyobjc_framework_CoreMedia-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:6ed3adf48fe3001d1b5acce688ecd5b75e0fa5f56d9f296ec120748cd36f2d24", size = 28677 }, - { url = "https://files.pythonhosted.org/packages/19/a8/3cff23ea7971958a26d28a98f68fb43c1b479d9e872f145625d27d9d4bc8/pyobjc_framework_CoreMedia-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b5bbed395bb8a8b0b4b8bb5475fd19f2a28d385c4d3a783cb590c9ea5e801baa", size = 29020 }, ] [[distribution]] @@ -3955,13 +2835,9 @@ dependencies = [ { name = "pyobjc-framework-cocoa" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/fb/1c3646f09d4f5c190f56a5983ede6fbe772a8bf21b28a2257d1b5902f219/pyobjc_framework_CoreMotion-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f8c320df1806ccd8c2b1ac32c9b9a7337816ff13cf338a710a2f15ee550f58cb", size = 9806 }, { url = "https://files.pythonhosted.org/packages/c9/7a/c208726685a2bae7edd597d6209f275d5052e3244ebed3d8c0f9b2e3de5a/pyobjc_framework_CoreMotion-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a003478eeb520c7f28be4d9dc8f9e02df6ffa8921d46c8879e2b298c9fbc6926", size = 9805 }, { url = "https://files.pythonhosted.org/packages/d3/2c/dda7dbf8ffd5ae61986b2201ded7c600da7d6e3edab967065317a5b233e1/pyobjc_framework_CoreMotion-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:63c8f831ad522212627f99ae8d6f34161628230afd544203646e7d66596d6437", size = 9835 }, { url = "https://files.pythonhosted.org/packages/fb/b3/521793543cc0266d6a6a2e4be3b660d99d0e16508cfa54436c116597b49e/pyobjc_framework_CoreMotion-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b78d2bcc71149821a49266eb548faea23abd7a25b7cd3f7a7f20b1d343a8786", size = 9794 }, - { url = "https://files.pythonhosted.org/packages/43/0c/d0599cfcbf4de0f182b6b5f54106981308e0dc128ace0d6f7eb510ff29f6/pyobjc_framework_CoreMotion-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28b431e448b884830c846d156d9c6626b265d9ede70ad233d77ceceb67366a17", size = 7636 }, - { url = "https://files.pythonhosted.org/packages/69/62/09c770ef3367ff5255c24331a4ff4311a4f2aa7d08efe1aac5ac3b85ecd8/pyobjc_framework_CoreMotion-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:7d4f95398ac5741a6dd1711e129f6173111385e26d858c59be8462543f62a8a1", size = 10095 }, - { url = "https://files.pythonhosted.org/packages/42/90/6e4c1bf1930cdaea2ee7c9b0831921f38cfdb5923f6f7c921cf4c739490a/pyobjc_framework_CoreMotion-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:89c78be31e276aa88d848b69a2f8d11360deaa7297222bd5369ecd1910de166d", size = 9796 }, ] [[distribution]] @@ -4008,13 +2884,9 @@ dependencies = [ { name = "pyobjc-framework-quartz" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/8c/64/797595a57048b4dedfcbf3f7f65446f11ec64d481a1752159a8ec226ffa1/pyobjc_framework_CoreText-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd6123cfccc38e32be884d1a13fb62bd636ecb192b9e8ae2b8011c977dec229e", size = 30265 }, { url = "https://files.pythonhosted.org/packages/0e/f6/ccc934adf50fa77c7d7d8bdb13ede25d1a0a62c67fec571ae2bd8557c41d/pyobjc_framework_CoreText-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:834142a14235bd80edaef8d3a28d1e203ed3c988810a9b78005df7c561390288", size = 30266 }, { url = "https://files.pythonhosted.org/packages/66/8e/4341253c550d6cf4da1a8c33d8d310b6ddbbaaea09eca26ea5eaff176e4b/pyobjc_framework_CoreText-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ae6c09d29eeaf30a67aa70e08a465b1f1e47d12e22b3a34ae8bc8fdb7e2e7342", size = 30404 }, { url = "https://files.pythonhosted.org/packages/6d/7a/850261594a2a7ec54f27449db2c2494cc0b79897c765fea1581e03268f7e/pyobjc_framework_CoreText-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:51ca95df1db9401366f11a7467f64be57f9a0630d31c357237d4062df0216938", size = 30331 }, - { url = "https://files.pythonhosted.org/packages/ae/1d/af8d97264cc855ad79d4e1d0ede3534bf87c0f7a1c1c23357a3cb33e269d/pyobjc_framework_CoreText-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b75bdc267945b3f33c937c108d79405baf9d7c4cd530f922e5df243082a5031", size = 24420 }, - { url = "https://files.pythonhosted.org/packages/85/3e/1efdfb9612ed58a952729e5514cec45ae80bffd46cefb68f57bfa6bb10cb/pyobjc_framework_CoreText-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:029b24c338f58fc32a004256d8559507e4f366dfe4eb09d3144273d536012d90", size = 30167 }, - { url = "https://files.pythonhosted.org/packages/79/84/4a8afe722712745cf6338b30ff3c2f62b1877463cddb9fcb98b5ca3eda27/pyobjc_framework_CoreText-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:418a55047dbff999fcd2b78cca167c4105587020b6c51567cfa28993bbfdc8ed", size = 30252 }, ] [[distribution]] @@ -4225,13 +3097,9 @@ dependencies = [ { name = "pyobjc-framework-cocoa" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/73/e8/a29e9a06bc7f015045bd61e441accef1c04aa1c87524d50b369010466403/pyobjc_framework_FileProvider-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:36f66bbd308fdf80d8fe21b89212af4b89bc80dff8cee5f785d5a6fcce942bec", size = 18164 }, { url = "https://files.pythonhosted.org/packages/00/39/5e4358e76d1285607166b623a8e0222b75e1560142907b8ff18b4ba9b0f2/pyobjc_framework_FileProvider-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b44bcbf3d826fd8a0cbc53142c65655433d553205fb36811486757e2089e6c5f", size = 18163 }, { url = "https://files.pythonhosted.org/packages/d2/87/3925b479aac490f3e96c5d56da813bfddcb75dca5597526d958eb0b3484b/pyobjc_framework_FileProvider-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b28294768dc71190019c2b2638e27b7ebf6edb65a90721b86613083bd86f6b2d", size = 18140 }, { url = "https://files.pythonhosted.org/packages/89/bc/4465ba82721da0718c0555cdc74bb777ac40eaf5b49e97248530fca2fc62/pyobjc_framework_FileProvider-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bb07a0b7e259030c7bc034c590c77a22e44427320c99bf74e5348551fe0da011", size = 18108 }, - { url = "https://files.pythonhosted.org/packages/ae/0e/465924515b906b98a0a164adadbc4294c51d9be0987c4fae298fd6e8e9a0/pyobjc_framework_FileProvider-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3e61b20aef5083df2303bf36f181fb83b02b9a7f4868af0e9229d94d7bc1828f", size = 12509 }, - { url = "https://files.pythonhosted.org/packages/8e/14/ece5bf3ba25c177be28e6082f7f9ac970d961e112c965441e0ea96146bca/pyobjc_framework_FileProvider-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:2ad657fa433d1922f40d581e87af1c2f7002c4835fa49235fdb3909eda23e1e8", size = 18154 }, - { url = "https://files.pythonhosted.org/packages/89/74/d12def69986d605d618d15cb69de6cecebf3456292dfa287decf6cc49346/pyobjc_framework_FileProvider-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e66548dfc9e81489bc66e245c97760c457371c25ced87a28bdeca655b548447e", size = 18157 }, ] [[distribution]] @@ -4443,13 +3311,9 @@ dependencies = [ { name = "pyobjc-framework-intents" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/be/189fdcd1465848672d20b230a4e287fa0af701ae4762ee302ca707c1c25f/pyobjc_framework_IntentsUI-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:23a606af7ea47bd899012b896e0b2d10c677f7facec80197ab45a3bcf899874b", size = 9606 }, { url = "https://files.pythonhosted.org/packages/8a/ed/adbe8714da27be1056a936e51cfbba36bed6046ba1fedc3f54b006f7f0cf/pyobjc_framework_IntentsUI-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bd2fed37c96f1d97abcbd6d98b2da90ba2c744f968e2c4e0735dce77bbbc95f4", size = 9607 }, { url = "https://files.pythonhosted.org/packages/6b/fc/97bf965283261206b971f329a7d02180cdf14ad5a30d5cae2f9962b0153a/pyobjc_framework_IntentsUI-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e9fe0ba78c9dd500ef9c13227dd1a60e39df460c84180d8325f5022edd80178b", size = 9642 }, { url = "https://files.pythonhosted.org/packages/ce/23/d23acf3e451bc64d40d2b7cf0e03620399a3540c74b16e8d5b6a191cfbd2/pyobjc_framework_IntentsUI-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6c124ceb8e7b7a1f3fb6c2c159e47f9dca42ece6e1645d763235660ea98e7915", size = 9591 }, - { url = "https://files.pythonhosted.org/packages/bc/d6/5cec88636cf8a690bed278607a6f618ffffb3c4eb5b26d169d7b07888295/pyobjc_framework_IntentsUI-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bfed2841fc9099cad850e058e3dfa23845a0988e53666f5ffc82cd1b91bbe824", size = 6472 }, - { url = "https://files.pythonhosted.org/packages/ca/b4/73a613e4006053fb41518ba627a69909a0d060fb5b64972369607bf99413/pyobjc_framework_IntentsUI-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:d6a802bc5ccb01a22c312f4dfaf88300a2edd4db2e2f7568b10d29176ae05edd", size = 9477 }, - { url = "https://files.pythonhosted.org/packages/e7/92/04da686542ed3d4a34c6d3cd7377278857c46ed3e10574aee4244c9af817/pyobjc_framework_IntentsUI-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3ae02ba54c689cd672bfc49c039d18cc5e9515d7d95608bcbb34357ae90fd9ff", size = 9595 }, ] [[distribution]] @@ -4556,13 +3420,9 @@ dependencies = [ { name = "pyobjc-framework-cocoa" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/40/e8/daa42227ff9c90d9bd37386cc9f6e3565fe88cd5dc18823dc3070b39c14d/pyobjc_framework_libdispatch-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5543aea8acd53fb02bcf962b003a2a9c2bdacf28dc290c31a3d2de7543ef8392", size = 20493 }, { url = "https://files.pythonhosted.org/packages/5b/8b/44d0a44bfb68ead2481f95516f1d791e6e72667a9514c36d8d7df87a58bc/pyobjc_framework_libdispatch-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3e0db3138aae333f0b87b42586bc016430a76638af169aab9cef6afee4e5f887", size = 20491 }, { url = "https://files.pythonhosted.org/packages/40/1c/4d16cbe1d41462184e908d757537349cebddc7444950ea24dfbaf2a957ca/pyobjc_framework_libdispatch-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b209dbc9338cd87e053ede4d782b8c445bcc0b9a3d0365a6ffa1f9cd5143c301", size = 20542 }, { url = "https://files.pythonhosted.org/packages/fa/36/c95b42c290d41687c2f01599feff82f4b6f9774006c4dd051f5d6a9949fe/pyobjc_framework_libdispatch-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a74e62314376dc2d34bc5d4a86cedaf5795786178ebccd0553c58e8fa73400a3", size = 15643 }, - { url = "https://files.pythonhosted.org/packages/a0/f3/f14890052bb1d9dc7b6af48a074cd6895be8f266f7dcb5b1ae5b44e33850/pyobjc_framework_libdispatch-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8e8fb27ac86d48605eb2107ac408ed8de281751df81f5430fe66c8228d7626b8", size = 13328 }, - { url = "https://files.pythonhosted.org/packages/54/1d/bff9fd3689cd2048dd662d030ac790adc2ffd6ebe8df4a201aa7fea6afac/pyobjc_framework_libdispatch-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:0a7a19afef70c98b3b527fb2c9adb025444bcb50f65c8d7b949f1efb51bde577", size = 15612 }, - { url = "https://files.pythonhosted.org/packages/96/62/64d2886726477829f08d5e2b06840e937cd2507d7e0b088395a8ace5519d/pyobjc_framework_libdispatch-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:109044cddecb3332cbb75f14819cd01b98aacfefe91204c776b491eccc58a112", size = 20472 }, ] [[distribution]] @@ -4575,13 +3435,9 @@ dependencies = [ { name = "pyobjc-framework-cocoa" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/40/40/43de31e4a25219cf0bb740acc6964657f99f1469f82368ba0bca8e0f955b/pyobjc_framework_libxpc-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9e287591a708f96e4e3d1929425a50c4e83188eb8bf3094b688de149946ac752", size = 19485 }, { url = "https://files.pythonhosted.org/packages/14/58/70effee80f0f0f840b6e6639252cdc749a4f7ee043d2ad66528ce354b507/pyobjc_framework_libxpc-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0afba29b6bf5c3de3ef51f60e06c026ab7be7ce44600047dece5d3bf4e758af", size = 19484 }, { url = "https://files.pythonhosted.org/packages/2c/5f/bd9bcd9d13a1ccb61c906b68f998556b3319ea83ce722be7ee5559103ce5/pyobjc_framework_libxpc-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:123b72dff148a56d48120448bd9742190326f87661f4ae6f5363e112de0e554f", size = 19582 }, { url = "https://files.pythonhosted.org/packages/8c/56/ef3ede2cea30acf4b251a5da5a2f32db17486acbf66ab8cfc28ae2a922d5/pyobjc_framework_libxpc-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:72a35a21f4bbbfb4a5c4c23e3180c3273b7720fe4cd150b975cb5d08cbc4fe13", size = 19531 }, - { url = "https://files.pythonhosted.org/packages/bb/2f/882f2024f63f5f718ac6367f23fb9e533a655c1a60dd73aa304b35d593cd/pyobjc_framework_libxpc-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d14f6fa976df50de90affa41b4dc2381554fe1e8503564f54cd71a8c6cc4b0eb", size = 12333 }, - { url = "https://files.pythonhosted.org/packages/c5/79/d5531e409a6c430285cd9d2ebd17a1e1c00c047f712f50872f4c5be57a43/pyobjc_framework_libxpc-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:0d8a5d29952db92d9d7112c642ba7cdc9d8496118ec14e8186f93353b092a818", size = 19149 }, - { url = "https://files.pythonhosted.org/packages/f0/bf/74479bbaae31f50aac4c2ef9bb8f747c1a78439e67695a897a94253b8288/pyobjc_framework_libxpc-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f4232996766f4c21f80da51344296651f40ec8fc14f353fca0bc75af718ee950", size = 19476 }, ] [[distribution]] @@ -4801,13 +3657,9 @@ dependencies = [ { name = "pyobjc-framework-cocoa" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/63/a72f925370163dacc2d36edf4466f7666387c232f049ad1c9faadb2ebebb/pyobjc_framework_MetricKit-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ad28bb10e452b33af285137fb89f573294759571fa02d66201b78304add91513", size = 8164 }, { url = "https://files.pythonhosted.org/packages/d5/7e/f940ff748d257d0c44415a4f7d1dfad1fa0fabb4d76f77bec62e780abf3d/pyobjc_framework_MetricKit-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:59b6959d6f79f71080d386ad08665c19e52d0cc57943716da180bbb3369c9569", size = 8165 }, { url = "https://files.pythonhosted.org/packages/a5/c3/0308e5941f509f84b0026dd56329941d4a7bb3859028ddcf4acaede186e9/pyobjc_framework_MetricKit-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f73d240b5e8f2351d6c2258b71a6d06b45ec964523f54acf05af50dc4ffac821", size = 8179 }, { url = "https://files.pythonhosted.org/packages/fe/ba/3f3e0272354366a6759a0529b32f6fc2f0d21a5071873fd26fc89f304c16/pyobjc_framework_MetricKit-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:58dbfc7b9ae7701a59b9b2a5a5f874a9e393f10b27f39155714d1b49ea725226", size = 8124 }, - { url = "https://files.pythonhosted.org/packages/bb/47/2808174768686e11acfd79edf30ea740b4031ea1ac6631880d294858fbfa/pyobjc_framework_MetricKit-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f462b68c22632f952d52b7c858d03727315107bb22c0a2152994baec1350534b", size = 5918 }, - { url = "https://files.pythonhosted.org/packages/f8/c4/a8c0e4fe0a28559247b3f400a6cba4610b2a0cdcd5678760012e4373558b/pyobjc_framework_MetricKit-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:321ea41e7dcfb142f6ef91916cdfb5296a9888571f7c1ccd8799e51b1fc4a6c5", size = 8458 }, - { url = "https://files.pythonhosted.org/packages/3b/dc/54502041e99e58bfd22294c3bffdc67ea800df70f6f1d84aa7a9ebd344f7/pyobjc_framework_MetricKit-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3460fad9a31f6331884775905bb55d38db621b2f3613f44fd037777eb304d787", size = 8168 }, ] [[distribution]] @@ -5100,13 +3952,9 @@ dependencies = [ { name = "pyobjc-framework-cocoa" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/29/026a4cb41bed4bbd090b320e2027dd2fd9226f35723af4bfea989a0924d7/pyobjc_framework_Quartz-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5ef4fd315ed2bc42ef77fdeb2bae28a88ec986bd7b8079a87ba3b3475348f96e", size = 227245 }, { url = "https://files.pythonhosted.org/packages/62/b3/ba33c4a3406fec862a5107da03d8daacbc11daa355f446a8849e1bf2c73e/pyobjc_framework_Quartz-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:96578d4a3e70164efe44ad7dc320ecd4e211758ffcde5dcd694de1bbdfe090a4", size = 227260 }, { url = "https://files.pythonhosted.org/packages/0f/08/215f38dbebfca74f49276a9471531f360b4fb7888106f78953909919ca53/pyobjc_framework_Quartz-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ca35f92486869a41847a1703bb176aab8a53dbfd8e678d1f4d68d8e6e1581c71", size = 227195 }, { url = "https://files.pythonhosted.org/packages/ce/7a/78b512061af37a4466607143a9876192f04c5810b16e4cb097fbbfa02dc5/pyobjc_framework_Quartz-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:00a0933267e3a46ea4afcc35d117b2efb920f06de797fa66279c52e7057e3590", size = 226586 }, - { url = "https://files.pythonhosted.org/packages/41/b3/72a00d04a973ac4f0015558ca58b7a2319609e1daa02fb56f4a7b5792f08/pyobjc_framework_Quartz-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a161bedb4c5257a02ad56a910cd7eefb28bdb0ea78607df0d70ed4efe4ea54c1", size = 146338 }, - { url = "https://files.pythonhosted.org/packages/a7/e8/7eee5de346cc912c44e2cfa381ca047e70712c1964130b8ea82ce4fb67e8/pyobjc_framework_Quartz-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:d7a8028e117a94923a511944bfa9daf9744e212f06cf89010c60934a479863a5", size = 227881 }, - { url = "https://files.pythonhosted.org/packages/a3/c3/49c4018d3ce5f53ae24c0c4f3356eb6a57f683958764c1fb13be02532ede/pyobjc_framework_Quartz-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:de00c983b3267eb26fa42c6ed9f15e2bf006bde8afa7fe2b390646aa21a5d6fc", size = 227176 }, ] [[distribution]] @@ -5200,13 +4048,9 @@ dependencies = [ { name = "pyobjc-framework-coremedia" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/dd/2f5db2192817a2af7d6b3057e91b57699b6437694f17b80d5552ef40928d/pyobjc_framework_ScreenCaptureKit-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e69a1e15502543c80c084399d7e06d6ebfb089a3afd248860e24dd03e654456a", size = 11399 }, { url = "https://files.pythonhosted.org/packages/1a/67/ff55c30ac3508f3c1214a084f321d2268c56d15fe5be436591a5ee24eb7e/pyobjc_framework_ScreenCaptureKit-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0953f8d43bd7f0012decebe34401d361c4a64472190960204b3214e4850e4ef2", size = 11398 }, { url = "https://files.pythonhosted.org/packages/b2/c7/25af6462a4f161dca7ffb375348716b6cb271c29e356bbfd4e4693f87b69/pyobjc_framework_ScreenCaptureKit-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a80928dc483046ac72294fd576c53f793045aad700b740ec9591b23a3ccc011d", size = 11435 }, { url = "https://files.pythonhosted.org/packages/cd/3d/17cb4d822faf26efe04e2f0749783abeaddb86529c1af59ec8f8270deccb/pyobjc_framework_ScreenCaptureKit-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:4d8e280a076e7bc40eaa9730f97da84421b891c30f6e3fdea4f6c30bdb298243", size = 11368 }, - { url = "https://files.pythonhosted.org/packages/a9/f1/8a9fb3e51b249c7ede1a58ea71213e181324a3b458ee8362479bd903d106/pyobjc_framework_ScreenCaptureKit-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:757a62e30ae68307d4705288bb808d91e10569c8ba3b54192bb5bbaaddcfa802", size = 8202 }, - { url = "https://files.pythonhosted.org/packages/95/53/f6bc5d2d6b4d4e4a24dc393984e02fb4d5e98ce138e11866fc62ce1b60e8/pyobjc_framework_ScreenCaptureKit-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:c55a2bdc3ff934841a668db1b5b2f74b9352696419ce87fea31637b89a04b6c7", size = 11280 }, - { url = "https://files.pythonhosted.org/packages/2e/6b/e42bd15528fdd110798cfe7b2480f95c14861de869b25fa8478bbecb0546/pyobjc_framework_ScreenCaptureKit-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a0ccf558123fe0b7fcfbb74280678aa0f0973c96765a03cb658fd4d8c5e732e9", size = 11397 }, ] [[distribution]] @@ -5277,13 +4121,9 @@ dependencies = [ { name = "pyobjc-framework-cocoa" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/69/0f/7001e87bd544297f5ad42a3b7844575ac73e5b9e54c9cb49bf3f2d001b7b/pyobjc_framework_Security-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9de850e5d29cb8605c0d7f7fb4a8d29ad5ece6c58a2ab16fba3f985e6b9ee05a", size = 41022 }, { url = "https://files.pythonhosted.org/packages/6f/d2/c8e65fd0d5905883bfae7c087645bba247e109570d5c55f814cdaa027eea/pyobjc_framework_Security-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:499372b4b87de0198601e0c6b3d3e43d48605218149a5808c6567b601147a9bf", size = 41023 }, { url = "https://files.pythonhosted.org/packages/36/96/f8f714d8eaa7e7741475a53c3e6a06cc550cd996153e5076fe2276e00ad2/pyobjc_framework_Security-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b3daed9661bd80245dd8dbc738a17870226969db27f6dbb3424ec0ebdbb6ba83", size = 41069 }, { url = "https://files.pythonhosted.org/packages/5a/32/4d233b667ae2b7a9106c4a7ebb2552801cc4474c66f6a23750d13f60e289/pyobjc_framework_Security-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6120e91282985bcec3b44c1bc4f9c26d40cd07b4ac3dc81f745d73c13f8b5523", size = 41021 }, - { url = "https://files.pythonhosted.org/packages/b9/e3/802ffe745f306a62b4cc59b3faa72c0376f2c5b5cda86a4824967d421dc2/pyobjc_framework_Security-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:43450895cd84256b313b547c9b256a4c0dc4b91195ec3e744f4f247d3cda0b77", size = 33165 }, - { url = "https://files.pythonhosted.org/packages/94/0e/859b3daf85c4e4b69486cb8631244a9112bfbc861633d6347eae768f9a7c/pyobjc_framework_Security-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:de52be2ce5ea98f2c224fea248227dcb3e7028d9814d0894ea6ea3c6da0f9160", size = 40933 }, - { url = "https://files.pythonhosted.org/packages/f5/e9/a32251b195c1e415fb09a10badbdd243dedc6dcd904c1a31c61b9c932ab0/pyobjc_framework_Security-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:df39effeeb79482dd5805fd05e34a7c3ab30233a6e06e251cf7f8620430574fe", size = 41022 }, ] [[distribution]] @@ -5386,13 +4226,9 @@ dependencies = [ { name = "pyobjc-framework-cocoa" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/85/f680ba2fee00fb5f1d9fbadc77d8f5c7c8e6c698c62f92b6559d1e45e238/pyobjc_framework_ShazamKit-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dac6a729d7fed5e96ac4cb2a7894c79002670b4c06559ef4795dfe8c6fa15dda", size = 8631 }, { url = "https://files.pythonhosted.org/packages/05/05/ac965959bfd2261bbcc590e1db7f9b7b59a39736db6b7398a20a8d510d38/pyobjc_framework_ShazamKit-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cc77fde1503ec1f96d7b9a05ad784d29d94065732f0cfe089321be423e5045f3", size = 8628 }, { url = "https://files.pythonhosted.org/packages/77/03/470f30e129d93faee2cc418a38acabd16b331b403cb201d3cefe380ae9a4/pyobjc_framework_ShazamKit-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:012560cab1997c1da6e19388b5192f68dcdf806c2f8d7bd1e66da37512d18b30", size = 8652 }, { url = "https://files.pythonhosted.org/packages/d0/23/2139cd328324253b27384d99a50232ee930ac33fb829cfad3f7e29283455/pyobjc_framework_ShazamKit-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:4356bdcb9ca50da243b9d79da27851b799483865072f7c86a8a9674300d31819", size = 8592 }, - { url = "https://files.pythonhosted.org/packages/19/8c/8d232d325f92237e4e04170224d604eb88bd3727ce5db9d7a603e71551b8/pyobjc_framework_ShazamKit-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:26dafb6ac23c15d8cdee4c2083757aac29fad4f945b97f120f6351aed5cdab72", size = 6381 }, - { url = "https://files.pythonhosted.org/packages/02/c7/7b4f363281d89af123ef093b59223ecab6b9a672cc8e855d153496f928cb/pyobjc_framework_ShazamKit-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:95e4e717cb7a675544e08c53fb86d55715aa5d633b4ec35737fb02293098d368", size = 8944 }, - { url = "https://files.pythonhosted.org/packages/b4/4f/f63c16f523e59b821c478552f77ff65e72f3eee3d16e49a2b995ec8b42d0/pyobjc_framework_ShazamKit-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:808bdfe5dcfc44d4c1df3ae3f384396908e9a1d3832e34408950db522859e91e", size = 8623 }, ] [[distribution]] @@ -5448,13 +4284,9 @@ dependencies = [ { name = "pyobjc-framework-quartz" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/90/b4/574a17673ee3861b7dd09db7e8b0d95f9c8fb4022bcdc25e0af40712b318/pyobjc_framework_SpriteKit-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:31a5ce3ba471bf12f3e9ae3b5865d400e4e70ab4bb94317880783ee04c07b1f5", size = 17824 }, { url = "https://files.pythonhosted.org/packages/cd/15/df384944ae0699ff3dffe20e0f9f3d64f09d58d2ee33dbc4beff2e359e38/pyobjc_framework_SpriteKit-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:af355eccc18437e0932e1b327817e8f50d194bfa471b65b4733185ba606ab792", size = 17827 }, { url = "https://files.pythonhosted.org/packages/78/19/60a5a3da996744095234e01445e93cbfdedb44dd0b0e01b661bb6618de7b/pyobjc_framework_SpriteKit-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c3fd6aaecd7abd6ebc83d4c37a22950d55b75911fdb99628b2677f44085a0212", size = 17881 }, { url = "https://files.pythonhosted.org/packages/fb/ef/f237933784a49e693948cbe0926e132e886d7f0b3009eb92b9d822b829cb/pyobjc_framework_SpriteKit-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a1f0537bc0331cca58cc50307f3b114ab8bfd51576df3038b6037353aa77085f", size = 17833 }, - { url = "https://files.pythonhosted.org/packages/36/8d/4f3f54867403200b53214df3c1c3db488e6e388078752f471f8027d87c6f/pyobjc_framework_SpriteKit-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ffe7a07c8a3e17552e73b517b4fdcff7b2e6ca7e89b093a5daccfc285708216c", size = 12696 }, - { url = "https://files.pythonhosted.org/packages/83/7f/675dbb3197c7ef47f6af72921181eab3e53eb0a4cebaaa9bfcf3458c5728/pyobjc_framework_SpriteKit-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:e1d79aab298f7b42436b2468e37ff84718f1b8b579c1440de7002a55d5f8762e", size = 17710 }, - { url = "https://files.pythonhosted.org/packages/90/63/ce737ef4233f50ac1d21f5cf2878187f7b0fb370420e80a2fa640c1f366d/pyobjc_framework_SpriteKit-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cd08925baf8b3f511842f49fb5512ae56875a923d23254fcc022124788180d47", size = 17826 }, ] [[distribution]] @@ -5683,11 +4515,6 @@ dependencies = [ { name = "packaging" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/57/49/0c9d79e76e35ead21e08dfa1dbb6640ffe3e4795ff7c7b464f20ea575dd3/pyogrio-0.9.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:1a495ca4fb77c69595747dd688f8f17bb7d2ea9cd86603aa71c7fc98cc8b4174", size = 14750955 }, - { url = "https://files.pythonhosted.org/packages/e6/5b/74b66afcfbed2171d012756ec1f9f9f0b4befa39f553fb41db7ea8beface/pyogrio-0.9.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:6dc94a67163218581c7df275223488ac9b31dc582ccd756da607c3338908566c", size = 16083649 }, - { url = "https://files.pythonhosted.org/packages/a2/02/ced7d7c24750f59ff78241d9adf424fbd295c130d9a287326fa1891738fa/pyogrio-0.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e38c3c6d37cf2cc969407e4d051dcb507cfd948eb26c7b0840c4f7d7d4a71bd4", size = 23119278 }, - { url = "https://files.pythonhosted.org/packages/60/d4/238db9a337af817ed4fe185238992d8a486f2bbb73d2aedf06bade90d5ff/pyogrio-0.9.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:f47c9b6818cc0f420015b672d5dcc488530a5ee63e5ba35a184957b21ea3922a", size = 22329476 }, - { url = "https://files.pythonhosted.org/packages/39/f6/340775c4833818621b75a978074f277b1d9831621c5789ba43e73f331c64/pyogrio-0.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb04bd80964428491951766452f0071b0bc37c7d38c45ef02502dbd83e5d74a0", size = 15916090 }, { url = "https://files.pythonhosted.org/packages/21/c2/f4ce7e004550a1ff74c83465fb9d11507f2d77dfab54203320e68fcd3c90/pyogrio-0.9.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f5d80eb846be4fc4e642cbedc1ed0c143e8d241653382ecc76a7620bbd2a5c3a", size = 14750921 }, { url = "https://files.pythonhosted.org/packages/70/b1/d04cdfe873f79fdf166c6bc8d774788bc9b981a1da61a24cb37d477f9c4e/pyogrio-0.9.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:2f2ec57ab74785db9c2bf47c0a6731e5175595a13f8253f06fa84136adb310a9", size = 16084054 }, { url = "https://files.pythonhosted.org/packages/9f/b1/3fe38d767f141a355e4fa60db18cdcb2c2d6d93ac118358eb7a8b32d6de6/pyogrio-0.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a289584da6df7ca318947301fe0ba9177e7f863f63110e087c80ac5f3658de8", size = 23293617 }, @@ -5698,16 +4525,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2d/61/9554c20853c45f157084e53b10380acc75f2aab52e65350c9c12e9613e2c/pyogrio-0.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f964002d445521ad5b8e732a6b5ef0e2d2be7fe566768e5075c1d71398da64a", size = 23262597 }, { url = "https://files.pythonhosted.org/packages/ed/22/0bd9af84c9aa6998fcf47deb68a1393109997c170ebee1300b1bb4d353ae/pyogrio-0.9.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:083351b258b3e08b6c6085dac560bd321b68de5cb4a66229095da68d5f3d696b", size = 22441210 }, { url = "https://files.pythonhosted.org/packages/c3/fa/45efa8c96744ddd92c3ce3a80ddba8512954cc7c5407876e2ff2ffea0c10/pyogrio-0.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:796e4f6a4e769b2eb6fea9a10546ea4bdee16182d1e29802b4d6349363c3c1d7", size = 15905657 }, - { url = "https://files.pythonhosted.org/packages/f7/b9/da97488c0bcba03ea13e455501eecb87318e56d63cd88fdf84f99ddfca95/pyogrio-0.9.0-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:7fcafed24371fe6e23bcf5abebbb29269f8d79915f1dd818ac85453657ea714a", size = 14748821 }, - { url = "https://files.pythonhosted.org/packages/98/9e/8734b86fbe60579c71a8d24919005a6915dccf4d94704447ee34994c556f/pyogrio-0.9.0-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:30cbeeaedb9bced7012487e7438919aa0c7dfba18ac3d4315182b46eb3139b9d", size = 16081859 }, - { url = "https://files.pythonhosted.org/packages/c4/61/090411fe84b9007b205a7ca43df4161e860fdbc05c5ba0514386775a7302/pyogrio-0.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4da0b9deb380bd9a200fee13182c4f95b02b4c554c923e2e0032f32aaf1439ed", size = 23168743 }, - { url = "https://files.pythonhosted.org/packages/6a/33/0b290d100f84c5441c8a2fb295747894932c4ea6368c52e4bf2aad4f1a67/pyogrio-0.9.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:4e0f90a6c3771ee1f1fea857778b4b6a1b64000d851b819f435f9091b3c38c60", size = 22384871 }, - { url = "https://files.pythonhosted.org/packages/24/87/f822f26db42450fbf4850cb313ee7457a2ab0ef0e6494ec06f1c32f0c3b1/pyogrio-0.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:959022f3ad04053f8072dc9a2ad110c46edd9e4f92352061ba835fc91df3ca96", size = 15944535 }, - { url = "https://files.pythonhosted.org/packages/2b/5c/83a2406c69cfb79136104abdec4413801f725f9d06c44560c0598b822cbd/pyogrio-0.9.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:2829615cf58b1b24a9f96fea42abedaa1a800dd351c67374cc2f6341138608f3", size = 14751187 }, - { url = "https://files.pythonhosted.org/packages/9c/c3/f9ad3251922e9b0ff672a4f7f04364c8f5644b0041009e53608f8ef70f90/pyogrio-0.9.0-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:17420febc17651876d5140b54b24749aa751d482b5f9ef6267b8053e6e962876", size = 16083763 }, - { url = "https://files.pythonhosted.org/packages/a0/f6/564e90bc8a07cb4895e15e396bc10aeb214a369cd9594f67672c93e1c111/pyogrio-0.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a2fcaa269031dbbc8ebd91243c6452c5d267d6df939c008ab7533413c9cf92d", size = 23114424 }, - { url = "https://files.pythonhosted.org/packages/21/2f/88b69cc7fd095d2c802843282cab554a9a5c7ff81ba929c402a75706c525/pyogrio-0.9.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:019731a856a9abfe909e86f50eb13f8362f6742337caf757c54b7c8acfe75b89", size = 22318694 }, - { url = "https://files.pythonhosted.org/packages/eb/4f/06e4b3ad1b300bfb863093a10614b1c014a4d7a955c14016087dd4269387/pyogrio-0.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:d668cb10f2bf6ccd7c402f91e8b06290722dd09dbe265ae95b2c13db29ebeba0", size = 15917284 }, ] [[distribution]] @@ -5721,11 +4538,6 @@ dependencies = [ { name = "pytools" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/df/7f/2aa3f9edc4e6ac47f4bc16d31b15b26b7ccf1c846f58f4e856d4642d4091/pyopencl-2024.2.7-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:6ad2524b2e411fd5e0357278db18cc24d65535557a377500b6de915ebc4666bd", size = 450745 }, - { url = "https://files.pythonhosted.org/packages/d7/9d/b7c5008f85b3cf55ec87c491df4968057de6d25214e7966fde24dc34699d/pyopencl-2024.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f74df6a07f46bfd213af5827a3c82edeab1d43413df28b0da4b44a923986ab0", size = 443045 }, - { url = "https://files.pythonhosted.org/packages/c3/3b/408eea99dc5733e2546387882f827c272dba8493e1d8dfb0ed38533ad336/pyopencl-2024.2.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e5876a32fc0a2c38e8a2eeb714eb7cb8720b04a20f49bb23274eb600a4390ac", size = 698147 }, - { url = "https://files.pythonhosted.org/packages/23/4c/c20942a7e2a597421be5e7adeb3d2c65697ecba6b7577e309b6d25a14ed8/pyopencl-2024.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:49a899205d7aa8d03a03578f7f7b3b8355a5bbddc530fc58ed7a84ed8217f8df", size = 1023339 }, - { url = "https://files.pythonhosted.org/packages/22/ed/7d21fab83eea089ead361fa76ed788eb371c79299d5ee030bfa9ae231a51/pyopencl-2024.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:465c4bdb17daf11d3cd4ab4e5ba4f87e5b2c4d9c04071bacc608857fab57ad6c", size = 489019 }, { url = "https://files.pythonhosted.org/packages/04/2b/0c830171d30de73c76a3ff92989959278d88d50e50e03b1ce5f1ffb04169/pyopencl-2024.2.7-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:31cc3907adb4d88e4b2cc05270054598a4544ed59539547a7eba11bb2304ea17", size = 450436 }, { url = "https://files.pythonhosted.org/packages/12/fc/db5f1a1c4251b8bc7ece6e55664b84de30d5fc71f4d505b5974082e366b3/pyopencl-2024.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a65049fa87b461fe35a28a35f63f33f7e8e5a9f2862c401a3dfaddf2597c6954", size = 442814 }, { url = "https://files.pythonhosted.org/packages/b2/fe/e91597055c9d38e654f60a359db88848be8c5ea845a5b5199d312248ee81/pyopencl-2024.2.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e891c16828d7702240429da667992639802407345e3b3d134054d06e006cb1e", size = 697975 }, @@ -5736,16 +4548,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a9/c1/5b42d9d23ddb7586a29df5c368071c3fd3078f7736d9c23d10a634cdf13a/pyopencl-2024.2.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dff4233a16f4809b236100902c58ac2b071a11955127b1798885ead739077b", size = 697909 }, { url = "https://files.pythonhosted.org/packages/67/6c/88b9d848f9b50bdc27c534efc8636b82f92a4d34b282bbc5cd58329fe31f/pyopencl-2024.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:69f58764bcde9d7c9a48aaabf831fcc0e8e54f5cc3ebf1806f392bb56f8c6d6d", size = 1023229 }, { url = "https://files.pythonhosted.org/packages/68/27/2078a4990e45e29b1fb09feb8ec0310e965ef0333e59174882107a813a1e/pyopencl-2024.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:59565d08cb03e03e6c63582dba849472846254465ba8ae532ff87aec0c41f4ea", size = 489398 }, - { url = "https://files.pythonhosted.org/packages/82/d4/9ed65bdf5fa4b529f8a5847e46d99b1d71c7a2e8003266709130e994670f/pyopencl-2024.2.7-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:5b466b17b9a268c0e5de80dfb05355d517c16988a4e4a802b3afbe142464a128", size = 449964 }, - { url = "https://files.pythonhosted.org/packages/ac/a0/f6640fc13d78070b3a5b7ae03ab1bea00cd460432c128100e953c36e3afb/pyopencl-2024.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:94c9693498c2eb84d26557a692cc03bcdb77d458b9a8c8eedf1c2aa128f826d6", size = 442423 }, - { url = "https://files.pythonhosted.org/packages/bf/70/08be160355597d2f0e4d6cb7437f9b645c2f15868ba99aba65aa0216594e/pyopencl-2024.2.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fcfff2bd54c04b0cf40c478d6883a912ebd2ab28d6881298f5031f11c4fea1", size = 698201 }, - { url = "https://files.pythonhosted.org/packages/09/44/f07c416552370a8d3e4770aa0d995343f04bb24568f80b8372cd3c0ee7e0/pyopencl-2024.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:38955c210cfc7f2bf7e94dcee505a233a6256c0812ef3f2b80d16bb644b70d21", size = 1023342 }, - { url = "https://files.pythonhosted.org/packages/ea/16/b148cd0dedd1916fe5837dcd653817bf189d53d0fd133b9ec1f4e3974def/pyopencl-2024.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:29ca194f6cb6c1ef373fc62eff6dd57e457c5f62a00cd3fb3059513b7e615000", size = 489022 }, - { url = "https://files.pythonhosted.org/packages/f5/9d/208e44e9fa88a0e88a24c00a4752b26a6b98d33cd709da93f546b1a1567f/pyopencl-2024.2.7-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b1aaf0ad28092ff42677dffb07c9112ef91bee58efa231131a50ab298a9f07df", size = 450955 }, - { url = "https://files.pythonhosted.org/packages/be/52/b09fd67764342725031ae3a2e14c0d0c46b04182088c28b586f684176fbd/pyopencl-2024.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3fe5c9b6cfe380256c97e80b56410ea47be8c770c88b6732f7f50f05714073d6", size = 443193 }, - { url = "https://files.pythonhosted.org/packages/fe/f2/c589895e159dcb693c9662b368378c79880b64eca78d8f27aaa50a337c3e/pyopencl-2024.2.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40ccd4321bb506b3042e00646cb3040216dd9148e97f5ed2445b741536cf373d", size = 698389 }, - { url = "https://files.pythonhosted.org/packages/f9/19/4f9b60f4fab1c9a0b8d9f3554f30cd25827c94b2e0849467593d00b9e4dd/pyopencl-2024.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e08d60e2f229ac9deda90edb38c491a5d58b38dac4d7e36d19e9f11e3f7c81cf", size = 1023536 }, - { url = "https://files.pythonhosted.org/packages/8d/af/2825d560e22236f9a55add0eea2782d024ad8f7ec4f4abfd1f6048b38ec4/pyopencl-2024.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:b0b6706c4e0ad87e90d2a2d3491632e64dab8d1f493ca96b3afb4c65e696cec8", size = 489416 }, ] [[distribution]] @@ -5790,12 +4592,6 @@ dependencies = [ { name = "certifi" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/32/63cf474f4a8d4804b3bdf7c16b8589f38142e8e2f8319dcea27e0bc21a87/pyproj-3.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ab7aa4d9ff3c3acf60d4b285ccec134167a948df02347585fdd934ebad8811b4", size = 6142763 }, - { url = "https://files.pythonhosted.org/packages/18/86/2e7cb9de40492f1bafbf11f4c9072edc394509a40b5e4c52f8139546f039/pyproj-3.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4bc0472302919e59114aa140fd7213c2370d848a7249d09704f10f5b062031fe", size = 4877123 }, - { url = "https://files.pythonhosted.org/packages/5e/c5/928d5a26995dbefbebd7507d982141cd9153bc7e4392b334fff722c4af12/pyproj-3.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5279586013b8d6582e22b6f9e30c49796966770389a9d5b85e25a4223286cd3f", size = 6190576 }, - { url = "https://files.pythonhosted.org/packages/f6/2b/b60cf73b0720abca313bfffef34e34f7f7dae23852b2853cf0368d49426b/pyproj-3.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80fafd1f3eb421694857f254a9bdbacd1eb22fc6c24ca74b136679f376f97d35", size = 8328075 }, - { url = "https://files.pythonhosted.org/packages/d9/a8/7193f46032636be917bc775506ae987aad72c931b1f691b775ca812a2917/pyproj-3.6.1-cp310-cp310-win32.whl", hash = "sha256:c41e80ddee130450dcb8829af7118f1ab69eaf8169c4bf0ee8d52b72f098dc2f", size = 5635713 }, - { url = "https://files.pythonhosted.org/packages/89/8f/27350c8fba71a37cd0d316f100fbd96bf139cc2b5ff1ab0dcbc7ac64010a/pyproj-3.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:db3aedd458e7f7f21d8176f0a1d924f1ae06d725228302b872885a1c34f3119e", size = 6087932 }, { url = "https://files.pythonhosted.org/packages/84/a6/a300c1b14b2112e966e9f90b18f9c13b586bdcf417207cee913ae9005da3/pyproj-3.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ebfbdbd0936e178091309f6cd4fcb4decd9eab12aa513cdd9add89efa3ec2882", size = 6147442 }, { url = "https://files.pythonhosted.org/packages/30/bd/b9bd3761f08754e8dbb34c5a647db2099b348ab5da338e90980caf280e37/pyproj-3.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:447db19c7efad70ff161e5e46a54ab9cc2399acebb656b6ccf63e4bc4a04b97a", size = 4880331 }, { url = "https://files.pythonhosted.org/packages/f4/0a/d82aeeb605b5d6870bc72307c3b5e044e632eb7720df8885e144f51a8eac/pyproj-3.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7e13c40183884ec7f94eb8e0f622f08f1d5716150b8d7a134de48c6110fee85", size = 6192425 }, @@ -5808,14 +4604,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/19/9b/c57569132174786aa3f72275ac306956859a639dad0ce8d95c8411ce8209/pyproj-3.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb059ba3bced6f6725961ba758649261d85ed6ce670d3e3b0a26e81cf1aa8d", size = 8660747 }, { url = "https://files.pythonhosted.org/packages/0e/ab/1c2159ec757677c5a6b8803f6be45c2b550dc42c84ec4a228dc219849bbb/pyproj-3.6.1-cp312-cp312-win32.whl", hash = "sha256:2d6ff73cc6dbbce3766b6c0bce70ce070193105d8de17aa2470009463682a8eb", size = 5626805 }, { url = "https://files.pythonhosted.org/packages/c7/f3/2f32fe143cd7ba1d4d68f1b6dce9ca402d909cbd5a5830e3a8fa3d1acbbf/pyproj-3.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:7a27151ddad8e1439ba70c9b4b2b617b290c39395fa9ddb7411ebb0eb86d6fb0", size = 6079779 }, - { url = "https://files.pythonhosted.org/packages/d7/50/d369bbe62d7a0d1e2cb40bc211da86a3f6e0f3c99f872957a72c3d5492d6/pyproj-3.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4ba1f9b03d04d8cab24d6375609070580a26ce76eaed54631f03bab00a9c737b", size = 6144755 }, - { url = "https://files.pythonhosted.org/packages/2c/c2/8d4f61065dfed965e53badd41201ad86a05af0c1bbc75dffb12ef0f5a7dd/pyproj-3.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18faa54a3ca475bfe6255156f2f2874e9a1c8917b0004eee9f664b86ccc513d3", size = 4879187 }, - { url = "https://files.pythonhosted.org/packages/31/38/2cf8777cb2d5622a78195e690281b7029098795fde4751aec8128238b8bb/pyproj-3.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd43bd9a9b9239805f406fd82ba6b106bf4838d9ef37c167d3ed70383943ade1", size = 6192339 }, - { url = "https://files.pythonhosted.org/packages/97/0a/b1525be9680369cc06dd288e12c59d24d5798b4afcdcf1b0915836e1caa6/pyproj-3.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50100b2726a3ca946906cbaa789dd0749f213abf0cbb877e6de72ca7aa50e1ae", size = 8332638 }, - { url = "https://files.pythonhosted.org/packages/8d/e8/e826e0a962f36bd925a933829cf6ef218efe2055db5ea292be40974a929d/pyproj-3.6.1-cp39-cp39-win32.whl", hash = "sha256:9274880263256f6292ff644ca92c46d96aa7e57a75c6df3f11d636ce845a1877", size = 5638159 }, - { url = "https://files.pythonhosted.org/packages/43/d0/cbe29a4dcf38ee7e72bf695d0d3f2bee21b4f22ee6cf579ad974de9edfc8/pyproj-3.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:36b64c2cb6ea1cc091f329c5bd34f9c01bb5da8c8e4492c709bda6a09f96808f", size = 6090565 }, - { url = "https://files.pythonhosted.org/packages/43/28/e8d2ca71dd56c27cbe668e4226963d61956cded222a2e839e6fec1ab6d82/pyproj-3.6.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd93c1a0c6c4aedc77c0fe275a9f2aba4d59b8acf88cebfc19fe3c430cfabf4f", size = 6034252 }, - { url = "https://files.pythonhosted.org/packages/cb/39/1ce27cb86f51a1f5aed3a1617802a6131b59ea78492141d1fbe36722595e/pyproj-3.6.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6420ea8e7d2a88cb148b124429fba8cd2e0fae700a2d96eab7083c0928a85110", size = 6386263 }, ] [[distribution]] @@ -5839,10 +4627,6 @@ version = "12.13.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ee/81/fce2a475aa56c1f49707d9306b930695b6ff078c2242c9f2fd72a3214e1f/PyQt5_sip-12.13.0.tar.gz", hash = "sha256:7f321daf84b9c9dbca61b80e1ef37bdaffc0e93312edae2cd7da25b953971d91", size = 123225 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/08/5746a53447b75f4024324e9409d8c17d005ae94596cb8d1a1da7fd702de6/PyQt5_sip-12.13.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a7e3623b2c743753625c4650ec7696362a37fb36433b61824cf257f6d3d43cca", size = 144380 }, - { url = "https://files.pythonhosted.org/packages/c9/d5/2537affe91240214b4b84616ef6abe545bca6a56302280cad5e08062b23b/PyQt5_sip-12.13.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6e4ac714252370ca037c7d609da92388057165edd4f94e63354f6d65c3ed9d53", size = 338140 }, - { url = "https://files.pythonhosted.org/packages/56/d3/8d27ce7bed0139c0408ff7a662adeca567ec8b9c111e085eb90d91e4bed7/PyQt5_sip-12.13.0-cp310-cp310-win32.whl", hash = "sha256:d5032da3fff62da055104926ffe76fd6044c1221f8ad35bb60804bcb422fe866", size = 68692 }, - { url = "https://files.pythonhosted.org/packages/f3/0c/69bda293d75b3169515400820d2fa11d0ccde31046c48c48c5e9c8549d69/PyQt5_sip-12.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:9a8cdd6cb66adcbe5c941723ed1544eba05cf19b6c961851b58ccdae1c894afb", size = 78471 }, { url = "https://files.pythonhosted.org/packages/bc/de/fff654a38821e42beb914ecca72c4ac0ae3dab1f94666ae8015a152a197f/PyQt5_sip-12.13.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0f85fb633a522f04e48008de49dce1ff1d947011b48885b8428838973fbca412", size = 144454 }, { url = "https://files.pythonhosted.org/packages/ca/b0/5af957d148693e1d1b1e2e33c51dd9c8a3c29f7ac21008684d612c0b86c3/PyQt5_sip-12.13.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ec60162e034c42fb99859206d62b83b74f987d58937b3a82bdc07b5c3d190dec", size = 346673 }, { url = "https://files.pythonhosted.org/packages/d8/04/8682c882bb0adbc73dd5cf191c486cc2680acb53ffca312f254a806baf15/PyQt5_sip-12.13.0-cp311-cp311-win32.whl", hash = "sha256:205cd449d08a2b024a468fb6100cd7ed03e946b4f49706f508944006f955ae1a", size = 68704 }, @@ -5851,14 +4635,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3c/ab/f8f1e970768fcb4ab118d4aabbfcb9b7f781088b71e1f26d813fd51c4701/PyQt5_sip-12.13.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:773731b1b5ab1a7cf5621249f2379c95e3d2905e9bd96ff3611b119586daa876", size = 360986 }, { url = "https://files.pythonhosted.org/packages/46/e1/70222aac7ed23f85b54e69507fb5256e53be1205bdc4f678463f2ed74aa2/PyQt5_sip-12.13.0-cp312-cp312-win32.whl", hash = "sha256:fb4a5271fa3f6bc2feb303269a837a95a6d8dd16be553aa40e530de7fb81bfdf", size = 69214 }, { url = "https://files.pythonhosted.org/packages/dd/88/41bab90e8cde04220d9fb688750d69441633a8c570638e7b204ebf63ab01/PyQt5_sip-12.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:3a4498f3b1b15f43f5d12963accdce0fd652b0bcaae6baf8008663365827444c", size = 77706 }, - { url = "https://files.pythonhosted.org/packages/c8/26/81bdb1df1cbf8807b94c753f75882323ed618c3623224eb6b386564066ca/PyQt5_sip-12.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9b984c2620a7a7eaf049221b09ae50a345317add2624c706c7d2e9e6632a9587", size = 85411 }, - { url = "https://files.pythonhosted.org/packages/d6/06/0d34b0f57e1c9d3b6ea1ce8157153b009efd8eefa87dbb9ffb7e909c0c78/PyQt5_sip-12.13.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3188a06956aef86f604fb0d14421a110fad70d2a9e943dbacbfc3303f651dade", size = 335458 }, - { url = "https://files.pythonhosted.org/packages/ab/c2/f5908a64a5b1445471c94b2fa2c8953df1cdb3f9e7a73fe232fcba56aefa/PyQt5_sip-12.13.0-cp38-cp38-win32.whl", hash = "sha256:108a15f603e1886988c4b0d9d41cb74c9f9815bf05cefc843d559e8c298a10ce", size = 68554 }, - { url = "https://files.pythonhosted.org/packages/88/cd/dd21cdb92d053ca71c02c75ab7bd32874b82b33bef61d6d70b5d898e684b/PyQt5_sip-12.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:db228cd737f5cbfc66a3c3e50042140cb80b30b52edc5756dbbaa2346ec73137", size = 78263 }, - { url = "https://files.pythonhosted.org/packages/cf/00/442b0fd2ae8d88eece790856b71b35f2a0cf467e63d7adfc4512cd50ef44/PyQt5_sip-12.13.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5338773bbaedaa4f16a73c142fb23cc18c327be6c338813af70260b756c7bc92", size = 144366 }, - { url = "https://files.pythonhosted.org/packages/51/ba/fcd923fc4ca1247daa76cf024f647014ef266238326dc07cc0ec02d7efc9/PyQt5_sip-12.13.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:29fa9cc964517c9fc3f94f072b9a2aeef4e7a2eda1879cb835d9e06971161cdf", size = 335709 }, - { url = "https://files.pythonhosted.org/packages/ed/dd/15c6aeaec1391c7784dbe30c35267b1991e65540e51cc4e7028387103c55/PyQt5_sip-12.13.0-cp39-cp39-win32.whl", hash = "sha256:96414c93f3d33963887cf562d50d88b955121fbfd73f937c8eca46643e77bf61", size = 68589 }, - { url = "https://files.pythonhosted.org/packages/a5/d5/657447dc60ee79447781543c967dbd5500ae729730fe76126236ff26b72d/PyQt5_sip-12.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:bbc7cd498bf19e0862097be1ad2243e824dea56726f00c11cff1b547c2d31d01", size = 78513 }, ] [[distribution]] @@ -5985,15 +4761,15 @@ wheels = [ [[distribution]] name = "pytest-subtests" -version = "0.12.1" +version = "0.13.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/e1/07e3f31938c689dcf368fcb0e58d2285e6da158cc2dc2b419f18c4218303/pytest-subtests-0.12.1.tar.gz", hash = "sha256:d6605dcb88647e0b7c1889d027f8ef1c17d7a2c60927ebfdc09c7b0d8120476d", size = 15303 } +sdist = { url = "https://files.pythonhosted.org/packages/95/be/cebc1b9f6358d174443f46737979e244048a385fe2b0be6fab2b96771dc5/pytest_subtests-0.13.0.tar.gz", hash = "sha256:9e02b9d243c0379b02abf3e0887da122bcb2714b021c3608a37f17ce210adce5", size = 15842 } dependencies = [ { name = "attrs" }, { name = "pytest" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/a9/0afec13651a03a4c00bce27aa80ede29fbff469ea8021a71dfbcfbd48054/pytest_subtests-0.12.1-py3-none-any.whl", hash = "sha256:100d9f7eb966fc98efba7026c802812ae327e8b5b37181fb260a2ea93226495c", size = 7524 }, + { url = "https://files.pythonhosted.org/packages/74/19/9fd9ff6e8827983bcfc74a39c4a98ab6b4c32b3f3403b917f352f7b83777/pytest_subtests-0.13.0-py3-none-any.whl", hash = "sha256:5a142064218df37a52299ddb393b1a6b2c1161ca19e71ca60c3a8040eb17e811", size = 8038 }, ] [[distribution]] @@ -6083,20 +4859,12 @@ name = "pywin32" version = "306" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/dc/28c668097edfaf4eac4617ef7adf081b9cf50d254672fcf399a70f5efc41/pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d", size = 8506422 }, - { url = "https://files.pythonhosted.org/packages/d3/d6/891894edec688e72c2e308b3243fad98b4066e1839fd2fe78f04129a9d31/pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8", size = 9226392 }, { url = "https://files.pythonhosted.org/packages/8b/1e/fc18ad83ca553e01b97aa8393ff10e33c1fb57801db05488b83282ee9913/pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407", size = 8507689 }, { url = "https://files.pythonhosted.org/packages/7e/9e/ad6b1ae2a5ad1066dc509350e0fbf74d8d50251a51e420a2a8feaa0cecbd/pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e", size = 9227547 }, { url = "https://files.pythonhosted.org/packages/91/20/f744bff1da8f43388498503634378dbbefbe493e65675f2cc52f7185c2c2/pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a", size = 10388324 }, { url = "https://files.pythonhosted.org/packages/14/91/17e016d5923e178346aabda3dfec6629d1a26efe587d19667542105cf0a6/pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b", size = 8507705 }, { url = "https://files.pythonhosted.org/packages/83/1c/25b79fc3ec99b19b0a0730cc47356f7e2959863bf9f3cd314332bddb4f68/pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e", size = 9227429 }, { url = "https://files.pythonhosted.org/packages/1c/43/e3444dc9a12f8365d9603c2145d16bf0a2f8180f343cf87be47f5579e547/pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040", size = 10388145 }, - { url = "https://files.pythonhosted.org/packages/28/19/6b8f416ff02132c404042f251eb90a41d15abe677481fcff22077e943c6f/pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65", size = 8612400 }, - { url = "https://files.pythonhosted.org/packages/80/e6/08192cb5728a6ffdb70ea990d9a1351b320d31a751bb463e652d9e05e7aa/pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36", size = 9334533 }, - { url = "https://files.pythonhosted.org/packages/0e/57/c3ec32b498f24a2392404d1f0fd29f47a3f7339d7d579df7a0560cff337c/pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a", size = 8632118 }, - { url = "https://files.pythonhosted.org/packages/fa/80/a6b22e031590cc5f4fcbd5bf4bcf63a9dabce9d59065f53add99a8caaec5/pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0", size = 9373699 }, - { url = "https://files.pythonhosted.org/packages/7e/7f/419c4fcadcaa374a0ae41cbdf6c3a81452892dd6c523aea629d17e49146e/pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802", size = 8573451 }, - { url = "https://files.pythonhosted.org/packages/1c/f7/24d8ed4fd9c43b90354df7764f81f0dd5e623f9a50f1538f90fe085d6dff/pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4", size = 9312883 }, ] [[distribution]] @@ -6137,14 +4905,6 @@ version = "6.0.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/cd/e5/af35f7ea75cf72f2cd079c95ee16797de7cd71f29ea7c68ae5ce7be1eda0/PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", size = 125201 } wheels = [ - { url = "https://files.pythonhosted.org/packages/96/06/4beb652c0fe16834032e54f0956443d4cc797fe645527acee59e7deaa0a2/PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", size = 189447 }, - { url = "https://files.pythonhosted.org/packages/5b/07/10033a403b23405a8fc48975444463d3d10a5c2736b7eb2550b07b367429/PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f", size = 169264 }, - { url = "https://files.pythonhosted.org/packages/f1/26/55e4f21db1f72eaef092015d9017c11510e7e6301c62a6cfee91295d13c6/PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", size = 677003 }, - { url = "https://files.pythonhosted.org/packages/ba/91/090818dfa62e85181f3ae23dd1e8b7ea7f09684864a900cab72d29c57346/PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", size = 699070 }, - { url = "https://files.pythonhosted.org/packages/29/61/bf33c6c85c55bc45a29eee3195848ff2d518d84735eb0e2d8cb42e0d285e/PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", size = 705525 }, - { url = "https://files.pythonhosted.org/packages/07/91/45dfd0ef821a7f41d9d0136ea3608bb5b1653e42fd56a7970532cb5c003f/PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", size = 707514 }, - { url = "https://files.pythonhosted.org/packages/b6/a0/b6700da5d49e9fed49dc3243d3771b598dad07abb37cc32e524607f96adc/PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", size = 130488 }, - { url = "https://files.pythonhosted.org/packages/24/97/9b59b43431f98d01806b288532da38099cc6f2fea0f3d712e21e269c0279/PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", size = 145338 }, { url = "https://files.pythonhosted.org/packages/ec/0d/26fb23e8863e0aeaac0c64e03fd27367ad2ae3f3cccf3798ee98ce160368/PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", size = 187867 }, { url = "https://files.pythonhosted.org/packages/28/09/55f715ddbf95a054b764b547f617e22f1d5e45d83905660e9a088078fe67/PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", size = 167530 }, { url = "https://files.pythonhosted.org/packages/5e/94/7d5ee059dfb92ca9e62f4057dcdec9ac08a9e42679644854dc01177f8145/PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", size = 732244 }, @@ -6160,33 +4920,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4f/78/77b40157b6cb5f2d3d31a3d9b2efd1ba3505371f76730d267e8b32cf4b7f/PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", size = 712604 }, { url = "https://files.pythonhosted.org/packages/2e/97/3e0e089ee85e840f4b15bfa00e4e63d84a3691ababbfea92d6f820ea6f21/PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", size = 126098 }, { url = "https://files.pythonhosted.org/packages/2b/9f/fbade56564ad486809c27b322d0f7e6a89c01f6b4fe208402e90d4443a99/PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", size = 138675 }, - { url = "https://files.pythonhosted.org/packages/02/74/b2320ebe006b6a521cf929c78f12a220b9db319b38165023623ed195654b/PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", size = 189453 }, - { url = "https://files.pythonhosted.org/packages/03/f7/4f8b71f3ce8cfb2c06e814aeda5b26ecc62ecb5cf85f5c8898be34e6eb6a/PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", size = 669628 }, - { url = "https://files.pythonhosted.org/packages/fe/88/def2e57fe740544f2eefb1645f1d6e0094f56c00f4eade708140b6137ead/PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", size = 694933 }, - { url = "https://files.pythonhosted.org/packages/62/2a/df7727c52e151f9e7b852d7d1580c37bd9e39b2f29568f0f81b29ed0abc2/PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", size = 677167 }, - { url = "https://files.pythonhosted.org/packages/41/9a/1c4c51f1a0d2b6fd805973701ab0ec84d5e622c5aaa573b0e1157f132809/PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", size = 137460 }, - { url = "https://files.pythonhosted.org/packages/27/d5/fb4f7a3c96af89c214387af42c76117d2c2a0a40576e217632548a6e1aff/PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", size = 153098 }, - { url = "https://files.pythonhosted.org/packages/c7/d1/02baa09d39b1bb1ebaf0d850d106d1bdcb47c91958557f471153c49dc03b/PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", size = 189627 }, - { url = "https://files.pythonhosted.org/packages/e5/31/ba812efa640a264dbefd258986a5e4e786230cb1ee4a9f54eb28ca01e14a/PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", size = 658438 }, - { url = "https://files.pythonhosted.org/packages/4d/f1/08f06159739254c8947899c9fc901241614195db15ba8802ff142237664c/PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", size = 680304 }, - { url = "https://files.pythonhosted.org/packages/d7/8f/db62b0df635b9008fe90aa68424e99cee05e68b398740c8a666a98455589/PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", size = 670140 }, - { url = "https://files.pythonhosted.org/packages/cc/5c/fcabd17918348c7db2eeeb0575705aaf3f7ab1657f6ce29b2e31737dd5d1/PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", size = 137577 }, - { url = "https://files.pythonhosted.org/packages/1e/ae/964ccb88a938f20ece5754878f182cfbd846924930d02d29d06af8d4c69e/PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", size = 153248 }, - { url = "https://files.pythonhosted.org/packages/7f/5d/2779ea035ba1e533c32ed4a249b4e0448f583ba10830b21a3cddafe11a4e/PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", size = 191734 }, - { url = "https://files.pythonhosted.org/packages/e1/a1/27bfac14b90adaaccf8c8289f441e9f76d94795ec1e7a8f134d9f2cb3d0b/PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", size = 723767 }, - { url = "https://files.pythonhosted.org/packages/c1/39/47ed4d65beec9ce07267b014be85ed9c204fa373515355d3efa62d19d892/PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", size = 749067 }, - { url = "https://files.pythonhosted.org/packages/c8/6b/6600ac24725c7388255b2f5add93f91e58a5d7efaf4af244fdbcc11a541b/PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", size = 736569 }, - { url = "https://files.pythonhosted.org/packages/0d/46/62ae77677e532c0af6c81ddd6f3dbc16bdcc1208b077457354442d220bfb/PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", size = 787738 }, - { url = "https://files.pythonhosted.org/packages/d6/6a/439d1a6f834b9a9db16332ce16c4a96dd0e3970b65fe08cbecd1711eeb77/PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", size = 139797 }, - { url = "https://files.pythonhosted.org/packages/29/0f/9782fa5b10152abf033aec56a601177ead85ee03b57781f2d9fced09eefc/PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", size = 157350 }, - { url = "https://files.pythonhosted.org/packages/57/c5/5d09b66b41d549914802f482a2118d925d876dc2a35b2d127694c1345c34/PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", size = 197846 }, - { url = "https://files.pythonhosted.org/packages/0e/88/21b2f16cb2123c1e9375f2c93486e35fdc86e63f02e274f0e99c589ef153/PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", size = 174396 }, - { url = "https://files.pythonhosted.org/packages/ac/6c/967d91a8edf98d2b2b01d149bd9e51b8f9fb527c98d80ebb60c6b21d60c4/PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", size = 731824 }, - { url = "https://files.pythonhosted.org/packages/4a/4b/c71ef18ef83c82f99e6da8332910692af78ea32bd1d1d76c9787dfa36aea/PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", size = 754777 }, - { url = "https://files.pythonhosted.org/packages/7d/39/472f2554a0f1e825bd7c5afc11c817cd7a2f3657460f7159f691fbb37c51/PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", size = 738883 }, - { url = "https://files.pythonhosted.org/packages/40/da/a175a35cf5583580e90ac3e2a3dbca90e43011593ae62ce63f79d7b28d92/PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", size = 750294 }, - { url = "https://files.pythonhosted.org/packages/24/62/7fcc372442ec8ea331da18c24b13710e010c5073ab851ef36bf9dacb283f/PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", size = 136936 }, - { url = "https://files.pythonhosted.org/packages/84/4d/82704d1ab9290b03da94e6425f5e87396b999fd7eb8e08f3a92c158402bf/PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", size = 152751 }, ] [[distribution]] @@ -6210,18 +4943,6 @@ dependencies = [ { name = "cffi", marker = "implementation_name == 'pypy'" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/56/81/75e659b02ed9b8e8675fd9e3d6e9e3b37860788f65829c2d521034f8b259/pyzmq-26.0.3-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:44dd6fc3034f1eaa72ece33588867df9e006a7303725a12d64c3dff92330f625", size = 1392625 }, - { url = "https://files.pythonhosted.org/packages/da/1b/5ce0293717cf3a2c341501dd5a7456dde80b8f309dd727ccc64dcd5d34b7/pyzmq-26.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:acb704195a71ac5ea5ecf2811c9ee19ecdc62b91878528302dd0be1b9451cc90", size = 1060044 }, - { url = "https://files.pythonhosted.org/packages/65/e1/0e9d05cb6ddf7afa9c0cf9b207e355c9bcdb4b7414ce2787800b6c2f1eed/pyzmq-26.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbb9c997932473a27afa93954bb77a9f9b786b4ccf718d903f35da3232317de", size = 723684 }, - { url = "https://files.pythonhosted.org/packages/a5/98/5f746e33fc3b5ee6699095d016102505e0730c5afc445c0f90a34062b685/pyzmq-26.0.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bcb34f869d431799c3ee7d516554797f7760cb2198ecaa89c3f176f72d062be", size = 962416 }, - { url = "https://files.pythonhosted.org/packages/c4/0f/24ff63c1bc2cdbde7a703fcb35031d1bfa73f0e27e81235952c3b66636c6/pyzmq-26.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ece17ec5f20d7d9b442e5174ae9f020365d01ba7c112205a4d59cf19dc38ee", size = 919841 }, - { url = "https://files.pythonhosted.org/packages/40/4f/088d0fe18b188a0754483b7d632a97ef608dce80c2648219d071c9f1715c/pyzmq-26.0.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ba6e5e6588e49139a0979d03a7deb9c734bde647b9a8808f26acf9c547cab1bf", size = 919801 }, - { url = "https://files.pythonhosted.org/packages/eb/f6/9911bcd104547396f48ed65f274624831fe4526380a292453dd87b95527c/pyzmq-26.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3bf8b000a4e2967e6dfdd8656cd0757d18c7e5ce3d16339e550bd462f4857e59", size = 1254065 }, - { url = "https://files.pythonhosted.org/packages/e9/34/bc58392501f1342232cae269afbaf290f1422098f3b8f685cf829e796c7b/pyzmq-26.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2136f64fbb86451dbbf70223635a468272dd20075f988a102bf8a3f194a411dc", size = 1565530 }, - { url = "https://files.pythonhosted.org/packages/8c/ad/7e6e5a78735108dd691967593ddff1d24f8223d094a4683e3316da5a9fe1/pyzmq-26.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e8918973fbd34e7814f59143c5f600ecd38b8038161239fd1a3d33d5817a38b8", size = 1465390 }, - { url = "https://files.pythonhosted.org/packages/73/9d/2aab0be1f9a82a46205294f74ca9f66f29482fe038ef6d7fd0963d97b3a7/pyzmq-26.0.3-cp310-cp310-win32.whl", hash = "sha256:0aaf982e68a7ac284377d051c742610220fd06d330dcd4c4dbb4cdd77c22a537", size = 681026 }, - { url = "https://files.pythonhosted.org/packages/85/e7/fd7f3564525f16460720c483ae3b9cc3bd3a3e7571bdbd1649e995a7d0e0/pyzmq-26.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:f1a9b7d00fdf60b4039f4455afd031fe85ee8305b019334b72dcf73c567edc47", size = 773727 }, - { url = "https://files.pythonhosted.org/packages/2a/a0/fca2f7ad38d573d1421ac20597e5ddffd5625feb370bea32d760675f181f/pyzmq-26.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:80b12f25d805a919d53efc0a5ad7c0c0326f13b4eae981a5d7b7cc343318ebb7", size = 862468 }, { url = "https://files.pythonhosted.org/packages/4b/60/4e5170ffdf1720791752f09261a813efd5e59ec8ccf3e909d50d62a13b7d/pyzmq-26.0.3-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:a72a84570f84c374b4c287183debc776dc319d3e8ce6b6a0041ce2e400de3f32", size = 1393498 }, { url = "https://files.pythonhosted.org/packages/33/fa/e35e8c9e677604bbaa15e0f5887a5c0b031361ae25c6a3577c4720e106c2/pyzmq-26.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ca684ee649b55fd8f378127ac8462fb6c85f251c2fb027eb3c887e8ee347bcd", size = 1060015 }, { url = "https://files.pythonhosted.org/packages/e5/b5/625e45790a1b091f54d5d47fd267d051cabdec4f01144f6b2fcb7306515b/pyzmq-26.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e222562dc0f38571c8b1ffdae9d7adb866363134299264a1958d077800b193b7", size = 723307 }, @@ -6246,57 +4967,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/76/e2/69fce04f1c7d6767c05dc9f83c8bbb915209f6eb245d04109b2d4ada3c12/pyzmq-26.0.3-cp312-cp312-win32.whl", hash = "sha256:2b291d1230845871c00c8462c50565a9cd6026fe1228e77ca934470bb7d70ea0", size = 678713 }, { url = "https://files.pythonhosted.org/packages/6c/45/905ec497208808aa0ba2470b2ab36d779b53f4016617feca93baffb6ba7f/pyzmq-26.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:926838a535c2c1ea21c903f909a9a54e675c2126728c21381a94ddf37c3cbddf", size = 770140 }, { url = "https://files.pythonhosted.org/packages/f6/21/3becf31685c26c455cd1b5b4ba4bd46a07fdd38e735aa3f41d9b6beb4a9a/pyzmq-26.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:5bf6c237f8c681dfb91b17f8435b2735951f0d1fad10cc5dfd96db110243370b", size = 859695 }, - { url = "https://files.pythonhosted.org/packages/7f/d6/ede4df566e890dbf0c53330557e8a2f57780049649fab36cd67f4aee211d/pyzmq-26.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c0991f5a96a8e620f7691e61178cd8f457b49e17b7d9cfa2067e2a0a89fc1d5", size = 1057718 }, - { url = "https://files.pythonhosted.org/packages/58/93/1ad68e657f84159800bf46a6c36348220960cfa49999ed7e8abd165dad04/pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dbf012d8fcb9f2cf0643b65df3b355fdd74fc0035d70bb5c845e9e30a3a4654b", size = 957067 }, - { url = "https://files.pythonhosted.org/packages/b3/dc/652c216779bf7d6143ebaa463003ad536e6f7cc32a841771309332e6b8e3/pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:01fbfbeb8249a68d257f601deb50c70c929dc2dfe683b754659569e502fbd3aa", size = 908960 }, - { url = "https://files.pythonhosted.org/packages/e3/a8/6a7580ce2c497f82f3eca2de2d2e9a312fafac8c53a3ba1b7a9ef5a6769a/pyzmq-26.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c8eb19abe87029c18f226d42b8a2c9efdd139d08f8bf6e085dd9075446db450", size = 723433 }, - { url = "https://files.pythonhosted.org/packages/f9/df/846c90d1c230d1baa81118130fb900395c51f7e2036d0c2a590728c79e9a/pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5344b896e79800af86ad643408ca9aa303a017f6ebff8cee5a3163c1e9aec987", size = 1256840 }, - { url = "https://files.pythonhosted.org/packages/ee/d9/7bbb276d659f124735dbaa39dafecaa6d7fd6c681cfa5c0bc87751312c5e/pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:204e0f176fd1d067671157d049466869b3ae1fc51e354708b0dc41cf94e23a3a", size = 1566810 }, - { url = "https://files.pythonhosted.org/packages/3d/ac/5f2adbca1874c0b18815e30a64aa96be85f20e3a18347289d8ed6d8f1037/pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a42db008d58530efa3b881eeee4991146de0b790e095f7ae43ba5cc612decbc5", size = 1465895 }, - { url = "https://files.pythonhosted.org/packages/75/41/126d3ae28225d1178691013a177b40903cd9a9088779ff972dd9b7d0099a/pyzmq-26.0.3-cp37-cp37m-win32.whl", hash = "sha256:8d7a498671ca87e32b54cb47c82a92b40130a26c5197d392720a1bce1b3c77cf", size = 681076 }, - { url = "https://files.pythonhosted.org/packages/2b/67/f6569c49cf522594ab155487755a0c21b1682f2038466d0a3de6b7efaec1/pyzmq-26.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:3b4032a96410bdc760061b14ed6a33613ffb7f702181ba999df5d16fb96ba16a", size = 799900 }, - { url = "https://files.pythonhosted.org/packages/84/8e/b51abddf5ccc0a2c330a9ac570ec4c41583d3a1c97e955b76d230b609e6e/pyzmq-26.0.3-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:2cc4e280098c1b192c42a849de8de2c8e0f3a84086a76ec5b07bfee29bda7d18", size = 1392960 }, - { url = "https://files.pythonhosted.org/packages/71/04/2d3ad27df7408c8d35123bc3ffad998deef223b562160f07f6ae1e42fb36/pyzmq-26.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5bde86a2ed3ce587fa2b207424ce15b9a83a9fa14422dcc1c5356a13aed3df9d", size = 1059377 }, - { url = "https://files.pythonhosted.org/packages/e2/8e/e0e1035e80854794bb766b3f2c81fea3d89def4b6e06574f2d8cf411cb5d/pyzmq-26.0.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:34106f68e20e6ff253c9f596ea50397dbd8699828d55e8fa18bd4323d8d966e6", size = 958317 }, - { url = "https://files.pythonhosted.org/packages/49/4b/01c0d1e8279a12dd40b690fd41b1f078d551631fa650351a5d6748c01a8d/pyzmq-26.0.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ebbbd0e728af5db9b04e56389e2299a57ea8b9dd15c9759153ee2455b32be6ad", size = 912770 }, - { url = "https://files.pythonhosted.org/packages/01/ff/f6dee688fe845f213a9feebf3aae3a2bc9a6e4b3086fb3d1f23472f1c5d0/pyzmq-26.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6b1d1c631e5940cac5a0b22c5379c86e8df6a4ec277c7a856b714021ab6cfad", size = 724564 }, - { url = "https://files.pythonhosted.org/packages/7d/fc/0401ca39c31c0d3a29beaa7d0f4428bbf13eea09bbab352872f10eebc797/pyzmq-26.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e891ce81edd463b3b4c3b885c5603c00141151dd9c6936d98a680c8c72fe5c67", size = 1257295 }, - { url = "https://files.pythonhosted.org/packages/10/de/ac4267080805b2df0e97ce5a10515af108b71fa725c637457db2bc1517d1/pyzmq-26.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9b273ecfbc590a1b98f014ae41e5cf723932f3b53ba9367cfb676f838038b32c", size = 1566613 }, - { url = "https://files.pythonhosted.org/packages/e6/f8/dbbd6b02524ff5a36983b1e6bcf6eca1f1816e70f2afe653f1c755fe0a28/pyzmq-26.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b32bff85fb02a75ea0b68f21e2412255b5731f3f389ed9aecc13a6752f58ac97", size = 1468256 }, - { url = "https://files.pythonhosted.org/packages/9b/9b/88891279f292e1f1402fbc817efd643235e2f0f5e84f36e11242d802f917/pyzmq-26.0.3-cp38-cp38-win32.whl", hash = "sha256:f6c21c00478a7bea93caaaef9e7629145d4153b15a8653e8bb4609d4bc70dbfc", size = 681706 }, - { url = "https://files.pythonhosted.org/packages/d6/dd/f288efb66810aabdab54cc347a2271ce43c6ed851ba0e051464f2b8f2f55/pyzmq-26.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:3401613148d93ef0fd9aabdbddb212de3db7a4475367f49f590c837355343972", size = 801731 }, - { url = "https://files.pythonhosted.org/packages/32/7f/77324143424424b8dccd5f0e2ec5676f388667d1b38f9c4b30cdb706fef1/pyzmq-26.0.3-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:2ed8357f4c6e0daa4f3baf31832df8a33334e0fe5b020a61bc8b345a3db7a606", size = 1393998 }, - { url = "https://files.pythonhosted.org/packages/b9/08/d643b44c022a738bdfb700a45335fae634537fe8b7e86cfed6c3a2ca86de/pyzmq-26.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c1c8f2a2ca45292084c75bb6d3a25545cff0ed931ed228d3a1810ae3758f975f", size = 1060624 }, - { url = "https://files.pythonhosted.org/packages/5b/22/3c5bdfd6eb587574b7d52af75634818becbcc6dada874c8c00b9a75fd569/pyzmq-26.0.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b63731993cdddcc8e087c64e9cf003f909262b359110070183d7f3025d1c56b5", size = 958346 }, - { url = "https://files.pythonhosted.org/packages/64/b8/1c181c13e118cabccfd25bd3e169e44958c649180b0d78b798a66899e08b/pyzmq-26.0.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b3cd31f859b662ac5d7f4226ec7d8bd60384fa037fc02aee6ff0b53ba29a3ba8", size = 912754 }, - { url = "https://files.pythonhosted.org/packages/8f/10/cd881e64c831ce1c250e637e4f033b9fb8628844f0e02913e4e21f701087/pyzmq-26.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:115f8359402fa527cf47708d6f8a0f8234f0e9ca0cab7c18c9c189c194dbf620", size = 724227 }, - { url = "https://files.pythonhosted.org/packages/da/cf/b0060122c875570923d097a8e788c5176930ba712c641501e1d155f2089b/pyzmq-26.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:715bdf952b9533ba13dfcf1f431a8f49e63cecc31d91d007bc1deb914f47d0e4", size = 1254783 }, - { url = "https://files.pythonhosted.org/packages/78/3a/9928f73afe1f1a336bfa1bd405b235c169097c8f0d10387c1419a8ecfb37/pyzmq-26.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e1258c639e00bf5e8a522fec6c3eaa3e30cf1c23a2f21a586be7e04d50c9acab", size = 1566288 }, - { url = "https://files.pythonhosted.org/packages/b9/f0/16d39b44849728abba22b7171787758cae20c30602911c17199f51afe4ec/pyzmq-26.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:15c59e780be8f30a60816a9adab900c12a58d79c1ac742b4a8df044ab2a6d920", size = 1466141 }, - { url = "https://files.pythonhosted.org/packages/6d/1c/4ebba66628b96f50e3742c1373a5e8f952d8709d3f7587ded91ce4fb58b1/pyzmq-26.0.3-cp39-cp39-win32.whl", hash = "sha256:d0cdde3c78d8ab5b46595054e5def32a755fc028685add5ddc7403e9f6de9879", size = 682158 }, - { url = "https://files.pythonhosted.org/packages/98/b0/d4c5120e5d3655b18d9eb6bdc3432153172f63ce85393f89d572e2527fe2/pyzmq-26.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:ce828058d482ef860746bf532822842e0ff484e27f540ef5c813d516dd8896d2", size = 774825 }, - { url = "https://files.pythonhosted.org/packages/99/c3/912ada694171cde952b45798aa0a5755910a978ecdd880d8ed0092c775f4/pyzmq-26.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:788f15721c64109cf720791714dc14afd0f449d63f3a5487724f024345067381", size = 863470 }, - { url = "https://files.pythonhosted.org/packages/fb/7a/b88317d85b3c1d5fe57bfa8c20b84d9b26351ac24e3a6aaf1394f958a130/pyzmq-26.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c18645ef6294d99b256806e34653e86236eb266278c8ec8112622b61db255de", size = 958123 }, - { url = "https://files.pythonhosted.org/packages/33/79/16f68cef4d8b5be599385ef6a679954f1be54b032d93724bc8b561f7a293/pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e6bc96ebe49604df3ec2c6389cc3876cabe475e6bfc84ced1bf4e630662cb35", size = 616285 }, - { url = "https://files.pythonhosted.org/packages/9e/9c/6f837ba9a123a2fdaf73d0f0e715a2736ab69f0e881d754502dda10933e4/pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:971e8990c5cc4ddcff26e149398fc7b0f6a042306e82500f5e8db3b10ce69f84", size = 845193 }, - { url = "https://files.pythonhosted.org/packages/49/cc/ffcef67f96ee7e4d2b3a2f46e1a4fa8f3b45c294aad5a7b43be39154af45/pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8416c23161abd94cc7da80c734ad7c9f5dbebdadfdaa77dad78244457448223", size = 803663 }, - { url = "https://files.pythonhosted.org/packages/70/f9/a3ec923e9b32d6579ac74f1894c2f71a7fbf38fcc35ae96db9c709f875fa/pyzmq-26.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:082a2988364b60bb5de809373098361cf1dbb239623e39e46cb18bc035ed9c0c", size = 708704 }, - { url = "https://files.pythonhosted.org/packages/a4/39/017e7029b85f9a05144721163edd248bac2beefdfe0d7fbbf791244edc66/pyzmq-26.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d57dfbf9737763b3a60d26e6800e02e04284926329aee8fb01049635e957fe81", size = 958117 }, - { url = "https://files.pythonhosted.org/packages/29/e8/f0cf024fb93620ad4ebc92feb672a10046ef404276de33c721e819391a6b/pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:77a85dca4c2430ac04dc2a2185c2deb3858a34fe7f403d0a946fa56970cf60a1", size = 852933 }, - { url = "https://files.pythonhosted.org/packages/60/90/0d6597787eb1bd27b7d9ea4d7dbf86383c882aab97df9138b5faa376592b/pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4c82a6d952a1d555bf4be42b6532927d2a5686dd3c3e280e5f63225ab47ac1f5", size = 807766 }, - { url = "https://files.pythonhosted.org/packages/19/8c/92bf146f38af63154630e8921f7bd9ab041aed353b64cb2fe7021c4f1b95/pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4496b1282c70c442809fc1b151977c3d967bfb33e4e17cedbf226d97de18f709", size = 616280 }, - { url = "https://files.pythonhosted.org/packages/b9/21/40b2911afb3c53899579dd5ff6f1e17589dee6611f7890929a028f3dfc36/pyzmq-26.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e4946d6bdb7ba972dfda282f9127e5756d4f299028b1566d1245fa0d438847e6", size = 709344 }, - { url = "https://files.pythonhosted.org/packages/64/a1/e7fa215b40c5fb0ccb593eddec33dffc7fb570586cb43380d387c3e7a052/pyzmq-26.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03c0ae165e700364b266876d712acb1ac02693acd920afa67da2ebb91a0b3c09", size = 958118 }, - { url = "https://files.pythonhosted.org/packages/77/8b/39116c1e42384487d5a0bd4d505b8d31c48ad2236d69b5011b84259ff58a/pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3e3070e680f79887d60feeda051a58d0ac36622e1759f305a41059eff62c6da7", size = 852928 }, - { url = "https://files.pythonhosted.org/packages/c6/21/1ecbe40764c5d35ca6ece620d43c46e4baee543ca1ddf73525d51a5ffb69/pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6ca08b840fe95d1c2bd9ab92dac5685f949fc6f9ae820ec16193e5ddf603c3b2", size = 807767 }, - { url = "https://files.pythonhosted.org/packages/b1/db/30f29f29db52ef75bb98e0562c1947f45df40cd233388a27dff4f3507b69/pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e76654e9dbfb835b3518f9938e565c7806976c07b37c33526b574cc1a1050480", size = 616284 }, - { url = "https://files.pythonhosted.org/packages/c8/2b/a5532717282bcd40312fa942afd6c6a75589282ebe3345a7f5fa57f4f5f7/pyzmq-26.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:871587bdadd1075b112e697173e946a07d722459d20716ceb3d1bd6c64bd08ce", size = 709343 }, - { url = "https://files.pythonhosted.org/packages/74/22/8ba37bfc214dc5909dc8cd96619889829128c42fa2a1279f6c486c5596f9/pyzmq-26.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d0a2d1bd63a4ad79483049b26514e70fa618ce6115220da9efdff63688808b17", size = 958115 }, - { url = "https://files.pythonhosted.org/packages/01/a1/16387aa34668135b308c8ab36c3512e30f847e1d4080c2e4b2754f5858a9/pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0270b49b6847f0d106d64b5086e9ad5dc8a902413b5dbbb15d12b60f9c1747a4", size = 616281 }, - { url = "https://files.pythonhosted.org/packages/7f/6c/16490963af912ff0d4925fc1ab3140c09539a60845624dabc812e028e2d1/pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:703c60b9910488d3d0954ca585c34f541e506a091a41930e663a098d3b794c67", size = 845189 }, - { url = "https://files.pythonhosted.org/packages/98/43/d8fb6bea21503edc3c338bb78e68f0f6c6a3fce3f7f5b96b179bdbabbef0/pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74423631b6be371edfbf7eabb02ab995c2563fee60a80a30829176842e71722a", size = 803656 }, - { url = "https://files.pythonhosted.org/packages/56/e4/c0467f13f5682247aab3b9204ea1b3fece1d6f35b77c7541f2c8b91887a7/pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4adfbb5451196842a88fda3612e2c0414134874bffb1c2ce83ab4242ec9e027d", size = 802194 }, - { url = "https://files.pythonhosted.org/packages/cb/20/8328228f7487fc273421394852ecfa474ed355614194b174589c7fdd9a30/pyzmq-26.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3516119f4f9b8671083a70b6afaa0a070f5683e431ab3dc26e9215620d7ca1ad", size = 709345 }, ] [[distribution]] @@ -6376,14 +5046,6 @@ dependencies = [ { name = "numpy" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/90/face72921ce52d74880b380e6f86b3caa6c65766c5808fbe179e208b9c6d/scipy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e911933d54ead4d557c02402710c2396529540b81dd554fc1ba270eb7308484", size = 39120226 }, - { url = "https://files.pythonhosted.org/packages/6e/a1/0093566d31ae662e942d4079e2a4dea4256723bf3d072ae67f5ba41aee0d/scipy-1.14.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:687af0a35462402dd851726295c1a5ae5f987bd6e9026f52e9505994e2f84ef6", size = 29866893 }, - { url = "https://files.pythonhosted.org/packages/52/21/05a182fb405a53dfbdf6415308bf185677e89188bc2206de011a3653f48e/scipy-1.14.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:07e179dc0205a50721022344fb85074f772eadbda1e1b3eecdc483f8033709b7", size = 23076258 }, - { url = "https://files.pythonhosted.org/packages/5c/63/9954d14012a2f4aff4570f1aaf076d7f65f3fc246ae4483b765488d57d51/scipy-1.14.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a9c9a9b226d9a21e0a208bdb024c3982932e43811b62d202aaf1bb59af264b1", size = 25454715 }, - { url = "https://files.pythonhosted.org/packages/57/b8/ca969a99d34956c6546cbb9ea3f863a387009f68cdbad13cdb07db0cc23d/scipy-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076c27284c768b84a45dcf2e914d4000aac537da74236a0d45d82c6fa4b7b3c0", size = 35569038 }, - { url = "https://files.pythonhosted.org/packages/e2/20/15c8fe0dfebb6facd81b3d08bf45dfa080e305deb17172b0a40eba59e927/scipy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42470ea0195336df319741e230626b6225a740fd9dce9642ca13e98f667047c0", size = 41135959 }, - { url = "https://files.pythonhosted.org/packages/df/a2/8721f93fbf98a69067d20bdfded36a7de2a3d811f192edba9eeefbde61b8/scipy-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:176c6f0d0470a32f1b2efaf40c3d37a24876cebf447498a4cefb947a79c21e9d", size = 41118514 }, - { url = "https://files.pythonhosted.org/packages/a3/0c/82c1330c08f31d61142d38cb9a185e01c2403c990d10dab208032e62d0fa/scipy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad36af9626d27a4326c8e884917b7ec321d8a1841cd6dacc67d2a9e90c2f0359", size = 44763252 }, { url = "https://files.pythonhosted.org/packages/10/55/d6096721c0f0d7e7369da9660a854c14e6379ab7aba603ea5d492d77fa23/scipy-1.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6d056a8709ccda6cf36cdd2eac597d13bc03dba38360f418560a93050c76a16e", size = 39129318 }, { url = "https://files.pythonhosted.org/packages/56/95/1a3a04b5facab8287325ad2335dbb6b78b98d73690c832099c9c498f7a4d/scipy-1.14.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f0a50da861a7ec4573b7c716b2ebdcdf142b66b756a0d392c236ae568b3a93fb", size = 29880413 }, { url = "https://files.pythonhosted.org/packages/8b/d2/78e3342f5db363ddf92de84007d43e47c8bb24363bd509e1b75a5102a25d/scipy-1.14.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:94c164a9e2498e68308e6e148646e486d979f7fcdb8b4cf34b5441894bdb9caf", size = 23089804 }, @@ -6404,11 +5066,11 @@ wheels = [ [[distribution]] name = "scons" -version = "4.7.0" +version = "4.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7b/68/6895065c86c65a9388eb760a43ea695ec5b9b1c98a9675a3bcd682dbe9c0/SCons-4.7.0.tar.gz", hash = "sha256:d8b617f6610a73e46509de70dcf82f76861b79762ff602d546f4e80918ec81f3", size = 3220727 } +sdist = { url = "https://files.pythonhosted.org/packages/ec/5c/cc835a17633de8b260ec1a6e527b5c57f4975cee5949f49e57ad4d5fab4b/scons-4.8.0.tar.gz", hash = "sha256:2c7377ff6a22ca136c795ae3dc3d0824696e5478d1e4940f2af75659b0d45454", size = 3243129 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/f7/ba9224b44691535426b07fae648fce898ccf17fd360a19a526f1f6d5c0ba/SCons-4.7.0-py3-none-any.whl", hash = "sha256:93308e564966760a63a4c1e016b2cc15d07bb40db67b1c907732da0b9e9f8959", size = 4277687 }, + { url = "https://files.pythonhosted.org/packages/7b/01/4ea08ba8414db39e597939ff82d587082674f616f78e3dc505dae4b6a176/SCons-4.8.0-py3-none-any.whl", hash = "sha256:760fbfd05e459113e9a1362ab2b00e12ea4195607e820a127d30e6275c8436a1", size = 4122772 }, ] [[distribution]] @@ -6427,15 +5089,15 @@ wheels = [ [[distribution]] name = "sentry-sdk" -version = "2.7.1" +version = "2.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b8/63/310d89868a0dab17f6d7c1f35eba9c304dd06c2a17d0d26905738763b614/sentry_sdk-2.7.1.tar.gz", hash = "sha256:25006c7e68b75aaa5e6b9c6a420ece22e8d7daec4b7a906ffd3a8607b67c037b", size = 273297 } +sdist = { url = "https://files.pythonhosted.org/packages/c9/9d/d61d64819ecb0481647229c3ee8ddc00887552acc23745fd65d0d4d066f3/sentry_sdk-2.8.0.tar.gz", hash = "sha256:aa4314f877d9cd9add5a0c9ba18e3f27f99f7de835ce36bd150e48a41c7c646f", size = 273663 } dependencies = [ { name = "certifi" }, { name = "urllib3" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/90/6a/a7d19d776ba9899c97acb223ceba4080ef9f5de9d7599203ae64b56ed597/sentry_sdk-2.7.1-py2.py3-none-any.whl", hash = "sha256:ef1b3d54eb715825657cd4bb3cb42bb4dc85087bac14c56b0fd8c21abd968c9a", size = 300153 }, + { url = "https://files.pythonhosted.org/packages/80/f4/8e1be145ce63c4ef4e126ee362992ae1ada5e716723883912b74829583e7/sentry_sdk-2.8.0-py2.py3-none-any.whl", hash = "sha256:6051562d2cfa8087bb8b4b8b79dc44690f8a054762a29c07e22588b1f619bfb5", size = 300617 }, ] [[distribution]] @@ -6456,13 +5118,6 @@ dependencies = [ { name = "numpy" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/18/56af9329f5c7eb29d40fb76101829d6bbd142924b8aee09e4a4cd30f8b0b/shapely-2.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:011b77153906030b795791f2fdfa2d68f1a8d7e40bce78b029782ade3afe4f2f", size = 2504177 }, - { url = "https://files.pythonhosted.org/packages/5f/7e/216c5c3f518000c1feabc52c31a5746eaf14878bd62daf5a46442df57327/shapely-2.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9831816a5d34d5170aa9ed32a64982c3d6f4332e7ecfe62dc97767e163cb0b17", size = 1434652 }, - { url = "https://files.pythonhosted.org/packages/30/15/5ec9c535b48d335e508b0afd6a77045d6db72a8626e76cc0fe81cdcbf8ee/shapely-2.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5c4849916f71dc44e19ed370421518c0d86cf73b26e8656192fcfcda08218fbd", size = 1274923 }, - { url = "https://files.pythonhosted.org/packages/d4/1c/13ee6dab51e86de949a85116cc6be6428432e3e298b1cddf4c1e1d7d4324/shapely-2.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:841f93a0e31e4c64d62ea570d81c35de0f6cea224568b2430d832967536308e6", size = 2381635 }, - { url = "https://files.pythonhosted.org/packages/81/77/e1475695606a8305c9ad5f5132d911abe8ed1655a6f5c817a69bdd2b5324/shapely-2.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b4431f522b277c79c34b65da128029a9955e4481462cbf7ebec23aab61fc58", size = 2467290 }, - { url = "https://files.pythonhosted.org/packages/78/85/ab34b973129fe08854b45af0ba1905b8baefabb7dd463b5eef9358e3b215/shapely-2.0.4-cp310-cp310-win32.whl", hash = "sha256:92a41d936f7d6743f343be265ace93b7c57f5b231e21b9605716f5a47c2879e7", size = 1294145 }, - { url = "https://files.pythonhosted.org/packages/6f/6e/fcb8ae881480a7b501d6f92fc6b7eb082cae8b66b3c43553f6412e1f4d0f/shapely-2.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:30982f79f21bb0ff7d7d4a4e531e3fcaa39b778584c2ce81a147f95be1cd58c9", size = 1440137 }, { url = "https://files.pythonhosted.org/packages/12/f6/b1b54fd7749e9cde332d8f55dd417cba189839b9a8a295ea4dbbab8a5fa3/shapely-2.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:de0205cb21ad5ddaef607cda9a3191eadd1e7a62a756ea3a356369675230ac35", size = 2503648 }, { url = "https://files.pythonhosted.org/packages/93/fd/b205661ed60294a344406fb04227042fcede9501e81ee1e7018e9159455a/shapely-2.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7d56ce3e2a6a556b59a288771cf9d091470116867e578bebced8bfc4147fbfd7", size = 1434573 }, { url = "https://files.pythonhosted.org/packages/2a/fb/e3f72b10a90e26bb1a92a38b3f30f3074ebac6d532f87848ac09c3e8a73b/shapely-2.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:58b0ecc505bbe49a99551eea3f2e8a9b3b24b3edd2a4de1ac0dc17bc75c9ec07", size = 1274613 }, @@ -6477,25 +5132,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1f/11/9f70f606f492ee6fd8071df4f963843c92b16344bf9cf30016a3b0a4f63f/shapely-2.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3e700abf4a37b7b8b90532fa6ed5c38a9bfc777098bc9fbae5ec8e618ac8f30", size = 2524488 }, { url = "https://files.pythonhosted.org/packages/8f/32/bc72211f652ebf0fc487b015cc5fab9703d1c8c6cf6b5c57c5d1261ecb68/shapely-2.0.4-cp312-cp312-win32.whl", hash = "sha256:4f2ab0faf8188b9f99e6a273b24b97662194160cc8ca17cf9d1fb6f18d7fb93f", size = 1294603 }, { url = "https://files.pythonhosted.org/packages/81/35/6d8b5cf9a747b94e8940619d914280fc4ce8e86e411ad19d39e7e8be036c/shapely-2.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:03152442d311a5e85ac73b39680dd64a9892fa42bb08fd83b3bab4fe6999bfa0", size = 1441463 }, - { url = "https://files.pythonhosted.org/packages/36/31/2d20ca2c18b3bee4e6984f236b2679693680a853dc453fa80540602f13f6/shapely-2.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:994c244e004bc3cfbea96257b883c90a86e8cbd76e069718eb4c6b222a56f78b", size = 1432894 }, - { url = "https://files.pythonhosted.org/packages/87/79/29e0fda2b64564d3ebc7e8e124d60afadaa540bf681109c2bc78047ef405/shapely-2.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05ffd6491e9e8958b742b0e2e7c346635033d0a5f1a0ea083547fcc854e5d5cf", size = 2340631 }, - { url = "https://files.pythonhosted.org/packages/d7/d5/7baa2741defad363aba6f6537403584f9145e69187e252447d2f743f633b/shapely-2.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbdc1140a7d08faa748256438291394967aa54b40009f54e8d9825e75ef6113", size = 2427569 }, - { url = "https://files.pythonhosted.org/packages/31/7f/d6ce1ae8c3c6b4986bf712e2431a8e84924667e30d78cac670918131b74c/shapely-2.0.4-cp37-cp37m-win32.whl", hash = "sha256:5af4cd0d8cf2912bd95f33586600cac9c4b7c5053a036422b97cfe4728d2eb53", size = 1294743 }, - { url = "https://files.pythonhosted.org/packages/26/d6/ba5ab07d8d5b413774a3d3914b086d2c8136d493a5023fb392aff4d431b3/shapely-2.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:464157509ce4efa5ff285c646a38b49f8c5ef8d4b340f722685b09bb033c5ccf", size = 1455265 }, - { url = "https://files.pythonhosted.org/packages/18/ed/b54777e8364eab641fac8e5ac7fc6cf68736d9bc0e8b329b778a4e8c6861/shapely-2.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:489c19152ec1f0e5c5e525356bcbf7e532f311bff630c9b6bc2db6f04da6a8b9", size = 2501583 }, - { url = "https://files.pythonhosted.org/packages/cc/30/5f6deb8b97dc858aa8589fa780ce8262f8d0d8e131814f8195316c60f699/shapely-2.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b79bbd648664aa6f44ef018474ff958b6b296fed5c2d42db60078de3cffbc8aa", size = 1433269 }, - { url = "https://files.pythonhosted.org/packages/9f/28/a82210943c1bd7968d2277896f57384da03ac4308574ac3de3a8aad784e6/shapely-2.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:674d7baf0015a6037d5758496d550fc1946f34bfc89c1bf247cabdc415d7747e", size = 1273617 }, - { url = "https://files.pythonhosted.org/packages/96/ac/3b91deb96b022f3833076893ccf11eebb03d6d0bc1199334badc0515ec85/shapely-2.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6cd4ccecc5ea5abd06deeaab52fcdba372f649728050c6143cc405ee0c166679", size = 2408741 }, - { url = "https://files.pythonhosted.org/packages/a5/0d/40f176f80ca897950c6599b1250505f5e1c50827ffae6c8c58dbd0feb520/shapely-2.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb5cdcbbe3080181498931b52a91a21a781a35dcb859da741c0345c6402bf00c", size = 2497062 }, - { url = "https://files.pythonhosted.org/packages/14/79/6e10274c7f9615576e9d6a930f3471dc54849159894575b98dd3d438fb98/shapely-2.0.4-cp38-cp38-win32.whl", hash = "sha256:55a38dcd1cee2f298d8c2ebc60fc7d39f3b4535684a1e9e2f39a80ae88b0cea7", size = 1295652 }, - { url = "https://files.pythonhosted.org/packages/1d/f9/6ff57fa487e67166b0cf26bd52cbefc70c4ccb33c903a87b4f3dbce0cc64/shapely-2.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:ec555c9d0db12d7fd777ba3f8b75044c73e576c720a851667432fabb7057da6c", size = 1455996 }, - { url = "https://files.pythonhosted.org/packages/1f/a1/5443ff93e0d4b9535bf1cdabc2d8afcac63be5f921c5f941f251849c77e7/shapely-2.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3f9103abd1678cb1b5f7e8e1af565a652e036844166c91ec031eeb25c5ca8af0", size = 2506839 }, - { url = "https://files.pythonhosted.org/packages/1f/b8/0ae46102f91eb8753a145ed0f391dacc980351db077f88724ea0dab7b249/shapely-2.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:263bcf0c24d7a57c80991e64ab57cba7a3906e31d2e21b455f493d4aab534aaa", size = 1435780 }, - { url = "https://files.pythonhosted.org/packages/ed/0f/0d0063a407a6827f2335c53190535c35fa6744a9da7ce4a77f56b984b109/shapely-2.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ddf4a9bfaac643e62702ed662afc36f6abed2a88a21270e891038f9a19bc08fc", size = 1276447 }, - { url = "https://files.pythonhosted.org/packages/7d/11/51ee0fd72718c8c21554d890e88043eedba4a22a6e855236a777818d9080/shapely-2.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:485246fcdb93336105c29a5cfbff8a226949db37b7473c89caa26c9bae52a242", size = 2388330 }, - { url = "https://files.pythonhosted.org/packages/f3/5d/1ff630d519dbb850531034da66d3f31df5df5fa8e126e0c62e23680826c5/shapely-2.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8de4578e838a9409b5b134a18ee820730e507b2d21700c14b71a2b0757396acc", size = 2472522 }, - { url = "https://files.pythonhosted.org/packages/c7/74/9db2656b0356c3aed4cc1709afd432ee2227a5bf2eecd04e56f07937a066/shapely-2.0.4-cp39-cp39-win32.whl", hash = "sha256:9dab4c98acfb5fb85f5a20548b5c0abe9b163ad3525ee28822ffecb5c40e724c", size = 1295941 }, - { url = "https://files.pythonhosted.org/packages/84/e9/434a57e07360f73d5b52216dfbfcd828bac6f87cb06cc56daae4e80e0d7a/shapely-2.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:31c19a668b5a1eadab82ff070b5a260478ac6ddad3a5b62295095174a8d26398", size = 1442010 }, ] [[distribution]] @@ -6635,9 +5271,6 @@ name = "spidev" version = "3.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c7/d9/401c0a7be089e02826cf2c201f489876b601f15be100fe391ef9c2faed83/spidev-3.6.tar.gz", hash = "sha256:14dbc37594a4aaef85403ab617985d3c3ef464d62bc9b769ef552db53701115b", size = 11917 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/28/73/48c2f27691b95dc7eff2263e92e62522b2f034186be5ecc294087b3d38aa/spidev-3.6-cp39-cp39-linux_armv7l.whl", hash = "sha256:280abc00a1ef7780ef62c3f294f52a2527b6c47d8c269fea98664970bcaf6da5", size = 40010 }, -] [[distribution]] name = "sympy" @@ -6749,27 +5382,12 @@ version = "4.0.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/1b/f9/b01e4632aed9a6ecc2b3e501feffd3af5aa0eb4e3b0283fc9525bf503c38/watchdog-4.0.1.tar.gz", hash = "sha256:eebaacf674fa25511e8867028d281e602ee6500045b57f43b08778082f7f8b44", size = 126583 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/51/11f6d62e07434849e47ab0ff90679443bd19c568118fbe47a1094ebcdca8/watchdog-4.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:da2dfdaa8006eb6a71051795856bedd97e5b03e57da96f98e375682c48850645", size = 101628 }, - { url = "https://files.pythonhosted.org/packages/1a/3f/4a4e866d69051d1144cbc5ebc11cdb5367b66d7ed6022bff1c7c927c3c1a/watchdog-4.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e93f451f2dfa433d97765ca2634628b789b49ba8b504fdde5837cdcf25fdb53b", size = 92462 }, - { url = "https://files.pythonhosted.org/packages/3e/a5/65044f27764c6c93c7698a2a117ddb888a55a69222da3d6fe20c39cc087c/watchdog-4.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ef0107bbb6a55f5be727cfc2ef945d5676b97bffb8425650dadbb184be9f9a2b", size = 92952 }, { url = "https://files.pythonhosted.org/packages/1c/bc/a1ce8b77eede5a2f4fbcdc923079eb85b7c6e0f5e366ad06661b4dd807e1/watchdog-4.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:17e32f147d8bf9657e0922c0940bcde863b894cd871dbb694beb6704cfbd2fb5", size = 101627 }, { url = "https://files.pythonhosted.org/packages/c2/84/9c66fb603bb683fe559ceeba8f3d5dbea3293b631b2eba319d7d47a2d7fb/watchdog-4.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:03e70d2df2258fb6cb0e95bbdbe06c16e608af94a3ffbd2b90c3f1e83eb10767", size = 92464 }, { url = "https://files.pythonhosted.org/packages/5a/a5/72b9557e77ac3e6c41816fb16f643069b17cf21f745d26e2931cb1bf136c/watchdog-4.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:123587af84260c991dc5f62a6e7ef3d1c57dfddc99faacee508c71d287248459", size = 92953 }, { url = "https://files.pythonhosted.org/packages/f3/d1/85c1f5841190ee1e39f4a8a01df6eb13b44bd366060fc735505a38613484/watchdog-4.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:093b23e6906a8b97051191a4a0c73a77ecc958121d42346274c6af6520dec175", size = 101708 }, { url = "https://files.pythonhosted.org/packages/a9/eb/8d1f9150dd5e86082913ab15d4fd4bea436186845be1b1752efd19b020d1/watchdog-4.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:611be3904f9843f0529c35a3ff3fd617449463cb4b73b1633950b3d97fa4bfb7", size = 92508 }, { url = "https://files.pythonhosted.org/packages/52/67/62eea67ef31214ea4867b97351ea4f6b3a52dd1c4c93360ff8ad6e4ad72f/watchdog-4.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:62c613ad689ddcb11707f030e722fa929f322ef7e4f18f5335d2b73c61a85c28", size = 92977 }, - { url = "https://files.pythonhosted.org/packages/f8/35/44650dfdeb57337dc743b89990ccac5cab42ba865f1737b1b11ee9a76572/watchdog-4.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d4925e4bf7b9bddd1c3de13c9b8a2cdb89a468f640e66fbfabaf735bd85b3e35", size = 101626 }, - { url = "https://files.pythonhosted.org/packages/84/52/2f3bbdbf02dbaf5d3a200668e41c7b474c3b6dc37fc06597901730f56f50/watchdog-4.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cad0bbd66cd59fc474b4a4376bc5ac3fc698723510cbb64091c2a793b18654db", size = 92463 }, - { url = "https://files.pythonhosted.org/packages/d5/94/62a6c6f53fee88ac8959ed418b45875fd649c63e09ed4c2afb08a3798b2a/watchdog-4.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a3c2c317a8fb53e5b3d25790553796105501a235343f5d2bf23bb8649c2c8709", size = 92953 }, - { url = "https://files.pythonhosted.org/packages/23/cd/c9eba46749e703476d65d6292d6f6de1be776315b9106f3fa42998ff6844/watchdog-4.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c9904904b6564d4ee8a1ed820db76185a3c96e05560c776c79a6ce5ab71888ba", size = 101625 }, - { url = "https://files.pythonhosted.org/packages/d4/4f/26652a5fdc0510e1c6c4a85b1dafc9e463c0db5bf74b166c0cd086e96b08/watchdog-4.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:667f3c579e813fcbad1b784db7a1aaa96524bed53437e119f6a2f5de4db04235", size = 92456 }, - { url = "https://files.pythonhosted.org/packages/cc/08/2d2460ccea7dd8a70a0096aec93d5f5dbb0305e5bbbf9c913d2d2360ac68/watchdog-4.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d10a681c9a1d5a77e75c48a3b8e1a9f2ae2928eda463e8d33660437705659682", size = 92955 }, - { url = "https://files.pythonhosted.org/packages/72/59/04de07819896f834fc35d031a8d840516ada8ac7b1cefccd62b0ed8f4fc9/watchdog-4.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0144c0ea9997b92615af1d94afc0c217e07ce2c14912c7b1a5731776329fcfc7", size = 91884 }, - { url = "https://files.pythonhosted.org/packages/45/17/3e3b159ed0b5d9456d34420c8d0262e8dd0d7bd92cbf83f811a4ee03ca9b/watchdog-4.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:998d2be6976a0ee3a81fb8e2777900c28641fb5bfbd0c84717d89bca0addcdc5", size = 92319 }, - { url = "https://files.pythonhosted.org/packages/59/1c/e6e24e713cbfd5b36a29b3f634617552f7b606509b53ec1f8ef97b20de94/watchdog-4.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e7921319fe4430b11278d924ef66d4daa469fafb1da679a2e48c935fa27af193", size = 91879 }, - { url = "https://files.pythonhosted.org/packages/1f/f1/e9199ba2a2617469daf40d89a938f488a381f406c64a92a4e1b7e53f7253/watchdog-4.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:f0de0f284248ab40188f23380b03b59126d1479cd59940f2a34f8852db710625", size = 92309 }, - { url = "https://files.pythonhosted.org/packages/3a/76/0c36f7097022470aa9fb9d090052970834f91e08b199c52791ca9772d156/watchdog-4.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bca36be5707e81b9e6ce3208d92d95540d4ca244c006b61511753583c81c70dd", size = 91877 }, - { url = "https://files.pythonhosted.org/packages/60/34/31d20941af7ddd1ebb13b5349d8e0bafee164f024a025152aa43c690b2c9/watchdog-4.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ab998f567ebdf6b1da7dc1e5accfaa7c6992244629c0fdaef062f43249bd8dee", size = 92317 }, { url = "https://files.pythonhosted.org/packages/3a/36/28ce38b960f2bf1e1be573d85e8127c9ac66b4de63a7bef3f61b3f77ce57/watchdog-4.0.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:dddba7ca1c807045323b6af4ff80f5ddc4d654c8bce8317dde1bd96b128ed253", size = 83011 }, { url = "https://files.pythonhosted.org/packages/05/7b/efc5b4134c97f08b161faa703327cde3fe647c5c48c156fde0c343471095/watchdog-4.0.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:4513ec234c68b14d4161440e07f995f231be21a09329051e67a2118a7a612d2d", size = 83009 }, { url = "https://files.pythonhosted.org/packages/c3/bb/1fac328ba90ea091ef04e7bdefe638a933076530d802c1b1cf1f03fe7e89/watchdog-4.0.1-py3-none-manylinux2014_i686.whl", hash = "sha256:4107ac5ab936a63952dea2a46a734a23230aa2f6f9db1291bf171dac3ebd53c6", size = 83011 }, @@ -6815,21 +5433,6 @@ dependencies = [ { name = "multidict" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/6c/27/cda5a927df3a894eddfee4efacdd230c2d8486e322fc672194fd651f82c5/yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e", size = 129061 }, - { url = "https://files.pythonhosted.org/packages/d5/fc/40b85bea1f5686092ea37f472c94c023d6347266852ffd55baa01c40f596/yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2", size = 81246 }, - { url = "https://files.pythonhosted.org/packages/81/c6/06938036ea48fa74521713499fba1459b0eb60af9b9afbe8e0e9e1a96c36/yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66", size = 79176 }, - { url = "https://files.pythonhosted.org/packages/30/b5/215d586d5cb17ca9748d7a2d597c07147f210c0c0785257492094d083b65/yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234", size = 297669 }, - { url = "https://files.pythonhosted.org/packages/dd/90/2958ae9f2e12084d616eef95b6a48c8e6d96448add04367c20dc53a33ff2/yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392", size = 311909 }, - { url = "https://files.pythonhosted.org/packages/0b/58/dd3c69651381a57ac991dba54b20ae2da359eb4b03a661e71c451d6525c6/yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551", size = 308690 }, - { url = "https://files.pythonhosted.org/packages/c3/a0/0ade1409d184cbc9e85acd403a386a7c0563b92ff0f26d138ff9e86e48b4/yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455", size = 301580 }, - { url = "https://files.pythonhosted.org/packages/6d/a1/db0bdf8cc48515e9c02daf04ae2916fc27ce6498eca21432fc9ffa63f71b/yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c", size = 291231 }, - { url = "https://files.pythonhosted.org/packages/b2/4f/796b0c73e9ff30a1047a7ee3390e157ab8424d4401b9f32a2624013a5b39/yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53", size = 301079 }, - { url = "https://files.pythonhosted.org/packages/0b/a3/7774786ec6e2dca0bb38b286f12a11af97957546e5fbcce71752a8d2cf07/yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385", size = 295202 }, - { url = "https://files.pythonhosted.org/packages/70/a9/ef6d69ce9a4e82080290bcb6db735bb8a6d6db92f2bbb92b6951bde97e7c/yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863", size = 311784 }, - { url = "https://files.pythonhosted.org/packages/44/ae/fdbc9965ef69e650c3b5b04d60badef90ff0cde21a30770f0700e148b12f/yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b", size = 311134 }, - { url = "https://files.pythonhosted.org/packages/cc/2a/abbaf1460becba856e163f2a1274f5d34b1969d476da8e68a8fc2aeb5661/yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541", size = 304584 }, - { url = "https://files.pythonhosted.org/packages/a3/73/dd7ced8d9731bd2ef4fdff5da23ce2f772ca04e8ddee886a6b15248d9e65/yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d", size = 70175 }, - { url = "https://files.pythonhosted.org/packages/31/d4/2085272a5ccf87af74d4e02787c242c5d60367840a4637b2835565264302/yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b", size = 76402 }, { url = "https://files.pythonhosted.org/packages/12/65/4c7f3676209a569405c9f0f492df2bc3a387c253f5d906e36944fdd12277/yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099", size = 132836 }, { url = "https://files.pythonhosted.org/packages/3b/c5/81e3dbf5271ab1510860d2ae7a704ef43f93f7cb9326bf7ebb1949a7260b/yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c", size = 83215 }, { url = "https://files.pythonhosted.org/packages/20/3d/7dabf580dfc0b588e48830486b488858122b10a61f33325e0d7cf1d6180b/yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0", size = 81237 }, @@ -6860,49 +5463,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/85/8a/c364d6e2eeb4e128a5ee9a346fc3a09aa76739c0c4e2a7305989b54f174b/yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10", size = 328251 }, { url = "https://files.pythonhosted.org/packages/ec/9d/0da94b33b9fb89041e10f95a14a55b0fef36c60b6a1d5ff85a0c2ecb1a97/yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7", size = 70195 }, { url = "https://files.pythonhosted.org/packages/c5/f4/2fdc5a11503bc61818243653d836061c9ce0370e2dd9ac5917258a007675/yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984", size = 76397 }, - { url = "https://files.pythonhosted.org/packages/3a/dc/7edf78171850d262c56a837a83855e9284eda13cee05ebf779bd712242c6/yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f", size = 82970 }, - { url = "https://files.pythonhosted.org/packages/10/c0/c74f437b5028dec458a3d57375794a5d5c80a1eddbea818965cd0c69ca35/yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17", size = 286143 }, - { url = "https://files.pythonhosted.org/packages/a6/c0/a1bcbc0dfba5a7f1724bb4c5239b7bed46a90aa648f7cb0c525a8dac0e33/yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14", size = 301267 }, - { url = "https://files.pythonhosted.org/packages/c2/1c/167bc933a857c90d7c12ad701c0f220a579aef78bfe5efda11d0c541c43e/yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5", size = 294493 }, - { url = "https://files.pythonhosted.org/packages/45/33/d958b3f31420ccc99075e9355d9cb27b0c39d712dbcb0a6cda408c1aa6c4/yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd", size = 289764 }, - { url = "https://files.pythonhosted.org/packages/06/48/ba25250d3de4ee9c0ed5881b44da95bfdc71328a740d5cd022c6a296a0ea/yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7", size = 280251 }, - { url = "https://files.pythonhosted.org/packages/6c/49/c9a6646ff0331f11ef8c99c7c9a59257866ab1f7bed6771f4a062e15aba2/yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e", size = 288721 }, - { url = "https://files.pythonhosted.org/packages/3f/fb/08747cdda53a0107683e56dbd0066dc27c999220aebed6319d182fb16328/yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec", size = 283535 }, - { url = "https://files.pythonhosted.org/packages/5e/50/6c5d061ca467c03329751a452a8981d1b84931a20dab3bf19926cb034171/yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c", size = 297020 }, - { url = "https://files.pythonhosted.org/packages/f0/31/75742817be8cb130a66dfee39045227a11af780cf75b33a8cf6fbe09dacd/yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead", size = 295937 }, - { url = "https://files.pythonhosted.org/packages/98/7f/b13924faae6da3fe367e120fb06f76902d67e6f67b8fd92b4a68ecea5e4a/yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434", size = 291925 }, - { url = "https://files.pythonhosted.org/packages/57/1a/b7eda2dd1511aede7c42195aea477eea4b67c389400cd31bf5133ebeccff/yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749", size = 70793 }, - { url = "https://files.pythonhosted.org/packages/c4/c4/204f384e5a70d5be67b6278d7a93f8ff18eabea53c7f45888648d92f501b/yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2", size = 77161 }, - { url = "https://files.pythonhosted.org/packages/8a/0a/5e432118ae570f5dbe9e40f8c8ffc41e1947f39f3643dcd0846e8bb9908d/yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be", size = 134240 }, - { url = "https://files.pythonhosted.org/packages/46/ea/8404aa172ffe74da750efeb09aa293bf0247fa6ab4f593aea93f85f74844/yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f", size = 83722 }, - { url = "https://files.pythonhosted.org/packages/fc/ca/33754d12ecbe4ccb677353f4e1c7ce3ea748cc5ab9f435535ebf3bf7ac8c/yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf", size = 82028 }, - { url = "https://files.pythonhosted.org/packages/16/07/719c440f9009c0e7293181f5adb72ba102e4b64312069d03a2bf9b68e97f/yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1", size = 305512 }, - { url = "https://files.pythonhosted.org/packages/79/51/fe155dda79b8564dee3e377a548d7e9fe84dcebc0460d9d1a92f0932d980/yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57", size = 318139 }, - { url = "https://files.pythonhosted.org/packages/af/39/1794787f94b4c75bfc94a4b3e751507ef91d75819411adc8e60520895be3/yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa", size = 314986 }, - { url = "https://files.pythonhosted.org/packages/58/c0/8d9a1c02f217f900f248e0ee31377849f4041aff3d36b71b1f30b4a0fa33/yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130", size = 308756 }, - { url = "https://files.pythonhosted.org/packages/0f/aa/e610398c48bc4a9d250d548cf065560e0192de4191e8568d28568c551963/yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559", size = 298226 }, - { url = "https://files.pythonhosted.org/packages/7a/2e/fd7d98be29db31457930c7490047637991f65a3ad137ac60a020fd7546b2/yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23", size = 314961 }, - { url = "https://files.pythonhosted.org/packages/61/24/bbb3964f849adebe825dc00fff2905289b8bb203cf0f588ece27221cb8f5/yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec", size = 309636 }, - { url = "https://files.pythonhosted.org/packages/75/3c/6d5b2fe70f58528e7e38115da13778623c9a258dfc97f978f9d844948e92/yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78", size = 325489 }, - { url = "https://files.pythonhosted.org/packages/f6/ed/8dc99df4caae1650f82dce04628678f6f987150dd3baab0a62dc697101cc/yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be", size = 324841 }, - { url = "https://files.pythonhosted.org/packages/d2/fa/e401c492c2ebfab5958359b9837e71c20e5c0c6e2d77c5bad1a61d5310fd/yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3", size = 317004 }, - { url = "https://files.pythonhosted.org/packages/8e/d9/807f1ace5f3dfc74f2dc35cdb93838b8d89bd84ae91c9591b72ae5c4f7ee/yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece", size = 70790 }, - { url = "https://files.pythonhosted.org/packages/16/3b/ce8756872540331d841aa8966056a90ee93c88d793f33e29af19f3ff2f3c/yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b", size = 77055 }, - { url = "https://files.pythonhosted.org/packages/34/e7/9d51111429691ffdfb6ce526b2dd2b66fc9d2746df053ecb4062a3969f65/yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27", size = 134018 }, - { url = "https://files.pythonhosted.org/packages/8f/0f/9fa6f044b04267d22ec29df23936ffd4bf4572ccecd889c6b2b1761c2c5c/yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1", size = 83661 }, - { url = "https://files.pythonhosted.org/packages/f9/b0/c213007560d001c9908649ff4b1dd11d1ff388235e773828e19d4637f502/yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91", size = 81842 }, - { url = "https://files.pythonhosted.org/packages/c6/d6/5b30ae1d8a13104ee2ceb649f28f2db5ad42afbd5697fd0fc61528bb112c/yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b", size = 300908 }, - { url = "https://files.pythonhosted.org/packages/d0/50/af41ddf09ff0a6a3f952288ff4ed703a1a6ecc0fbb3a6a9fe50bd33dc7cc/yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5", size = 315681 }, - { url = "https://files.pythonhosted.org/packages/ec/17/376715c245a28f81f01e72e832d84404cffd29576fcc645ee40e3c03f5f4/yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34", size = 312857 }, - { url = "https://files.pythonhosted.org/packages/69/ea/d7e961ea9b1b818a43b155ee512117be6ab9ab67c1e94967b2e64126e8e4/yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136", size = 304255 }, - { url = "https://files.pythonhosted.org/packages/46/8c/02d0c2eed8c6b41de0f8f26aeefc7a285779cbb370cc7bf043285de18a75/yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7", size = 295014 }, - { url = "https://files.pythonhosted.org/packages/c2/5c/093c1fd1d8e95b1de4feb282fa3d9c3172c6d8cb5be2cfa19ca0170f9287/yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e", size = 303653 }, - { url = "https://files.pythonhosted.org/packages/96/f1/c2af401567c7b32f908195c8c1a807670f20ea62e10866b71e1d9e3860a1/yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4", size = 298147 }, - { url = "https://files.pythonhosted.org/packages/65/ac/b5a3cc5bf4675db5d27ec92453e562f3ee4bfef5133ed071880ac07125e9/yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec", size = 314358 }, - { url = "https://files.pythonhosted.org/packages/3d/4d/b8a950fd92a3aa5c95039731d2eda32a701ac0c789663827e67e398c166a/yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c", size = 313842 }, - { url = "https://files.pythonhosted.org/packages/57/68/bfac2e16a15af85234cbd2a5c82abb33caa98e981abbfd6e0f9458b6d1a9/yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0", size = 306771 }, - { url = "https://files.pythonhosted.org/packages/ab/5f/156e00c7bdc6d84efc7615fe0e14b2febf8ea360a8e1307fb3ba9cc14b73/yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575", size = 70773 }, - { url = "https://files.pythonhosted.org/packages/a4/e0/5b4376d7361fe09a46dbb206131e8d85b1cb845da03c212a620d5b6b98d8/yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15", size = 76935 }, { url = "https://files.pythonhosted.org/packages/4d/05/4d79198ae568a92159de0f89e710a8d19e3fa267b719a236582eee921f4a/yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad", size = 31638 }, ] @@ -6921,21 +5481,6 @@ version = "1.5.5.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ba/b4/bf8c6a6b73c6b267a13df955f821f041fcc770b56820b135849f33e3b888/zstd-1.5.5.1.tar.gz", hash = "sha256:1ef980abf0e1e072b028d2d76ef95b476632651c96225cf30b619c6eef625672", size = 1106585 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/cb/28679127ea1efe57d0c3dc7aff7a9006bc6636effdaae4998a1ecd1ac4bc/zstd-1.5.5.1-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:555779789bc75cd05089c3ba857f45a0a8c4b87d45e5ced02fec77fa8719237a", size = 290845 }, - { url = "https://files.pythonhosted.org/packages/08/07/477ec11ea56437f103732b7c7d92faa1781cd896853f89f104a25ebc42e4/zstd-1.5.5.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:86496bd4830cdb7b4b05a9ce6ce2baee87d327ff90845da4ee308452bfbbed4e", size = 1323726 }, - { url = "https://files.pythonhosted.org/packages/88/ff/0abbdb468154d346f301e75698da400e84ae59d632cc75387fe0d66c6155/zstd-1.5.5.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:b487c2e67ed42a4e0d47997d209f4456b01b334023083ef61873f79577c84c62", size = 1356057 }, - { url = "https://files.pythonhosted.org/packages/0c/22/4e534290ff388d529e480e2615e71b39f4f2959976d0c9c0397ec81be4dd/zstd-1.5.5.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:45ccd45a5b681088fca1a863ca9236ded5112b8011f1d5bf69e908f5eb32023a", size = 1323744 }, - { url = "https://files.pythonhosted.org/packages/8d/2a/6b4462097d7529449ca7537e76d4b908ef3b94137f519e263f0a641c3b6a/zstd-1.5.5.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8403fe84207d8b0c7b17bca6c4caad431ac765b1b9b626ad9fae4bb93a64a9d8", size = 1356038 }, - { url = "https://files.pythonhosted.org/packages/c1/d3/6466fa91c2acab321e16c85c6b065405bfba4a6a7c113816931cd9f7f370/zstd-1.5.5.1-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:0ab979c6357b8927f0c025ea2f72f25e15d03ce17a8a6c1789e2d5b108bf39ae", size = 287602 }, - { url = "https://files.pythonhosted.org/packages/34/fc/7324340fac376e6bf0b82ad6bb2dc107100682e3709a05437a00ac1fce30/zstd-1.5.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:98cbee6c1b2fe85f02fd475d885f98363c63bc64eebc249d7eb7469a0ff70283", size = 227495 }, - { url = "https://files.pythonhosted.org/packages/be/7e/031b0ca0bb69ed7a7d54775dedb2121da483bfca7910e2be4246104b6cb2/zstd-1.5.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9962714b89641301029f3832bdf07c20f60b9e64e39e8d7b6253451a82b54f5c", size = 1758841 }, - { url = "https://files.pythonhosted.org/packages/3b/28/fff1aa8dfbee4319d99a51d0f7c26c7af19b16c23dc7db406b2be6828f24/zstd-1.5.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f59cc92d71537f8082306f75aa403ddb4a4a1069a39f104525673110e4d23f7", size = 1784502 }, - { url = "https://files.pythonhosted.org/packages/8b/c0/a62141e75beba1e80628a6c321d83c91b5a00ab5cc3ff00d6a6a24be70ad/zstd-1.5.5.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:569f13d0c926ddafceebce8ac73baddfc2bd9cbbbbc922b6b3073338cc43dae6", size = 1637890 }, - { url = "https://files.pythonhosted.org/packages/dc/0c/ba2b43916084c43f509116dcb661d4cca8236b745caeb1295ee041ffcd7d/zstd-1.5.5.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ba530c44f252016acc6ef906d7d2070c1ad0cfe835c498fdcd37493e4772ac6e", size = 1892777 }, - { url = "https://files.pythonhosted.org/packages/80/97/07a3f2bde9de73f7ef61a7797a965f2ec9809ed31aae80b8c6b8d5539365/zstd-1.5.5.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ee3496ed8fff3add6c6e658b207f18d96474c3db0c28ab7a69623380b1a0a8c", size = 1825758 }, - { url = "https://files.pythonhosted.org/packages/1d/f9/1815a63845046c63cb5c6960af0789605b011ddeb60cc0aa818588ab07dd/zstd-1.5.5.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:530d69bea2791cde8afa7fe988f3a37c3ba37015f6a1d5593c0500f089f3090e", size = 1930838 }, - { url = "https://files.pythonhosted.org/packages/59/b0/bf8b9e655c47cff2fc03bd07f449fb083b6fdb49ea4adf60fba5b3213129/zstd-1.5.5.1-cp310-cp310-win32.whl", hash = "sha256:cf179e51f447b6a7ff47e449fcb98fb5fe15aedcc90401697cf7c93dd6e4434e", size = 150760 }, - { url = "https://files.pythonhosted.org/packages/b2/c4/b05b4cfcaed1f6241136f9517403bb948706d178b74893ea015d018c26fb/zstd-1.5.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:5f5e6e0805d710d7509c8d175a467eb89c631a4142b1a630ceeb8e3e3138d152", size = 167979 }, { url = "https://files.pythonhosted.org/packages/10/6f/5b8a828394af6153ec08fd4814c9a4bbae9ec5bce3cb948bb0b9b6872022/zstd-1.5.5.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:022f935a8666e08f0fff6204938a84d9fe4fcd8235a205787275933a07a164fb", size = 287614 }, { url = "https://files.pythonhosted.org/packages/99/33/a51e2e4e469af134d5a8450d59da05c34017eea9bb16d1d1ed7b83b5ed98/zstd-1.5.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3d15a2d18dac8bcafdde52fdf5d40ecae1f73b7de19b171f42339d2e51346d0", size = 227505 }, { url = "https://files.pythonhosted.org/packages/cf/1a/ec11fdf56b282ca627c979b5b0c9c2ef14b416c0b2ad4264972c6765b634/zstd-1.5.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45b9c67989f50ba63ffa0c50c9eaa037c2d14abacb0813e838ad705135245b4b", size = 1758942 }, @@ -6946,65 +5491,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f6/2f/3d346dcf2c525f1c3e4b0efebf653cc1da69f287bc4084391fb3a449f691/zstd-1.5.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:edea52a0109f48fd46f4763689d3d356dcafd20ddf6789c559a1bd2e62b40a32", size = 1930928 }, { url = "https://files.pythonhosted.org/packages/a2/f3/c7d49044609ad59bf4e09cf182215474b229128514885f1f0db82386c5a8/zstd-1.5.5.1-cp311-cp311-win32.whl", hash = "sha256:88410481209520298ec4430e0d1d57e004c45e0b27c3035674fb182ccd2d8b7b", size = 150758 }, { url = "https://files.pythonhosted.org/packages/af/39/6314d344793ca78556832b281c4a4916362bfca0943ced3eff25221b5385/zstd-1.5.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:dce18aaefbacf8b133367be86beec670baf68c0420bfcca49be08dbdbf933db6", size = 167971 }, - { url = "https://files.pythonhosted.org/packages/cc/f6/f2fc2eebe17fa4606f036241c46e717e3d09006b5e84653f9f7dddc5ac83/zstd-1.5.5.1-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:634dc632f7cf87e95dabf74dcf682e3507bd5cb9dd1bcdb81f92a6521aab0bd2", size = 291047 }, - { url = "https://files.pythonhosted.org/packages/03/40/4c67caf4c90ca72c21d6f297a37f3f488878226cf3a6d3e2acdf39588056/zstd-1.5.5.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:608414eb75ead573891d97a1e529848b8f31749d21a440e80838548a19d8c0e6", size = 1330611 }, - { url = "https://files.pythonhosted.org/packages/d6/75/db66ca96d6dfaf1e9309b1670466a609f41287d499671e1414f18082e5f3/zstd-1.5.5.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:384128f7a731e3f45da49976591cec03fc4079e70653df10d9ea43a1d3b49d50", size = 1357365 }, - { url = "https://files.pythonhosted.org/packages/c6/fc/d03774378b6f768b45bacd8473fdf72ddb79beb2bfdb7b7a7325a631a589/zstd-1.5.5.1-cp35-cp35m-win32.whl", hash = "sha256:4bce254174ef05cea01021d67e18489d5d08db1168e758b62ecee121572a52a9", size = 208339 }, - { url = "https://files.pythonhosted.org/packages/63/18/213d794c21375917fa9ab598cf878c07e14729d7be86cc923ffc3c28616f/zstd-1.5.5.1-cp35-cp35m-win_amd64.whl", hash = "sha256:3f0ff81232b49d7eb4f4d9e6f92443c9d242c139ad98ffedac0e889568f900ce", size = 236816 }, - { url = "https://files.pythonhosted.org/packages/55/7e/6fbbd4632c207a40f5ba4c7570322d2ee0a4685cdf811976f15523af550b/zstd-1.5.5.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:a871df41b801a260cc849c2c76f300ebb9d286c4b7a1fd6ce45fe0c91340b767", size = 287387 }, - { url = "https://files.pythonhosted.org/packages/f4/28/0c089c8f492744e9b96951497ef748f69be8f1b102dc7ef8022c3620d6e2/zstd-1.5.5.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5a53860dbfbea281eb690ce09cae28967cf1df8e6d7560e4a8bf5b9fcb258147", size = 1330755 }, - { url = "https://files.pythonhosted.org/packages/ff/58/fee1ca1cfd93f00999a7fd4405e4fa5daaadb0b520d54714884fc5b43b87/zstd-1.5.5.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:a37cbc0580fdfd66c8b3ec65f9af00a4a34e9781b54dfb89f04d301dc375c90a", size = 1357525 }, - { url = "https://files.pythonhosted.org/packages/10/b7/d14efbe8222be2f1d2989f67a6227f8d60d1d8ebc42884801ef57dd79cee/zstd-1.5.5.1-cp36-cp36m-win32.whl", hash = "sha256:5531b683539ae1f7b2ad23dacee8a73e5d7eaa6702ea8df5a24bd3318647dee1", size = 208335 }, - { url = "https://files.pythonhosted.org/packages/f1/f9/9177a076a12b9bda24cbd5818161805f9aac76e68ff096ce28d4c2c72dd1/zstd-1.5.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:eeaff418269b41eee8c7971fbba9d32d07d3f6aa26f962a72aff725071096a1b", size = 236817 }, - { url = "https://files.pythonhosted.org/packages/00/14/136ded4d155f279aedaa8820522097aa233086f0c253dfe66107055f5862/zstd-1.5.5.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:8bd6a9050de8bbe844447348372ca17d01bc05207619f6a5d448567d111b5cd9", size = 287586 }, - { url = "https://files.pythonhosted.org/packages/b2/fd/b44dd823538923824a44315c9aa58fcf008ad197a937fa59fae9d1e4eecd/zstd-1.5.5.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2ece3d20ef357370584f304407fbd1e4ff9c231209320e08a889b8e3725d56e", size = 1759662 }, - { url = "https://files.pythonhosted.org/packages/94/31/e3f4f509ce0dfd61400ab569b3fc74513ea5f9d6cef661fd6bd393c01bd4/zstd-1.5.5.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:687f9e03dc9f9b8803840425bb23bf6bc700888b4860afcf43c4f238102752d2", size = 1785603 }, - { url = "https://files.pythonhosted.org/packages/4d/9b/ab91fe7adb84b6f54453efc94203342f1a06caf48043ad92fab96db3fe96/zstd-1.5.5.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a649daac9c8f1b37d29f2b3d0a43f134061659b54877fe4b0da6df2965dc91f", size = 1638977 }, - { url = "https://files.pythonhosted.org/packages/fc/d0/d22a476801ffd54d3afd06c5a7d0847fbae3f52b58a432ae2be6b665ef26/zstd-1.5.5.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:bddc7e3c3ce31c01fe1edaa7c03c0b9e71eadf4ce1609746d32f86d95a0449e6", size = 1893397 }, - { url = "https://files.pythonhosted.org/packages/bf/57/0aaf844e5857c8504663ffa014a8123a07cebb5bf3f8dc4e36be2b402516/zstd-1.5.5.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:12bf8e04add8bb84f9fe9117f3de6d9394eade6a5a82fe4d6bd95914fc6ef423", size = 1826259 }, - { url = "https://files.pythonhosted.org/packages/51/9b/ce8652ad4f91f6781307ad456c8d4ce20b184c4bdd0521b3f1c1a4044920/zstd-1.5.5.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9e6a15fa4d2e65c5902ab2a4e41279ac126cb371ce6c3c75ad5789bb20dd1f54", size = 1932046 }, - { url = "https://files.pythonhosted.org/packages/04/1d/ba98ffb91e904891696b21eaef7d67fc6b29b4988b41f51d6db56f008520/zstd-1.5.5.1-cp37-cp37m-win32.whl", hash = "sha256:a1c269243a4321beb948635b544ccbe6390846358ace620fd000ab7099011d9c", size = 150760 }, - { url = "https://files.pythonhosted.org/packages/e3/c0/2926c9e5b9ab981c1033fd02a907b6dee0d34e88e95e46131702c71e641c/zstd-1.5.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:91366e36773241cb4b049a32f4495d33dd274df1eea5b55396f5f3984a3de22e", size = 167952 }, - { url = "https://files.pythonhosted.org/packages/38/19/912b44e6ce720ac8e4dbf157fdb4ee0397b9f74042e3bbcc540d9ddc7366/zstd-1.5.5.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:d3ce2cb310690994274d133ea7f269dd4b81799fdbce158690556209723d7d4e", size = 287588 }, - { url = "https://files.pythonhosted.org/packages/7a/c5/cb3476e783f17e645b0bc35259398b54ed38088672f449ad75f746a1dc4d/zstd-1.5.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e0c87bfbfa9d852f79c90bcd7426c3ba46cf3285e6984013636d4fc854ba9230", size = 227495 }, - { url = "https://files.pythonhosted.org/packages/1c/b5/0df0b8728886bb3758abce7d5f661f088d849df48a2c06e1cd95d33071b1/zstd-1.5.5.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce6d829d515f272fddb3a87e1a5f32cc0f1a7b0cba24d360c89f4a165b74b", size = 1759079 }, - { url = "https://files.pythonhosted.org/packages/35/50/0d7185bb530ca48963f65af1d85909004c6d013ac5d796b4af0fbd2d2d49/zstd-1.5.5.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e05f81f346213b23ed1b12d84fc1f72e65eacd8978e1e88facf185c82bd3d053", size = 1784690 }, - { url = "https://files.pythonhosted.org/packages/fc/c6/a43a72a6fc93089345ed39ddea62c2f9fab340eaba4fd2eea9b3247381f7/zstd-1.5.5.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43ec66c4c3a76351c672c6ef9f0ff3412fca9ede0a56d18dddaf6418a93faef8", size = 1638164 }, - { url = "https://files.pythonhosted.org/packages/2d/78/4670f25d0430dda8ef36b81ae7187300db023612b0ee09b0d1223057d41f/zstd-1.5.5.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:58e554e91e0d49f4f2b2df390cdd0f64aa9b6fd5f4dcb208c094bfd079b30f3a", size = 1893004 }, - { url = "https://files.pythonhosted.org/packages/a5/69/5481b61cc7abfff08df7d029eb6cac5c10db394e77268ffffe291c81707b/zstd-1.5.5.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:883c6d3b6f5574e1765ca97f4b6a41b69094a41be56175552faebc0e0e43b65e", size = 1825939 }, - { url = "https://files.pythonhosted.org/packages/40/47/5b04dd08b0c17198c093622d28927a732394a0469cced365e4a20f97f542/zstd-1.5.5.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d52b6932cab5419c434bccfea3e5640e755369fc9eeb51e3d17e15bf8e8cb103", size = 1931156 }, - { url = "https://files.pythonhosted.org/packages/96/5d/4f98a2a4cfc66a9af449e4e3cb6df2d80c6b40d670e37b0fddffcb0eb309/zstd-1.5.5.1-cp38-cp38-win32.whl", hash = "sha256:dcaf44270ec88552e969be4dd3359b34aa3065663ccd8168a257c78f150a356c", size = 150753 }, - { url = "https://files.pythonhosted.org/packages/1f/80/61e6b77f23885b7a3f777212a7de72aa274f4b2af399abbabff3a1a268c7/zstd-1.5.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:627f12cb7035723c8f3d8d4cefcad6d950ed9cba33fd3eb46bae04ccab479234", size = 167971 }, - { url = "https://files.pythonhosted.org/packages/c1/f2/c3d421c2c90e6bc6cb4c23ca6efac2c9bcdfda17faa27fbe3bf4679c6594/zstd-1.5.5.1-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:c0dab132c1a5a7cc838a7c3e4e380ad153b9d7bd1fadafabf6cfeb780b916201", size = 287593 }, - { url = "https://files.pythonhosted.org/packages/c4/62/ac4a06fd2f39ebfcd308c658002228ff9bb3e439f57cb455aaa66e9aa721/zstd-1.5.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d4ab0a5dd9a41d3b083304beee7ada40ee36431acbeb75132032f4fe5cf0490a", size = 227502 }, - { url = "https://files.pythonhosted.org/packages/56/7e/be5a706c9048b28a9749371dce365207963fcb003279c9dc31df28b48526/zstd-1.5.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f6e38f496d287020658c6b4cdb5e815ecc6998889bd0f1f9ab0825f2e3d74ef", size = 1758697 }, - { url = "https://files.pythonhosted.org/packages/32/31/30ae83f08914e2d15f9c858ebc550e77cbcd80e9cdb8fb2e7c6428b3f7cb/zstd-1.5.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0096c8ee0ed4bfe406bc961019f55552109e19771bfd3eb32d2af56ea27085c", size = 1784345 }, - { url = "https://files.pythonhosted.org/packages/f2/6c/a70c1533565fbf7b8d010c1a5843b3399f7a68802782f89f7f6b375ddf18/zstd-1.5.5.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a0f1527728c50b6aa8f04b47a07580f0ae13cfc6c6d9c96bb0bdf5259487559", size = 1637775 }, - { url = "https://files.pythonhosted.org/packages/72/c3/4f7e673a994ce524ca9ce03aee874b57a327d5799cf27d966eb74a94f244/zstd-1.5.5.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6a64e420c904063c5c3de53c00ec0993ebc0a48cebbef97dc6c768562c5abab5", size = 1892617 }, - { url = "https://files.pythonhosted.org/packages/c8/98/5de848af37a5d65a44bbf82ef3d1f317bfb2ef268d5cec322f4e5752e0a2/zstd-1.5.5.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:03444e357b7632c64480a81ce7095242dab9d7f8aed317326563ef6c663263eb", size = 1825566 }, - { url = "https://files.pythonhosted.org/packages/80/1e/981183513bd4abcdb426ef1e676a541630bdb2177d996161f75ad0c3263f/zstd-1.5.5.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:88b9a10f80d2b87bf8cc1a1fc20a815ed92b5eefdc15cbe8062021f0b5a26a10", size = 1930680 }, - { url = "https://files.pythonhosted.org/packages/1e/1a/14b3be56f67f165e71538a1386152e615f588d24c07e3b3a5616a7a8fb6f/zstd-1.5.5.1-cp39-cp39-win32.whl", hash = "sha256:c91cc1606eb8b3a6fed11faaef4c6e55f1133d70cf0db0c829a2cf9c2ac1dfd9", size = 150754 }, - { url = "https://files.pythonhosted.org/packages/1a/ed/707ed4070063088ac6c68061908b717014eb4e77fbf72b11408c6df2f326/zstd-1.5.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:f462e2ebf26dcbfc2c8dddd6b5c56859683f0b77edb8f268e637f7d390a58f74", size = 167976 }, { url = "https://files.pythonhosted.org/packages/e4/1c/b86aeee12cc1edd59f5a2aae7c15c9651f92ff2de59f2eed9b54f3571954/zstd-1.5.5.1-pp27-pypy_73-macosx_10_14_x86_64.whl", hash = "sha256:c63f916732e3e309e49ec95e7a0af5d37ff1321f3df2aac10e507bd2b56fceda", size = 279624 }, { url = "https://files.pythonhosted.org/packages/50/3c/d0064d52f83ef0b0927ca38a117df1dc413312499f409fcc6314208e2e7b/zstd-1.5.5.1-pp27-pypy_73-manylinux1_x86_64.whl", hash = "sha256:50d4850d758bb033df50722cc13ed913b2afcd5385250be4f3ffb79a26b319c3", size = 253751 }, { url = "https://files.pythonhosted.org/packages/99/08/222f3f732c4af90239c0f09703d8b82089846451621d27194467f864cf85/zstd-1.5.5.1-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:0412d666515e78a91ada7e2d78e9dd6b25ddda1b41623b145b99653275c7f3ce", size = 253752 }, - { url = "https://files.pythonhosted.org/packages/d8/17/13d06d1bc5abdf2e0a3ff9ec30101a80bd4ef236395c8ac88cf428f02bce/zstd-1.5.5.1-pp36-pypy36_pp73-macosx_10_14_x86_64.whl", hash = "sha256:0ea91f74869a3cdcb2dde08f8f30ee3da72782c5d1737afed9c703232815864e", size = 279823 }, - { url = "https://files.pythonhosted.org/packages/de/bf/2765bc9aeed023b9f41d91ca8a67b569f5fcc346473f36e969793358b011/zstd-1.5.5.1-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:477548897dc2b8b595af7bec5f0f55dcba8e9a282335f687cc663b52b171357b", size = 254108 }, - { url = "https://files.pythonhosted.org/packages/fb/8e/4b729f71e421eec5e93ad5966ae17dd3ab44c6b34a611bc93ce0ebbfba54/zstd-1.5.5.1-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:c518938b57a56001ee04dcf79a432152f5bd431416f3b22819ba959bc6054d89", size = 254111 }, - { url = "https://files.pythonhosted.org/packages/44/3f/045360aca530895bd43acdbf5df14da6743ca2a0647a5b301c77d186ecd1/zstd-1.5.5.1-pp36-pypy36_pp73-win32.whl", hash = "sha256:894a8fe0228d5e24dc286a8d98eb0ce2883f8e2e57f3b7e7619ebdb67967120a", size = 208412 }, - { url = "https://files.pythonhosted.org/packages/4a/d3/b812cae617abeddbf690375ce69b2201ef35b681d70c2b4421a8b2dc33b5/zstd-1.5.5.1-pp37-pypy37_pp73-macosx_10_14_x86_64.whl", hash = "sha256:42ec0a4ae9bedd9909fa4f580f3c800469da1b631faeaa94f204e1b66c767fa2", size = 280032 }, - { url = "https://files.pythonhosted.org/packages/5e/bb/09b73f6071c708f190e3ac347d1d42a53519f60d46b5adaebd0f6760b3fd/zstd-1.5.5.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d56dedaa04ab8ecc23492972b12e0bf8529f64c9bceb28c11f43c2369c9768b3", size = 245071 }, - { url = "https://files.pythonhosted.org/packages/6c/b3/9a61cf00ec2ae814785fb308cc6339a0972d2e43ee293b5fb5aeb8b8dab1/zstd-1.5.5.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5b060770d796e4c01f5848b345c3cea8a177ab4e7cd95a1963a355042d429e1", size = 244798 }, - { url = "https://files.pythonhosted.org/packages/70/63/d2a0bd3cf1720a2471524ce36910ee3174f2ea20eb806379e5c3077b67f3/zstd-1.5.5.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fea04805ef6e1cb93d6e5d6bbc7a03bc75a5c733fd352d5aaa81109986fdf1ef", size = 251773 }, - { url = "https://files.pythonhosted.org/packages/18/df/6d48f84bd6d86add31284b93557d208add41e4c607d9389693d72fd436db/zstd-1.5.5.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:405c28a35756e57a434bbd7ed29dc5e6490cd2fc2118cbf78b60eaebd134f5e9", size = 168054 }, - { url = "https://files.pythonhosted.org/packages/51/ec/9b976b40e7001ef01b9bb44933432ef95513c13d75e87dec2600eb626adf/zstd-1.5.5.1-pp38-pypy38_pp73-macosx_10_14_x86_64.whl", hash = "sha256:c42e630443b01a891277426365a51a2aa630b059ce675992c70c1928d30eccb4", size = 280030 }, - { url = "https://files.pythonhosted.org/packages/f7/29/6ea755d3afa6cbeab79efeecf03e43a69dfee5fa66136db734bdcc2dd288/zstd-1.5.5.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1520d23f24f26cdfbcdb4dc86947446b8f694838bfce728d7fc4b3492397357c", size = 243462 }, - { url = "https://files.pythonhosted.org/packages/be/b8/bf454f7c597900a4039cd33507135fcc962cd341df56e8414600118f971b/zstd-1.5.5.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f4730737f63cf802321743ded6acc85e747e7f5587c5ba2e51a760bf009f7de", size = 242453 }, - { url = "https://files.pythonhosted.org/packages/39/5e/0f34cd1033cbbabddcf4fb478c1a4fee08ec268ad91830c3d85fc934eb58/zstd-1.5.5.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9f8c014395e89ad7f67ffe873c0fa1d8e9b4dea8b1801d24e8d9ccd8259858d", size = 249483 }, - { url = "https://files.pythonhosted.org/packages/6a/89/ae02b82f2a3fea651a439ac6a08f27ed6eaf58b81e1cfff960a1125332ca/zstd-1.5.5.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5d9ba4f6af0945809bfa3387c6a1208a22937a876521b9ec347e7183d623311b", size = 168053 }, - { url = "https://files.pythonhosted.org/packages/16/df/ee13ef4e6bef46bac31d814d2c7b3849b10f8b7f6a1dc0c8cfbe75090feb/zstd-1.5.5.1-pp39-pypy39_pp73-macosx_10_14_x86_64.whl", hash = "sha256:04dfd9f46b0b0b1bc413884fe028b726febcb726d4f66e3cf8afc00c2d9026bf", size = 280032 }, - { url = "https://files.pythonhosted.org/packages/c2/ab/b07a5f00673a5b56c789e4feba0071919ff84bd739742f931495fba0df65/zstd-1.5.5.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af52436a2eb5caa925d95461973984cb34d472a963b6be1c0a9f2dfbafad096f", size = 243479 }, - { url = "https://files.pythonhosted.org/packages/f4/f4/fc09d90503a43ff71baba4670929c3c03c147a17252870e99e30e3de5994/zstd-1.5.5.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610928b888a2e7ae9d2018ffa814859d47ec4ba75f89a1188ab4eb9232636ee5", size = 242436 }, - { url = "https://files.pythonhosted.org/packages/bc/26/a8472d043a9f531a3dccb44e69266905804bb4671b48176d9e534f204c1c/zstd-1.5.5.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee3c9feea99c7f4ff43129a885da056b5aa0cde3f7876bf6397bfb9433f44352", size = 249476 }, - { url = "https://files.pythonhosted.org/packages/a4/f7/6f5d9350be2c3709a7f8a911f763ba645ff130b5a904bfff79370cae1e21/zstd-1.5.5.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6ac9768eeb3c6b530db93de2fec9b363776075dc8a00ee4049612ba5397ca8e", size = 168053 }, ] From 76686e197605d26be226e71e9ba803a05fa04d2f Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Mon, 8 Jul 2024 12:14:32 -0700 Subject: [PATCH 008/229] docs: only push on master (#32935) only on master --- .github/workflows/docs.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 012ee9dfde..cb55d2f831 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -35,13 +35,13 @@ jobs: # Push to docs.comma.ai - uses: actions/checkout@v4 - #if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' + if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' with: path: openpilot-docs ssh-key: ${{ secrets.OPENPILOT_DOCS_KEY }} repository: commaai/openpilot-docs - name: Push - #if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' + if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' run: | set -x From 12d729a0a0c3c1d9bbf988c09ea3a5b68433e83f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 9 Jul 2024 04:50:31 +0800 Subject: [PATCH 009/229] CarParams: set no traversal limit (#32929) * Increase traversal_limit_in_words to Fix Traversal Limit Errors * just use log_from_bytes * come on pycharm * no free lunch --------- Co-authored-by: Shane Smiskol --- cereal/messaging/__init__.py | 4 ++-- selfdrive/controls/controlsd.py | 3 +-- selfdrive/controls/plannerd.py | 3 +-- selfdrive/controls/radard.py | 3 +-- selfdrive/locationd/paramsd.py | 6 ++---- selfdrive/locationd/torqued.py | 3 +-- selfdrive/modeld/modeld.py | 4 ++-- 7 files changed, 10 insertions(+), 16 deletions(-) diff --git a/cereal/messaging/__init__.py b/cereal/messaging/__init__.py index 4ba55cf7b9..8dfa42056d 100644 --- a/cereal/messaging/__init__.py +++ b/cereal/messaging/__init__.py @@ -17,8 +17,8 @@ from cereal.services import SERVICE_LIST NO_TRAVERSAL_LIMIT = 2**64-1 -def log_from_bytes(dat: bytes) -> capnp.lib.capnp._DynamicStructReader: - with log.Event.from_bytes(dat, traversal_limit_in_words=NO_TRAVERSAL_LIMIT) as msg: +def log_from_bytes(dat: bytes, struct: capnp.lib.capnp._StructModule = log.Event) -> capnp.lib.capnp._DynamicStructReader: + with struct.from_bytes(dat, traversal_limit_in_words=NO_TRAVERSAL_LIMIT) as msg: return msg diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 416a9aa8c5..583cbaea1f 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -64,8 +64,7 @@ class Controls: if CI is None: cloudlog.info("controlsd is waiting for CarParams") - with car.CarParams.from_bytes(self.params.get("CarParams", block=True)) as msg: - self.CP = msg + self.CP = messaging.log_from_bytes(self.params.get("CarParams", block=True), car.CarParams) cloudlog.info("controlsd got CarParams") # Uses car interface helper functions, altering state won't be considered by card for actuation diff --git a/selfdrive/controls/plannerd.py b/selfdrive/controls/plannerd.py index 681518be19..a9577cbefd 100755 --- a/selfdrive/controls/plannerd.py +++ b/selfdrive/controls/plannerd.py @@ -12,8 +12,7 @@ def plannerd_thread(): cloudlog.info("plannerd is waiting for CarParams") params = Params() - with car.CarParams.from_bytes(params.get("CarParams", block=True)) as msg: - CP = msg + CP = messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams) cloudlog.info("plannerd got CarParams: %s", CP.carName) longitudinal_planner = LongitudinalPlanner(CP) diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index ac3ec97dcc..c3fb60c61a 100755 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -288,8 +288,7 @@ def main(): # wait for stats about the car to come in from controls cloudlog.info("radard is waiting for CarParams") - with car.CarParams.from_bytes(Params().get("CarParams", block=True)) as msg: - CP = msg + CP = messaging.log_from_bytes(Params().get("CarParams", block=True), car.CarParams) cloudlog.info("radard got CarParams") # import the radar from the fingerprint diff --git a/selfdrive/locationd/paramsd.py b/selfdrive/locationd/paramsd.py index d124eb5f05..650ee06017 100755 --- a/selfdrive/locationd/paramsd.py +++ b/selfdrive/locationd/paramsd.py @@ -5,8 +5,7 @@ import json import numpy as np import cereal.messaging as messaging -from cereal import car -from cereal import log +from cereal import car, log from openpilot.common.params import Params from openpilot.common.realtime import config_realtime_process, DT_MDL from openpilot.common.numpy_fast import clip @@ -129,8 +128,7 @@ def main(): params_reader = Params() # wait for stats about the car to come in from controls cloudlog.info("paramsd is waiting for CarParams") - with car.CarParams.from_bytes(params_reader.get("CarParams", block=True)) as msg: - CP = msg + CP = messaging.log_from_bytes(params_reader.get("CarParams", block=True), car.CarParams) cloudlog.info("paramsd got CarParams") min_sr, max_sr = 0.5 * CP.steerRatio, 2.0 * CP.steerRatio diff --git a/selfdrive/locationd/torqued.py b/selfdrive/locationd/torqued.py index 06f9044738..569496b584 100755 --- a/selfdrive/locationd/torqued.py +++ b/selfdrive/locationd/torqued.py @@ -223,8 +223,7 @@ def main(demo=False): sm = messaging.SubMaster(['carControl', 'carOutput', 'carState', 'liveLocationKalman'], poll='liveLocationKalman') params = Params() - with car.CarParams.from_bytes(params.get("CarParams", block=True)) as CP: - estimator = TorqueEstimator(CP) + estimator = TorqueEstimator(messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams)) while True: sm.update() diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py index d5812d6f5a..d2cc9d8fd7 100755 --- a/selfdrive/modeld/modeld.py +++ b/selfdrive/modeld/modeld.py @@ -172,8 +172,8 @@ def main(demo=False): if demo: CP = get_demo_car_params() else: - with car.CarParams.from_bytes(params.get("CarParams", block=True)) as msg: - CP = msg + CP = messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams) + cloudlog.info("modeld got CarParams: %s", CP.carName) # TODO this needs more thought, use .2s extra for now to estimate other delays From fa2f7a4dd43df834393b95f32c5282a85e39278e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 8 Jul 2024 14:16:44 -0700 Subject: [PATCH 010/229] [bot] Fingerprints: add missing FW versions from new users (#32936) Export fingerprints --- selfdrive/car/chrysler/fingerprints.py | 1 + selfdrive/car/honda/fingerprints.py | 1 + 2 files changed, 2 insertions(+) diff --git a/selfdrive/car/chrysler/fingerprints.py b/selfdrive/car/chrysler/fingerprints.py index 1bc6a32431..8f6359c06b 100644 --- a/selfdrive/car/chrysler/fingerprints.py +++ b/selfdrive/car/chrysler/fingerprints.py @@ -245,6 +245,7 @@ FW_VERSIONS = { b'68416680AE ', b'68416680AF ', b'68416680AG ', + b'68444228AC ', b'68444228AD ', b'68444228AE ', b'68444228AF ', diff --git a/selfdrive/car/honda/fingerprints.py b/selfdrive/car/honda/fingerprints.py index 0904d5e12c..191fd8e44a 100644 --- a/selfdrive/car/honda/fingerprints.py +++ b/selfdrive/car/honda/fingerprints.py @@ -529,6 +529,7 @@ FW_VERSIONS = { b'28102-5MX-A900\x00\x00', b'28102-5MX-A910\x00\x00', b'28102-5MX-C001\x00\x00', + b'28102-5MX-C610\x00\x00', b'28102-5MX-C910\x00\x00', b'28102-5MX-D001\x00\x00', b'28102-5MX-D710\x00\x00', From 31ff8eda9cedb54aa32df8ebf5dc729addf82ef2 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 8 Jul 2024 14:45:01 -0700 Subject: [PATCH 011/229] Chrysler Pacifica Hybrid: combine 2017 and 2018 (#32937) * Chrysler Pacifica: combine 2017 and 2018 hybrids torque params are not accurate for either (might be ~1.5 for both checking a few dongles) * remove duplicate fingerprints * combine docs lines fix --- docs/CARS.md | 5 ++- selfdrive/car/chrysler/fingerprints.py | 42 ++++++++------------------ selfdrive/car/chrysler/interface.py | 4 +-- selfdrive/car/chrysler/values.py | 16 ++++------ selfdrive/car/fingerprints.py | 3 +- selfdrive/car/tests/routes.py | 2 +- selfdrive/car/torque_data/params.toml | 1 - 7 files changed, 26 insertions(+), 47 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 769fe6e27a..8fafc483f2 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified. -# 288 Supported Cars +# 287 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Hardware Needed
 |Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -25,8 +25,7 @@ A supported vehicle is one that just works when you install a comma device. All |Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Chrysler|Pacifica 2021-23|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Chrysler|Pacifica Hybrid 2017|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Chrysler|Pacifica Hybrid 2018|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Chrysler|Pacifica Hybrid 2019-24|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None|| |CUPRA|Ateca 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/chrysler/fingerprints.py b/selfdrive/car/chrysler/fingerprints.py index 8f6359c06b..5528bfd5d5 100644 --- a/selfdrive/car/chrysler/fingerprints.py +++ b/selfdrive/car/chrysler/fingerprints.py @@ -4,35 +4,6 @@ from openpilot.selfdrive.car.chrysler.values import CAR Ecu = car.CarParams.Ecu FW_VERSIONS = { - CAR.CHRYSLER_PACIFICA_2017_HYBRID: { - (Ecu.combinationMeter, 0x742, None): [ - b'68239262AH', - b'68239262AI', - b'68239262AJ', - b'68239263AH', - b'68239263AJ', - ], - (Ecu.srs, 0x744, None): [ - b'68238840AH', - ], - (Ecu.fwdRadar, 0x753, None): [ - b'68226356AI', - ], - (Ecu.eps, 0x75a, None): [ - b'68288309AC', - b'68288309AD', - ], - (Ecu.engine, 0x7e0, None): [ - b'68277480AV ', - b'68277480AX ', - b'68277480AZ ', - ], - (Ecu.hybrid, 0x7e2, None): [ - b'05190175BF', - b'05190175BH', - b'05190226AK', - ], - }, CAR.CHRYSLER_PACIFICA_2018: { (Ecu.combinationMeter, 0x742, None): [ b'68227902AF', @@ -181,26 +152,39 @@ FW_VERSIONS = { }, CAR.CHRYSLER_PACIFICA_2018_HYBRID: { (Ecu.combinationMeter, 0x742, None): [ + b'68239262AH', + b'68239262AI', + b'68239262AJ', + b'68239263AH', + b'68239263AJ', b'68358439AE', b'68358439AG', ], (Ecu.srs, 0x744, None): [ + b'68238840AH', b'68358990AC', b'68405939AA', ], (Ecu.fwdRadar, 0x753, None): [ b'04672758AA', + b'68226356AI', ], (Ecu.eps, 0x75a, None): [ + b'68288309AC', b'68288309AD', b'68525339AA', ], (Ecu.engine, 0x7e0, None): [ + b'68277480AV ', + b'68277480AX ', + b'68277480AZ ', b'68366580AI ', b'68366580AK ', b'68366580AM ', ], (Ecu.hybrid, 0x7e2, None): [ + b'05190175BF', + b'05190175BH', b'05190226AI', b'05190226AK', b'05190226AM', diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index 217a1a756c..eb1f6703cd 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -35,8 +35,8 @@ class CarInterface(CarInterfaceBase): ret.flags |= ChryslerFlags.HIGHER_MIN_STEERING_SPEED.value # Chrysler - if candidate in (CAR.CHRYSLER_PACIFICA_2017_HYBRID, CAR.CHRYSLER_PACIFICA_2018, CAR.CHRYSLER_PACIFICA_2018_HYBRID, \ - CAR.CHRYSLER_PACIFICA_2019_HYBRID, CAR.CHRYSLER_PACIFICA_2020, CAR.DODGE_DURANGO): + if candidate in (CAR.CHRYSLER_PACIFICA_2018, CAR.CHRYSLER_PACIFICA_2018_HYBRID, CAR.CHRYSLER_PACIFICA_2019_HYBRID, + CAR.CHRYSLER_PACIFICA_2020, CAR.DODGE_DURANGO): ret.lateralTuning.init('pid') ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kiBP = [[9., 20.], [9., 20.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]] diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 3315a0a983..c44c647fd4 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -32,34 +32,30 @@ class ChryslerCarSpecs(CarSpecs): class CAR(Platforms): # Chrysler - CHRYSLER_PACIFICA_2017_HYBRID = ChryslerPlatformConfig( - [ChryslerCarDocs("Chrysler Pacifica Hybrid 2017")], - ChryslerCarSpecs(mass=2242., wheelbase=3.089, steerRatio=16.2), - ) CHRYSLER_PACIFICA_2018_HYBRID = ChryslerPlatformConfig( - [ChryslerCarDocs("Chrysler Pacifica Hybrid 2018")], - CHRYSLER_PACIFICA_2017_HYBRID.specs, + [ChryslerCarDocs("Chrysler Pacifica Hybrid 2017-18")], + ChryslerCarSpecs(mass=2242., wheelbase=3.089, steerRatio=16.2), ) CHRYSLER_PACIFICA_2019_HYBRID = ChryslerPlatformConfig( [ChryslerCarDocs("Chrysler Pacifica Hybrid 2019-24")], - CHRYSLER_PACIFICA_2017_HYBRID.specs, + CHRYSLER_PACIFICA_2018_HYBRID.specs, ) CHRYSLER_PACIFICA_2018 = ChryslerPlatformConfig( [ChryslerCarDocs("Chrysler Pacifica 2017-18")], - CHRYSLER_PACIFICA_2017_HYBRID.specs, + CHRYSLER_PACIFICA_2018_HYBRID.specs, ) CHRYSLER_PACIFICA_2020 = ChryslerPlatformConfig( [ ChryslerCarDocs("Chrysler Pacifica 2019-20"), ChryslerCarDocs("Chrysler Pacifica 2021-23", package="All"), ], - CHRYSLER_PACIFICA_2017_HYBRID.specs, + CHRYSLER_PACIFICA_2018_HYBRID.specs, ) # Dodge DODGE_DURANGO = ChryslerPlatformConfig( [ChryslerCarDocs("Dodge Durango 2020-21")], - CHRYSLER_PACIFICA_2017_HYBRID.specs, + CHRYSLER_PACIFICA_2018_HYBRID.specs, ) # Jeep diff --git a/selfdrive/car/fingerprints.py b/selfdrive/car/fingerprints.py index 1128a31c29..dc93c38246 100644 --- a/selfdrive/car/fingerprints.py +++ b/selfdrive/car/fingerprints.py @@ -130,7 +130,8 @@ MIGRATION = { # Removal of platform_str, see https://github.com/commaai/openpilot/pull/31868/ "COMMA BODY": BODY.COMMA_BODY, - "CHRYSLER PACIFICA HYBRID 2017": CHRYSLER.CHRYSLER_PACIFICA_2017_HYBRID, + "CHRYSLER PACIFICA HYBRID 2017": CHRYSLER.CHRYSLER_PACIFICA_2018_HYBRID, + "CHRYSLER_PACIFICA_2017_HYBRID": CHRYSLER.CHRYSLER_PACIFICA_2018_HYBRID, "CHRYSLER PACIFICA HYBRID 2018": CHRYSLER.CHRYSLER_PACIFICA_2018_HYBRID, "CHRYSLER PACIFICA HYBRID 2019": CHRYSLER.CHRYSLER_PACIFICA_2019_HYBRID, "CHRYSLER PACIFICA 2018": CHRYSLER.CHRYSLER_PACIFICA_2018, diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index b1156f0e89..0fc800a47d 100755 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -39,7 +39,7 @@ routes = [ CarTestRoute("0c94aa1e1296d7c6|2021-05-05--19-48-37", CHRYSLER.JEEP_GRAND_CHEROKEE), CarTestRoute("91dfedae61d7bd75|2021-05-22--20-07-52", CHRYSLER.JEEP_GRAND_CHEROKEE_2019), - CarTestRoute("420a8e183f1aed48|2020-03-05--07-15-29", CHRYSLER.CHRYSLER_PACIFICA_2017_HYBRID), + CarTestRoute("420a8e183f1aed48|2020-03-05--07-15-29", CHRYSLER.CHRYSLER_PACIFICA_2018_HYBRID), # 2017 CarTestRoute("43a685a66291579b|2021-05-27--19-47-29", CHRYSLER.CHRYSLER_PACIFICA_2018), CarTestRoute("378472f830ee7395|2021-05-28--07-38-43", CHRYSLER.CHRYSLER_PACIFICA_2018_HYBRID), CarTestRoute("8190c7275a24557b|2020-01-29--08-33-58", CHRYSLER.CHRYSLER_PACIFICA_2019_HYBRID), diff --git a/selfdrive/car/torque_data/params.toml b/selfdrive/car/torque_data/params.toml index 34cfd0e066..4bb8d45c53 100644 --- a/selfdrive/car/torque_data/params.toml +++ b/selfdrive/car/torque_data/params.toml @@ -7,7 +7,6 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "CHEVROLET_VOLT" = [1.5961527626411784, 1.8422651988094612, 0.1572393918005158] "CHRYSLER_PACIFICA_2018" = [2.07140, 1.3366521181047952, 0.13776367250652022] "CHRYSLER_PACIFICA_2020" = [1.86206, 1.509076559398423, 0.14328246159386085] -"CHRYSLER_PACIFICA_2017_HYBRID" = [1.79422, 1.06831764583744, 0.116237] "CHRYSLER_PACIFICA_2018_HYBRID" = [2.08887, 1.2943025830995154, 0.114818] "CHRYSLER_PACIFICA_2019_HYBRID" = [1.90120, 1.1958788168371808, 0.131520] "GENESIS_G70" = [3.8520195946707947, 2.354697063349854, 0.06830285485626221] From 36815cc6d536ab8926f6335574ea587947c4e222 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 9 Jul 2024 05:50:31 +0800 Subject: [PATCH 012/229] cabana: bug fixes and improvements (#32934) bug fixes and improvements --- tools/cabana/chart/chart.cc | 14 ++--- tools/cabana/chart/chart.h | 1 + tools/cabana/chart/chartswidget.cc | 26 +++++---- tools/cabana/chart/sparkline.cc | 9 +-- tools/cabana/chart/tiplabel.h | 2 + tools/cabana/dbc/dbcmanager.cc | 7 ++- tools/cabana/historylog.cc | 4 +- tools/cabana/streams/abstractstream.cc | 48 ++++++++-------- tools/cabana/streams/abstractstream.h | 30 +++++----- tools/cabana/streams/livestream.cc | 6 +- tools/cabana/streams/livestream.h | 7 ++- tools/cabana/streams/pandastream.h | 6 ++ tools/cabana/streams/replaystream.cc | 13 +---- tools/cabana/streams/replaystream.h | 9 ++- tools/cabana/tools/findsignal.cc | 6 +- tools/cabana/utils/export.cc | 6 +- tools/cabana/videowidget.cc | 77 +++++++++++++++++--------- tools/cabana/videowidget.h | 27 +++++++-- tools/replay/consoleui.cc | 10 ++-- tools/replay/replay.cc | 24 ++++++-- tools/replay/replay.h | 8 ++- 21 files changed, 199 insertions(+), 141 deletions(-) diff --git a/tools/cabana/chart/chart.cc b/tools/cabana/chart/chart.cc index 28d4e068ee..128c33baec 100644 --- a/tools/cabana/chart/chart.cc +++ b/tools/cabana/chart/chart.cc @@ -289,10 +289,9 @@ void ChartView::appendCanEvents(const cabana::Signal *sig, const std::vectorrouteStartTime() * 1e9; for (const CanEvent *e : events) { if (sig->getValue(e->dat, e->size, &value)) { - const double ts = (e->mono_time - std::min(e->mono_time, begin_mono_time)) / 1e9; + const double ts = can->toSeconds(e->mono_time); vals.emplace_back(ts, value); if (!step_vals.empty()) step_vals.emplace_back(ts, step_vals.back().y()); @@ -312,7 +311,7 @@ void ChartView::updateSeries(const cabana::Signal *sig, const MessageEventsMap * auto it = events->find(s.msg_id); if (it == events->end() || it->second.empty()) continue; - if (s.vals.empty() || (it->second.back()->mono_time / 1e9 - can->routeStartTime()) > s.vals.back().x()) { + if (s.vals.empty() || can->toSeconds(it->second.back()->mono_time) > s.vals.back().x()) { appendCanEvents(s.sig, it->second, s.vals, s.step_vals); } else { std::vector vals, step_vals; @@ -500,8 +499,8 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { rubber->hide(); auto rect = rubber->geometry().normalized(); // Prevent zooming/seeking past the end of the route - double min = std::clamp(chart()->mapToValue(rect.topLeft()).x(), 0., can->totalSeconds()); - double max = std::clamp(chart()->mapToValue(rect.bottomRight()).x(), 0., can->totalSeconds()); + double min = std::clamp(chart()->mapToValue(rect.topLeft()).x(), can->minSeconds(), can->maxSeconds()); + double max = std::clamp(chart()->mapToValue(rect.bottomRight()).x(), can->minSeconds(), can->maxSeconds()); if (rubber->width() <= 0) { // no rubber dragged, seek to mouse position can->seekTo(min); @@ -531,7 +530,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { // Scrubbing if (is_scrubbing && QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier)) { if (plot_area.contains(ev->pos())) { - can->seekTo(std::clamp(chart()->mapToValue(ev->pos()).x(), 0., can->totalSeconds())); + can->seekTo(std::clamp(chart()->mapToValue(ev->pos()).x(), can->minSeconds(), can->maxSeconds())); } } @@ -540,8 +539,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { clearTrackPoints(); if (!is_zooming && plot_area.contains(ev->pos()) && isActiveWindow()) { - const double sec = chart()->mapToValue(ev->pos()).x(); - charts_widget->showValueTip(sec); + charts_widget->showValueTip(secondsAtPoint(ev->pos())); } else if (tip_label->isVisible()) { charts_widget->showValueTip(-1); } diff --git a/tools/cabana/chart/chart.h b/tools/cabana/chart/chart.h index 1bfec6355a..f9472bd4f6 100644 --- a/tools/cabana/chart/chart.h +++ b/tools/cabana/chart/chart.h @@ -39,6 +39,7 @@ public: void showTip(double sec); void hideTip(); void startAnimation(); + double secondsAtPoint(const QPointF &pt) const { return chart()->mapToValue(pt).x(); } struct SigItem { MessageId msg_id; diff --git a/tools/cabana/chart/chartswidget.cc b/tools/cabana/chart/chartswidget.cc index 9822eaa307..27846f9c92 100644 --- a/tools/cabana/chart/chartswidget.cc +++ b/tools/cabana/chart/chartswidget.cc @@ -93,7 +93,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { current_theme = settings.theme; column_count = std::clamp(settings.chart_column_count, 1, MAX_COLUMN_COUNT); max_chart_range = std::clamp(settings.chart_range, 1, settings.max_cached_minutes * 60); - display_range = {0, max_chart_range}; + display_range = std::make_pair(can->minSeconds(), can->minSeconds() + max_chart_range); range_slider->setValue(max_chart_range); updateToolBar(); @@ -192,10 +192,10 @@ void ChartsWidget::updateState() { if (!time_range.has_value()) { double pos = (cur_sec - display_range.first) / std::max(1.0, max_chart_range); if (pos < 0 || pos > 0.8) { - display_range.first = std::max(0.0, cur_sec - max_chart_range * 0.1); + display_range.first = std::max(can->minSeconds(), cur_sec - max_chart_range * 0.1); } - double max_sec = std::min(display_range.first + max_chart_range, can->totalSeconds()); - display_range.first = std::max(0.0, max_sec - max_chart_range); + double max_sec = std::min(display_range.first + max_chart_range, can->maxSeconds()); + display_range.first = std::max(can->minSeconds(), max_sec - max_chart_range); display_range.second = display_range.first + max_chart_range; } @@ -435,14 +435,20 @@ void ChartsWidget::alignCharts() { bool ChartsWidget::eventFilter(QObject *o, QEvent *e) { if (value_tip_visible_ && e->type() == QEvent::MouseMove) { - auto pos = static_cast(e)->globalPos(); - bool outside_plot_area =std::none_of(charts.begin(), charts.end(), [&pos](auto c) { - return c->chart()->plotArea().contains(c->mapFromGlobal(pos)); - }); + bool on_tip = qobject_cast(o) != nullptr; + auto global_pos = static_cast(e)->globalPos(); - if (outside_plot_area) { - showValueTip(-1); + for (const auto &c : charts) { + auto local_pos = c->mapFromGlobal(global_pos); + if (c->chart()->plotArea().contains(local_pos)) { + if (on_tip) { + showValueTip(c->secondsAtPoint(local_pos)); + } + return false; + } } + + showValueTip(-1); } return false; } diff --git a/tools/cabana/chart/sparkline.cc b/tools/cabana/chart/sparkline.cc index 34bc76b7c4..1cadda2bd8 100644 --- a/tools/cabana/chart/sparkline.cc +++ b/tools/cabana/chart/sparkline.cc @@ -8,10 +8,11 @@ void Sparkline::update(const MessageId &msg_id, const cabana::Signal *sig, double last_msg_ts, int range, QSize size) { const auto &msgs = can->events(msg_id); - uint64_t ts = (last_msg_ts + can->routeStartTime()) * 1e9; - uint64_t first_ts = (ts > range * 1e9) ? ts - range * 1e9 : 0; - auto first = std::lower_bound(msgs.cbegin(), msgs.cend(), first_ts, CompareCanEvent()); - auto last = std::upper_bound(first, msgs.cend(), ts, CompareCanEvent()); + + auto range_start = can->toMonoTime(last_msg_ts - range); + auto range_end = can->toMonoTime(last_msg_ts); + auto first = std::lower_bound(msgs.cbegin(), msgs.cend(), range_start, CompareCanEvent()); + auto last = std::upper_bound(first, msgs.cend(), range_end, CompareCanEvent()); if (first == last || size.isEmpty()) { pixmap = QPixmap(); diff --git a/tools/cabana/chart/tiplabel.h b/tools/cabana/chart/tiplabel.h index ac6e09e976..cc96aa9864 100644 --- a/tools/cabana/chart/tiplabel.h +++ b/tools/cabana/chart/tiplabel.h @@ -3,6 +3,8 @@ #include class TipLabel : public QLabel { + Q_OBJECT + public: TipLabel(QWidget *parent = nullptr); void showText(const QPoint &pt, const QString &sec, QWidget *w, const QRect &rect); diff --git a/tools/cabana/dbc/dbcmanager.cc b/tools/cabana/dbc/dbcmanager.cc index 250ec225b5..8e98d95322 100644 --- a/tools/cabana/dbc/dbcmanager.cc +++ b/tools/cabana/dbc/dbcmanager.cc @@ -1,5 +1,6 @@ #include "tools/cabana/dbc/dbcmanager.h" +#include #include #include @@ -124,16 +125,16 @@ cabana::Msg *DBCManager::msg(uint8_t source, const QString &name) { QStringList DBCManager::signalNames() { // Used for autocompletion - QStringList ret; + QSet names; for (auto &f : allDBCFiles()) { for (auto &[_, m] : f->getMessages()) { for (auto sig : m.getSignals()) { - ret << sig->name; + names.insert(sig->name); } } } + QStringList ret = names.values(); ret.sort(); - ret.removeDuplicates(); return ret; } diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 55ba0a4919..7e73da55f0 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -13,7 +13,7 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { const auto &m = messages[index.row()]; const int col = index.column(); if (role == Qt::DisplayRole) { - if (col == 0) return QString::number((m.mono_time / (double)1e9) - can->routeStartTime(), 'f', 3); + if (col == 0) return QString::number(can->toSeconds(m.mono_time), 'f', 3); if (!isHexMode()) return sigs[col - 1]->formatValue(m.sig_values[col - 1], false); } else if (role == Qt::TextAlignmentRole) { return (uint32_t)(Qt::AlignRight | Qt::AlignVCenter); @@ -80,7 +80,7 @@ void HistoryLogModel::updateState(bool clear) { messages.clear(); endRemoveRows(); } - uint64_t current_time = (can->lastMessage(msg_id).ts + can->routeStartTime()) * 1e9 + 1; + uint64_t current_time = can->toMonoTime(can->lastMessage(msg_id).ts) + 1; fetchData(messages.begin(), current_time, messages.empty() ? 0 : messages.front().mono_time); } diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index 2584106ce4..ee6a1143c8 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -1,6 +1,5 @@ #include "tools/cabana/streams/abstractstream.h" -#include #include #include @@ -20,9 +19,9 @@ AbstractStream::AbstractStream(QObject *parent) : QObject(parent) { assert(parent != nullptr); event_buffer_ = std::make_unique(EVENT_NEXT_BUFFER_SIZE); - QObject::connect(QApplication::instance(), &QCoreApplication::aboutToQuit, this, &AbstractStream::stop); QObject::connect(this, &AbstractStream::privateUpdateLastMsgsSignal, this, &AbstractStream::updateLastMessages, Qt::QueuedConnection); QObject::connect(this, &AbstractStream::seekedTo, this, &AbstractStream::updateLastMsgsTo); + QObject::connect(this, &AbstractStream::seeking, this, [this](double sec) { current_sec_ = sec; }); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &AbstractStream::updateMasks); QObject::connect(dbc(), &DBCManager::maskUpdated, this, &AbstractStream::updateMasks); QObject::connect(this, &AbstractStream::streamStarted, [this]() { @@ -64,14 +63,12 @@ void AbstractStream::suppressDefinedSignals(bool suppress) { size_t AbstractStream::suppressHighlighted() { std::lock_guard lk(mutex_); size_t cnt = 0; - const double cur_ts = currentSec(); for (auto &[_, m] : messages_) { for (auto &last_change : m.last_changes) { - const double dt = cur_ts - last_change.ts; + const double dt = current_sec_ - last_change.ts; if (dt < 2.0) { last_change.suppressed = true; } - // clear bit change counts last_change.bit_change_counts.fill(0); cnt += last_change.suppressed; } @@ -90,20 +87,16 @@ void AbstractStream::updateLastMessages() { auto prev_src_size = sources.size(); auto prev_msg_size = last_msgs.size(); std::set msgs; + { std::lock_guard lk(mutex_); - double max_sec = 0; for (const auto &id : new_msgs_) { const auto &can_data = messages_[id]; - max_sec = std::max(max_sec, can_data.ts); + current_sec_ = std::max(current_sec_, can_data.ts); last_msgs[id] = can_data; sources.insert(id.source); } - - if (!new_msgs_.empty()) { - msgs = std::move(new_msgs_); - current_sec_ = max_sec; - } + msgs = std::move(new_msgs_); } if (time_range_ && (current_sec_ < time_range_->first || current_sec_ >= time_range_->second)) { @@ -138,7 +131,7 @@ const std::vector &AbstractStream::events(const MessageId &id) return it != events_.end() ? it->second : empty_events; } -const CanData &AbstractStream::lastMessage(const MessageId &id) { +const CanData &AbstractStream::lastMessage(const MessageId &id) const { static CanData empty_data = {}; auto it = last_msgs.find(id); return it != last_msgs.end() ? it->second : empty_data; @@ -148,15 +141,13 @@ const CanData &AbstractStream::lastMessage(const MessageId &id) { // updateLastMsgsTo is always called in UI thread. void AbstractStream::updateLastMsgsTo(double sec) { current_sec_ = sec; - uint64_t last_ts = (sec + routeStartTime()) * 1e9; + uint64_t last_ts = toMonoTime(sec); std::unordered_map msgs; msgs.reserve(events_.size()); for (const auto &[id, ev] : events_) { auto it = std::upper_bound(ev.begin(), ev.end(), last_ts, CompareCanEvent()); if (it != ev.begin()) { - auto prev = std::prev(it); - double ts = (*prev)->mono_time / 1e9 - routeStartTime(); auto &m = msgs[id]; double freq = 0; // Keep suppressed bits. @@ -167,7 +158,9 @@ void AbstractStream::updateLastMsgsTo(double sec) { std::back_inserter(m.last_changes), [](const auto &change) { return CanData::ByteLastChange{.suppressed = change.suppressed}; }); } - m.compute(id, (*prev)->dat, (*prev)->size, ts, getSpeed(), {}, freq); + + auto prev = std::prev(it); + m.compute(id, (*prev)->dat, (*prev)->size, toSeconds((*prev)->mono_time), getSpeed(), {}, freq); m.count = std::distance(ev.begin(), prev) + 1; } } @@ -213,7 +206,6 @@ void AbstractStream::mergeEvents(const std::vector &events) { all_events_.insert(pos, events.cbegin(), events.cend()); emit eventsMerged(msg_events); } - lastest_event_ts = all_events_.empty() ? 0 : all_events_.back()->mono_time; } namespace { @@ -236,14 +228,18 @@ inline QColor blend(const QColor &a, const QColor &b) { // Calculate the frequency from the past one minute data double calc_freq(const MessageId &msg_id, double current_sec) { const auto &events = can->events(msg_id); - uint64_t cur_mono_time = (can->routeStartTime() + current_sec) * 1e9; - uint64_t first_mono_time = std::max(0, cur_mono_time - 59 * 1e9); - auto first = std::lower_bound(events.begin(), events.end(), first_mono_time, CompareCanEvent()); - auto second = std::lower_bound(first, events.end(), cur_mono_time, CompareCanEvent()); - if (first != events.end() && second != events.end()) { - double duration = ((*second)->mono_time - (*first)->mono_time) / 1e9; - uint32_t count = std::distance(first, second); - return count / std::max(1.0, duration); + if (events.empty()) return 0.0; + + auto current_mono_time = can->toMonoTime(current_sec); + auto start_mono_time = can->toMonoTime(current_sec - 59); + + auto first = std::lower_bound(events.begin(), events.end(), start_mono_time, CompareCanEvent()); + auto last = std::upper_bound(first, events.end(), current_mono_time, CompareCanEvent()); + + int count = std::distance(first, last); + if (count > 1) { + double duration = ((*std::prev(last))->mono_time - (*first)->mono_time) / 1e9; + return count / duration; } return 0; } diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 822dd03d84..9e3f92dc5d 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -28,10 +29,10 @@ struct CanData { std::vector colors; struct ByteLastChange { - double ts; - int delta; - int same_delta_counter; - bool suppressed; + double ts = 0; + int delta = 0; + int same_delta_counter = 0; + bool suppressed = false; std::array bit_change_counts; }; std::vector last_changes; @@ -51,12 +52,6 @@ struct CompareCanEvent { constexpr bool operator()(uint64_t ts, const CanEvent *const e) const { return ts < e->mono_time; } }; -struct BusConfig { - int can_speed_kbps = 500; - int data_speed_kbps = 2000; - bool can_fd = false; -}; - typedef std::unordered_map> MessageEventsMap; class AbstractStream : public QObject { @@ -66,15 +61,14 @@ public: AbstractStream(QObject *parent); virtual ~AbstractStream() {} virtual void start() = 0; - virtual void stop() {} virtual bool liveStreaming() const { return true; } virtual void seekTo(double ts) {} virtual QString routeName() const = 0; virtual QString carFingerprint() const { return ""; } virtual QDateTime beginDateTime() const { return {}; } - virtual double routeStartTime() const { return 0; } - inline double currentSec() const { return current_sec_; } - virtual double totalSeconds() const { return lastEventMonoTime() / 1e9 - routeStartTime(); } + virtual uint64_t beginMonoTime() const { return 0; } + virtual double minSeconds() const { return 0; } + virtual double maxSeconds() const { return 0; } virtual void setSpeed(float speed) {} virtual double getSpeed() { return 1; } virtual bool isPaused() const { return false; } @@ -82,10 +76,14 @@ public: void setTimeRange(const std::optional> &range); const std::optional> &timeRange() const { return time_range_; } + inline double currentSec() const { return current_sec_; } + inline uint64_t toMonoTime(double sec) const { return beginMonoTime() + std::max(sec, 0.0) * 1e9; } + inline double toSeconds(uint64_t mono_time) const { return std::max(0.0, (mono_time - beginMonoTime()) / 1e9); } + inline const std::unordered_map &lastMessages() const { return last_msgs; } inline const MessageEventsMap &eventsMap() const { return events_; } inline const std::vector &allEvents() const { return all_events_; } - const CanData &lastMessage(const MessageId &id); + const CanData &lastMessage(const MessageId &id) const; const std::vector &events(const MessageId &id) const; size_t suppressHighlighted(); @@ -111,12 +109,10 @@ protected: void mergeEvents(const std::vector &events); const CanEvent *newEvent(uint64_t mono_time, const cereal::CanData::Reader &c); void updateEvent(const MessageId &id, double sec, const uint8_t *data, uint8_t size); - uint64_t lastEventMonoTime() const { return lastest_event_ts; } std::vector all_events_; double current_sec_ = 0; std::optional> time_range_; - uint64_t lastest_event_ts = 0; private: void updateLastMessages(); diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc index d9d96e23b0..6bcb1c1d54 100644 --- a/tools/cabana/streams/livestream.cc +++ b/tools/cabana/streams/livestream.cc @@ -92,6 +92,8 @@ void LiveStream::timerEvent(QTimerEvent *event) { // merge events received from live stream thread. std::lock_guard lk(lock); mergeEvents(received_events_); + uint64_t last_received_ts = !received_events_.empty() ? received_events_.back()->mono_time : 0; + lastest_event_ts = std::max(lastest_event_ts, last_received_ts); received_events_.clear(); } if (!all_events_.empty()) { @@ -136,8 +138,8 @@ void LiveStream::updateEvents() { void LiveStream::seekTo(double sec) { sec = std::max(0.0, sec); first_update_ts = nanos_since_boot(); - current_event_ts = first_event_ts = std::min(sec * 1e9 + begin_event_ts, lastEventMonoTime()); - post_last_event = (first_event_ts == lastEventMonoTime()); + current_event_ts = first_event_ts = std::min(sec * 1e9 + begin_event_ts, lastest_event_ts); + post_last_event = (first_event_ts == lastest_event_ts); emit seekedTo((current_event_ts - begin_event_ts) / 1e9); } diff --git a/tools/cabana/streams/livestream.h b/tools/cabana/streams/livestream.h index 9ca7e8d745..24b9285092 100644 --- a/tools/cabana/streams/livestream.h +++ b/tools/cabana/streams/livestream.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -14,9 +15,10 @@ public: LiveStream(QObject *parent); virtual ~LiveStream(); void start() override; - void stop() override; + void stop(); inline QDateTime beginDateTime() const { return begin_date_time; } - inline double routeStartTime() const override { return begin_event_ts / 1e9; } + inline uint64_t beginMonoTime() const override { return begin_event_ts; } + double maxSeconds() const override { return std::max(1.0, (lastest_event_ts - begin_event_ts) / 1e9); } void setSpeed(float speed) override { speed_ = speed; } double getSpeed() override { return speed_; } bool isPaused() const override { return paused_; } @@ -41,6 +43,7 @@ private: QDateTime begin_date_time; uint64_t begin_event_ts = 0; + uint64_t lastest_event_ts = 0; uint64_t current_event_ts = 0; uint64_t first_event_ts = 0; uint64_t first_update_ts = 0; diff --git a/tools/cabana/streams/pandastream.h b/tools/cabana/streams/pandastream.h index 3e76247680..ad792ec292 100644 --- a/tools/cabana/streams/pandastream.h +++ b/tools/cabana/streams/pandastream.h @@ -12,6 +12,12 @@ const uint32_t speeds[] = {10U, 20U, 50U, 100U, 125U, 250U, 500U, 1000U}; const uint32_t data_speeds[] = {10U, 20U, 50U, 100U, 125U, 250U, 500U, 1000U, 2000U, 5000U}; +struct BusConfig { + int can_speed_kbps = 500; + int data_speed_kbps = 2000; + bool can_fd = false; +}; + struct PandaStreamConfig { QString serial = ""; std::vector bus_config; diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index 302a25696e..09ba3db417 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -88,16 +88,10 @@ void ReplayStream::start() { replay->start(); } -void ReplayStream::stop() { - if (replay) { - replay->stop(); - } -} - bool ReplayStream::eventFilter(const Event *event) { static double prev_update_ts = 0; if (event->which == cereal::Event::Which::CAN) { - double current_sec = event->mono_time / 1e9 - routeStartTime(); + double current_sec = toSeconds(event->mono_time); capnp::FlatArrayMessageReader reader(event->data); auto e = reader.getRoot(); for (const auto &c : e.getCan()) { @@ -115,11 +109,6 @@ bool ReplayStream::eventFilter(const Event *event) { return true; } -void ReplayStream::seekTo(double ts) { - current_sec_ = ts; - replay->seekTo(std::max(double(0), ts), false); -} - void ReplayStream::pause(bool pause) { replay->pause(pause); emit(pause ? paused() : resume()); diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index ced78680d1..217d1ac1d3 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -16,17 +16,16 @@ class ReplayStream : public AbstractStream { public: ReplayStream(QObject *parent); void start() override; - void stop() override; bool loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags = REPLAY_FLAG_NONE); bool eventFilter(const Event *event); - void seekTo(double ts) override; + void seekTo(double ts) override { replay->seekTo(std::max(double(0), ts), false); } bool liveStreaming() const override { return false; } inline QString routeName() const override { return replay->route()->name(); } inline QString carFingerprint() const override { return replay->carFingerprint().c_str(); } - double totalSeconds() const override { return replay->totalSeconds(); } + double minSeconds() const override { return replay->minSeconds(); } + double maxSeconds() const { return replay->maxSeconds(); } inline QDateTime beginDateTime() const { return replay->routeDateTime(); } - inline double routeStartTime() const override { return replay->routeStartTime() / (double)1e9; } - inline const Route *route() const { return replay->route(); } + inline uint64_t beginMonoTime() const override { return replay->routeStartNanos(); } inline void setSpeed(float speed) override { replay->setSpeed(speed); } inline float getSpeed() const { return replay->getSpeed(); } inline Replay *getReplay() const { return replay.get(); } diff --git a/tools/cabana/tools/findsignal.cc b/tools/cabana/tools/findsignal.cc index 387a912787..8e1749ba8e 100644 --- a/tools/cabana/tools/findsignal.cc +++ b/tools/cabana/tools/findsignal.cc @@ -46,7 +46,7 @@ void FindSignalModel::search(std::function cmp) { auto it = std::find_if(first, last, [&](const CanEvent *e) { return cmp(get_raw_value(e->dat, e->size, s.sig)); }); if (it != last) { auto values = s.values; - values += QString("(%1, %2)").arg((*it)->mono_time / 1e9 - can->routeStartTime(), 0, 'f', 2).arg(get_raw_value((*it)->dat, (*it)->size, s.sig)); + values += QString("(%1, %2)").arg(can->toSeconds((*it)->mono_time), 0, 'f', 3).arg(get_raw_value((*it)->dat, (*it)->size, s.sig)); std::lock_guard lk(lock); filtered_signals.push_back({.id = s.id, .mono_time = (*it)->mono_time, .sig = s.sig, .values = values}); } @@ -217,10 +217,10 @@ void FindSignalDlg::setInitialSignals() { double first_time_val = first_time_edit->text().toDouble(); double last_time_val = last_time_edit->text().toDouble(); auto [first_sec, last_sec] = std::minmax(first_time_val, last_time_val); - uint64_t first_time = (can->routeStartTime() + first_sec) * 1e9; + uint64_t first_time = can->toMonoTime(first_sec); model->last_time = std::numeric_limits::max(); if (last_sec > 0) { - model->last_time = (can->routeStartTime() + last_sec) * 1e9; + model->last_time = can->toMonoTime(last_sec); } model->initial_signals.clear(); diff --git a/tools/cabana/utils/export.cc b/tools/cabana/utils/export.cc index 10f69ad548..79ca97ba8f 100644 --- a/tools/cabana/utils/export.cc +++ b/tools/cabana/utils/export.cc @@ -10,11 +10,10 @@ namespace utils { void exportToCSV(const QString &file_name, std::optional msg_id) { QFile file(file_name); if (file.open(QIODevice::ReadWrite | QIODevice::Truncate)) { - const uint64_t start_time = can->routeStartTime(); QTextStream stream(&file); stream << "time,addr,bus,data\n"; for (auto e : msg_id ? can->events(*msg_id) : can->allEvents()) { - stream << QString::number((e->mono_time / 1e9) - start_time, 'f', 2) << "," + stream << QString::number(can->toSeconds(e->mono_time), 'f', 3) << "," << "0x" << QString::number(e->address, 16) << "," << e->src << "," << "0x" << QByteArray::fromRawData((const char *)e->dat, e->size).toHex().toUpper() << "\n"; } @@ -30,9 +29,8 @@ void exportSignalsToCSV(const QString &file_name, const MessageId &msg_id) { stream << "," << s->name; stream << "\n"; - const uint64_t start_time = can->routeStartTime(); for (auto e : can->events(msg_id)) { - stream << QString::number((e->mono_time / 1e9) - start_time, 'f', 2) << "," + stream << QString::number(can->toSeconds(e->mono_time), 'f', 3) << "," << "0x" << QString::number(e->address, 16) << "," << e->src; for (auto s : msg->sigs) { double value = 0; diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index d2f78babc1..8d2f8674b3 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -27,6 +27,13 @@ static const QColor timeline_colors[] = { [(int)TimelineType::AlertCritical] = QColor(199, 0, 57), }; +static Replay *getReplay() { + auto stream = qobject_cast(can); + if (!stream) return nullptr; + + return stream->getReplay(); +} + VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) { setFrameStyle(QFrame::StyledPanel | QFrame::Plain); auto main_layout = new QVBoxLayout(this); @@ -76,7 +83,7 @@ QHBoxLayout *VideoWidget::createPlaybackController() { // set speed to 1.0 speed_btn->menu()->actions()[7]->setChecked(true); can->pause(false); - can->seekTo(can->totalSeconds() + 1); + can->seekTo(can->maxSeconds() + 1); }); } @@ -141,7 +148,7 @@ QWidget *VideoWidget::createCameraWidget() { QStackedLayout *stacked = new QStackedLayout(); stacked->setStackingMode(QStackedLayout::StackAll); - stacked->addWidget(cam_widget = new CameraWidget("camerad", VISION_STREAM_ROAD, false)); + stacked->addWidget(cam_widget = new StreamCameraView("camerad", VISION_STREAM_ROAD, false)); cam_widget->setMinimumHeight(MIN_VIDEO_HEIGHT); cam_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); stacked->addWidget(alert_label = new InfoLabel(this)); @@ -149,9 +156,11 @@ QWidget *VideoWidget::createCameraWidget() { l->addWidget(slider = new Slider(w)); slider->setSingleStep(0); + slider->setTimeRange(can->minSeconds(), can->maxSeconds()); - setMaximumTime(can->totalSeconds()); QObject::connect(slider, &QSlider::sliderReleased, [this]() { can->seekTo(slider->currentSecond()); }); + QObject::connect(can, &AbstractStream::paused, cam_widget, [c = cam_widget]() { c->showPausedOverlay(); }); + QObject::connect(can, &AbstractStream::resume, cam_widget, [c = cam_widget]() { c->update(); }); QObject::connect(can, &AbstractStream::eventsMerged, this, [this]() { slider->update(); }); QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); }); QObject::connect(cam_widget, &CameraWidget::vipcAvailableStreamsUpdated, this, &VideoWidget::vipcAvailableStreamsUpdated); @@ -161,7 +170,7 @@ QWidget *VideoWidget::createCameraWidget() { auto replay = static_cast(can)->getReplay(); QObject::connect(replay, &Replay::qLogLoaded, slider, &Slider::parseQLog, Qt::QueuedConnection); - QObject::connect(replay, &Replay::totalSecondsUpdated, this, &VideoWidget::setMaximumTime, Qt::QueuedConnection); + QObject::connect(replay, &Replay::minMaxTimeChanged, this, &VideoWidget::timeRangeChanged, Qt::QueuedConnection); return w; } @@ -185,7 +194,7 @@ void VideoWidget::vipcAvailableStreamsUpdated(std::set streams } void VideoWidget::loopPlaybackClicked() { - auto replay = qobject_cast(can)->getReplay(); + auto replay = getReplay(); if (!replay) return; if (replay->hasFlag(REPLAY_FLAG_NO_LOOP)) { @@ -197,18 +206,15 @@ void VideoWidget::loopPlaybackClicked() { } } -void VideoWidget::setMaximumTime(double sec) { - maximum_time = sec; - slider->setTimeRange(0, sec); -} - -void VideoWidget::timeRangeChanged(const std::optional> &time_range) { +void VideoWidget::timeRangeChanged() { + const auto time_range = can->timeRange(); if (can->liveStreaming()) { skip_to_end_btn->setEnabled(!time_range.has_value()); return; } time_range ? slider->setTimeRange(time_range->first, time_range->second) - : slider->setTimeRange(0, maximum_time); + : slider->setTimeRange(can->minSeconds(), can->maxSeconds()); + updateState(); } QString VideoWidget::formatTime(double sec, bool include_milliseconds) { @@ -219,8 +225,9 @@ QString VideoWidget::formatTime(double sec, bool include_milliseconds) { void VideoWidget::updateState() { if (slider) { - if (!slider->isSliderDown()) + if (!slider->isSliderDown()) { slider->setCurrentSecond(can->currentSec()); + } alert_label->showAlert(slider->alertInfo(can->currentSec())); time_btn->setText(QString("%1 / %2").arg(formatTime(can->currentSec(), true), formatTime(slider->maximum() / slider->factor))); @@ -242,15 +249,14 @@ Slider::Slider(QWidget *parent) : QSlider(Qt::Horizontal, parent) { } AlertInfo Slider::alertInfo(double seconds) { - uint64_t mono_time = (seconds + can->routeStartTime()) * 1e9; + uint64_t mono_time = can->toMonoTime(seconds); auto alert_it = alerts.lower_bound(mono_time); bool has_alert = (alert_it != alerts.end()) && ((alert_it->first - mono_time) <= 1e8); return has_alert ? alert_it->second : AlertInfo{}; } QPixmap Slider::thumbnail(double seconds) { - uint64_t mono_time = (seconds + can->routeStartTime()) * 1e9; - auto it = thumbnails.lowerBound(mono_time); + auto it = thumbnails.lowerBound(can->toMonoTime(seconds)); return it != thumbnails.end() ? it.value() : QPixmap(); } @@ -298,16 +304,18 @@ void Slider::paintEvent(QPaintEvent *ev) { p.fillRect(r, color); }; - const auto replay = qobject_cast(can)->getReplay(); - for (auto [begin, end, type] : replay->getTimeline()) { - fillRange(begin, end, timeline_colors[(int)type]); - } + auto replay = getReplay(); + if (replay) { + for (auto [begin, end, type] : replay->getTimeline()) { + fillRange(begin, end, timeline_colors[(int)type]); + } - QColor empty_color = palette().color(QPalette::Window); - empty_color.setAlpha(160); - for (const auto &[n, seg] : replay->segments()) { - if (!(seg && seg->isLoaded())) - fillRange(n * 60.0, (n + 1) * 60.0, empty_color); + QColor empty_color = palette().color(QPalette::Window); + empty_color.setAlpha(160); + for (const auto &[n, seg] : replay->segments()) { + if (!(seg && seg->isLoaded())) + fillRange(n * 60.0, (n + 1) * 60.0, empty_color); + } } QStyleOptionSlider opt; @@ -411,3 +419,22 @@ void InfoLabel::paintEvent(QPaintEvent *event) { p.drawText(text_rect, Qt::AlignTop | Qt::AlignHCenter | Qt::TextWordWrap, text); } } + +StreamCameraView::StreamCameraView(std::string stream_name, VisionStreamType stream_type, bool zoom, QWidget *parent) + : CameraWidget(stream_name, stream_type, zoom, parent) { + fade_animation = new QPropertyAnimation(this, "overlayOpacity"); + fade_animation->setDuration(500); + fade_animation->setStartValue(0.2f); + fade_animation->setEndValue(0.7f); +} + +void StreamCameraView::paintGL() { + CameraWidget::paintGL(); + + if (can->isPaused()) { + QPainter p(this); + p.setPen(QColor(200, 200, 200, static_cast(255 * overlay_opacity))); + p.setFont(QFont(font().family(), 16, QFont::Bold)); + p.drawText(rect(), Qt::AlignCenter, tr("PAUSED")); + } +} diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index ac34c66007..1e793e9d1d 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -4,10 +4,12 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -57,16 +59,34 @@ private: InfoLabel *thumbnail_label; }; +class StreamCameraView : public CameraWidget { + Q_OBJECT + Q_PROPERTY(float overlayOpacity READ overlayOpacity WRITE setOverlayOpacity) + +public: + StreamCameraView(std::string stream_name, VisionStreamType stream_type, bool zoom, QWidget *parent = nullptr); + void paintGL() override; + void showPausedOverlay() { fade_animation->start(); } + float overlayOpacity() const { return overlay_opacity; } + void setOverlayOpacity(float opacity) { + overlay_opacity = opacity; + update(); + } + +private: + float overlay_opacity; + QPropertyAnimation *fade_animation; +}; + class VideoWidget : public QFrame { Q_OBJECT public: VideoWidget(QWidget *parnet = nullptr); - void setMaximumTime(double sec); protected: QString formatTime(double sec, bool include_milliseconds = false); - void timeRangeChanged(const std::optional> &time_range); + void timeRangeChanged(); void updateState(); void updatePlayBtnState(); QWidget *createCameraWidget(); @@ -74,8 +94,7 @@ protected: void loopPlaybackClicked(); void vipcAvailableStreamsUpdated(std::set streams); - CameraWidget *cam_widget; - double maximum_time = 0; + StreamCameraView *cam_widget; QToolButton *time_btn = nullptr; ToolButton *seek_backward_btn = nullptr; ToolButton *play_btn = nullptr; diff --git a/tools/replay/consoleui.cc b/tools/replay/consoleui.cc index eaff78c691..21ca0ad74b 100644 --- a/tools/replay/consoleui.cc +++ b/tools/replay/consoleui.cc @@ -171,7 +171,7 @@ void ConsoleUI::updateStatus() { if (status != Status::Paused) { auto events = replay->events(); - uint64_t current_mono_time = replay->routeStartTime() + replay->currentSeconds() * 1e9; + uint64_t current_mono_time = replay->routeStartNanos() + replay->currentSeconds() * 1e9; bool playing = !events->empty() && events->back().mono_time > current_mono_time; status = playing ? Status::Playing : Status::Waiting; } @@ -262,10 +262,10 @@ void ConsoleUI::updateTimeline() { mvwhline(win, 2, 0, ' ', width); wattroff(win, COLOR_PAIR(Color::Disengaged)); - const int total_sec = replay->totalSeconds(); + const int total_sec = replay->maxSeconds() - replay->minSeconds(); for (auto [begin, end, type] : replay->getTimeline()) { - int start_pos = (begin / total_sec) * width; - int end_pos = (end / total_sec) * width; + int start_pos = ((begin - replay->minSeconds()) / total_sec) * width; + int end_pos = ((end - replay->minSeconds()) / total_sec) * width; if (type == TimelineType::Engaged) { mvwchgat(win, 1, start_pos, end_pos - start_pos + 1, A_COLOR, Color::Engaged, NULL); mvwchgat(win, 2, start_pos, end_pos - start_pos + 1, A_COLOR, Color::Engaged, NULL); @@ -280,7 +280,7 @@ void ConsoleUI::updateTimeline() { } } - int cur_pos = ((double)replay->currentSeconds() / total_sec) * width; + int cur_pos = ((replay->currentSeconds() - replay->minSeconds()) / total_sec) * width; wattron(win, COLOR_PAIR(Color::BrightWhite)); mvwaddch(win, 0, cur_pos, ACS_VLINE); mvwaddch(win, 3, cur_pos, ACS_VLINE); diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc index 15daecf01f..4fea879f8b 100644 --- a/tools/replay/replay.cc +++ b/tools/replay/replay.cc @@ -85,6 +85,7 @@ bool Replay::load() { return false; } rInfo("load route %s with %zu valid segments", qPrintable(route_->name()), segments_.size()); + max_seconds_ = (segments_.rbegin()->first + 1) * 60; return true; } @@ -108,7 +109,11 @@ void Replay::seekTo(double seconds, bool relative) { target_time = std::max(double(0.0), target_time); int target_segment = (int)target_time / 60; if (segments_.count(target_segment) == 0) { - rWarning("Can't seek to %d s segment %d is invalid", (int)target_time, target_segment); + rWarning("Can't seek to %.2f s segment %d is invalid", target_time, target_segment); + return true; + } + if (target_time > max_seconds_) { + rWarning("Can't seek to %.2f s, time is invalid", target_time); return true; } @@ -193,15 +198,22 @@ void Replay::buildTimeline() { } } + if (it->first == route_segments.rbegin()->first) { + if (engaged) { + timeline.push_back({toSeconds(engaged_begin), toSeconds(log->events.back().mono_time), TimelineType::Engaged}); + } + if (!alert_type.empty() && alert_size != cereal::ControlsState::AlertSize::NONE) { + timeline.push_back({toSeconds(alert_begin), toSeconds(log->events.back().mono_time), timeline_types[(int)alert_status]}); + } + + max_seconds_ = std::ceil(toSeconds(log->events.back().mono_time)); + emit minMaxTimeChanged(route_segments.cbegin()->first * 60.0, max_seconds_); + } { std::lock_guard lk(timeline_lock); timeline_.insert(timeline_.end(), timeline.begin(), timeline.end()); std::sort(timeline_.begin(), timeline_.end(), [](auto &l, auto &r) { return std::get<2>(l) < std::get<2>(r); }); } - - if (it->first == route_segments.rbegin()->first) { - emit totalSecondsUpdated(toSeconds(log->events.back().mono_time)); - } emit qLogLoaded(log); } } @@ -463,7 +475,7 @@ void Replay::streamThread() { int last_segment = segments_.rbegin()->first; if (current_segment_ >= last_segment && isSegmentMerged(last_segment)) { rInfo("reaches the end of route, restart from beginning"); - QMetaObject::invokeMethod(this, std::bind(&Replay::seekTo, this, 0, false), Qt::QueuedConnection); + QMetaObject::invokeMethod(this, std::bind(&Replay::seekTo, this, minSeconds(), false), Qt::QueuedConnection); } } } diff --git a/tools/replay/replay.h b/tools/replay/replay.h index 7e1815ede0..ac829ffb71 100644 --- a/tools/replay/replay.h +++ b/tools/replay/replay.h @@ -76,9 +76,10 @@ public: inline double currentSeconds() const { return double(cur_mono_time_ - route_start_ts_) / 1e9; } inline QDateTime routeDateTime() const { return route_date_time_; } inline QDateTime currentDateTime() const { return route_date_time_.addSecs(currentSeconds()); } - inline uint64_t routeStartTime() const { return route_start_ts_; } + inline uint64_t routeStartNanos() const { return route_start_ts_; } inline double toSeconds(uint64_t mono_time) const { return (mono_time - route_start_ts_) / 1e9; } - inline int totalSeconds() const { return (!segments_.empty()) ? (segments_.rbegin()->first + 1) * 60 : 0; } + inline double minSeconds() const { return !segments_.empty() ? segments_.begin()->first * 60 : 0; } + inline double maxSeconds() const { return max_seconds_; } inline void setSpeed(float speed) { speed_ = speed; } inline float getSpeed() const { return speed_; } inline const std::vector *events() const { return &events_; } @@ -95,7 +96,7 @@ signals: void seeking(double sec); void seekedTo(double sec); void qLogLoaded(std::shared_ptr qlog); - void totalSecondsUpdated(double sec); + void minMaxTimeChanged(double min_sec, double max_sec); protected slots: void segmentLoadFinished(bool success); @@ -133,6 +134,7 @@ protected: QDateTime route_date_time_; uint64_t route_start_ts_ = 0; std::atomic cur_mono_time_ = 0; + std::atomic max_seconds_ = 0; std::vector events_; std::set merged_segments_; From 67038d5b59d82b1eb094746ab99fa7d8e7d10e71 Mon Sep 17 00:00:00 2001 From: dany7915 Date: Tue, 9 Jul 2024 06:54:11 +0900 Subject: [PATCH 013/229] Fingerprint: Kia K5 HEV 2020 (#32875) fingerprint added --- selfdrive/car/hyundai/fingerprints.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index c7e1418cb6..4ad7e0e0aa 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -585,6 +585,7 @@ FW_VERSIONS = { b'\xf1\x00DL3 MDPS C 1.00 1.02 56310-L7220 4DLHC102', ], (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00DL3HMFC AT KOR LHD 1.00 1.01 99210-L2000 191022', b'\xf1\x00DL3HMFC AT KOR LHD 1.00 1.02 99210-L2000 200309', b'\xf1\x00DL3HMFC AT KOR LHD 1.00 1.04 99210-L2000 210527', ], From 4014109666e66ca8ed0b096159d424b4b55caca4 Mon Sep 17 00:00:00 2001 From: JaReal07 <153245974+JaReal07@users.noreply.github.com> Date: Mon, 8 Jul 2024 18:58:22 -0300 Subject: [PATCH 014/229] Update fingerprints.py Corolla 2024 (South America) (#32864) Add Corolla Sedan 2024 (South America), new 'engine' and 'eps' fwversion --- selfdrive/car/toyota/fingerprints.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/toyota/fingerprints.py b/selfdrive/car/toyota/fingerprints.py index 5e746d1311..67203da7d0 100644 --- a/selfdrive/car/toyota/fingerprints.py +++ b/selfdrive/car/toyota/fingerprints.py @@ -441,6 +441,7 @@ FW_VERSIONS = { b'\x01896630ZU8000\x00\x00\x00\x00', b'\x01896630ZU9000\x00\x00\x00\x00', b'\x01896630ZX4000\x00\x00\x00\x00', + b'\x01896630ZX7100\x00\x00\x00\x00', b'\x018966312L8000\x00\x00\x00\x00', b'\x018966312M0000\x00\x00\x00\x00', b'\x018966312M9000\x00\x00\x00\x00', @@ -516,6 +517,7 @@ FW_VERSIONS = { b'\x018965B1254000\x00\x00\x00\x00', b'\x018965B1255000\x00\x00\x00\x00', b'\x018965B1256000\x00\x00\x00\x00', + b'\x018965B1270000\x00\x00\x00\x00', b'8965B12361\x00\x00\x00\x00\x00\x00', b'8965B12451\x00\x00\x00\x00\x00\x00', b'8965B16011\x00\x00\x00\x00\x00\x00', From 15d3397ec6d32bb4e3319ff615526b175b267949 Mon Sep 17 00:00:00 2001 From: Hoang Bui <47828508+bongbui321@users.noreply.github.com> Date: Mon, 8 Jul 2024 19:42:26 -0400 Subject: [PATCH 015/229] CI: Compile openpilot on macOS (#32909) * working * cache * bring back --- .github/workflows/selfdrive_tests.yaml | 13 +++++++++++-- tools/mac_setup.sh | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 3359f2a15e..419c472084 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -106,8 +106,17 @@ jobs: SKIP_PROMPT: 1 # package install has DeprecationWarnings PYTHONWARNINGS: default - - name: Test openpilot environment - run: . .venv/bin/activate && scons -h + - run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV + - name: Getting scons cache + uses: 'actions/cache@v4' + with: + path: /tmp/scons_cache + key: scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }} + restore-keys: | + scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }} + scons-${{ runner.arch }}-macos + - name: Building openpilot + run: . .venv/bin/activate && scons -j$(nproc) static_analysis: name: static analysis diff --git a/tools/mac_setup.sh b/tools/mac_setup.sh index 6b2d668524..9823427e65 100755 --- a/tools/mac_setup.sh +++ b/tools/mac_setup.sh @@ -63,6 +63,7 @@ brew "qt@5" brew "zeromq" cask "gcc-arm-embedded" brew "portaudio" +brew "gcc@13" EOS echo "[ ] finished brew install t=$SECONDS" From f6189568eab0244ed792ef299fb781cc4c92fb9b Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 8 Jul 2024 16:55:16 -0700 Subject: [PATCH 016/229] mvp of new docs.comma.ai (#32926) * ssh docs * strict * need an index * push to prod --- .github/workflows/docs.yaml | 2 +- docs/docs/car-porting/what-is-a-car-port.md | 25 +++++++++---- docs/docs/contributing/architecture.md | 1 + docs/docs/contributing/roadmap.md | 5 +++ .../docs/getting-started/what-is-openpilot.md | 2 +- .../docs/how-to/connect-to-comma.md | 36 ++++++++++--------- docs/docs/how-to/first-pr.md | 0 docs/docs/index.md | 1 + docs/mkdocs.yml | 16 ++++++++- {tools/ssh => system/hardware/tici}/id_rsa | 0 10 files changed, 63 insertions(+), 25 deletions(-) create mode 100644 docs/docs/contributing/architecture.md create mode 100644 docs/docs/contributing/roadmap.md rename tools/ssh/README.md => docs/docs/how-to/connect-to-comma.md (63%) create mode 100644 docs/docs/how-to/first-pr.md create mode 120000 docs/docs/index.md rename {tools/ssh => system/hardware/tici}/id_rsa (100%) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index cb55d2f831..b14ae65842 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -62,4 +62,4 @@ jobs: git commit -m "build docs" # docs live in different repo to not bloat openpilot's full clone size - git push -f origin tmp:gh-pages2 + git push -f origin tmp:gh-pages diff --git a/docs/docs/car-porting/what-is-a-car-port.md b/docs/docs/car-porting/what-is-a-car-port.md index d089d9513e..b918bb50e0 100644 --- a/docs/docs/car-porting/what-is-a-car-port.md +++ b/docs/docs/car-porting/what-is-a-car-port.md @@ -1,9 +1,22 @@ # What is a car port? -All car ports live in `openpilot/selfdrive/car/`. +A car port enables openpilot support on a particular car. Each car model openpilot supports needs to be individually ported. All car ports live in `openpilot/selfdrive/car/`. -* interface.py: Interface for the car, defines the CarInterface class -* carstate.py: Reads CAN from car and builds openpilot CarState message -* carcontroller.py: Builds CAN messages to send to car -* values.py: Limits for actuation, general constants for cars, and supported car documentation -* radar_interface.py: Interface for parsing radar points from the car +The complexity of a car port varies depending on many factors including: +* existing openpilot support for similar cars +* architecture and APIs available in the car + + +# Structure of a car port +* `interface.py`: Interface for the car, defines the CarInterface class +* `carstate.py`: Reads CAN from car and builds openpilot CarState message +* `carcontroller.py`: Builds CAN messages to send to car +* `values.py`: Limits for actuation, general constants for cars, and supported car documentation +* `radar_interface.py`: Interface for parsing radar points from the car + + +# Overiew + +[Jason Young](https://github.com/jyoung8607) gave a talk at COMMA_CON with an overview of the car porting process. The talk is available on YouTube: + +https://youtu.be/KcfzEHB6ms4?si=5szh1PX6TksOCKmM diff --git a/docs/docs/contributing/architecture.md b/docs/docs/contributing/architecture.md new file mode 100644 index 0000000000..c79bec1ac6 --- /dev/null +++ b/docs/docs/contributing/architecture.md @@ -0,0 +1 @@ +# Architecture diff --git a/docs/docs/contributing/roadmap.md b/docs/docs/contributing/roadmap.md new file mode 100644 index 0000000000..64ccdb3b75 --- /dev/null +++ b/docs/docs/contributing/roadmap.md @@ -0,0 +1,5 @@ +# Roadmap + +Coming soon... + +For now, check out our GitHub [milestones](https://github.com/commaai/openpilot/milestones) and [bounties](https://comma.ai/bounties). diff --git a/docs/docs/getting-started/what-is-openpilot.md b/docs/docs/getting-started/what-is-openpilot.md index de45ae035b..b3c56c8410 100644 --- a/docs/docs/getting-started/what-is-openpilot.md +++ b/docs/docs/getting-started/what-is-openpilot.md @@ -1,6 +1,6 @@ # What is openpilot? -[openpilot](http://github.com/commaai/openpilot) is an open source driver assistance system. Currently, openpilot performs the functions of Adaptive Cruise Control (ACC), Automated Lane Centering (ALC), Forward Collision Warning (FCW), and Lane Departure Warning (LDW) for a growing variety of [supported car makes, models, and model years](docs/CARS.md). In addition, while openpilot is engaged, a camera-based Driver Monitoring (DM) feature alerts distracted and asleep drivers. See more about [the vehicle integration](docs/INTEGRATION.md) and [limitations](docs/LIMITATIONS.md). +[openpilot](http://github.com/commaai/openpilot) is an open source driver assistance system. Currently, openpilot performs the functions of Adaptive Cruise Control (ACC), Automated Lane Centering (ALC), Forward Collision Warning (FCW), and Lane Departure Warning (LDW) for a growing variety of [supported car makes, models, and model years](https://github.com/commaai/openpilot/blob/master/docs/CARS.md). In addition, while openpilot is engaged, a camera-based Driver Monitoring (DM) feature alerts distracted and asleep drivers. See more about [the vehicle integration](https://github.com/commaai/openpilot/blob/master/docs/INTEGRATION.md) and [limitations](https://github.com/commaai/openpilot/blob/master/docs/LIMITATIONS.md). ## How do I use it? diff --git a/tools/ssh/README.md b/docs/docs/how-to/connect-to-comma.md similarity index 63% rename from tools/ssh/README.md rename to docs/docs/how-to/connect-to-comma.md index 588ea71579..53460ac990 100644 --- a/tools/ssh/README.md +++ b/docs/docs/how-to/connect-to-comma.md @@ -1,39 +1,42 @@ -# SSH +# connect to a comma 3/3X -## Quick Start +A comma 3/3X is a normal [Linux](https://github.com/commaai/agnos-builder) computer that exposes [SSH](https://wiki.archlinux.org/title/Secure_Shell) and a [serial console](https://wiki.archlinux.org/title/Working_with_the_serial_console). + +## Serial Console + +On both the comma three and 3X, the serial console is accessible from the main OBD-C port. +Connect the comma 3/3X to your computer with a normal USB C cable, or use a [comma serial](https://comma.ai/shop/comma-serial) for steady 12V power. + +On the comma three, the serial console is exposed through a UART-to-USB chip, and `tools/serial/connect.sh` can be used to connect. + +On the comma 3X, the serial console is accessible through the [panda](https://github.com/commaai/panda) using the `panda/tests/som_debug.sh` script. + +## SSH In order to SSH into your device, you'll need a GitHub account with SSH keys. See this [GitHub article](https://docs.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh) for getting your account setup with SSH keys. * Enable SSH in your device's settings * Enter your GitHub username in the device's settings * Connect to your device - * Username: `comma` - * Port: `22` or `8022` + * Username: `comma` + * Port: `22` Here's an example command for connecting to your device using its tethered connection:
`ssh comma@192.168.43.1` For doing development work on device, it's recommended to use [SSH agent forwarding](https://docs.github.com/en/developers/overview/using-ssh-agent-forwarding). -## Notes +### Notes The public keys are only fetched from your GitHub account once. In order to update your device's authorized keys, you'll need to re-enter your GitHub username. The `id_rsa` key in this directory only works while your device is in the setup state with no software installed. After installation, that default key will be removed. -See the [community wiki](https://github.com/commaai/openpilot/wiki/SSH) for more detailed instructions and information. +#### ssh.comma.ai proxy -# Connecting to ssh.comma.ai -SSH into your comma device from anywhere with `ssh.comma.ai`. Requires a [comma prime subscription](https://comma.ai/connect). +With a [comma prime subscription](https://comma.ai/connect), you can SSH into your comma device from anywhere. -## Setup - -With software version 0.6.1 or newer, enter your GitHub username on your device under Developer Settings. Your GitHub authorized public keys will become your authorized SSH keys for `ssh.comma.ai`. You can add any additional keys in `/system/comma/home/.ssh/authorized_keys.persist`. - -## Recommended .ssh/config - -With the below SSH configuration, you can type `ssh comma-{dongleid}` to connect to your device through `ssh.comma.ai`.
-For example: `ssh comma-ffffffffffffffff` +With the below SSH configuration, you can type `ssh comma-{dongleid}` to connect to your device through `ssh.comma.ai`. ``` Host comma-* @@ -41,6 +44,7 @@ Host comma-* User comma IdentityFile ~/.ssh/my_github_key ProxyCommand ssh %h@ssh.comma.ai -W %h:%p + Host ssh.comma.ai Hostname ssh.comma.ai Port 22 diff --git a/docs/docs/how-to/first-pr.md b/docs/docs/how-to/first-pr.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/docs/index.md b/docs/docs/index.md new file mode 120000 index 0000000000..74ea27aeeb --- /dev/null +++ b/docs/docs/index.md @@ -0,0 +1 @@ +getting-started/what-is-openpilot.md \ No newline at end of file diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index b0f571954d..45a1503b0c 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -1,6 +1,9 @@ site_name: openpilot docs docs_dir: docs repo_url: https://github.com/commaai/openpilot/ +site_url: https://docs.comma.ai + +strict: true theme: name: terminal @@ -11,8 +14,19 @@ nav: - Getting Started: - What is openpilot?: getting-started/what-is-openpilot.md - How-to: - - Turn the speed blue: how-to/turning-the-speed-blue.md + #- Make my first pull request: how-to/first-pr.md + - Connect to a comma 3/3X: how-to/connect-to-comma.md - Car Porting: - What is a car port?: car-porting/what-is-a-car-port.md - Porting a car brand: car-porting/brand-port.md - Porting a car model: car-porting/model-port.md + - Contributing: + - Roadmap: contributing/roadmap.md + #- Architecture: contributing/architecture.md + - Contributing: https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md + - Links: + - Blog: https://blog.comma.ai + - Bounties: https://comma.ai/bounties + - GitHub: https://github.com/commaai + - Discord: https://discord.comma.ai + - X: https://x.com/comma_ai diff --git a/tools/ssh/id_rsa b/system/hardware/tici/id_rsa similarity index 100% rename from tools/ssh/id_rsa rename to system/hardware/tici/id_rsa From 8c6c6e435f0ef18456ad553cbf5c1555bfc210c7 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 8 Jul 2024 17:05:42 -0700 Subject: [PATCH 017/229] site -> docs --- .github/workflows/docs.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index b14ae65842..f5cc0d5003 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -52,11 +52,11 @@ jobs: git rm -rf . # copy over docs - cp -r ../docs/site/ site/ + cp -r ../docs/site/ docs/ # GitHub pages config - touch site/.nojekyll - echo -n docs.comma.ai > site/CNAME + touch docs/.nojekyll + echo -n docs.comma.ai > docs/CNAME git add -f . git commit -m "build docs" From 6745c66352ffacabbf1201f766ab7ff308724d18 Mon Sep 17 00:00:00 2001 From: signed-long <38993953+signed-long@users.noreply.github.com> Date: Mon, 8 Jul 2024 21:07:34 -0600 Subject: [PATCH 018/229] Update ci weekly report summary (#32911) * update ci weekly report summary * don't add skipped jobs to report * uncomment job condition * use jinja template * add run number to failure links * add run number to failure links * Log for run # * use list --------- Co-authored-by: Maxime Desroches --- .github/workflows/ci_weekly_report.yaml | 104 ++++++++++-------------- 1 file changed, 41 insertions(+), 63 deletions(-) diff --git a/.github/workflows/ci_weekly_report.yaml b/.github/workflows/ci_weekly_report.yaml index c5c98b46b5..22b8745872 100644 --- a/.github/workflows/ci_weekly_report.yaml +++ b/.github/workflows/ci_weekly_report.yaml @@ -10,38 +10,30 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +env: + CI_RUNS: ${{ github.event.inputs.ci_runs || '50' }} + jobs: setup: if: github.repository == 'commaai/openpilot' runs-on: ubuntu-latest outputs: - ci_runs: ${{ steps.ci_runs_setup.outputs.value }} + ci_runs: ${{ steps.ci_runs_setup.outputs.matrix }} steps: - id: ci_runs_setup + name: CI_RUNS=${{ env.CI_RUNS }} run: | - CI_RUNS=${{ inputs.ci_runs || '50' }} - mylist="value=[" + matrix=$(python3 -c "import json; print(json.dumps({ 'run_number' : list(range(${{ env.CI_RUNS }})) }))") + echo "matrix=$matrix" >> $GITHUB_OUTPUT - for i in $(seq 1 $CI_RUNS); - do - if [ $i != $CI_RUNS ]; then - mylist+="\"$i\", " - else - mylist+="\"$i\"]" - fi - done - - echo "$mylist" >> $GITHUB_OUTPUT - echo "Number of CI runs for report: $CI_RUNS" ci_matrix_run: needs: [ setup ] strategy: fail-fast: false - matrix: - value: ${{fromJSON(needs.setup.outputs.ci_runs)}} + matrix: ${{fromJSON(needs.setup.outputs.ci_runs)}} uses: commaai/openpilot/.github/workflows/ci_weekly_run.yaml@master with: - run_number: ${{ matrix.value }} + run_number: ${{ matrix.run_number }} report: needs: [ci_matrix_run] @@ -62,62 +54,48 @@ jobs: }) var report = {} jobs.slice(1, jobs.length-1).forEach(job => { - const jobName = job.name.split('/')[2].trim(); + if (job.conclusion === "skipped") return; + const jobName = job.name.split(" / ")[2]; + const runRegex = /\((.*?)\)/; + const run = job.name.match(runRegex)[1]; report[jobName] = report[jobName] || { successes: [], failures: [], cancelled: [] }; switch (job.conclusion) { case "success": - report[jobName].successes.push(job.html_url); break; + report[jobName].successes.push({ "run_number": run, "link": job.html_url}); break; case "failure": - report[jobName].failures.push(job.html_url); break; + report[jobName].failures.push({ "run_number": run, "link": job.html_url }); break; case "cancelled": - report[jobName].cancelled.push(job.html_url); break; + report[jobName].cancelled.push({ "run_number": run, "link": job.html_url }); break; } }); - return JSON.stringify(report); + return JSON.stringify({"jobs": report}); - name: Add job results to summary env: JOB_RESULTS: ${{ fromJSON(steps.get-job-results.outputs.result) }} run: | - echo $JOB_RESULTS > job_results.json - generate_html_table() { - echo "" - echo "" - echo " " - echo " " - echo " " - echo " " - echo " " - echo " " - echo "" - jq -r ' - "", - keys[] as $job | - "", - " ", - " ", - " ", - " ", - "" - ' job_results.json - echo "" - echo "
JobSucceeded ✅Failed ❌Cancelled (timed out) ⏰
\($job)", - "
", - " (\(.[$job].successes | length))", - " \(.[$job].successes[])
", - "
", - "
", - "
", - " (\(.[$job].failures | length))", - " \(.[$job].failures[])
", - "
", - "
", - "
", - " (\(.[$job].cancelled | length))", - " \(.[$job].cancelled[])
", - "
", - "
" - } - echo "# CI Job Summary" >> $GITHUB_STEP_SUMMARY - generate_html_table >> $GITHUB_STEP_SUMMARY + cat <> template.html + + + + + + + + + + + {% for key in jobs.keys() %} + + + + + + {% endfor %} +
Job✅ Passing❌ Failure Details
{% for i in range(5) %}{% if i+1 <= (5 * jobs[key]["successes"]|length // ${{ env.CI_RUNS }}) %}🟩{% else %}🟥{% endif %}{% endfor%}{{ key }}{{ 100 * jobs[key]["successes"]|length // ${{ env.CI_RUNS }} }}%{% if jobs[key]["failures"]|length > 0 %}
{% for failure in jobs[key]["failures"] %}Log for run #{{ failure['run_number'] }}
{% endfor %}
{% else %}{% endif %}
+ EOF + pip install jinja2-cli + echo $JOB_RESULTS | jinja2 template.html > report.html + echo "# CI Test Report - ${{ env.CI_RUNS }} Runs" >> $GITHUB_STEP_SUMMARY + cat report.html >> $GITHUB_STEP_SUMMARY From 481e5b28bd886703e69b05b9b342a7ef9804f9d6 Mon Sep 17 00:00:00 2001 From: Andrei Radulescu Date: Tue, 9 Jul 2024 08:08:38 +0300 Subject: [PATCH 019/229] Rewrite git history (#31562) * bfg * filter repo is the new shit * down to 27M * move big files to lfs; remove external and phonelibs * wip - rebase devel; don't delete external and phonelibs anymore * wip - rebase devel hacks * wip - rebase devel updates * wip - rebase updates; lfs updates * cleaned unused scripts * wip - lfs fixes * bfg with rebase with correct dates * bfg script with cherry-pick method * latest git-filter-repo analysis * latest git-filter-repo 'before' analysis * new lfs import * latest git-filter-repo analysis * lfs update; renamed rebase repos * renamed scripts * different tmp folders for rewrite scripts; lfs update * gitattributes after lfs import * tag-commit-map file with old tags pointing to old commits * new tags * final touches * squash setup commits; cherry-pick validation; reverted to commaai remote * removed rebase version * 0.9.7 tag in tag-commit-map * removed unused openpilot-release-archive * fixed archive of old history because of 2 GB limit * archive of old history push master first * fix tags being deleted * cleaning and more logs * rewrite other branches with master history * Former-commit-id * updates to previous commits * cleanup --------- Co-authored-by: Adeeb Shihadeh Co-authored-by: Maxime Desroches --- scripts/git_rewrite/rewrite-git-history.sh | 357 +++++++++++++++++++++ scripts/git_rewrite/tag-commit-map.txt | 82 +++++ 2 files changed, 439 insertions(+) create mode 100755 scripts/git_rewrite/rewrite-git-history.sh create mode 100644 scripts/git_rewrite/tag-commit-map.txt diff --git a/scripts/git_rewrite/rewrite-git-history.sh b/scripts/git_rewrite/rewrite-git-history.sh new file mode 100755 index 0000000000..4130b55db9 --- /dev/null +++ b/scripts/git_rewrite/rewrite-git-history.sh @@ -0,0 +1,357 @@ +#!/bin/bash +set -e + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" +cd $DIR + +SRC=/tmp/openpilot/ +SRC_CLONE=/tmp/openpilot-clone/ +OUT=/tmp/openpilot-tiny/ + +LOG_FILE=$DIR/git-rewrite-log-$(date +"%Y-%m-%dT%H:%M:%S%z").txt +exec > >(tee -a "$LOG_FILE") 2>&1 + +# INSTALL git-filter-repo +if [ ! -f /tmp/git-filter-repo ]; then + echo "Installing git-filter-repo..." + curl -sSo /tmp/git-filter-repo https://raw.githubusercontent.com/newren/git-filter-repo/main/git-filter-repo + chmod +x /tmp/git-filter-repo +fi + +# MIRROR openpilot +if [ ! -d $SRC ]; then + echo "Mirroring openpilot..." + git clone --mirror https://github.com/commaai/openpilot.git $SRC # 4.18 GiB (488034 objects) + + cd $SRC + + echo "Starting size $(du -sh .)" + + git remote update + + # the git-filter-repo analysis is bliss - can be found in the repo root/filter-repo/analysis + echo "Analyzing with git-filter-repo..." + /tmp/git-filter-repo --force --analyze + + echo "Pushing to openpilot-archive..." + # push to archive repo - in smaller parts because the 2 GB push limit - https://docs.github.com/en/get-started/using-git/troubleshooting-the-2-gb-push-limit + ARCHIVE_REPO=git@github.com:commaai/openpilot-archive.git + git push --prune $ARCHIVE_REPO +refs/heads/master:refs/heads/master # push master first so it's the default branch (when openpilot-archive is an empty repo) + git push --prune $ARCHIVE_REPO +refs/heads/*:refs/heads/* # 956.39 MiB (110725 objects) + git push --prune $ARCHIVE_REPO +refs/tags/*:refs/tags/* # 1.75 GiB (21694 objects) + # git push --mirror $ARCHIVE_REPO || true # fails to push refs/pull/* (deny updating a hidden ref) for pull requests + # we fail and continue - more reading: https://stackoverflow.com/a/34266401/639708 +fi + +# REWRITE master and tags +if [ ! -d $SRC_CLONE ]; then + echo "Cloning $SRC..." + GIT_LFS_SKIP_SMUDGE=1 git clone $SRC $SRC_CLONE + + cd $SRC_CLONE + + echo "Checking out old history..." + + git checkout tags/v0.7.1 + # checkout as main, since we need master ref later + git checkout -b main + + echo "Creating setup commits..." + + # rm these so we don't get conflicts later + git rm -r cereal opendbc panda selfdrive/ui/ui > /dev/null + git commit -m "removed conflicting files" + + # skip-smudge to get rid of some lfs errors that it can't find the reference of some lfs files + # we don't care about fetching/pushing lfs right now + git lfs install --skip-smudge --local + + # squash initial setup commits + git cherry-pick -n -X theirs 6c33a5c..59b3d06 + git commit -m "switching to master" -m "$(git log --reverse --format=%B 6c33a5c..59b3d06)" + + # get commits we want to cherry-pick + # will start with the next commit after #59b3d06 tools is local now + COMMITS=$(git rev-list --reverse 59b3d06..master) + + # we need this for logging + TOTAL_COMMITS=$(echo $COMMITS | wc -w) + CURRENT_COMMIT_NUMBER=0 + + # empty this file + > commit-map.txt + + echo "Rewriting master commits..." + + for COMMIT in $COMMITS; do + CURRENT_COMMIT_NUMBER=$((CURRENT_COMMIT_NUMBER + 1)) + echo -ne "[$CURRENT_COMMIT_NUMBER/$TOTAL_COMMITS] Cherry-picking commit: $COMMIT"\\r + + # set environment variables to preserve author/committer and dates + export GIT_AUTHOR_NAME=$(git show -s --format='%an' $COMMIT) + export GIT_AUTHOR_EMAIL=$(git show -s --format='%ae' $COMMIT) + export GIT_COMMITTER_NAME=$(git show -s --format='%cn' $COMMIT) + export GIT_COMMITTER_EMAIL=$(git show -s --format='%ce' $COMMIT) + export GIT_AUTHOR_DATE=$(git show -s --format='%ad' $COMMIT) + export GIT_COMMITTER_DATE=$(git show -s --format='%cd' $COMMIT) + + # cherry-pick the commit + if ! GIT_OUTPUT=$(git cherry-pick -m 1 -X theirs $COMMIT 2>&1); then + # check if the failure is because of an empty commit + if [[ "$GIT_OUTPUT" == *"The previous cherry-pick is now empty"* ]]; then + echo "Empty commit detected. Skipping commit $COMMIT" + git cherry-pick --skip + # log it was empty to the mapping file + echo "$COMMIT EMPTY" >> commit-map.txt + else + # handle other errors or conflicts + echo "Cherry-pick failed. Handling error..." + echo "$GIT_OUTPUT" + exit 1 + fi + else + # capture the new commit hash + NEW_COMMIT=$(git rev-parse HEAD) + + # save the old and new commit hashes to the mapping file + echo "$COMMIT $NEW_COMMIT" >> commit-map.txt + + # append the old commit ID to the commit message + git commit --amend -m "$(git log -1 --pretty=%B)" -m "Former-commit-id: $COMMIT" > /dev/null + fi + done + + echo "Rewriting tags..." + + # remove all old tags + git tag -l | xargs git tag -d + + # read each line from the tag-commit-map.txt + while IFS=' ' read -r TAG OLD_COMMIT; do + # search for the new commit in commit-map.txt corresponding to the old commit + NEW_COMMIT=$(grep "^$OLD_COMMIT " "commit-map.txt" | awk '{print $2}') + + # check if this is a rebased commit + if [ -z "$NEW_COMMIT" ]; then + # if not, then just use old commit hash + NEW_COMMIT=$OLD_COMMIT + fi + + printf "Rewriting tag %s from commit %s\n" "$TAG" "$NEW_COMMIT" + git tag -f "$TAG" "$NEW_COMMIT" + done < "$DIR/tag-commit-map.txt" + + # uninstall lfs since we don't want to touch (push to) lfs right now + # git push will also push lfs, if we don't uninstall (--local so just for this repo) + git lfs uninstall --local + + # force push new master + git push --force origin main:master + + # force push new tags + git push --force --tags +fi + +# REWRITE branches based on master +if [ ! -f "$SRC_CLONE/branch-diff.txt" ]; then + cd $SRC_CLONE + + # empty file + > branch-diff.txt + + echo "Rewriting branches based on master..." + + # will store raw diffs here, if exist + mkdir -p differences + + # get a list of all branches except master + BRANCHES=$(git branch -r | grep -v ' -> ' | sed 's/origin\///' | grep -v '^master$') + + for BRANCH in $BRANCHES; do + # check if the branch is based on master history + MERGE_BASE=$(git merge-base master origin/$BRANCH) || true + if [ -n "$MERGE_BASE" ]; then + echo "Rewriting branch: $BRANCH" + + # create a new branch based on the new master + NEW_MERGE_BASE=$(grep "^$MERGE_BASE " "commit-map.txt" | awk '{print $2}') + if [ -z "$NEW_MERGE_BASE" ]; then + echo "Error: could not find new merge base for branch $BRANCH" >> branch-diff.txt + continue + fi + git checkout -b ${BRANCH}_new $NEW_MERGE_BASE + + # get the range of commits unique to this branch + COMMITS=$(git rev-list --reverse $MERGE_BASE..origin/${BRANCH}) + + HAS_ERROR=0 + + # simple delimiter + echo "BRANCH ${BRANCH}" >> commit-map.txt + + for COMMIT in $COMMITS; do + # set environment variables to preserve author/committer and dates + export GIT_AUTHOR_NAME=$(git show -s --format='%an' $COMMIT) + export GIT_AUTHOR_EMAIL=$(git show -s --format='%ae' $COMMIT) + export GIT_COMMITTER_NAME=$(git show -s --format='%cn' $COMMIT) + export GIT_COMMITTER_EMAIL=$(git show -s --format='%ce' $COMMIT) + export GIT_AUTHOR_DATE=$(git show -s --format='%ad' $COMMIT) + export GIT_COMMITTER_DATE=$(git show -s --format='%cd' $COMMIT) + + # cherry-pick the commit + if ! GIT_OUTPUT=$(git cherry-pick -m 1 -X theirs $COMMIT 2>&1); then + # check if the failure is because of an empty commit + if [[ "$GIT_OUTPUT" == *"The previous cherry-pick is now empty"* ]]; then + echo "Empty commit detected. Skipping commit $COMMIT" + git cherry-pick --skip + # log it was empty to the mapping file + echo "$COMMIT EMPTY" >> commit-map.txt + else + # handle other errors or conflicts + echo "Cherry-pick of ${BRANCH} branch failed. Removing branch upstream..." >> branch-diff.txt + echo "$GIT_OUTPUT" > "differences/branch-${BRANCH}" + git cherry-pick --abort + git push --delete origin ${BRANCH} + HAS_ERROR=1 + break + fi + else + # capture the new commit hash + NEW_COMMIT=$(git rev-parse HEAD) + + # save the old and new commit hashes to the mapping file + echo "$COMMIT $NEW_COMMIT" >> commit-map.txt + + # append the old commit ID to the commit message + git commit --amend -m "$(git log -1 --pretty=%B)" -m "Former-commit-id: $COMMIT" > /dev/null + fi + done + + # force push the new branch + if [ $HAS_ERROR -eq 0 ]; then + # git lfs goes haywire here, so we need to install and uninstall + # git lfs install --skip-smudge --local + git lfs uninstall --local > /dev/null + git push -f origin ${BRANCH}_new:${BRANCH} + fi + + # clean up local branch + git checkout master > /dev/null + git branch -D ${BRANCH}_new > /dev/null + else + # echo "Skipping branch $BRANCH as it's not based on master history" >> branch-diff.txt + echo "Deleting branch $BRANCH as it's not based on master history" >> branch-diff.txt + git push --delete origin ${BRANCH} + fi + done +fi + +# VALIDATE cherry-pick +if [ ! -f "$SRC_CLONE/commit-diff.txt" ]; then + cd $SRC_CLONE + + TOTAL_COMMITS=$(grep -cve '^\s*$' commit-map.txt) + CURRENT_COMMIT_NUMBER=0 + COUNT_SAME=0 + COUNT_DIFF=0 + VALIDATE_IGNORE_FILES=( + ".github/ISSUE_TEMPLATE/bug_report.md" + ".github/pull_request_template.md" + ) + + # empty file + > commit-diff.txt + + echo "Validating commits..." + + # will store raw diffs here, if exist + mkdir -p differences + + # read each line from commit-map.txt + while IFS=' ' read -r OLD_COMMIT NEW_COMMIT; do + if [ "$NEW_COMMIT" == "EMPTY" ]; then + continue + fi + if [ "$OLD_COMMIT" == "BRANCH" ]; then + echo "Branch ${NEW_COMMIT} below:" >> commit-diff.txt + continue + fi + CURRENT_COMMIT_NUMBER=$((CURRENT_COMMIT_NUMBER + 1)) + # retrieve short hashes and dates for the old and new commits + OLD_COMMIT_SHORT=$(git rev-parse --short $OLD_COMMIT) + NEW_COMMIT_SHORT=$(git rev-parse --short $NEW_COMMIT) + OLD_DATE=$(git show -s --format='%cd' $OLD_COMMIT) + NEW_DATE=$(git show -s --format='%cd' $NEW_COMMIT) + + echo -ne "[$CURRENT_COMMIT_NUMBER/$TOTAL_COMMITS] Comparing old commit $OLD_COMMIT_SHORT ($OLD_DATE) with new commit $NEW_COMMIT_SHORT ($NEW_DATE)"\\r + + # generate lists of files and their hashes for the old and new commits, excluding ignored files + OLD_FILES=$(git ls-tree -r $OLD_COMMIT | grep -vE "$(IFS='|'; echo "${VALIDATE_IGNORE_FILES[*]}")") + NEW_FILES=$(git ls-tree -r $NEW_COMMIT | grep -vE "$(IFS='|'; echo "${VALIDATE_IGNORE_FILES[*]}")") + + # Compare the diffs + if diff <(echo "$OLD_FILES") <(echo "$NEW_FILES") > /dev/null; then + # echo "Old commit $OLD_COMMIT_SHORT and new commit $NEW_COMMIT_SHORT are equivalent." + COUNT_SAME=$((COUNT_SAME + 1)) + else + echo "[$CURRENT_COMMIT_NUMBER/$TOTAL_COMMITS] Difference found between old commit $OLD_COMMIT_SHORT and new commit $NEW_COMMIT_SHORT" >> commit-diff.txt + COUNT_DIFF=$((COUNT_DIFF + 1)) + set +e + diff -u <(echo "$OLD_FILES") <(echo "$NEW_FILES") > "differences/$CURRENT_COMMIT_NUMBER-$OLD_COMMIT_SHORT-$NEW_COMMIT_SHORT" + set -e + fi + done < "commit-map.txt" + + echo "Summary:" >> commit-diff.txt + echo "Equivalent commits: $COUNT_SAME" >> commit-diff.txt + echo "Different commits: $COUNT_DIFF" >> commit-diff.txt +fi + +if [ ! -d $OUT ]; then + cp -r $SRC $OUT + + cd $OUT + + # remove all non-master branches + # TODO: need to see if we "redo" the other branches (except master, master-ci, devel, devel-staging, release3, release3-staging, dashcam3, dashcam3-staging, testing-closet*, hotfix-*) + # git branch | grep -v "^ master$" | grep -v "\*" | xargs git branch -D + + # echo "cleaning up refs" + # delete pull request refs since we can't alter them anyway (https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally#error-failed-to-push-some-refs) + # git for-each-ref --format='%(refname)' | grep '^refs/pull/' | xargs -I {} git update-ref -d {} + + echo "importing new lfs files" + # import "almost" everything to lfs + git lfs migrate import --everything --include="*.dlc,*.onnx,*.svg,*.png,*.gif,*.ttf,*.wav,selfdrive/car/tests/test_models_segs.txt,system/hardware/tici/updater,selfdrive/ui/qt/spinner_larch64,selfdrive/ui/qt/text_larch64,third_party/**/*.a,third_party/**/*.so,third_party/**/*.so.*,third_party/**/*.dylib,third_party/acados/*/t_renderer,third_party/qt5/larch64/bin/lrelease,third_party/qt5/larch64/bin/lupdate,third_party/catch2/include/catch2/catch.hpp,*.apk,*.apkpatch,*.jar,*.pdf,*.jpg,*.mp3,*.thneed,*.tar.gz,*.npy,*.csv,*.a,*.so*,*.dylib,*.o,*.b64,selfdrive/hardware/tici/updater,selfdrive/boardd/tests/test_boardd,selfdrive/ui/qt/spinner_aarch64,installer/updater/updater,selfdrive/debug/profiling/simpleperf/**/*,selfdrive/hardware/eon/updater,selfdrive/ui/qt/text_aarch64,selfdrive/debug/profiling/pyflame/**/*,installer/installers/installer_openpilot,installer/installers/installer_dashcam,selfdrive/ui/text/text,selfdrive/ui/android/text/text,selfdrive/ui/spinner/spinner,selfdrive/visiond/visiond,selfdrive/loggerd/loggerd,selfdrive/sensord/sensord,selfdrive/sensord/gpsd,selfdrive/ui/android/spinner/spinner,selfdrive/ui/qt/spinner,selfdrive/ui/qt/text,_stringdefs.py,dfu-util-aarch64-linux,dfu-util-aarch64,dfu-util-x86_64-linux,dfu-util-x86_64,stb_image.h,clpeak3,clwaste,apk/**/*,external/**/*,phonelibs/**/*,third_party/boringssl/**/*,flask/**/*,panda/**/*,board/**/*,messaging/**/*,opendbc/**/*,tools/cabana/chartswidget.cc,third_party/nanovg/**/*,selfdrive/controls/lib/lateral_mpc/lib_mpc_export/**/*,selfdrive/ui/paint.cc,werkzeug/**/*,pyextra/**/*,third_party/android_hardware_libhardware/**/*,selfdrive/controls/lib/lead_mpc_lib/lib_mpc_export/**/*,selfdrive/locationd/laikad.py,selfdrive/locationd/test/test_laikad.py,tools/gpstest/test_laikad.py,selfdrive/locationd/laikad_helpers.py,tools/nui/**/*,jsonrpc/**/*,selfdrive/controls/lib/longitudinal_mpc/lib_mpc_export/**/*,selfdrive/controls/lib/lateral_mpc/mpc_export/**/*,selfdrive/camerad/cameras/camera_qcom.cc,selfdrive/manager.py,selfdrive/modeld/models/driving.cc,third_party/curl/**/*,selfdrive/modeld/thneed/debug/**/*,selfdrive/modeld/thneed/include/**/*,third_party/openmax/**/*,selfdrive/controls/lib/longitudinal_mpc/mpc_export/**/*,selfdrive/controls/lib/longitudinal_mpc_model/lib_mpc_export/**/*,Pipfile,Pipfile.lock,gunicorn/**/*,*.qm,jinja2/**/*,click/**/*,dbcs/**/*,websocket/**/*" + + echo "reflog and gc" + # this is needed after lfs import + git reflog expire --expire=now --all + git gc --prune=now --aggressive + + # check the git-filter-repo analysis again - can be found in the repo root/filter-repo/analysis + echo "Analyzing with git-filter-repo..." + /tmp/git-filter-repo --force --analyze + + echo "New size is $(du -sh .)" +fi + +cd $OUT + +# fetch all lfs files from https://github.com/commaai/openpilot.git +# some lfs files are missing on gitlab, but they can be found on github +git config lfs.url https://github.com/commaai/openpilot.git/info/lfs +git config lfs.pushurl ssh://git@github.com/commaai/openpilot.git +git lfs fetch --all || true + +# also fetch all lfs files from https://gitlab.com/commaai/openpilot-lfs.git +git config lfs.url https://gitlab.com/commaai/openpilot-lfs.git/info/lfs +git config lfs.pushurl ssh://git@gitlab.com/commaai/openpilot-lfs.git +git lfs fetch --all || true + +# final push - will also push lfs +# TODO: switch to git@github.com:commaai/openpilot.git when ready +# if using mirror, it will also delete non-master branches (master-ci, nightly, devel, release3, release3-staging, dashcam3, release2) +# git push --mirror git@github.com:commaai/openpilot-tiny.git +# using this instead - since this is also what --mirror does - https://blog.plataformatec.com.br/2013/05/how-to-properly-mirror-a-git-repository/ +git push git@github.com:commaai/openpilot-tiny.git +refs/heads/*:refs/heads/* +refs/tags/*:refs/tags/* diff --git a/scripts/git_rewrite/tag-commit-map.txt b/scripts/git_rewrite/tag-commit-map.txt new file mode 100644 index 0000000000..66b1fb00c1 --- /dev/null +++ b/scripts/git_rewrite/tag-commit-map.txt @@ -0,0 +1,82 @@ +v0.1 e94a30bec07e719c5a7b037ca1f4db8312702cce +v0.2 449b482cc3236ccf31829830b4f6a44b2dcc06c2 +v0.2.1 17d9becd3c673091b22f09aa02559a9ed9230f50 +v0.2.2 a64b9aa9b8cb5863c917b6926516291a63c02fe5 +v0.2.3 adaa4ed350acda4067fc0b455ad15b54cdf4c768 +v0.2.4 ecc565aa3fdc4c7e719aadc000e1fdc4d80d4fe0 +v0.2.5 29c58b45882ac79595356caf98580c1d2a626011 +v0.2.6 6c3afeec0fb439070b2912978b8dbb659033b1d9 +v0.2.7 c6ba5dc5391d3ca6cda479bf1923b88ce45509a0 +v0.2.8 95a349abcc050712c50d4d85a1c8a804eee7f6c2 +v0.2.9 693bcb0f83478f2651db6bac9be5ca5ad60d03f3 +v0.3.0 c5d8aec28b5230d34ae4b677c2091cc3dec7e3e8 +v0.3.1 41e3a0f699f5c39cb61a15c0eb7a4aa816d47c24 +v0.3.2 7fe46f1e1df5dec08a940451ba0feefd5c039165 +v0.3.3 5cf91d0496688fed4f2a6c7021349b1fc0e057a2 +v0.3.4 1b8c44b5067525a5d266b6e99799d8097da76a29 +v0.3.5 b111277f464cf66fa34b67819a83ea683e0f64df +v0.4.0.2 da52d065a4c4f52d6017a537f3a80326f5af8bdc +v0.4.1 4474b9b3718653aeb0aee26422caefb90460cc0e +v0.4.2 28c0797d30175043bbfa31307b63aab4197cf996 +v0.4.4 9a9ff839a9b70cb2601d7696af743f5652395389 +v0.4.5 37285038d3f91fa1b49159c4a35a8383168e644f +v0.4.6 c6df34f55ba8c5a911b60d3f9eb20e3fa45f68c1 +v0.4.7 ae5cb7a0dab8b1bed9d52292f9b4e8e66a0f8ec9 +v0.5 de33bc46452b1046387ee2b3a03191b2c71135fb +v0.5.1 8f22f52235c48eada586795ac57edb22688e4d08 +v0.5.2 0129a8a4ff8da5314e8e4d4d3336e89667ff6d54 +v0.5.3 285c52eb693265a0a530543e9ca0aeb593a2a55e +v0.5.4 a422246dc30bce11e970514f13f7c110f4470cc3 +v0.5.5 8f3539a27b28851153454eb737da9624cccaed2d +v0.5.6 860a48765d1016ba226fb2c64aea35a45fe40e4a +v0.5.7 9ce3045f139ee29bf0eea5ec59dfe7df9c3d2c51 +v0.5.8 2cee2e05ba0f3824fdbb8b957958800fa99071a1 +v0.5.9 ad145da3bcded0fe75306df02061d07a633963c3 +v0.5.10 ff4c1557d8358f158f4358788ff18ef93d2470ef +v0.5.11 d1866845df423c6855e2b365ff230cf7d89a420b +v0.5.12 f6e8ef27546e9a406724841e75f8df71cc4c2c97 +v0.5.13 dd34ccfe288ebda8e2568cf550994ae890379f45 +v0.6 60a20537c5f3fcc7f11946d81aebc8f90c08c117 +v0.6.1 cf5c4aeacb1703d0ffd35bdb5297d3494fee9a22 +v0.6.2 095ef5f9f60fca1b269aabcc3cfd322b17b9e674 +v0.6.3 d5f9caa82d80cdcc7f1b7748f2cf3ccbf94f82a3 +v0.6.4 58f376002e0c654fbc2de127765fa297cf694a33 +v0.6.5 70d17cd69b80e7627dcad8fd5b6438f2309ac307 +v0.6.6 d4eb5a6eafdd4803d09e6f3963918216cca5a81f +v0.7 a2ae18d1dbd1e59c38ce22fa25ddffbd1d3084e3 +v0.7.1 1e1de64a1e59476b7b3d3558b92149246d5c3292 +v0.7.2 59bd58c940673b4c4a6a86f299022614bcf42b22 +v0.7.3 d7acd8b68f8131e0e714400cf124a3e228638643 +v0.7.4 e93649882c5e914eec4a8b8b593dc0587e497033 +v0.7.5 8abc0afe464626a461d2c7e192c912eeebeccc65 +v0.7.6 69aacd9d179fe6dd3110253a099c38b34cff7899 +v0.7.7 f1caed7299cdba5e45635d8377da6cc1e5fd7072 +v0.7.8 2189fe8741b635d8394d55dee28959425cfd5ad0 +v0.7.9 86dc54b836a973f132ed26db9f5a60b29f9b25b2 +v0.7.10 47a42ff432db8a2494e922ca5e767e58020f0446 +v0.7.11 f46ed718ba8d6bb4d42cd7b0f0150c406017c373 +v0.8 d56e04c0d960c8d3d4ab88b578dc508a2b4e07dc +v0.8.1 cd6f26664cb8d32a13847d6648567c47c580e248 +v0.8.2 7cc0999aebfe63b6bb6dd83c1dff62c3915c4820 +v0.8.3 986500fe2f10870018f1fba1e5465476b8915977 +v0.8.4 f0d0b82b8d6f5f450952113e234d0a5a49e80c48 +v0.8.5 f5d9ddc6c2a2802a61e5ce590c6b6688bf736a69 +v0.8.6 75904ed7452c6cbfb2a70cd379a899d8a75b97c2 +v0.8.7 4f9e568019492126e236da85b5ca0a059f292900 +v0.8.8 a949a49d5efaaf2d881143d23e9fb5ff9e28e88c +v0.8.9 a034926264cd1025c69d6ceb3fe444965f960b75 +v0.8.10 59accdd814398b884167c0f41dbf46dcccf0c29c +v0.8.11 d630ec9092f039cb5e51c5dd6d92fc47b91407e4 +v0.8.12 57871c99031cf597ffa0d819057ac1401e129f32 +v0.8.13 e43e6e876513450d235124fcb711f1724ed9814c +v0.8.14 71901c94dbbaa2f9f156a80c14cc7ea65219fc7c +v0.8.15 5a7c2f90361e72e9c35e88abd2e11acdc4aba354 +v0.8.16 f41dc62a12cc0f3cb8c5453c0caa0ba21e1bd01e +v0.9.0 58b84fb401a804967aa0dd5ee66fafa90194fd30 +v0.9.1 89f68bf0cbf53a81b0553d3816fdbe522f941fa1 +v0.9.2 c7d3b28b93faa6c955fb24bc64031512ee985ee9 +v0.9.3 8704c1ff952b5c85a44f50143bbd1a4f7b4887e2 +v0.9.4 fa310d9e2542cf497d92f007baec8fd751ffa99c +v0.9.5 3b1e9017c560499786d8a0e46aaaeea65037acac +v0.9.6 0b4d08fab8e35a264bc7383e878538f8083c33e5 +v0.9.7 f8cb04e4a8b032b72a909f68b808a50936184bee From 35df0a4fda99e42f49a734890de2dea5a641c639 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 8 Jul 2024 22:53:59 -0700 Subject: [PATCH 020/229] torqued: rename lat_active (#32942) * Update torqued.py * lint * not necessary --- selfdrive/locationd/torqued.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/locationd/torqued.py b/selfdrive/locationd/torqued.py index 569496b584..c254896e2b 100755 --- a/selfdrive/locationd/torqued.py +++ b/selfdrive/locationd/torqued.py @@ -159,7 +159,7 @@ class TorqueEstimator(ParameterEstimator): def handle_log(self, t, which, msg): if which == "carControl": self.raw_points["carControl_t"].append(t + self.lag) - self.raw_points["active"].append(msg.latActive) + self.raw_points["lat_active"].append(msg.latActive) elif which == "carOutput": self.raw_points["carOutput_t"].append(t + self.lag) self.raw_points["steer_torque"].append(-msg.actuatorsOutput.steer) @@ -171,12 +171,12 @@ class TorqueEstimator(ParameterEstimator): if len(self.raw_points['steer_torque']) == self.hist_len: yaw_rate = msg.angularVelocityCalibrated.value[2] roll = msg.orientationNED.value[0] - active = np.interp(np.arange(t - MIN_ENGAGE_BUFFER, t, DT_MDL), self.raw_points['carControl_t'], self.raw_points['active']).astype(bool) + lat_active = np.interp(np.arange(t - MIN_ENGAGE_BUFFER, t, DT_MDL), self.raw_points['carControl_t'], self.raw_points['lat_active']).astype(bool) steer_override = np.interp(np.arange(t - MIN_ENGAGE_BUFFER, t, DT_MDL), self.raw_points['carState_t'], self.raw_points['steer_override']).astype(bool) vego = np.interp(t, self.raw_points['carState_t'], self.raw_points['vego']) steer = np.interp(t, self.raw_points['carOutput_t'], self.raw_points['steer_torque']) lateral_acc = (vego * yaw_rate) - (np.sin(roll) * ACCELERATION_DUE_TO_GRAVITY) - if all(active) and (not any(steer_override)) and (vego > MIN_VEL) and (abs(steer) > STEER_MIN_THRESHOLD) and (abs(lateral_acc) <= LAT_ACC_THRESHOLD): + if all(lat_active) and not any(steer_override) and (vego > MIN_VEL) and (abs(steer) > STEER_MIN_THRESHOLD) and (abs(lateral_acc) <= LAT_ACC_THRESHOLD): self.filtered_points.add_point(float(steer), float(lateral_acc)) def get_msg(self, valid=True, with_points=False): From 133f25eecbd7be2343624c8ed3c426663bd027e5 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Tue, 9 Jul 2024 15:01:16 -0700 Subject: [PATCH 021/229] switch cereal to pytest (#32950) pytest --- cereal/messaging/tests/test_messaging.py | 52 ++++++++----------- cereal/messaging/tests/test_pub_sub_master.py | 44 +++++++--------- cereal/messaging/tests/test_services.py | 13 ++--- pyproject.toml | 2 +- 4 files changed, 45 insertions(+), 66 deletions(-) mode change 100755 => 100644 cereal/messaging/tests/test_messaging.py mode change 100755 => 100644 cereal/messaging/tests/test_pub_sub_master.py mode change 100755 => 100644 cereal/messaging/tests/test_services.py diff --git a/cereal/messaging/tests/test_messaging.py b/cereal/messaging/tests/test_messaging.py old mode 100755 new mode 100644 index 429c2d3c53..58fa7f7b28 --- a/cereal/messaging/tests/test_messaging.py +++ b/cereal/messaging/tests/test_messaging.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import os import capnp import multiprocessing @@ -6,8 +5,8 @@ import numbers import random import threading import time -import unittest from parameterized import parameterized +import pytest from cereal import log, car import cereal.messaging as messaging @@ -28,12 +27,6 @@ def zmq_sleep(t=1): if "ZMQ" in os.environ: time.sleep(t) -def zmq_expected_failure(func): - if "ZMQ" in os.environ: - return unittest.expectedFailure(func) - else: - return func - # TODO: this should take any capnp struct and returrn a msg with random populated data def random_carstate(): @@ -58,12 +51,12 @@ def delayed_send(delay, sock, dat): threading.Timer(delay, send_func).start() -class TestMessaging(unittest.TestCase): +class TestMessaging: def setUp(self): # TODO: ZMQ tests are too slow; all sleeps will need to be # replaced with logic to block on the necessary condition if "ZMQ" in os.environ: - raise unittest.SkipTest + pytest.skip() # ZMQ pub socket takes too long to die # sleep to prevent multiple publishers error between tests @@ -75,9 +68,9 @@ class TestMessaging(unittest.TestCase): msg = messaging.new_message(evt) except capnp.lib.capnp.KjException: msg = messaging.new_message(evt, random.randrange(200)) - self.assertLess(time.monotonic() - msg.logMonoTime, 0.1) - self.assertFalse(msg.valid) - self.assertEqual(evt, msg.which()) + assert (time.monotonic() - msg.logMonoTime) < 0.1 + assert not msg.valid + assert evt == msg.which() @parameterized.expand(events) def test_pub_sock(self, evt): @@ -99,8 +92,8 @@ class TestMessaging(unittest.TestCase): # no wait and no msgs in queue msgs = func(sub_sock) - self.assertIsInstance(msgs, list) - self.assertEqual(len(msgs), 0) + assert isinstance(msgs, list) + assert len(msgs) == 0 # no wait but msgs are queued up num_msgs = random.randrange(3, 10) @@ -108,9 +101,9 @@ class TestMessaging(unittest.TestCase): pub_sock.send(messaging.new_message(sock).to_bytes()) time.sleep(0.1) msgs = func(sub_sock) - self.assertIsInstance(msgs, list) - self.assertTrue(all(isinstance(msg, expected_type) for msg in msgs)) - self.assertEqual(len(msgs), num_msgs) + assert isinstance(msgs, list) + assert all(isinstance(msg, expected_type) for msg in msgs) + assert len(msgs) == num_msgs def test_recv_sock(self): sock = "carState" @@ -120,14 +113,14 @@ class TestMessaging(unittest.TestCase): # no wait and no msg in queue, socket should timeout recvd = messaging.recv_sock(sub_sock) - self.assertTrue(recvd is None) + assert recvd is None # no wait and one msg in queue msg = random_carstate() pub_sock.send(msg.to_bytes()) time.sleep(0.01) recvd = messaging.recv_sock(sub_sock) - self.assertIsInstance(recvd, capnp._DynamicStructReader) + assert isinstance(recvd, capnp._DynamicStructReader) # https://github.com/python/mypy/issues/13038 assert_carstate(msg.carState, recvd.carState) @@ -139,16 +132,16 @@ class TestMessaging(unittest.TestCase): # no msg in queue, socket should timeout recvd = messaging.recv_one(sub_sock) - self.assertTrue(recvd is None) + assert recvd is None # one msg in queue msg = random_carstate() pub_sock.send(msg.to_bytes()) recvd = messaging.recv_one(sub_sock) - self.assertIsInstance(recvd, capnp._DynamicStructReader) + assert isinstance(recvd, capnp._DynamicStructReader) assert_carstate(msg.carState, recvd.carState) - @zmq_expected_failure + @pytest.mark.xfail(condition="ZMQ" in os.environ, reason='ZMQ detected') def test_recv_one_or_none(self): sock = "carState" pub_sock = messaging.pub_sock(sock) @@ -157,13 +150,13 @@ class TestMessaging(unittest.TestCase): # no msg in queue, socket shouldn't block recvd = messaging.recv_one_or_none(sub_sock) - self.assertTrue(recvd is None) + assert recvd is None # one msg in queue msg = random_carstate() pub_sock.send(msg.to_bytes()) recvd = messaging.recv_one_or_none(sub_sock) - self.assertIsInstance(recvd, capnp._DynamicStructReader) + assert isinstance(recvd, capnp._DynamicStructReader) assert_carstate(msg.carState, recvd.carState) def test_recv_one_retry(self): @@ -179,7 +172,7 @@ class TestMessaging(unittest.TestCase): p = multiprocessing.Process(target=messaging.recv_one_retry, args=(sub_sock,)) p.start() time.sleep(sock_timeout*15) - self.assertTrue(p.is_alive()) + assert p.is_alive() p.terminate() # wait 15 socket timeouts before sending @@ -187,9 +180,6 @@ class TestMessaging(unittest.TestCase): delayed_send(sock_timeout*15, pub_sock, msg.to_bytes()) start_time = time.monotonic() recvd = messaging.recv_one_retry(sub_sock) - self.assertGreaterEqual(time.monotonic() - start_time, sock_timeout*15) - self.assertIsInstance(recvd, capnp._DynamicStructReader) + assert (time.monotonic() - start_time) >= sock_timeout*15 + assert isinstance(recvd, capnp._DynamicStructReader) assert_carstate(msg.carState, recvd.carState) - -if __name__ == "__main__": - unittest.main() diff --git a/cereal/messaging/tests/test_pub_sub_master.py b/cereal/messaging/tests/test_pub_sub_master.py old mode 100755 new mode 100644 index 81a1cf2d57..ba5b397aad --- a/cereal/messaging/tests/test_pub_sub_master.py +++ b/cereal/messaging/tests/test_pub_sub_master.py @@ -1,8 +1,6 @@ -#!/usr/bin/env python3 import random import time from typing import Sized, cast -import unittest import cereal.messaging as messaging from cereal.messaging.tests.test_messaging import events, random_sock, random_socks, \ @@ -10,9 +8,9 @@ from cereal.messaging.tests.test_messaging import events, random_sock, random_so zmq_sleep -class TestSubMaster(unittest.TestCase): +class TestSubMaster: - def setUp(self): + def setup_method(self): # ZMQ pub socket takes too long to die # sleep to prevent multiple publishers error between tests zmq_sleep(3) @@ -21,21 +19,21 @@ class TestSubMaster(unittest.TestCase): sm = messaging.SubMaster(events) for p in [sm.updated, sm.recv_time, sm.recv_frame, sm.alive, sm.sock, sm.data, sm.logMonoTime, sm.valid]: - self.assertEqual(len(cast(Sized, p)), len(events)) + assert len(cast(Sized, p)) == len(events) def test_init_state(self): socks = random_socks() sm = messaging.SubMaster(socks) - self.assertEqual(sm.frame, -1) - self.assertFalse(any(sm.updated.values())) - self.assertFalse(any(sm.alive.values())) - self.assertTrue(all(t == 0. for t in sm.recv_time.values())) - self.assertTrue(all(f == 0 for f in sm.recv_frame.values())) - self.assertTrue(all(t == 0 for t in sm.logMonoTime.values())) + assert sm.frame == -1 + assert not any(sm.updated.values()) + assert not any(sm.alive.values()) + assert all(t == 0. for t in sm.recv_time.values()) + assert all(f == 0 for f in sm.recv_frame.values()) + assert all(t == 0 for t in sm.logMonoTime.values()) for p in [sm.updated, sm.recv_time, sm.recv_frame, sm.alive, sm.sock, sm.data, sm.logMonoTime, sm.valid]: - self.assertEqual(len(cast(Sized, p)), len(socks)) + assert len(cast(Sized, p)) == len(socks) def test_getitem(self): sock = "carState" @@ -59,8 +57,8 @@ class TestSubMaster(unittest.TestCase): msg = messaging.new_message(sock) pub_sock.send(msg.to_bytes()) sm.update(1000) - self.assertEqual(sm.frame, i) - self.assertTrue(all(sm.updated.values())) + assert sm.frame == i + assert all(sm.updated.values()) def test_update_timeout(self): sock = random_sock() @@ -70,9 +68,9 @@ class TestSubMaster(unittest.TestCase): start_time = time.monotonic() sm.update(timeout) t = time.monotonic() - start_time - self.assertGreaterEqual(t, timeout/1000.) - self.assertLess(t, 5) - self.assertFalse(any(sm.updated.values())) + assert t >= timeout/1000. + assert t < 5 + assert not any(sm.updated.values()) def test_avg_frequency_checks(self): for poll in (True, False): @@ -118,12 +116,12 @@ class TestSubMaster(unittest.TestCase): pub_sock.send(msg.to_bytes()) time.sleep(0.01) sm.update(1000) - self.assertEqual(sm[sock].vEgo, n) + assert sm[sock].vEgo == n -class TestPubMaster(unittest.TestCase): +class TestPubMaster: - def setUp(self): + def setup_method(self): # ZMQ pub socket takes too long to die # sleep to prevent multiple publishers error between tests zmq_sleep(3) @@ -156,8 +154,4 @@ class TestPubMaster(unittest.TestCase): if capnp: msg.clear_write_flag() msg = msg.to_bytes() - self.assertEqual(msg, recvd, i) - - -if __name__ == "__main__": - unittest.main() + assert msg == recvd, i diff --git a/cereal/messaging/tests/test_services.py b/cereal/messaging/tests/test_services.py old mode 100755 new mode 100644 index ec96c90bc2..01e859a5a3 --- a/cereal/messaging/tests/test_services.py +++ b/cereal/messaging/tests/test_services.py @@ -1,26 +1,21 @@ -#!/usr/bin/env python3 import os import tempfile from typing import Dict -import unittest from parameterized import parameterized import cereal.services as services from cereal.services import SERVICE_LIST -class TestServices(unittest.TestCase): +class TestServices: @parameterized.expand(SERVICE_LIST.keys()) def test_services(self, s): service = SERVICE_LIST[s] - self.assertTrue(service.frequency <= 104) - self.assertTrue(service.decimation != 0) + assert service.frequency <= 104 + assert service.decimation != 0 def test_generated_header(self): with tempfile.NamedTemporaryFile(suffix=".h") as f: ret = os.system(f"python3 {services.__file__} > {f.name} && clang++ {f.name}") - self.assertEqual(ret, 0, "generated services header is not valid C") - -if __name__ == "__main__": - unittest.main() + assert ret == 0, "generated services header is not valid C" diff --git a/pyproject.toml b/pyproject.toml index 1023de9186..0f5d9aa1cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -136,7 +136,7 @@ packages = [ "." ] [tool.pytest.ini_options] minversion = "6.0" -addopts = "--ignore=openpilot/ --ignore=cereal/ --ignore=opendbc/ --ignore=panda/ --ignore=rednose_repo/ --ignore=tinygrad_repo/ --ignore=teleoprtc_repo/ --ignore=msgq/ -Werror --strict-config --strict-markers --durations=10 -n auto --dist=loadgroup" +addopts = "--ignore=openpilot/ --ignore=opendbc/ --ignore=panda/ --ignore=rednose_repo/ --ignore=tinygrad_repo/ --ignore=teleoprtc_repo/ --ignore=msgq/ -Werror --strict-config --strict-markers --durations=10 -n auto --dist=loadgroup" cpp_files = "test_*" cpp_harness = "selfdrive/test/cpp_harness.py" python_files = "test_*.py" From ba129989868274ed4bf8d91806ffeeb0620b3cbd Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Tue, 9 Jul 2024 22:59:44 -0400 Subject: [PATCH 022/229] ui: onroad: `drawLead` cleanup --- selfdrive/ui/qt/onroad/annotated_camera.cc | 30 +++++++++++++--------- selfdrive/ui/qt/onroad/annotated_camera.h | 3 ++- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc index 7e5629c4ef..009ff76138 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.cc +++ b/selfdrive/ui/qt/onroad/annotated_camera.cc @@ -1490,13 +1490,14 @@ void AnnotatedCameraWidget::rocketFuel(QPainter &p) { } void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, - int num, float radar_d_rel, float v_ego, float radar_v_rel, int chevron_data, bool isMetric) { + int num, const cereal::CarState::Reader &car_data, int chevron_data) { painter.save(); const float speedBuff = 10.; const float leadBuff = 40.; const float d_rel = lead_data.getDRel(); const float v_rel = lead_data.getVRel(); + const float v_ego = car_data.getVEgo(); float fillAlpha = 0; if (d_rel < leadBuff) { @@ -1524,22 +1525,29 @@ void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState painter.drawPolygon(chevron, std::size(chevron)); if (num == 0) { // Display metrics to the 0th lead car - QStringList chevron_text[2]; + int chevron_types = 2; + QStringList chevron_text[chevron_types]; + int position; + float val; if (chevron_data == 1 || chevron_data == 3) { - chevron_text[0].append(QString::number(radar_d_rel,'f', 0) + " " + "m"); + position = 0; + val = std::max(0.0f, d_rel); + chevron_text[position].append(QString::number(val,'f', 0) + " " + "m"); } if (chevron_data == 2 || chevron_data == 3) { - chevron_text[chevron_data - 2].append(QString::number((radar_v_rel + v_ego) * (isMetric ? MS_TO_KPH : MS_TO_MPH),'f', 0) + " " + (isMetric ? "km/h" : "mph")); + position = (chevron_data == 2) ? 0 : 1; + val = std::max(0.0f, (v_rel + v_ego) * (is_metric ? static_cast(MS_TO_KPH) : static_cast(MS_TO_MPH))); + chevron_text[position].append(QString::number(val,'f', 0) + " " + (is_metric ? "km/h" : "mph")); } - int str_w = 200; // Width of the text box, might need adjustment - int str_h = 50; // Height of the text box, adjust as necessary + float str_w = 200; // Width of the text box, might need adjustment + float str_h = 50; // Height of the text box, adjust as necessary painter.setFont(InterFont(45, QFont::Bold)); // Calculate the center of the chevron and adjust the text box position float text_y = y + sz + 12; // Position the text at the bottom of the chevron QRect textRect(x - str_w / 2, text_y, str_w, str_h); // Adjust the rectangle to center the text horizontally at the chevron's bottom QPoint shadow_offset(2, 2); - for (int i = 0; i < 2; ++i) { + for (int i = 0; i < chevron_types; ++i) { if (!chevron_text[i].isEmpty()) { painter.setPen(QColor(0x0, 0x0, 0x0, 200)); // Draw shadow painter.drawText(textRect.translated(shadow_offset.x(), shadow_offset.y() + i * str_h), Qt::AlignBottom | Qt::AlignHCenter, chevron_text[i].at(0)); @@ -1623,17 +1631,15 @@ void AnnotatedCameraWidget::paintEvent(QPaintEvent *event) { if (s->scene.longitudinal_control && sm.rcv_frame("radarState") > s->scene.started_frame) { auto radar_state = sm["radarState"].getRadarState(); + auto car_state = sm["carState"].getCarState(); update_leads(s, radar_state, model.getPosition()); auto lead_one = radar_state.getLeadOne(); auto lead_two = radar_state.getLeadTwo(); - float v_ego = sm["carState"].getCarState().getVEgo(); - float radar_d_rel = radar_state.getLeadOne().getDRel(); - float radar_v_rel = radar_state.getLeadOne().getVRel(); if (lead_one.getStatus()) { - drawLead(painter, lead_one, s->scene.lead_vertices[0], 0, radar_d_rel, v_ego, radar_v_rel, s->scene.chevron_data, s->scene.is_metric); + drawLead(painter, lead_one, s->scene.lead_vertices[0], 0, car_state, s->scene.chevron_data); } if (lead_two.getStatus() && (std::abs(lead_one.getDRel() - lead_two.getDRel()) > 3.0)) { - drawLead(painter, lead_two, s->scene.lead_vertices[1], 1, radar_d_rel, v_ego, radar_v_rel, s->scene.chevron_data, s->scene.is_metric); + drawLead(painter, lead_two, s->scene.lead_vertices[1], 1, car_state, s->scene.chevron_data); } rocketFuel(painter); diff --git a/selfdrive/ui/qt/onroad/annotated_camera.h b/selfdrive/ui/qt/onroad/annotated_camera.h index 94bd12c8c0..29b9c4833b 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.h +++ b/selfdrive/ui/qt/onroad/annotated_camera.h @@ -211,7 +211,8 @@ protected: void showEvent(QShowEvent *event) override; void updateFrameMat() override; void drawLaneLines(QPainter &painter, const UIState *s); - void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, int num, float radar_d_rel, float v_ego, float radar_v_rel, int chevron_data, bool isMetric); + void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, + int num, const cereal::CarState::Reader &car_data, int chevron_data); void drawHud(QPainter &p); void drawDriverState(QPainter &painter, const UIState *s); inline QColor redColor(int alpha = 255) { return QColor(201, 34, 49, alpha); } From 0c58e35b6c2294ef9ad149081a95739524fe74ae Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 9 Jul 2024 21:16:36 -0700 Subject: [PATCH 023/229] format torqued.py --- selfdrive/locationd/torqued.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/selfdrive/locationd/torqued.py b/selfdrive/locationd/torqued.py index c254896e2b..4ec4b928ab 100755 --- a/selfdrive/locationd/torqued.py +++ b/selfdrive/locationd/torqued.py @@ -36,8 +36,8 @@ ALLOWED_CARS = ['toyota', 'hyundai'] def slope2rot(slope): - sin = np.sqrt(slope**2 / (slope**2 + 1)) - cos = np.sqrt(1 / (slope**2 + 1)) + sin = np.sqrt(slope ** 2 / (slope ** 2 + 1)) + cos = np.sqrt(1 / (slope ** 2 + 1)) return np.array([[cos, -sin], [sin, cos]]) @@ -52,7 +52,7 @@ class TorqueBuckets(PointBuckets): class TorqueEstimator(ParameterEstimator): def __init__(self, CP, decimated=False): self.hist_len = int(HISTORY / DT_MDL) - self.lag = CP.steerActuatorDelay + .2 # from controlsd + self.lag = CP.steerActuatorDelay + .2 # from controlsd if decimated: self.min_bucket_points = MIN_BUCKET_POINTS / 10 self.min_points_total = MIN_POINTS_TOTAL_QLOG @@ -242,8 +242,10 @@ def main(demo=False): msg = estimator.get_msg(valid=sm.all_checks(), with_points=True) params.put_nonblocking("LiveTorqueParameters", msg.to_bytes()) + if __name__ == "__main__": import argparse + parser = argparse.ArgumentParser(description='Process the --demo argument.') parser.add_argument('--demo', action='store_true', help='A boolean for demo mode.') args = parser.parse_args() From 5efdaf202624956f03a9c5f521bf692dae213c48 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 9 Jul 2024 22:21:50 -0700 Subject: [PATCH 024/229] torqued: option to keep track of all points (#32957) * how about this * here * rename * revert * revert this too * can do this * ugh inside TorqueBuckets it implicitly limits steer torque to 50%!!!!!!!! * fix * move up --- selfdrive/locationd/torqued.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/selfdrive/locationd/torqued.py b/selfdrive/locationd/torqued.py index 4ec4b928ab..cb10fa93ab 100755 --- a/selfdrive/locationd/torqued.py +++ b/selfdrive/locationd/torqued.py @@ -50,9 +50,10 @@ class TorqueBuckets(PointBuckets): class TorqueEstimator(ParameterEstimator): - def __init__(self, CP, decimated=False): + def __init__(self, CP, decimated=False, track_all_points=False): self.hist_len = int(HISTORY / DT_MDL) self.lag = CP.steerActuatorDelay + .2 # from controlsd + self.track_all_points = track_all_points # for offline analysis, without max lateral accel or max steer torque filters if decimated: self.min_bucket_points = MIN_BUCKET_POINTS / 10 self.min_points_total = MIN_POINTS_TOTAL_QLOG @@ -135,6 +136,7 @@ class TorqueEstimator(ParameterEstimator): min_points_total=self.min_points_total, points_per_bucket=POINTS_PER_BUCKET, rowsize=3) + self.all_torque_points = [] def estimate_params(self): points = self.filtered_points.get_points(self.fit_points) @@ -174,10 +176,14 @@ class TorqueEstimator(ParameterEstimator): lat_active = np.interp(np.arange(t - MIN_ENGAGE_BUFFER, t, DT_MDL), self.raw_points['carControl_t'], self.raw_points['lat_active']).astype(bool) steer_override = np.interp(np.arange(t - MIN_ENGAGE_BUFFER, t, DT_MDL), self.raw_points['carState_t'], self.raw_points['steer_override']).astype(bool) vego = np.interp(t, self.raw_points['carState_t'], self.raw_points['vego']) - steer = np.interp(t, self.raw_points['carOutput_t'], self.raw_points['steer_torque']) - lateral_acc = (vego * yaw_rate) - (np.sin(roll) * ACCELERATION_DUE_TO_GRAVITY) - if all(lat_active) and not any(steer_override) and (vego > MIN_VEL) and (abs(steer) > STEER_MIN_THRESHOLD) and (abs(lateral_acc) <= LAT_ACC_THRESHOLD): - self.filtered_points.add_point(float(steer), float(lateral_acc)) + steer = np.interp(t, self.raw_points['carOutput_t'], self.raw_points['steer_torque']).item() + lateral_acc = (vego * yaw_rate) - (np.sin(roll) * ACCELERATION_DUE_TO_GRAVITY).item() + if all(lat_active) and not any(steer_override) and (vego > MIN_VEL) and (abs(steer) > STEER_MIN_THRESHOLD): + if abs(lateral_acc) <= LAT_ACC_THRESHOLD: + self.filtered_points.add_point(steer, lateral_acc) + + if self.track_all_points: + self.all_torque_points.append([steer, lateral_acc]) def get_msg(self, valid=True, with_points=False): msg = messaging.new_message('liveTorqueParameters') From fbc53a24a3b1977814b50c4021ba9c445c8f7f74 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 9 Jul 2024 22:26:58 -0700 Subject: [PATCH 025/229] torqued: clean up (#32958) * formatting * function signatures didn't match * function signatures didn't match * filtered and raw mean something totally different when it comes to params filtered and raw mean something totally different when it comes to params * cmt * probably better for organization * add todo * STASH * revert some stuff * clean up * oof --- selfdrive/locationd/helpers.py | 2 +- selfdrive/locationd/torqued.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/selfdrive/locationd/helpers.py b/selfdrive/locationd/helpers.py index 786bdbbfec..8f7211aebf 100644 --- a/selfdrive/locationd/helpers.py +++ b/selfdrive/locationd/helpers.py @@ -38,7 +38,7 @@ class PointBuckets: def is_calculable(self) -> bool: return all(len(v) > 0 for v in self.buckets.values()) - def add_point(self, x: float, y: float, bucket_val: float) -> None: + def add_point(self, x: float, y: float) -> None: raise NotImplementedError def get_points(self, num_points: int = None) -> Any: diff --git a/selfdrive/locationd/torqued.py b/selfdrive/locationd/torqued.py index cb10fa93ab..ba649b318d 100755 --- a/selfdrive/locationd/torqued.py +++ b/selfdrive/locationd/torqued.py @@ -120,7 +120,8 @@ class TorqueEstimator(ParameterEstimator): for param in initial_params: self.filtered_params[param] = FirstOrderFilter(initial_params[param], self.decay, DT_MDL) - def get_restore_key(self, CP, version): + @staticmethod + def get_restore_key(CP, version): a, b = None, None if CP.lateralTuning.which() == 'torque': a = CP.lateralTuning.torque.friction @@ -167,8 +168,11 @@ class TorqueEstimator(ParameterEstimator): self.raw_points["steer_torque"].append(-msg.actuatorsOutput.steer) elif which == "carState": self.raw_points["carState_t"].append(t + self.lag) + # TODO: check if high aEgo affects resulting lateral accel self.raw_points["vego"].append(msg.vEgo) self.raw_points["steer_override"].append(msg.steeringPressed) + + # calculate lateral accel from past steering torque elif which == "liveLocationKalman": if len(self.raw_points['steer_torque']) == self.hist_len: yaw_rate = msg.angularVelocityCalibrated.value[2] From d9da6064c0a5dac539916bd4e30772e4dc10aaf4 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Wed, 10 Jul 2024 11:04:46 -0400 Subject: [PATCH 026/229] ui: Build `mapsd` in UBUNTU_FOCAL-based AGNOS --- selfdrive/navd/SConscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/navd/SConscript b/selfdrive/navd/SConscript index 1a8a3ee42b..eb726b1e5e 100644 --- a/selfdrive/navd/SConscript +++ b/selfdrive/navd/SConscript @@ -6,7 +6,7 @@ libs = ['qt_widgets', 'qt_util', 'QMapLibre', common, messaging, visionipc, tran if arch == 'larch64': libs.append(':libEGL_mesa.so.0') -if arch in ['larch64', 'aarch64', 'x86_64'] and not UBUNTU_FOCAL: +if arch in ['larch64', 'aarch64', 'x86_64']: if arch == 'x86_64': rpath = Dir(f"#third_party/maplibre-native-qt/{arch}/lib").srcnode().abspath map_env["RPATH"] += [rpath, ] From 606fb2d7c91351e1d86cc7b85ce5d66fdb823a7c Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Wed, 10 Jul 2024 17:01:57 +0000 Subject: [PATCH 027/229] sunnylink: disable log upload handler --- system/athena/sunnylinkd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/athena/sunnylinkd.py b/system/athena/sunnylinkd.py index ca24f24090..3b4c81b680 100755 --- a/system/athena/sunnylinkd.py +++ b/system/athena/sunnylinkd.py @@ -43,7 +43,7 @@ def handle_long_poll(ws: WebSocket, exit_event: threading.Event | None) -> None: threading.Thread(target=ws_ping, args=(ws, end_event), name='ws_ping'), threading.Thread(target=ws_queue, args=(end_event,), name='ws_queue'), # threading.Thread(target=upload_handler, args=(end_event,), name='upload_handler'), - threading.Thread(target=sunny_log_handler, args=(end_event, comma_prime_cellular_end_event), name='log_handler'), + # threading.Thread(target=sunny_log_handler, args=(end_event, comma_prime_cellular_end_event), name='log_handler'), # threading.Thread(target=stat_handler, args=(end_event,), name='stat_handler'), ] + [ threading.Thread(target=jsonrpc_handler, args=(end_event,), name=f'worker_{x}') From c17c34187b6e9c14b3c00135386625bbb601ed22 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 11 Jul 2024 06:10:24 +0800 Subject: [PATCH 028/229] cabana: simplify stream management and remove problematic autosave feature (#32945) simplify code and remove problematic code --- tools/cabana/cabana.cc | 29 +--- tools/cabana/chart/chart.cc | 9 +- tools/cabana/chart/chartswidget.h | 1 - tools/cabana/chart/signalselector.cc | 3 +- tools/cabana/chart/sparkline.cc | 9 +- tools/cabana/chart/sparkline.h | 1 + tools/cabana/dbc/dbcfile.cc | 23 +-- tools/cabana/dbc/dbcfile.h | 6 +- tools/cabana/mainwin.cc | 207 +++++++++--------------- tools/cabana/mainwin.h | 17 +- tools/cabana/signalview.cc | 2 +- tools/cabana/signalview.h | 1 + tools/cabana/streams/abstractstream.cc | 11 -- tools/cabana/streams/abstractstream.h | 21 +-- tools/cabana/streams/devicestream.cc | 11 +- tools/cabana/streams/devicestream.h | 6 +- tools/cabana/streams/livestream.cc | 1 - tools/cabana/streams/pandastream.cc | 13 +- tools/cabana/streams/pandastream.h | 6 +- tools/cabana/streams/replaystream.cc | 17 +- tools/cabana/streams/replaystream.h | 8 +- tools/cabana/streams/socketcanstream.cc | 13 +- tools/cabana/streams/socketcanstream.h | 6 +- tools/cabana/streamselector.cc | 16 +- tools/cabana/streamselector.h | 6 +- 25 files changed, 134 insertions(+), 309 deletions(-) diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index 4a3b4126dd..a798d13a81 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -38,26 +38,19 @@ int main(int argc, char *argv[]) { cmd_parser.addOption({"dbc", "dbc file to open", "dbc"}); cmd_parser.process(app); - QString dbc_file = cmd_parser.isSet("dbc") ? cmd_parser.value("dbc") : ""; - AbstractStream *stream = nullptr; + if (cmd_parser.isSet("stream")) { stream = new DeviceStream(&app, cmd_parser.value("zmq")); } else if (cmd_parser.isSet("panda") || cmd_parser.isSet("panda-serial")) { - PandaStreamConfig config = {}; - if (cmd_parser.isSet("panda-serial")) { - config.serial = cmd_parser.value("panda-serial"); - } try { - stream = new PandaStream(&app, config); + stream = new PandaStream(&app, {.serial = cmd_parser.value("panda-serial")}); } catch (std::exception &e) { qWarning() << e.what(); return 0; } } else if (cmd_parser.isSet("socketcan")) { - SocketCanStreamConfig config = {}; - config.device = cmd_parser.value("socketcan"); - stream = new SocketCanStream(&app, config); + stream = new SocketCanStream(&app, {.device = cmd_parser.value("socketcan")}); } else { uint32_t replay_flags = REPLAY_FLAG_NONE; if (cmd_parser.isSet("ecam")) replay_flags |= REPLAY_FLAG_ECAM; @@ -73,24 +66,14 @@ int main(int argc, char *argv[]) { route = DEMO_ROUTE; } if (!route.isEmpty()) { - auto replay_stream = new ReplayStream(&app); + auto replay_stream = std::make_unique(&app); if (!replay_stream->loadRoute(route, cmd_parser.value("data_dir"), replay_flags)) { return 0; } - stream = replay_stream; + stream = replay_stream.release(); } } - MainWindow w; - if (stream) { - stream->start(); - if (!dbc_file.isEmpty()) { - w.loadFile(dbc_file); - } - } else { - w.openStream(); - } - w.show(); - + MainWindow w(stream, cmd_parser.value("dbc")); return app.exec(); } diff --git a/tools/cabana/chart/chart.cc b/tools/cabana/chart/chart.cc index 128c33baec..6c13252e80 100644 --- a/tools/cabana/chart/chart.cc +++ b/tools/cabana/chart/chart.cc @@ -155,11 +155,10 @@ void ChartView::removeIf(std::function predicate) { } void ChartView::signalUpdated(const cabana::Signal *sig) { - if (std::any_of(sigs.cbegin(), sigs.cend(), [=](auto &s) { return s.sig == sig; })) { - for (const auto &s : sigs) { - if (s.sig == sig && s.series->color() != sig->color) { - setSeriesColor(s.series, sig->color); - } + auto it = std::find_if(sigs.begin(), sigs.end(), [sig](auto &s) { return s.sig == sig; }); + if (it != sigs.end()) { + if (it->series->color() != sig->color) { + setSeriesColor(it->series, sig->color); } updateTitle(); updateSeries(sig); diff --git a/tools/cabana/chart/chartswidget.h b/tools/cabana/chart/chartswidget.h index 0b948b3421..a925191792 100644 --- a/tools/cabana/chart/chartswidget.h +++ b/tools/cabana/chart/chartswidget.h @@ -110,7 +110,6 @@ private: QTimer *align_timer; int current_theme = 0; bool value_tip_visible_ = false; - friend class ZoomCommand; friend class ChartView; friend class ChartsContainer; }; diff --git a/tools/cabana/chart/signalselector.cc b/tools/cabana/chart/signalselector.cc index 0ddb212a8a..63f3a7d575 100644 --- a/tools/cabana/chart/signalselector.cc +++ b/tools/cabana/chart/signalselector.cc @@ -83,7 +83,8 @@ void SignalSelector::updateAvailableList(int index) { MessageId msg_id = msgs_combo->itemData(index).value(); auto selected_items = seletedItems(); for (auto s : dbc()->msg(msg_id)->getSignals()) { - bool is_selected = std::any_of(selected_items.begin(), selected_items.end(), [=, sig = s](auto it) { return it->msg_id == msg_id && it->sig == sig; }); + bool is_selected = std::any_of(selected_items.begin(), selected_items.end(), + [sig = s, &msg_id](auto it) { return it->msg_id == msg_id && it->sig == sig; }); if (!is_selected) { addItemToList(available_list, msg_id, s); } diff --git a/tools/cabana/chart/sparkline.cc b/tools/cabana/chart/sparkline.cc index 1cadda2bd8..094fe96182 100644 --- a/tools/cabana/chart/sparkline.cc +++ b/tools/cabana/chart/sparkline.cc @@ -4,8 +4,6 @@ #include #include -#include "tools/cabana/streams/abstractstream.h" - void Sparkline::update(const MessageId &msg_id, const cabana::Signal *sig, double last_msg_ts, int range, QSize size) { const auto &msgs = can->events(msg_id); @@ -14,11 +12,6 @@ void Sparkline::update(const MessageId &msg_id, const cabana::Signal *sig, doubl auto first = std::lower_bound(msgs.cbegin(), msgs.cend(), range_start, CompareCanEvent()); auto last = std::upper_bound(first, msgs.cend(), range_end, CompareCanEvent()); - if (first == last || size.isEmpty()) { - pixmap = QPixmap(); - return; - } - points.clear(); double value = 0; for (auto it = first; it != last; ++it) { @@ -27,7 +20,7 @@ void Sparkline::update(const MessageId &msg_id, const cabana::Signal *sig, doubl } } - if (points.empty()) { + if (points.empty() || size.isEmpty()) { pixmap = QPixmap(); return; } diff --git a/tools/cabana/chart/sparkline.h b/tools/cabana/chart/sparkline.h index 3bdd8a3ee5..806f0a61eb 100644 --- a/tools/cabana/chart/sparkline.h +++ b/tools/cabana/chart/sparkline.h @@ -5,6 +5,7 @@ #include #include "tools/cabana/dbc/dbc.h" +#include "tools/cabana/streams/abstractstream.h" class Sparkline { public: diff --git a/tools/cabana/dbc/dbcfile.cc b/tools/cabana/dbc/dbcfile.cc index 4a1c52819a..cca9d0c0fa 100644 --- a/tools/cabana/dbc/dbcfile.cc +++ b/tools/cabana/dbc/dbcfile.cc @@ -9,10 +9,6 @@ DBCFile::DBCFile(const QString &dbc_file_name) { if (file.open(QIODevice::ReadOnly)) { name_ = QFileInfo(dbc_file_name).baseName(); filename = dbc_file_name; - // Remove auto save file extension - if (dbc_file_name.endsWith(AUTO_SAVE_EXTENSION)) { - filename.chop(AUTO_SAVE_EXTENSION.length()); - } parse(file.readAll()); } else { throw std::runtime_error("Failed to open file."); @@ -20,17 +16,12 @@ DBCFile::DBCFile(const QString &dbc_file_name) { } DBCFile::DBCFile(const QString &name, const QString &content) : name_(name), filename("") { - // Open from clipboard parse(content); } bool DBCFile::save() { assert(!filename.isEmpty()); - if (writeContents(filename)) { - cleanupAutoSaveFile(); - return true; - } - return false; + return writeContents(filename); } bool DBCFile::saveAs(const QString &new_filename) { @@ -38,16 +29,6 @@ bool DBCFile::saveAs(const QString &new_filename) { return save(); } -bool DBCFile::autoSave() { - return !filename.isEmpty() && writeContents(filename + AUTO_SAVE_EXTENSION); -} - -void DBCFile::cleanupAutoSaveFile() { - if (!filename.isEmpty()) { - QFile::remove(filename + AUTO_SAVE_EXTENSION); - } -} - bool DBCFile::writeContents(const QString &fn) { QFile file(fn); if (file.open(QIODevice::WriteOnly)) { @@ -75,7 +56,7 @@ cabana::Msg *DBCFile::msg(const QString &name) { return it != msgs.end() ? &(it->second) : nullptr; } -cabana::Signal *DBCFile::signal(uint32_t address, const QString name) { +cabana::Signal *DBCFile::signal(uint32_t address, const QString &name) { auto m = msg(address); return m ? (cabana::Signal *)m->sig(name) : nullptr; } diff --git a/tools/cabana/dbc/dbcfile.h b/tools/cabana/dbc/dbcfile.h index 20de04a861..bd267898f9 100644 --- a/tools/cabana/dbc/dbcfile.h +++ b/tools/cabana/dbc/dbcfile.h @@ -5,8 +5,6 @@ #include "tools/cabana/dbc/dbc.h" -const QString AUTO_SAVE_EXTENSION = ".tmp"; - class DBCFile { public: DBCFile(const QString &dbc_file_name); @@ -15,9 +13,7 @@ public: bool save(); bool saveAs(const QString &new_filename); - bool autoSave(); bool writeContents(const QString &fn); - void cleanupAutoSaveFile(); QString generateDBC(); void updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &node, const QString &comment); @@ -27,7 +23,7 @@ public: cabana::Msg *msg(uint32_t address); cabana::Msg *msg(const QString &name); inline cabana::Msg *msg(const MessageId &id) { return msg(id.address); } - cabana::Signal *signal(uint32_t address, const QString name); + cabana::Signal *signal(uint32_t address, const QString &name); inline QString name() const { return name_.isEmpty() ? "untitled" : name_; } inline bool isEmpty() const { return msgs.empty() && name_.isEmpty(); } diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index bf1db63eea..34432707db 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -23,9 +24,8 @@ #include "tools/cabana/streamselector.h" #include "tools/cabana/tools/findsignal.h" #include "tools/cabana/utils/export.h" -#include "tools/replay/replay.h" -MainWindow::MainWindow() : QMainWindow() { +MainWindow::MainWindow(AbstractStream *stream, const QString &dbc_file) : QMainWindow() { loadFingerprints(); createDockWindows(); setCentralWidget(center_widget = new CenterWidget(this)); @@ -65,10 +65,10 @@ MainWindow::MainWindow() : QMainWindow() { QObject::connect(this, &MainWindow::updateProgressBar, this, &MainWindow::updateDownloadProgress); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &MainWindow::DBCFileChanged); QObject::connect(UndoStack::instance(), &QUndoStack::cleanChanged, this, &MainWindow::undoStackCleanChanged); - QObject::connect(UndoStack::instance(), &QUndoStack::indexChanged, this, &MainWindow::undoStackIndexChanged); QObject::connect(&settings, &Settings::changed, this, &MainWindow::updateStatus); - QObject::connect(StreamNotifier::instance(), &StreamNotifier::changingStream, this, &MainWindow::changingStream); - QObject::connect(StreamNotifier::instance(), &StreamNotifier::streamStarted, this, &MainWindow::streamStarted); + + QTimer::singleShot(0, this, [=]() { stream ? openStream(stream, dbc_file) : selectAndOpenStream(); }); + show(); } void MainWindow::loadFingerprints() { @@ -76,16 +76,12 @@ void MainWindow::loadFingerprints() { if (json_file.open(QIODevice::ReadOnly)) { fingerprint_to_dbc = QJsonDocument::fromJson(json_file.readAll()); } - // get opendbc names - for (auto fn : QDir(OPENDBC_FILE_PATH).entryList({"*.dbc"}, QDir::Files, QDir::Name)) { - opendbc_names << QFileInfo(fn).baseName(); - } } void MainWindow::createActions() { // File menu QMenu *file_menu = menuBar()->addMenu(tr("&File")); - file_menu->addAction(tr("Open Stream..."), this, &MainWindow::openStream); + file_menu->addAction(tr("Open Stream..."), this, &MainWindow::selectAndOpenStream); close_stream_act = file_menu->addAction(tr("Close stream"), this, &MainWindow::closeStream); export_to_csv_act = file_menu->addAction(tr("Export to CSV..."), this, &MainWindow::exportToCSV); close_stream_act->setEnabled(false); @@ -96,20 +92,15 @@ void MainWindow::createActions() { file_menu->addAction(tr("Open DBC File..."), [this]() { openFile(); }, QKeySequence::Open); manage_dbcs_menu = file_menu->addMenu(tr("Manage &DBC Files")); + QObject::connect(manage_dbcs_menu, &QMenu::aboutToShow, this, &MainWindow::updateLoadSaveMenus); open_recent_menu = file_menu->addMenu(tr("Open &Recent")); - for (int i = 0; i < MAX_RECENT_FILES; ++i) { - recent_files_acts[i] = new QAction(this); - recent_files_acts[i]->setVisible(false); - QObject::connect(recent_files_acts[i], &QAction::triggered, this, &MainWindow::openRecentFile); - open_recent_menu->addAction(recent_files_acts[i]); - } - updateRecentFileActions(); + QObject::connect(open_recent_menu, &QMenu::aboutToShow, this, &MainWindow::updateRecentFileMenu); file_menu->addSeparator(); QMenu *load_opendbc_menu = file_menu->addMenu(tr("Load DBC from commaai/opendbc")); // load_opendbc_menu->setStyleSheet("QMenu { menu-scrollable: true; }"); - for (const auto &dbc_name : opendbc_names) { + for (const auto &dbc_name : QDir(OPENDBC_FILE_PATH).entryList({"*.dbc"}, QDir::Files, QDir::Name)) { load_opendbc_menu->addAction(dbc_name, [this, name = dbc_name]() { loadDBCFromOpendbc(name); }); } @@ -180,6 +171,7 @@ void MainWindow::createDockWidgets() { messages_widget = new MessagesWidget(this); messages_dock->setWidget(messages_widget); QObject::connect(messages_widget, &MessagesWidget::titleChanged, messages_dock, &QDockWidget::setWindowTitle); + QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, center_widget, &CenterWidget::setMessage); // right panel charts_widget = new ChartsWidget(this); @@ -209,67 +201,52 @@ void MainWindow::createStatusBar() { progress_bar->setVisible(false); statusBar()->addWidget(new QLabel(tr("For Help, Press F1"))); statusBar()->addPermanentWidget(progress_bar); - statusBar()->addPermanentWidget(status_label = new QLabel(this)); updateStatus(); } void MainWindow::createShortcuts() { auto shortcut = new QShortcut(QKeySequence(Qt::Key_Space), this, nullptr, nullptr, Qt::ApplicationShortcut); - QObject::connect(shortcut, &QShortcut::activated, []() { can->pause(!can->isPaused()); }); + QObject::connect(shortcut, &QShortcut::activated, this, []() { + if (can) can->pause(!can->isPaused()); + }); // TODO: add more shortcuts here. } -void MainWindow::undoStackIndexChanged(int index) { - int count = UndoStack::instance()->count(); - if (count >= 0) { - QString command_text; - if (index == count) { - command_text = (count == prev_undostack_count ? "Redo " : "") + UndoStack::instance()->text(index - 1); - } else if (index < prev_undostack_index) { - command_text = tr("Undo %1").arg(UndoStack::instance()->text(index)); - } else if (index > prev_undostack_index) { - command_text = tr("Redo %1").arg(UndoStack::instance()->text(index - 1)); - } - statusBar()->showMessage(command_text, 2000); - } - prev_undostack_index = index; - prev_undostack_count = count; - autoSave(); - updateLoadSaveMenus(); -} - void MainWindow::undoStackCleanChanged(bool clean) { - if (clean) { - prev_undostack_index = 0; - prev_undostack_count = 0; - } setWindowModified(!clean); } void MainWindow::DBCFileChanged() { UndoStack::instance()->clear(); - updateLoadSaveMenus(); + + // Update file menu + int cnt = dbc()->nonEmptyDBCCount(); + save_dbc->setText(cnt > 1 ? tr("Save %1 DBCs...").arg(cnt) : tr("Save DBC...")); + save_dbc->setEnabled(cnt > 0); + save_dbc_as->setEnabled(cnt == 1); + // TODO: Support clipboard for multiple files + copy_dbc_to_clipboard->setEnabled(cnt == 1); + manage_dbcs_menu->setEnabled(dynamic_cast(can) == nullptr); + + QStringList title; + for (auto f : dbc()->allDBCFiles()) { + title.push_back(tr("(%1) %2").arg(toString(dbc()->sources(f)), f->name())); + } + setWindowFilePath(title.join(" | ")); } -void MainWindow::openStream() { - AbstractStream *stream = nullptr; - StreamSelector dlg(&stream, this); +void MainWindow::selectAndOpenStream() { + StreamSelector dlg(this); if (dlg.exec()) { - if (!dlg.dbcFile().isEmpty()) { - loadFile(dlg.dbcFile()); - } - stream->start(); - statusBar()->showMessage(tr("Route %1 loaded").arg(can->routeName()), 2000); + openStream(dlg.stream(), dlg.dbcFile()); } else if (!can) { - stream = new DummyStream(this); - stream->start(); + openStream(new DummyStream(this)); } } void MainWindow::closeStream() { - AbstractStream *stream = new DummyStream(this); - stream->start(); + openStream(new DummyStream(this)); if (dbc()->nonEmptyDBCCount() > 0) { emit dbc()->DBCFileChanged(); } @@ -301,18 +278,8 @@ void MainWindow::loadFile(const QString &fn, SourceSet s) { if (!fn.isEmpty()) { closeFile(s); - QString dbc_fn = fn; - // Prompt user to load auto saved file if it exists. - if (QFile::exists(fn + AUTO_SAVE_EXTENSION)) { - auto ret = QMessageBox::question(this, tr("Auto saved DBC found"), tr("Auto saved DBC file from previous session found. Do you want to load it instead?")); - if (ret == QMessageBox::Yes) { - dbc_fn += AUTO_SAVE_EXTENSION; - UndoStack::instance()->resetClean(); // Force user to save on close so the auto saved file is not lost - } - } - QString error; - if (dbc()->open(s, dbc_fn, &error)) { + if (dbc()->open(s, fn, &error)) { updateRecentFiles(fn); statusBar()->showMessage(tr("DBC File %1 loaded").arg(fn), 2000); } else { @@ -323,15 +290,8 @@ void MainWindow::loadFile(const QString &fn, SourceSet s) { } } -void MainWindow::openRecentFile() { - if (auto action = qobject_cast(sender())) { - loadFile(action->data().toString()); - } -} - void MainWindow::loadDBCFromOpendbc(const QString &name) { - QString opendbc_file_path = QString("%1/%2.dbc").arg(OPENDBC_FILE_PATH, name); - loadFile(opendbc_file_path); + loadFile(QString("%1/%2").arg(OPENDBC_FILE_PATH, name)); } void MainWindow::loadFromClipboard(SourceSet s, bool close_all) { @@ -349,13 +309,19 @@ void MainWindow::loadFromClipboard(SourceSet s, bool close_all) { } } -void MainWindow::changingStream() { +void MainWindow::openStream(AbstractStream *stream, const QString &dbc_file) { center_widget->clear(); delete messages_widget; delete video_splitter; -} -void MainWindow::streamStarted() { + delete can; + can = stream; + can->setParent(this); // take ownership + can->start(); + + loadFile(dbc_file); + statusBar()->showMessage(tr("Stream [%1] started").arg(can->routeName()), 2000); + bool has_stream = dynamic_cast(can) == nullptr; close_stream_act->setEnabled(has_stream); export_to_csv_act->setEnabled(has_stream); @@ -372,9 +338,20 @@ void MainWindow::streamStarted() { newFile(); } - QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, center_widget, &CenterWidget::setMessage); QObject::connect(can, &AbstractStream::eventsMerged, this, &MainWindow::eventsMerged); - QObject::connect(can, &AbstractStream::sourcesUpdated, this, &MainWindow::updateLoadSaveMenus); + + if (has_stream) { + auto wait_dlg = new QProgressDialog( + can->liveStreaming() ? tr("Waiting for the live stream to start...") : tr("Loading segment data..."), + tr("&Abort"), 0, 100, this); + wait_dlg->setWindowModality(Qt::WindowModal); + wait_dlg->setFixedSize(400, wait_dlg->sizeHint().height()); + QObject::connect(wait_dlg, &QProgressDialog::canceled, this, &MainWindow::close); + QObject::connect(can, &AbstractStream::eventsMerged, wait_dlg, &QProgressDialog::deleteLater); + QObject::connect(this, &MainWindow::updateProgressBar, wait_dlg, [=](uint64_t cur, uint64_t total, bool success) { + wait_dlg->setValue((int)((cur / (double)total) * 100)); + }); + } } void MainWindow::eventsMerged() { @@ -383,12 +360,8 @@ void MainWindow::eventsMerged() { .arg(can->routeName()) .arg(car_fingerprint.isEmpty() ? tr("Unknown Car") : car_fingerprint)); // Don't overwrite already loaded DBC - if (!dbc()->nonEmptyDBCCount() && !car_fingerprint.isEmpty()) { - auto dbc_name = fingerprint_to_dbc[car_fingerprint]; - if (dbc_name != QJsonValue::Undefined) { - // Prevent dialog that load autosaved file from blocking replay->start(). - QTimer::singleShot(0, this, [dbc_name, this]() { loadDBCFromOpendbc(dbc_name.toString()); }); - } + if (!dbc()->nonEmptyDBCCount() && fingerprint_to_dbc.object().contains(car_fingerprint)) { + QTimer::singleShot(0, this, [this]() { loadDBCFromOpendbc(fingerprint_to_dbc[car_fingerprint].toString() + ".dbc"); }); } } } @@ -409,22 +382,6 @@ void MainWindow::saveAs() { } } -void MainWindow::autoSave() { - if (!UndoStack::instance()->isClean()) { - for (auto dbc_file : dbc()->allDBCFiles()) { - if (!dbc_file->filename.isEmpty()) { - dbc_file->autoSave(); - } - } - } -} - -void MainWindow::cleanupAutoSaveFile() { - for (auto dbc_file : dbc()->allDBCFiles()) { - dbc_file->cleanupAutoSaveFile(); - } -} - void MainWindow::closeFile(SourceSet s) { remindSaveChanges(); if (s == SOURCE_ALL) { @@ -448,7 +405,6 @@ void MainWindow::saveFile(DBCFile *dbc_file) { assert(dbc_file != nullptr); if (!dbc_file->filename.isEmpty()) { dbc_file->save(); - updateLoadSaveMenus(); UndoStack::instance()->setClean(); statusBar()->showMessage(tr("File saved"), 2000); } else if (!dbc_file->isEmpty()) { @@ -464,7 +420,6 @@ void MainWindow::saveFileAs(DBCFile *dbc_file) { UndoStack::instance()->setClean(); statusBar()->showMessage(tr("File saved as %1").arg(fn), 2000); updateRecentFiles(fn); - updateLoadSaveMenus(); } } @@ -483,16 +438,7 @@ void MainWindow::saveFileToClipboard(DBCFile *dbc_file) { } void MainWindow::updateLoadSaveMenus() { - int cnt = dbc()->nonEmptyDBCCount(); - save_dbc->setText(cnt > 1 ? tr("Save %1 DBCs...").arg(cnt) : tr("Save DBC...")); - save_dbc->setEnabled(cnt > 0); - save_dbc_as->setEnabled(cnt == 1); - - // TODO: Support clipboard for multiple files - copy_dbc_to_clipboard->setEnabled(cnt == 1); - manage_dbcs_menu->clear(); - manage_dbcs_menu->setEnabled(dynamic_cast(can) == nullptr); for (int source : can->sources) { if (source >= 64) continue; // Sent and blocked buses are handled implicitly @@ -505,8 +451,8 @@ void MainWindow::updateLoadSaveMenus() { bus_menu->addAction(tr("Load DBC From Clipboard..."), [=]() { loadFromClipboard(ss, false); }); // Show sub-menu for each dbc for this source. - QString file_name = "No DBCs loaded"; - if (auto dbc_file = dbc()->findDBCFile(source)) { + auto dbc_file = dbc()->findDBCFile(source); + if (dbc_file) { bus_menu->addSeparator(); bus_menu->addAction(dbc_file->name() + " (" + toString(dbc()->sources(dbc_file)) + ")")->setEnabled(false); bus_menu->addAction(tr("Save..."), [=]() { saveFile(dbc_file); }); @@ -514,19 +460,11 @@ void MainWindow::updateLoadSaveMenus() { bus_menu->addAction(tr("Copy to Clipboard..."), [=]() { saveFileToClipboard(dbc_file); }); bus_menu->addAction(tr("Remove from this bus..."), [=]() { closeFile(ss); }); bus_menu->addAction(tr("Remove from all buses..."), [=]() { closeFile(dbc_file); }); - - file_name = dbc_file->name(); } + bus_menu->setTitle(tr("Bus %1 (%2)").arg(source).arg(dbc_file ? dbc_file->name() : "No DBCs loaded")); manage_dbcs_menu->addMenu(bus_menu); - bus_menu->setTitle(tr("Bus %1 (%2)").arg(source).arg(file_name)); } - - QStringList title; - for (auto f : dbc()->allDBCFiles()) { - title.push_back(tr("(%1) %2").arg(toString(dbc()->sources(f)), f->name())); - } - setWindowFilePath(title.join(" | ")); } void MainWindow::updateRecentFiles(const QString &fn) { @@ -536,21 +474,21 @@ void MainWindow::updateRecentFiles(const QString &fn) { settings.recent_files.removeLast(); } settings.last_dir = QFileInfo(fn).absolutePath(); - updateRecentFileActions(); } -void MainWindow::updateRecentFileActions() { +void MainWindow::updateRecentFileMenu() { + open_recent_menu->clear(); + int num_recent_files = std::min(settings.recent_files.size(), MAX_RECENT_FILES); + if (!num_recent_files) { + open_recent_menu->addAction(tr("No Recent Files"))->setEnabled(false); + return; + } + for (int i = 0; i < num_recent_files; ++i) { QString text = tr("&%1 %2").arg(i + 1).arg(QFileInfo(settings.recent_files[i]).fileName()); - recent_files_acts[i]->setText(text); - recent_files_acts[i]->setData(settings.recent_files[i]); - recent_files_acts[i]->setVisible(true); + open_recent_menu->addAction(text, this, [this, i=i](){ loadFile(settings.recent_files[i]); }); } - for (int i = num_recent_files; i < MAX_RECENT_FILES; ++i) { - recent_files_acts[i]->setVisible(false); - } - open_recent_menu->setEnabled(num_recent_files > 0); } void MainWindow::remindSaveChanges() { @@ -606,7 +544,6 @@ void MainWindow::toggleChartsDocking() { } void MainWindow::closeEvent(QCloseEvent *event) { - cleanupAutoSaveFile(); remindSaveChanges(); installDownloadProgressHandler(nullptr); @@ -618,7 +555,7 @@ void MainWindow::closeEvent(QCloseEvent *event) { // save states settings.geometry = saveGeometry(); settings.window_state = saveState(); - if (!can->liveStreaming()) { + if (can && !can->liveStreaming()) { settings.video_splitter_state = video_splitter->saveState(); } settings.message_header_state = messages_widget->saveHeaderState(); diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 77add4d789..9bc94c090f 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -20,22 +20,20 @@ class MainWindow : public QMainWindow { Q_OBJECT public: - MainWindow(); + MainWindow(AbstractStream *stream, const QString &dbc_file); void toggleChartsDocking(); void showStatusMessage(const QString &msg, int timeout = 0) { statusBar()->showMessage(msg, timeout); } void loadFile(const QString &fn, SourceSet s = SOURCE_ALL); ChartsWidget *charts_widget = nullptr; public slots: - void openStream(); + void selectAndOpenStream(); + void openStream(AbstractStream *stream, const QString &dbc_file = {}); void closeStream(); void exportToCSV(); - void changingStream(); - void streamStarted(); void newFile(SourceSet s = SOURCE_ALL); void openFile(SourceSet s = SOURCE_ALL); - void openRecentFile(); void loadDBCFromOpendbc(const QString &name); void save(); void saveAs(); @@ -55,10 +53,8 @@ protected: void saveFileToClipboard(DBCFile *dbc_file); void loadFingerprints(); void loadFromClipboard(SourceSet s = SOURCE_ALL, bool close_all = true); - void autoSave(); - void cleanupAutoSaveFile(); void updateRecentFiles(const QString &fn); - void updateRecentFileActions(); + void updateRecentFileMenu(); void createActions(); void createDockWindows(); void createStatusBar(); @@ -70,7 +66,6 @@ protected: void findSimilarBits(); void findSignal(); void undoStackCleanChanged(bool clean); - void undoStackIndexChanged(int index); void onlineHelp(); void toggleFullScreen(); void updateStatus(); @@ -88,10 +83,8 @@ protected: QProgressBar *progress_bar; QLabel *status_label; QJsonDocument fingerprint_to_dbc; - QStringList opendbc_names; QSplitter *video_splitter = nullptr; enum { MAX_RECENT_FILES = 15 }; - QAction *recent_files_acts[MAX_RECENT_FILES] = {}; QMenu *open_recent_menu = nullptr; QMenu *manage_dbcs_menu = nullptr; QMenu *tools_menu = nullptr; @@ -101,8 +94,6 @@ protected: QAction *save_dbc_as = nullptr; QAction *copy_dbc_to_clipboard = nullptr; QString car_fingerprint; - int prev_undostack_index = 0; - int prev_undostack_count = 0; QByteArray default_state; }; diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 8288c801b5..130b76d502 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -494,6 +494,7 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), } void SignalView::setMessage(const MessageId &id) { + max_value_width = 0; filter_edit->clear(); model->setMessage(id); } @@ -617,7 +618,6 @@ void SignalView::updateState(const std::set *msgs) { const auto &last_msg = can->lastMessage(model->msg_id); if (model->rowCount() == 0 || (msgs && !msgs->count(model->msg_id)) || last_msg.dat.size() == 0) return; - int max_value_width = 0; for (auto item : model->root->children) { double value = 0; if (item->sig->getValue(last_msg.dat.data(), last_msg.dat.size(), &value)) { diff --git a/tools/cabana/signalview.h b/tools/cabana/signalview.h index 6320b9b621..4e746ea105 100644 --- a/tools/cabana/signalview.h +++ b/tools/cabana/signalview.h @@ -135,6 +135,7 @@ private: QTreeView::leaveEvent(event); } }; + int max_value_width = 0; int value_column_width = 0; TreeView *tree; QLabel *sparkline_label; diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index ee6a1143c8..9bf80deb98 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -10,11 +10,6 @@ static const int EVENT_NEXT_BUFFER_SIZE = 6 * 1024 * 1024; // 6MB AbstractStream *can = nullptr; -StreamNotifier *StreamNotifier::instance() { - static StreamNotifier notifier; - return ¬ifier; -} - AbstractStream::AbstractStream(QObject *parent) : QObject(parent) { assert(parent != nullptr); event_buffer_ = std::make_unique(EVENT_NEXT_BUFFER_SIZE); @@ -24,12 +19,6 @@ AbstractStream::AbstractStream(QObject *parent) : QObject(parent) { QObject::connect(this, &AbstractStream::seeking, this, [this](double sec) { current_sec_ = sec; }); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &AbstractStream::updateMasks); QObject::connect(dbc(), &DBCManager::maskUpdated, this, &AbstractStream::updateMasks); - QObject::connect(this, &AbstractStream::streamStarted, [this]() { - emit StreamNotifier::instance()->changingStream(); - delete can; - can = this; - emit StreamNotifier::instance()->streamStarted(); - }); } void AbstractStream::updateMasks() { diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 9e3f92dc5d..7ae119bcf0 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -96,7 +96,6 @@ signals: void seeking(double sec); void seekedTo(double sec); void timeRangeChanged(const std::optional> &range); - void streamStarted(); void eventsMerged(const MessageEventsMap &events_map); void msgsReceived(const std::set *new_msgs, bool has_new_ids); void sourcesUpdated(const SourceSet &s); @@ -133,15 +132,11 @@ private: class AbstractOpenStreamWidget : public QWidget { Q_OBJECT public: - AbstractOpenStreamWidget(AbstractStream **stream, QWidget *parent = nullptr) : stream(stream), QWidget(parent) {} - virtual bool open() = 0; - virtual QString title() = 0; + AbstractOpenStreamWidget(QWidget *parent = nullptr) : QWidget(parent) {} + virtual AbstractStream *open() = 0; signals: void enableOpenButton(bool); - -protected: - AbstractStream **stream = nullptr; }; class DummyStream : public AbstractStream { @@ -149,17 +144,7 @@ class DummyStream : public AbstractStream { public: DummyStream(QObject *parent) : AbstractStream(parent) {} QString routeName() const override { return tr("No Stream"); } - void start() override { emit streamStarted(); } -}; - -class StreamNotifier : public QObject { - Q_OBJECT -public: - StreamNotifier(QObject *parent = nullptr) : QObject(parent) {} - static StreamNotifier* instance(); -signals: - void streamStarted(); - void changingStream(); + void start() override {} }; // A global pointer referring to the unique AbstractStream object diff --git a/tools/cabana/streams/devicestream.cc b/tools/cabana/streams/devicestream.cc index 80507391a7..6de63dfbbc 100644 --- a/tools/cabana/streams/devicestream.cc +++ b/tools/cabana/streams/devicestream.cc @@ -33,13 +33,9 @@ void DeviceStream::streamThread() { } } -AbstractOpenStreamWidget *DeviceStream::widget(AbstractStream **stream) { - return new OpenDeviceWidget(stream); -} - // OpenDeviceWidget -OpenDeviceWidget::OpenDeviceWidget(AbstractStream **stream) : AbstractOpenStreamWidget(stream) { +OpenDeviceWidget::OpenDeviceWidget(QWidget *parent) : AbstractOpenStreamWidget(parent) { QRadioButton *msgq = new QRadioButton(tr("MSGQ")); QRadioButton *zmq = new QRadioButton(tr("ZMQ")); ip_address = new QLineEdit(this); @@ -62,9 +58,8 @@ OpenDeviceWidget::OpenDeviceWidget(AbstractStream **stream) : AbstractOpenStream zmq->setChecked(true); } -bool OpenDeviceWidget::open() { +AbstractStream *OpenDeviceWidget::open() { QString ip = ip_address->text().isEmpty() ? "127.0.0.1" : ip_address->text(); bool msgq = group->checkedId() == 0; - *stream = new DeviceStream(qApp, msgq ? "" : ip); - return true; + return new DeviceStream(qApp, msgq ? "" : ip); } diff --git a/tools/cabana/streams/devicestream.h b/tools/cabana/streams/devicestream.h index a65f073458..3bdf224998 100644 --- a/tools/cabana/streams/devicestream.h +++ b/tools/cabana/streams/devicestream.h @@ -6,7 +6,6 @@ class DeviceStream : public LiveStream { Q_OBJECT public: DeviceStream(QObject *parent, QString address = {}); - static AbstractOpenStreamWidget *widget(AbstractStream **stream); inline QString routeName() const override { return QString("Live Streaming From %1").arg(zmq_address.isEmpty() ? "127.0.0.1" : zmq_address); } @@ -20,9 +19,8 @@ class OpenDeviceWidget : public AbstractOpenStreamWidget { Q_OBJECT public: - OpenDeviceWidget(AbstractStream **stream); - bool open() override; - QString title() override { return tr("&Device"); } + OpenDeviceWidget(QWidget *parent = nullptr); + AbstractStream *open() override; private: QLineEdit *ip_address; diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc index 6bcb1c1d54..ac9a6fa105 100644 --- a/tools/cabana/streams/livestream.cc +++ b/tools/cabana/streams/livestream.cc @@ -53,7 +53,6 @@ void LiveStream::startUpdateTimer() { } void LiveStream::start() { - emit streamStarted(); stream_thread->start(); startUpdateTimer(); begin_date_time = QDateTime::currentDateTime(); diff --git a/tools/cabana/streams/pandastream.cc b/tools/cabana/streams/pandastream.cc index 030783a899..cdf6da6d83 100644 --- a/tools/cabana/streams/pandastream.cc +++ b/tools/cabana/streams/pandastream.cc @@ -77,13 +77,9 @@ void PandaStream::streamThread() { } } -AbstractOpenStreamWidget *PandaStream::widget(AbstractStream **stream) { - return new OpenPandaWidget(stream); -} - // OpenPandaWidget -OpenPandaWidget::OpenPandaWidget(AbstractStream **stream) : AbstractOpenStreamWidget(stream) { +OpenPandaWidget::OpenPandaWidget(QWidget *parent) : AbstractOpenStreamWidget(parent) { form_layout = new QFormLayout(this); if (can && dynamic_cast(can) != nullptr) { form_layout->addWidget(new QLabel(tr("Already connected to %1.").arg(can->routeName()))); @@ -182,12 +178,11 @@ void OpenPandaWidget::buildConfigForm() { } } -bool OpenPandaWidget::open() { +AbstractStream *OpenPandaWidget::open() { try { - *stream = new PandaStream(qApp, config); - return true; + return new PandaStream(qApp, config); } catch (std::exception &e) { QMessageBox::warning(nullptr, tr("Warning"), tr("Failed to connect to panda: '%1'").arg(e.what())); - return false; + return nullptr; } } diff --git a/tools/cabana/streams/pandastream.h b/tools/cabana/streams/pandastream.h index ad792ec292..826b1aa986 100644 --- a/tools/cabana/streams/pandastream.h +++ b/tools/cabana/streams/pandastream.h @@ -28,7 +28,6 @@ class PandaStream : public LiveStream { public: PandaStream(QObject *parent, PandaStreamConfig config_ = {}); ~PandaStream() { stop(); } - static AbstractOpenStreamWidget *widget(AbstractStream **stream); inline QString routeName() const override { return QString("Panda: %1").arg(config.serial); } @@ -45,9 +44,8 @@ class OpenPandaWidget : public AbstractOpenStreamWidget { Q_OBJECT public: - OpenPandaWidget(AbstractStream **stream); - bool open() override; - QString title() override { return tr("&Panda"); } + OpenPandaWidget(QWidget *parent = nullptr); + AbstractStream *open() override; private: void refreshSerials(); diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index 09ba3db417..1616f2aec3 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -83,11 +83,6 @@ bool ReplayStream::loadRoute(const QString &route, const QString &data_dir, uint return success; } -void ReplayStream::start() { - emit streamStarted(); - replay->start(); -} - bool ReplayStream::eventFilter(const Event *event) { static double prev_update_ts = 0; if (event->which == cereal::Event::Which::CAN) { @@ -115,13 +110,9 @@ void ReplayStream::pause(bool pause) { } -AbstractOpenStreamWidget *ReplayStream::widget(AbstractStream **stream) { - return new OpenReplayWidget(stream); -} - // OpenReplayWidget -OpenReplayWidget::OpenReplayWidget(AbstractStream **stream) : AbstractOpenStreamWidget(stream) { +OpenReplayWidget::OpenReplayWidget(QWidget *parent) : AbstractOpenStreamWidget(parent) { QGridLayout *grid_layout = new QGridLayout(this); grid_layout->addWidget(new QLabel(tr("Route")), 0, 0); grid_layout->addWidget(route_edit = new QLineEdit(this), 0, 1); @@ -154,7 +145,7 @@ OpenReplayWidget::OpenReplayWidget(AbstractStream **stream) : AbstractOpenStream }); } -bool OpenReplayWidget::open() { +AbstractStream *OpenReplayWidget::open() { QString route = route_edit->text(); QString data_dir; if (int idx = route.lastIndexOf('/'); idx != -1 && util::file_exists(route.toStdString())) { @@ -173,8 +164,8 @@ bool OpenReplayWidget::open() { if (flags == REPLAY_FLAG_NONE && !cameras[0]->isChecked()) flags = REPLAY_FLAG_NO_VIPC; if (replay_stream->loadRoute(route, data_dir, flags)) { - *stream = replay_stream.release(); + return replay_stream.release(); } } - return *stream != nullptr; + return nullptr; } diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index 217d1ac1d3..25d6ef4a72 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -15,7 +15,7 @@ class ReplayStream : public AbstractStream { public: ReplayStream(QObject *parent); - void start() override; + void start() override { replay->start(); } bool loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags = REPLAY_FLAG_NONE); bool eventFilter(const Event *event); void seekTo(double ts) override { replay->seekTo(std::max(double(0), ts), false); } @@ -31,7 +31,6 @@ public: inline Replay *getReplay() const { return replay.get(); } inline bool isPaused() const override { return replay->isPaused(); } void pause(bool pause) override; - static AbstractOpenStreamWidget *widget(AbstractStream **stream); private: void mergeSegments(); @@ -44,9 +43,8 @@ class OpenReplayWidget : public AbstractOpenStreamWidget { Q_OBJECT public: - OpenReplayWidget(AbstractStream **stream); - bool open() override; - QString title() override { return tr("&Replay"); } + OpenReplayWidget(QWidget *parent = nullptr); + AbstractStream *open() override; private: QLineEdit *route_edit; diff --git a/tools/cabana/streams/socketcanstream.cc b/tools/cabana/streams/socketcanstream.cc index 0f13b9901b..1346a496bb 100644 --- a/tools/cabana/streams/socketcanstream.cc +++ b/tools/cabana/streams/socketcanstream.cc @@ -66,11 +66,7 @@ void SocketCanStream::streamThread() { } } -AbstractOpenStreamWidget *SocketCanStream::widget(AbstractStream **stream) { - return new OpenSocketCanWidget(stream); -} - -OpenSocketCanWidget::OpenSocketCanWidget(AbstractStream **stream) : AbstractOpenStreamWidget(stream) { +OpenSocketCanWidget::OpenSocketCanWidget(QWidget *parent) : AbstractOpenStreamWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->addStretch(1); @@ -104,12 +100,11 @@ void OpenSocketCanWidget::refreshDevices() { } -bool OpenSocketCanWidget::open() { +AbstractStream *OpenSocketCanWidget::open() { try { - *stream = new SocketCanStream(qApp, config); + return new SocketCanStream(qApp, config); } catch (std::exception &e) { QMessageBox::warning(nullptr, tr("Warning"), tr("Failed to connect to SocketCAN device: '%1'").arg(e.what())); - return false; + return nullptr; } - return true; } diff --git a/tools/cabana/streams/socketcanstream.h b/tools/cabana/streams/socketcanstream.h index 952f1aaa5c..8083b687e9 100644 --- a/tools/cabana/streams/socketcanstream.h +++ b/tools/cabana/streams/socketcanstream.h @@ -18,7 +18,6 @@ class SocketCanStream : public LiveStream { public: SocketCanStream(QObject *parent, SocketCanStreamConfig config_ = {}); ~SocketCanStream() { stop(); } - static AbstractOpenStreamWidget *widget(AbstractStream **stream); static bool available(); inline QString routeName() const override { @@ -37,9 +36,8 @@ class OpenSocketCanWidget : public AbstractOpenStreamWidget { Q_OBJECT public: - OpenSocketCanWidget(AbstractStream **stream); - bool open() override; - QString title() override { return tr("&SocketCAN"); } + OpenSocketCanWidget(QWidget *parent = nullptr); + AbstractStream *open() override; private: void refreshDevices(); diff --git a/tools/cabana/streamselector.cc b/tools/cabana/streamselector.cc index 209b577c9a..efd00d3985 100644 --- a/tools/cabana/streamselector.cc +++ b/tools/cabana/streamselector.cc @@ -10,7 +10,7 @@ #include "tools/cabana/streams/replaystream.h" #include "tools/cabana/streams/socketcanstream.h" -StreamSelector::StreamSelector(AbstractStream **stream, QWidget *parent) : QDialog(parent) { +StreamSelector::StreamSelector(QWidget *parent) : QDialog(parent) { setWindowTitle(tr("Open stream")); QVBoxLayout *layout = new QVBoxLayout(this); tab = new QTabWidget(this); @@ -33,17 +33,17 @@ StreamSelector::StreamSelector(AbstractStream **stream, QWidget *parent) : QDial btn_box = new QDialogButtonBox(QDialogButtonBox::Open | QDialogButtonBox::Cancel); layout->addWidget(btn_box); - addStreamWidget(ReplayStream::widget(stream)); - addStreamWidget(PandaStream::widget(stream)); + addStreamWidget(new OpenReplayWidget, tr("&Replay")); + addStreamWidget(new OpenPandaWidget, tr("&Panda")); if (SocketCanStream::available()) { - addStreamWidget(SocketCanStream::widget(stream)); + addStreamWidget(new OpenSocketCanWidget, tr("&SocketCAN")); } - addStreamWidget(DeviceStream::widget(stream)); + addStreamWidget(new OpenDeviceWidget, tr("&Device")); QObject::connect(btn_box, &QDialogButtonBox::rejected, this, &QDialog::reject); QObject::connect(btn_box, &QDialogButtonBox::accepted, [=]() { setEnabled(false); - if (((AbstractOpenStreamWidget *)tab->currentWidget())->open()) { + if (stream_ = ((AbstractOpenStreamWidget *)tab->currentWidget())->open(); stream_) { accept(); } setEnabled(true); @@ -57,8 +57,8 @@ StreamSelector::StreamSelector(AbstractStream **stream, QWidget *parent) : QDial }); } -void StreamSelector::addStreamWidget(AbstractOpenStreamWidget *w) { - tab->addTab(w, w->title()); +void StreamSelector::addStreamWidget(AbstractOpenStreamWidget *w, const QString &title) { + tab->addTab(w, title); auto open_btn = btn_box->button(QDialogButtonBox::Open); QObject::connect(w, &AbstractOpenStreamWidget::enableOpenButton, open_btn, &QPushButton::setEnabled); } diff --git a/tools/cabana/streamselector.h b/tools/cabana/streamselector.h index a702fc76ad..0919195e4e 100644 --- a/tools/cabana/streamselector.h +++ b/tools/cabana/streamselector.h @@ -11,11 +11,13 @@ class StreamSelector : public QDialog { Q_OBJECT public: - StreamSelector(AbstractStream **stream, QWidget *parent = nullptr); - void addStreamWidget(AbstractOpenStreamWidget *w); + StreamSelector(QWidget *parent = nullptr); + void addStreamWidget(AbstractOpenStreamWidget *w, const QString &title); QString dbcFile() const { return dbc_file->text(); } + AbstractStream *stream() const { return stream_; } private: + AbstractStream *stream_ = nullptr; QLineEdit *dbc_file; QTabWidget *tab; QDialogButtonBox *btn_box; From e36ff90996ca55ae80530f9e6e436da58d0b7c89 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Wed, 10 Jul 2024 18:10:42 -0400 Subject: [PATCH 029/229] Improved PlotJuggler layout for lateral accel torque controller (#32949) * improved PlotJuggler layout for lat accel controller * help estimate steerActuatorDelay * update Actuator Performance, add Vehicle Dynamics * disable Y limits on actuator performance because sunny * apply delay estimation feedback from harald * gc extra custom series that PJ copied in * label wordsmithing --- .../plotjuggler/layouts/torque-controller.xml | 241 ++++++++++++++---- 1 file changed, 197 insertions(+), 44 deletions(-) diff --git a/tools/plotjuggler/layouts/torque-controller.xml b/tools/plotjuggler/layouts/torque-controller.xml index d6e4684d63..b4edfdcc18 100644 --- a/tools/plotjuggler/layouts/torque-controller.xml +++ b/tools/plotjuggler/layouts/torque-controller.xml @@ -1,45 +1,193 @@ - - + + - - - - + + + + - - + + - - - + + + - - + + - - - + + + - - - + + + - - + + - - - + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -57,24 +205,10 @@ - + - return value * 3.6 - /carState/vEgo - - - - return value * 2.23694 - /carState/vEgo - - - - return (value * v1 ^ 2) - (v2 * 9.81) - /controlsState/desiredCurvature - - /carState/vEgo - /liveParameters/roll - + return (0) + /carState/canValid @@ -85,6 +219,25 @@ /liveParameters/roll + + + return (value * v1 ^ 2) - (v2 * 9.81) + /controlsState/desiredCurvature + + /carState/vEgo + /liveParameters/roll + + + + + return value * 2.23694 + /carState/vEgo + + + + return value * 3.6 + /carState/vEgo + From b247c3caaa5b5d503a9c1aa3336a7a206765167c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 10 Jul 2024 17:25:39 -0700 Subject: [PATCH 030/229] torqued: check steer override to current time (#32963) * lat active/steer override: check up to now * lint * Update ref_commit --- selfdrive/locationd/torqued.py | 7 +++++-- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/selfdrive/locationd/torqued.py b/selfdrive/locationd/torqued.py index ba649b318d..e0784eb8e6 100755 --- a/selfdrive/locationd/torqued.py +++ b/selfdrive/locationd/torqued.py @@ -177,8 +177,11 @@ class TorqueEstimator(ParameterEstimator): if len(self.raw_points['steer_torque']) == self.hist_len: yaw_rate = msg.angularVelocityCalibrated.value[2] roll = msg.orientationNED.value[0] - lat_active = np.interp(np.arange(t - MIN_ENGAGE_BUFFER, t, DT_MDL), self.raw_points['carControl_t'], self.raw_points['lat_active']).astype(bool) - steer_override = np.interp(np.arange(t - MIN_ENGAGE_BUFFER, t, DT_MDL), self.raw_points['carState_t'], self.raw_points['steer_override']).astype(bool) + # check lat active up to now (without lag compensation) + lat_active = np.interp(np.arange(t - MIN_ENGAGE_BUFFER, t + self.lag, DT_MDL), + self.raw_points['carControl_t'], self.raw_points['lat_active']).astype(bool) + steer_override = np.interp(np.arange(t - MIN_ENGAGE_BUFFER, t + self.lag, DT_MDL), + self.raw_points['carState_t'], self.raw_points['steer_override']).astype(bool) vego = np.interp(t, self.raw_points['carState_t'], self.raw_points['vego']) steer = np.interp(t, self.raw_points['carOutput_t'], self.raw_points['steer_torque']).item() lateral_acc = (vego * yaw_rate) - (np.sin(roll) * ACCELERATION_DUE_TO_GRAVITY).item() diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 1635012f3e..13b427b894 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -f6ff3601bd0496e78d8bc3b019d58bb7739f096b \ No newline at end of file +0adff03d45c99dcfb330c48b2aa9d2093ce674a2 From 11db7b683b4ea0427c0060b48bd17ac5b61b11ff Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 11 Jul 2024 02:49:42 -0700 Subject: [PATCH 031/229] hardwared: don't ignore quick ignition cycles (#32938) * check on either edge * clean up * clean up * good thing I tested this first :P --- system/hardware/hardwared.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/hardware/hardwared.py b/system/hardware/hardwared.py index e3a4c81711..ff34d95828 100755 --- a/system/hardware/hardwared.py +++ b/system/hardware/hardwared.py @@ -230,8 +230,8 @@ def hardware_thread(end_event, hw_queue) -> None: onroad_conditions["ignition"] = False cloudlog.error("panda timed out onroad") - # Run at 2Hz, plus rising edge of ignition - ign_edge = started_ts is None and onroad_conditions["ignition"] + # Run at 2Hz, plus either edge of ignition + ign_edge = (started_ts is not None) != onroad_conditions["ignition"] if (sm.frame % round(SERVICE_LIST['pandaStates'].frequency * DT_HW) != 0) and not ign_edge: continue From c1cd33dbc1ab93f06f927f3533e9e415a5b84eb9 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Thu, 11 Jul 2024 15:46:24 +0000 Subject: [PATCH 032/229] MADS: Fix extra gear check --- selfdrive/car/interfaces.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index a402a7797a..5fe64832c8 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -460,8 +460,9 @@ class CarInterfaceBase(ABC): events.add(EventName.doorOpen) if cs_out.seatbeltUnlatched and cs_out.gearShifter != GearShifter.park: events.add(EventName.seatbeltNotLatched) - if cs_out.gearShifter != GearShifter.drive and cs_out.gearShifter not in extra_gears and not \ - (cs_out.gearShifter == GearShifter.unknown and self.gear_warning < int(0.5/DT_CTRL)): + if cs_out.gearShifter != GearShifter.drive and (extra_gears is None or + cs_out.gearShifter not in extra_gears) and not (cs_out.gearShifter == GearShifter.unknown and + self.gear_warning < int(0.5/DT_CTRL)): if cs_out.vEgo < 5: events.add(EventName.silentWrongGear) else: From 71dd1e2ff6768c649d3d885d30280d9ca46841a4 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 11 Jul 2024 14:06:51 -0700 Subject: [PATCH 033/229] long planner: formatting --- .../controls/lib/longitudinal_planner.py | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index c59955d551..6a2a1570d8 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -45,22 +45,21 @@ def limit_accel_in_turns(v_ego, angle_steers, a_target, CP): def get_accel_from_plan(CP, speeds, accels): - if len(speeds) == CONTROL_N: - v_target_now = interp(DT_MDL, CONTROL_N_T_IDX, speeds) - a_target_now = interp(DT_MDL, CONTROL_N_T_IDX, accels) + if len(speeds) == CONTROL_N: + v_target_now = interp(DT_MDL, CONTROL_N_T_IDX, speeds) + a_target_now = interp(DT_MDL, CONTROL_N_T_IDX, accels) - v_target = interp(CP.longitudinalActuatorDelay + DT_MDL, CONTROL_N_T_IDX, speeds) - a_target = 2 * (v_target - v_target_now) / CP.longitudinalActuatorDelay - a_target_now + v_target = interp(CP.longitudinalActuatorDelay + DT_MDL, CONTROL_N_T_IDX, speeds) + a_target = 2 * (v_target - v_target_now) / CP.longitudinalActuatorDelay - a_target_now - v_target_1sec = interp(CP.longitudinalActuatorDelay + DT_MDL + 1.0, CONTROL_N_T_IDX, speeds) - else: - v_target = 0.0 - v_target_now = 0.0 - v_target_1sec = 0.0 - a_target = 0.0 - should_stop = (v_target < CP.vEgoStopping and - v_target_1sec < CP.vEgoStopping) - return a_target, should_stop + v_target_1sec = interp(CP.longitudinalActuatorDelay + DT_MDL + 1.0, CONTROL_N_T_IDX, speeds) + else: + v_target = 0.0 + v_target_1sec = 0.0 + a_target = 0.0 + should_stop = (v_target < CP.vEgoStopping and + v_target_1sec < CP.vEgoStopping) + return a_target, should_stop class LongitudinalPlanner: @@ -82,8 +81,8 @@ class LongitudinalPlanner: @staticmethod def parse_model(model_msg, model_error): if (len(model_msg.position.x) == ModelConstants.IDX_N and - len(model_msg.velocity.x) == ModelConstants.IDX_N and - len(model_msg.acceleration.x) == ModelConstants.IDX_N): + len(model_msg.velocity.x) == ModelConstants.IDX_N and + len(model_msg.acceleration.x) == ModelConstants.IDX_N): x = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.position.x) - model_error * T_IDXS_MPC v = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.velocity.x) - model_error a = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.acceleration.x) From 1a8170e8393e03d7991422d978e925574612c7a4 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Thu, 11 Jul 2024 23:51:17 -0400 Subject: [PATCH 034/229] Speed Limit Control: Gate behind longitudinal --- selfdrive/controls/lib/sunnypilot/speed_limit_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/sunnypilot/speed_limit_controller.py b/selfdrive/controls/lib/sunnypilot/speed_limit_controller.py index d3e966bfb1..27b3de88e9 100644 --- a/selfdrive/controls/lib/sunnypilot/speed_limit_controller.py +++ b/selfdrive/controls/lib/sunnypilot/speed_limit_controller.py @@ -295,7 +295,7 @@ class SpeedLimitController: def update(self, enabled, v_ego, a_ego, sm, v_cruise_setpoint, events=Events()): _car_state = sm['carState'] - self._op_enabled = sm['controlsState'].enabled and _car_state.cruiseState.enabled and \ + self._op_enabled = enabled and sm['controlsState'].enabled and _car_state.cruiseState.enabled and \ not (_car_state.brakePressed and (not self._brake_pressed_prev or not _car_state.standstill)) and \ not (events.contains(ET.OVERRIDE_LONGITUDINAL) and self._disengage_on_accelerator) self._v_ego = v_ego From e3e54fb28bad2e4848d9f3a510be8a45d9bd6ffa Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 13 Jul 2024 01:38:07 +0800 Subject: [PATCH 035/229] cabana: fix wrong file path handling for recent files menu (#32969) fix lambda --- tools/cabana/mainwin.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 34432707db..ee8f42ea72 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -487,7 +487,7 @@ void MainWindow::updateRecentFileMenu() { for (int i = 0; i < num_recent_files; ++i) { QString text = tr("&%1 %2").arg(i + 1).arg(QFileInfo(settings.recent_files[i]).fileName()); - open_recent_menu->addAction(text, this, [this, i=i](){ loadFile(settings.recent_files[i]); }); + open_recent_menu->addAction(text, this, [this, file = settings.recent_files[i]]() { loadFile(file); }); } } From 2156870df991bf6231121460810b0edcde74137b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 13 Jul 2024 07:20:49 +0800 Subject: [PATCH 036/229] pandad: remove return statement in constructor (#32975) remove return --- selfdrive/pandad/panda.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/selfdrive/pandad/panda.cc b/selfdrive/pandad/panda.cc index a404ad3880..fcb4ac67a4 100644 --- a/selfdrive/pandad/panda.cc +++ b/selfdrive/pandad/panda.cc @@ -26,8 +26,6 @@ Panda::Panda(std::string serial, uint32_t bus_offset) : bus_offset(bus_offset) { hw_type = get_hw_type(); can_reset_communications(); - - return; } bool Panda::connected() { From 122a7f2f0f6b0db435118e7f3e997c1528c8d8aa Mon Sep 17 00:00:00 2001 From: Andrei Radulescu Date: Sat, 13 Jul 2024 02:32:04 +0300 Subject: [PATCH 037/229] start for `curl openpilot.comma.ai | bash` (#32967) * initial setup.sh for curl|bash * --single-branch for faster pull and some final instructions * fix git lfs pull --- tools/setup.sh | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100755 tools/setup.sh diff --git a/tools/setup.sh b/tools/setup.sh new file mode 100755 index 0000000000..22d10be80b --- /dev/null +++ b/tools/setup.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +set -e + +if [ ! -f launch_openpilot.sh ]; then + if [ ! -d openpilot ]; then + git clone --single-branch --recurse-submodules https://github.com/commaai/openpilot.git + fi + cd openpilot +fi + +if [[ "$OSTYPE" == "darwin"* ]]; then + tools/mac_setup.sh +else + tools/ubuntu_setup.sh +fi + +git lfs pull + +source .venv/bin/activate + +echo "Building openpilot" +scons -u -j$(nproc) + +echo +echo "---- OPENPILOT BUILDING DONE ----" +echo "To push changes to your fork, run the following commands:" +echo "git remote remove origin" +echo "git remote add origin git@github.com:/openpilot.git" +echo "git fetch" +echo "git commit -m \"first commit\"" +echo "git push" From f1416f337cbf40c11de88903e13177f9f54dc544 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 13 Jul 2024 07:42:10 +0800 Subject: [PATCH 038/229] replay: update README (#32966) update README --- tools/replay/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/replay/README.md b/tools/replay/README.md index 91e89176a2..bf7280ae80 100644 --- a/tools/replay/README.md +++ b/tools/replay/README.md @@ -34,10 +34,21 @@ Options: -h, --help Displays this help. -a, --allow whitelist of services to send -b, --block blacklist of services to send + -c, --cache cache segments in memory. default is 5 -s, --start start from + -x playback . between 0.2 - 3 --demo use a demo route instead of providing your own + --data_dir local directory with routes + --prefix set OPENPILOT_PREFIX --dcam load driver camera --ecam load wide road camera + --no-loop stop at the end of the route + --no-cache turn off local cache + --qcam load qcamera + --no-hw-decoder disable HW video decoding + --no-vipc do not output video + --all do output all messages including uiDebug, userFlag. + this may causes issues when used along with UI Arguments: route the drive to replay. find your drives at From 32a5cfd84c804b671c54688120265b436610d7a9 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 13 Jul 2024 07:42:45 +0800 Subject: [PATCH 039/229] cabana: update README (#32965) improve README --- tools/cabana/README.md | 70 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/tools/cabana/README.md b/tools/cabana/README.md index 53723ef8a6..dbbdd8020c 100644 --- a/tools/cabana/README.md +++ b/tools/cabana/README.md @@ -29,4 +29,72 @@ Arguments: connect.comma.ai ``` -See [openpilot wiki](https://github.com/commaai/openpilot/wiki/Cabana) +## Examples + +### Running Cabana in Demo Mode +To run Cabana using a built-in demo route, use the following command: + +```shell +cabana --demo +``` + +### Loading a Specific Route + +To load a specific route for replay, provide the route as an argument: + +```shell +cabana "a2a0ccea32023010|2023-07-27--13-01-19" +``` + +Replace "0ccea32023010|2023-07-27--13-01-19" with your desired route identifier. + + +### Running Cabana with multiple cameras +To run Cabana with multiple cameras, use the following command: + +```shell +cabana "a2a0ccea32023010|2023-07-27--13-01-19" --dcam --ecam +``` + +### Streaming CAN Messages from a comma Device + +[SSH into your device](https://github.com/commaai/openpilot/wiki/SSH) and start the bridge with the following command: + +```shell +cd /data/openpilot/cereal/messaging/ +./bridge & +``` + +Then Run Cabana with the device's IP address: + +```shell +cabana --stream +``` + +Replace <ipaddress> with your comma device's IP address. + +While streaming from the device, Cabana will log the CAN messages to a local directory. By default, this directory is ~/cabana_live_stream/. You can change the log directory in Cabana by navigating to menu -> tools -> settings. + +After disconnecting from the device, you can replay the logged CAN messages from the stream selector dialog -> browse local route. + +### Streaming CAN Messages from Panda + +To read CAN messages from a connected Panda, use the following command: + +```shell +cabana --panda +``` + +### Using the Stream Selector Dialog + +If you run Cabana without any arguments, a stream selector dialog will pop up, allowing you to choose the stream. + +```shell +cabana +``` + +## Additional Information + +For more information, see the [openpilot wiki](https://github.com/commaai/openpilot/wiki/Cabana) + +If you encounter any issues or have feature requests, please contribute bug reports or discussions at: [new cabana feedback](https://github.com/commaai/openpilot/discussions/26091) \ No newline at end of file From 0f34e6e3b6e3627416129c34e4b9ff463d87c2ac Mon Sep 17 00:00:00 2001 From: eFini Date: Sat, 13 Jul 2024 07:44:22 +0800 Subject: [PATCH 040/229] PC: added missing hexdump package for selfdrive/debug/dump.py (#32959) added missing hexdump package --- pyproject.toml | 1 + uv.lock | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 0f5d9aa1cc..82f9c563bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -115,6 +115,7 @@ dev = [ "tabulate", "types-requests", "types-tabulate", + "hexdump", # this is only pinned since 5.15.11 is broken "pyqt5 ==5.15.2; platform_machine == 'x86_64'", # no aarch64 wheels for macOS/linux diff --git a/uv.lock b/uv.lock index 2797eee62f..57f8d9d7ee 100644 --- a/uv.lock +++ b/uv.lock @@ -766,6 +766,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a8/4d/3cbfd81ed84db450dbe73a89afcd8bc405273918415649ac6683356afe92/gymnasium-0.29.1-py3-none-any.whl", hash = "sha256:61c3384b5575985bb7f85e43213bcb40f36fcdff388cae6bc229304c71f2843e", size = 953939 }, ] +[[distribution]] +name = "hexdump" +version = "3.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/55/b3/279b1d57fa3681725d0db8820405cdcb4e62a9239c205e4ceac4391c78e4/hexdump-3.3.zip", hash = "sha256:d781a43b0c16ace3f9366aade73e8ad3a7bd5137d58f0b45ab2d3f54876f20db", size = 12658 } + [[distribution]] name = "humanfriendly" version = "10.0" @@ -1537,6 +1543,7 @@ dev = [ { name = "control" }, { name = "dictdiffer" }, { name = "flaky" }, + { name = "hexdump" }, { name = "inputs" }, { name = "lru-dict" }, { name = "matplotlib" }, From 50f55684a2a6b04bb744e7af1b8efbd26ac114be Mon Sep 17 00:00:00 2001 From: Andrei Radulescu Date: Sat, 13 Jul 2024 02:44:52 +0300 Subject: [PATCH 041/229] Rewrite git history update (#32955) Rewrite git history final touches --- scripts/git_rewrite/rewrite-git-history.sh | 119 +++++++++++++-------- 1 file changed, 76 insertions(+), 43 deletions(-) diff --git a/scripts/git_rewrite/rewrite-git-history.sh b/scripts/git_rewrite/rewrite-git-history.sh index 4130b55db9..5a97e6bbad 100755 --- a/scripts/git_rewrite/rewrite-git-history.sh +++ b/scripts/git_rewrite/rewrite-git-history.sh @@ -1,15 +1,40 @@ -#!/bin/bash -set -e - -DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" -cd $DIR +#!/bin/bash -e SRC=/tmp/openpilot/ SRC_CLONE=/tmp/openpilot-clone/ OUT=/tmp/openpilot-tiny/ -LOG_FILE=$DIR/git-rewrite-log-$(date +"%Y-%m-%dT%H:%M:%S%z").txt -exec > >(tee -a "$LOG_FILE") 2>&1 +REWRITE_IGNORE_BRANCHES=( + dashcam3 + devel + master-ci + nightly + release2 + release3 + release3-staging +) + +VALIDATE_IGNORE_FILES=( + ".github/ISSUE_TEMPLATE/bug_report.md" + ".github/pull_request_template.md" +) + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" +cd $DIR + +LOGS_DIR=$DIR/git-rewrite-$(date +"%Y-%m-%dT%H:%M:%S%z") +mkdir -p $LOGS_DIR + +GIT_REWRITE_LOG=$LOGS_DIR/git-rewrite-log.txt +BRANCH_DIFF_LOG=$LOGS_DIR/branch-diff-log.txt +COMMIT_DIFF_LOG=$LOGS_DIR/commit-diff-log.txt + +START_TIME=$(date +%s) +exec > >(while IFS= read -r line; do + CURRENT_TIME=$(date +%s) + ELAPSED_TIME=$((CURRENT_TIME - START_TIME)) + echo "[${ELAPSED_TIME}s] $line" +done | tee -a "$GIT_REWRITE_LOG") 2>&1 # INSTALL git-filter-repo if [ ! -f /tmp/git-filter-repo ]; then @@ -40,7 +65,7 @@ if [ ! -d $SRC ]; then git push --prune $ARCHIVE_REPO +refs/heads/*:refs/heads/* # 956.39 MiB (110725 objects) git push --prune $ARCHIVE_REPO +refs/tags/*:refs/tags/* # 1.75 GiB (21694 objects) # git push --mirror $ARCHIVE_REPO || true # fails to push refs/pull/* (deny updating a hidden ref) for pull requests - # we fail and continue - more reading: https://stackoverflow.com/a/34266401/639708 + # we fail and continue - more reading: https://stackoverflow.com/a/34266401/639708 and https://blog.plataformatec.com.br/2013/05/how-to-properly-mirror-a-git-repository/ fi # REWRITE master and tags @@ -52,7 +77,7 @@ if [ ! -d $SRC_CLONE ]; then echo "Checking out old history..." - git checkout tags/v0.7.1 + git checkout tags/v0.7.1 > /dev/null 2>&1 # checkout as main, since we need master ref later git checkout -b main @@ -60,22 +85,26 @@ if [ ! -d $SRC_CLONE ]; then # rm these so we don't get conflicts later git rm -r cereal opendbc panda selfdrive/ui/ui > /dev/null - git commit -m "removed conflicting files" + git commit -m "removed conflicting files" > /dev/null # skip-smudge to get rid of some lfs errors that it can't find the reference of some lfs files # we don't care about fetching/pushing lfs right now git lfs install --skip-smudge --local # squash initial setup commits - git cherry-pick -n -X theirs 6c33a5c..59b3d06 - git commit -m "switching to master" -m "$(git log --reverse --format=%B 6c33a5c..59b3d06)" + git cherry-pick -n -X theirs 6c33a5c..59b3d06 > /dev/null + git commit -m "switching to master" > /dev/null + + # squash the two commits + git reset --soft HEAD~2 + git commit -m "switching to master" -m "$(git log --reverse --format=%B 6c33a5c..59b3d06)" -m "removed conflicting files" > /dev/null # get commits we want to cherry-pick # will start with the next commit after #59b3d06 tools is local now COMMITS=$(git rev-list --reverse 59b3d06..master) # we need this for logging - TOTAL_COMMITS=$(echo $COMMITS | wc -w) + TOTAL_COMMITS=$(echo $COMMITS | wc -w | xargs) CURRENT_COMMIT_NUMBER=0 # empty this file @@ -85,7 +114,8 @@ if [ ! -d $SRC_CLONE ]; then for COMMIT in $COMMITS; do CURRENT_COMMIT_NUMBER=$((CURRENT_COMMIT_NUMBER + 1)) - echo -ne "[$CURRENT_COMMIT_NUMBER/$TOTAL_COMMITS] Cherry-picking commit: $COMMIT"\\r + # echo -ne "[$CURRENT_COMMIT_NUMBER/$TOTAL_COMMITS] Cherry-picking commit: $COMMIT"\\r + echo "[$CURRENT_COMMIT_NUMBER/$TOTAL_COMMITS] Cherry-picking commit: $COMMIT" # set environment variables to preserve author/committer and dates export GIT_AUTHOR_NAME=$(git show -s --format='%an' $COMMIT) @@ -119,6 +149,12 @@ if [ ! -d $SRC_CLONE ]; then # append the old commit ID to the commit message git commit --amend -m "$(git log -1 --pretty=%B)" -m "Former-commit-id: $COMMIT" > /dev/null fi + + # prune every 3000 commits to avoid gc errors + if [ $((CURRENT_COMMIT_NUMBER % 3000)) -eq 0 ]; then + echo "Pruning repo..." + git gc + fi done echo "Rewriting tags..." @@ -137,7 +173,7 @@ if [ ! -d $SRC_CLONE ]; then NEW_COMMIT=$OLD_COMMIT fi - printf "Rewriting tag %s from commit %s\n" "$TAG" "$NEW_COMMIT" + echo "Rewriting tag $TAG from commit $NEW_COMMIT" git tag -f "$TAG" "$NEW_COMMIT" done < "$DIR/tag-commit-map.txt" @@ -153,19 +189,20 @@ if [ ! -d $SRC_CLONE ]; then fi # REWRITE branches based on master -if [ ! -f "$SRC_CLONE/branch-diff.txt" ]; then +if [ ! -f "$SRC_CLONE/rewrite-branches-done" ]; then cd $SRC_CLONE + > rewrite-branches-done # empty file - > branch-diff.txt + > $BRANCH_DIFF_LOG echo "Rewriting branches based on master..." # will store raw diffs here, if exist mkdir -p differences - # get a list of all branches except master - BRANCHES=$(git branch -r | grep -v ' -> ' | sed 's/origin\///' | grep -v '^master$') + # get a list of all branches except master and REWRITE_IGNORE_BRANCHES + BRANCHES=$(git branch -r | grep -v ' -> ' | sed 's/.*origin\///' | grep -v '^master$' | grep -v -f <(echo "${REWRITE_IGNORE_BRANCHES[*]}" | tr ' ' '\n')) for BRANCH in $BRANCHES; do # check if the branch is based on master history @@ -176,7 +213,7 @@ if [ ! -f "$SRC_CLONE/branch-diff.txt" ]; then # create a new branch based on the new master NEW_MERGE_BASE=$(grep "^$MERGE_BASE " "commit-map.txt" | awk '{print $2}') if [ -z "$NEW_MERGE_BASE" ]; then - echo "Error: could not find new merge base for branch $BRANCH" >> branch-diff.txt + echo "Error: could not find new merge base for branch $BRANCH" >> $BRANCH_DIFF_LOG continue fi git checkout -b ${BRANCH}_new $NEW_MERGE_BASE @@ -208,8 +245,8 @@ if [ ! -f "$SRC_CLONE/branch-diff.txt" ]; then echo "$COMMIT EMPTY" >> commit-map.txt else # handle other errors or conflicts - echo "Cherry-pick of ${BRANCH} branch failed. Removing branch upstream..." >> branch-diff.txt - echo "$GIT_OUTPUT" > "differences/branch-${BRANCH}" + echo "Cherry-pick of ${BRANCH} branch failed. Removing branch upstream..." >> $BRANCH_DIFF_LOG + echo "$GIT_OUTPUT" > "$LOGS_DIR/branch-${BRANCH}" git cherry-pick --abort git push --delete origin ${BRANCH} HAS_ERROR=1 @@ -239,28 +276,24 @@ if [ ! -f "$SRC_CLONE/branch-diff.txt" ]; then git checkout master > /dev/null git branch -D ${BRANCH}_new > /dev/null else - # echo "Skipping branch $BRANCH as it's not based on master history" >> branch-diff.txt - echo "Deleting branch $BRANCH as it's not based on master history" >> branch-diff.txt - git push --delete origin ${BRANCH} + echo "Deleting branch $BRANCH as it's not based on master history" >> $BRANCH_DIFF_LOG + git push --delete origin ${BRANCH} fi done fi # VALIDATE cherry-pick -if [ ! -f "$SRC_CLONE/commit-diff.txt" ]; then +if [ ! -f "$SRC_CLONE/validation-done" ]; then cd $SRC_CLONE + > validation-done TOTAL_COMMITS=$(grep -cve '^\s*$' commit-map.txt) CURRENT_COMMIT_NUMBER=0 COUNT_SAME=0 COUNT_DIFF=0 - VALIDATE_IGNORE_FILES=( - ".github/ISSUE_TEMPLATE/bug_report.md" - ".github/pull_request_template.md" - ) # empty file - > commit-diff.txt + > $COMMIT_DIFF_LOG echo "Validating commits..." @@ -273,7 +306,7 @@ if [ ! -f "$SRC_CLONE/commit-diff.txt" ]; then continue fi if [ "$OLD_COMMIT" == "BRANCH" ]; then - echo "Branch ${NEW_COMMIT} below:" >> commit-diff.txt + echo "Branch ${NEW_COMMIT} below:" >> $COMMIT_DIFF_LOG continue fi CURRENT_COMMIT_NUMBER=$((CURRENT_COMMIT_NUMBER + 1)) @@ -283,7 +316,8 @@ if [ ! -f "$SRC_CLONE/commit-diff.txt" ]; then OLD_DATE=$(git show -s --format='%cd' $OLD_COMMIT) NEW_DATE=$(git show -s --format='%cd' $NEW_COMMIT) - echo -ne "[$CURRENT_COMMIT_NUMBER/$TOTAL_COMMITS] Comparing old commit $OLD_COMMIT_SHORT ($OLD_DATE) with new commit $NEW_COMMIT_SHORT ($NEW_DATE)"\\r + # echo -ne "[$CURRENT_COMMIT_NUMBER/$TOTAL_COMMITS] Comparing old commit $OLD_COMMIT_SHORT ($OLD_DATE) with new commit $NEW_COMMIT_SHORT ($NEW_DATE)"\\r + echo "[$CURRENT_COMMIT_NUMBER/$TOTAL_COMMITS] Comparing old commit $OLD_COMMIT_SHORT ($OLD_DATE) with new commit $NEW_COMMIT_SHORT ($NEW_DATE)" # generate lists of files and their hashes for the old and new commits, excluding ignored files OLD_FILES=$(git ls-tree -r $OLD_COMMIT | grep -vE "$(IFS='|'; echo "${VALIDATE_IGNORE_FILES[*]}")") @@ -294,17 +328,17 @@ if [ ! -f "$SRC_CLONE/commit-diff.txt" ]; then # echo "Old commit $OLD_COMMIT_SHORT and new commit $NEW_COMMIT_SHORT are equivalent." COUNT_SAME=$((COUNT_SAME + 1)) else - echo "[$CURRENT_COMMIT_NUMBER/$TOTAL_COMMITS] Difference found between old commit $OLD_COMMIT_SHORT and new commit $NEW_COMMIT_SHORT" >> commit-diff.txt + echo "[$CURRENT_COMMIT_NUMBER/$TOTAL_COMMITS] Difference found between old commit $OLD_COMMIT_SHORT and new commit $NEW_COMMIT_SHORT" >> $COMMIT_DIFF_LOG COUNT_DIFF=$((COUNT_DIFF + 1)) set +e - diff -u <(echo "$OLD_FILES") <(echo "$NEW_FILES") > "differences/$CURRENT_COMMIT_NUMBER-$OLD_COMMIT_SHORT-$NEW_COMMIT_SHORT" + diff -u <(echo "$OLD_FILES") <(echo "$NEW_FILES") > "$LOGS_DIR/commit-$CURRENT_COMMIT_NUMBER-$OLD_COMMIT_SHORT-$NEW_COMMIT_SHORT" set -e fi done < "commit-map.txt" - echo "Summary:" >> commit-diff.txt - echo "Equivalent commits: $COUNT_SAME" >> commit-diff.txt - echo "Different commits: $COUNT_DIFF" >> commit-diff.txt + echo "Summary:" >> $COMMIT_DIFF_LOG + echo "Equivalent commits: $COUNT_SAME" >> $COMMIT_DIFF_LOG + echo "Different commits: $COUNT_DIFF" >> $COMMIT_DIFF_LOG fi if [ ! -d $OUT ]; then @@ -313,7 +347,6 @@ if [ ! -d $OUT ]; then cd $OUT # remove all non-master branches - # TODO: need to see if we "redo" the other branches (except master, master-ci, devel, devel-staging, release3, release3-staging, dashcam3, dashcam3-staging, testing-closet*, hotfix-*) # git branch | grep -v "^ master$" | grep -v "\*" | xargs git branch -D # echo "cleaning up refs" @@ -322,7 +355,8 @@ if [ ! -d $OUT ]; then echo "importing new lfs files" # import "almost" everything to lfs - git lfs migrate import --everything --include="*.dlc,*.onnx,*.svg,*.png,*.gif,*.ttf,*.wav,selfdrive/car/tests/test_models_segs.txt,system/hardware/tici/updater,selfdrive/ui/qt/spinner_larch64,selfdrive/ui/qt/text_larch64,third_party/**/*.a,third_party/**/*.so,third_party/**/*.so.*,third_party/**/*.dylib,third_party/acados/*/t_renderer,third_party/qt5/larch64/bin/lrelease,third_party/qt5/larch64/bin/lupdate,third_party/catch2/include/catch2/catch.hpp,*.apk,*.apkpatch,*.jar,*.pdf,*.jpg,*.mp3,*.thneed,*.tar.gz,*.npy,*.csv,*.a,*.so*,*.dylib,*.o,*.b64,selfdrive/hardware/tici/updater,selfdrive/boardd/tests/test_boardd,selfdrive/ui/qt/spinner_aarch64,installer/updater/updater,selfdrive/debug/profiling/simpleperf/**/*,selfdrive/hardware/eon/updater,selfdrive/ui/qt/text_aarch64,selfdrive/debug/profiling/pyflame/**/*,installer/installers/installer_openpilot,installer/installers/installer_dashcam,selfdrive/ui/text/text,selfdrive/ui/android/text/text,selfdrive/ui/spinner/spinner,selfdrive/visiond/visiond,selfdrive/loggerd/loggerd,selfdrive/sensord/sensord,selfdrive/sensord/gpsd,selfdrive/ui/android/spinner/spinner,selfdrive/ui/qt/spinner,selfdrive/ui/qt/text,_stringdefs.py,dfu-util-aarch64-linux,dfu-util-aarch64,dfu-util-x86_64-linux,dfu-util-x86_64,stb_image.h,clpeak3,clwaste,apk/**/*,external/**/*,phonelibs/**/*,third_party/boringssl/**/*,flask/**/*,panda/**/*,board/**/*,messaging/**/*,opendbc/**/*,tools/cabana/chartswidget.cc,third_party/nanovg/**/*,selfdrive/controls/lib/lateral_mpc/lib_mpc_export/**/*,selfdrive/ui/paint.cc,werkzeug/**/*,pyextra/**/*,third_party/android_hardware_libhardware/**/*,selfdrive/controls/lib/lead_mpc_lib/lib_mpc_export/**/*,selfdrive/locationd/laikad.py,selfdrive/locationd/test/test_laikad.py,tools/gpstest/test_laikad.py,selfdrive/locationd/laikad_helpers.py,tools/nui/**/*,jsonrpc/**/*,selfdrive/controls/lib/longitudinal_mpc/lib_mpc_export/**/*,selfdrive/controls/lib/lateral_mpc/mpc_export/**/*,selfdrive/camerad/cameras/camera_qcom.cc,selfdrive/manager.py,selfdrive/modeld/models/driving.cc,third_party/curl/**/*,selfdrive/modeld/thneed/debug/**/*,selfdrive/modeld/thneed/include/**/*,third_party/openmax/**/*,selfdrive/controls/lib/longitudinal_mpc/mpc_export/**/*,selfdrive/controls/lib/longitudinal_mpc_model/lib_mpc_export/**/*,Pipfile,Pipfile.lock,gunicorn/**/*,*.qm,jinja2/**/*,click/**/*,dbcs/**/*,websocket/**/*" + BRANCHES=$(git for-each-ref --format='%(refname)' refs/heads/ | sed 's%refs/heads/%%g' | grep -v -f <(echo "${REWRITE_IGNORE_BRANCHES[*]}" | tr ' ' '\n') | tr '\n' ' ') + git lfs migrate import --include="*.dlc,*.onnx,*.svg,*.png,*.gif,*.ttf,*.wav,selfdrive/car/tests/test_models_segs.txt,system/hardware/tici/updater,selfdrive/ui/qt/spinner_larch64,selfdrive/ui/qt/text_larch64,third_party/**/*.a,third_party/**/*.so,third_party/**/*.so.*,third_party/**/*.dylib,third_party/acados/*/t_renderer,third_party/qt5/larch64/bin/lrelease,third_party/qt5/larch64/bin/lupdate,third_party/catch2/include/catch2/catch.hpp,*.apk,*.apkpatch,*.jar,*.pdf,*.jpg,*.mp3,*.thneed,*.tar.gz,*.npy,*.csv,*.a,*.so*,*.dylib,*.o,*.b64,selfdrive/hardware/tici/updater,selfdrive/boardd/tests/test_boardd,selfdrive/ui/qt/spinner_aarch64,installer/updater/updater,selfdrive/debug/profiling/simpleperf/**/*,selfdrive/hardware/eon/updater,selfdrive/ui/qt/text_aarch64,selfdrive/debug/profiling/pyflame/**/*,installer/installers/installer_openpilot,installer/installers/installer_dashcam,selfdrive/ui/text/text,selfdrive/ui/android/text/text,selfdrive/ui/spinner/spinner,selfdrive/visiond/visiond,selfdrive/loggerd/loggerd,selfdrive/sensord/sensord,selfdrive/sensord/gpsd,selfdrive/ui/android/spinner/spinner,selfdrive/ui/qt/spinner,selfdrive/ui/qt/text,_stringdefs.py,dfu-util-aarch64-linux,dfu-util-aarch64,dfu-util-x86_64-linux,dfu-util-x86_64,stb_image.h,clpeak3,clwaste,apk/**/*,external/**/*,phonelibs/**/*,third_party/boringssl/**/*,flask/**/*,panda/**/*,board/**/*,messaging/**/*,opendbc/**/*,tools/cabana/chartswidget.cc,third_party/nanovg/**/*,selfdrive/controls/lib/lateral_mpc/lib_mpc_export/**/*,selfdrive/ui/paint.cc,werkzeug/**/*,pyextra/**/*,third_party/android_hardware_libhardware/**/*,selfdrive/controls/lib/lead_mpc_lib/lib_mpc_export/**/*,selfdrive/locationd/laikad.py,selfdrive/locationd/test/test_laikad.py,tools/gpstest/test_laikad.py,selfdrive/locationd/laikad_helpers.py,tools/nui/**/*,jsonrpc/**/*,selfdrive/controls/lib/longitudinal_mpc/lib_mpc_export/**/*,selfdrive/controls/lib/lateral_mpc/mpc_export/**/*,selfdrive/camerad/cameras/camera_qcom.cc,selfdrive/manager.py,selfdrive/modeld/models/driving.cc,third_party/curl/**/*,selfdrive/modeld/thneed/debug/**/*,selfdrive/modeld/thneed/include/**/*,third_party/openmax/**/*,selfdrive/controls/lib/longitudinal_mpc/mpc_export/**/*,selfdrive/controls/lib/longitudinal_mpc_model/lib_mpc_export/**/*,Pipfile,Pipfile.lock,gunicorn/**/*,*.qm,jinja2/**/*,click/**/*,dbcs/**/*,websocket/**/*" $BRANCHES echo "reflog and gc" # this is needed after lfs import @@ -351,7 +385,6 @@ git lfs fetch --all || true # final push - will also push lfs # TODO: switch to git@github.com:commaai/openpilot.git when ready -# if using mirror, it will also delete non-master branches (master-ci, nightly, devel, release3, release3-staging, dashcam3, release2) # git push --mirror git@github.com:commaai/openpilot-tiny.git -# using this instead - since this is also what --mirror does - https://blog.plataformatec.com.br/2013/05/how-to-properly-mirror-a-git-repository/ -git push git@github.com:commaai/openpilot-tiny.git +refs/heads/*:refs/heads/* +refs/tags/*:refs/tags/* +# using this instead to ignore refs/pull/* - since this is also what --mirror does - https://blog.plataformatec.com.br/2013/05/how-to-properly-mirror-a-git-repository/ +git push --prune git@github.com:commaai/openpilot-tiny.git +refs/heads/*:refs/heads/* +refs/tags/*:refs/tags/* From 953e5667b1dce769611e742622e3612b0b09d9f4 Mon Sep 17 00:00:00 2001 From: James <91348155+FrogAi@users.noreply.github.com> Date: Fri, 12 Jul 2024 17:07:57 -0700 Subject: [PATCH 042/229] Re-use "is_metric" declaration (#32948) --- selfdrive/ui/qt/onroad/annotated_camera.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc index b08420a713..60f2380dc5 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.cc +++ b/selfdrive/ui/qt/onroad/annotated_camera.cc @@ -31,11 +31,13 @@ void AnnotatedCameraWidget::updateState(const UIState &s) { const auto cs = sm["controlsState"].getControlsState(); const auto car_state = sm["carState"].getCarState(); + is_metric = s.scene.is_metric; + // Handle older routes where vCruiseCluster is not set float v_cruise = cs.getVCruiseCluster() == 0.0 ? cs.getVCruise() : cs.getVCruiseCluster(); setSpeed = cs_alive ? v_cruise : SET_SPEED_NA; is_cruise_set = setSpeed > 0 && (int)setSpeed != SET_SPEED_NA; - if (is_cruise_set && !s.scene.is_metric) { + if (is_cruise_set && !is_metric) { setSpeed *= KM_TO_MILE; } @@ -43,10 +45,9 @@ void AnnotatedCameraWidget::updateState(const UIState &s) { v_ego_cluster_seen = v_ego_cluster_seen || car_state.getVEgoCluster() != 0.0; float v_ego = v_ego_cluster_seen ? car_state.getVEgoCluster() : car_state.getVEgo(); speed = cs_alive ? std::max(0.0, v_ego) : 0.0; - speed *= s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH; + speed *= is_metric ? MS_TO_KPH : MS_TO_MPH; - is_metric = s.scene.is_metric; - speedUnit = s.scene.is_metric ? tr("km/h") : tr("mph"); + speedUnit = is_metric ? tr("km/h") : tr("mph"); hideBottomIcons = (cs.getAlertSize() != cereal::ControlsState::AlertSize::NONE); status = s.status; From 75b07c042f09f39275452df84c5dfd46e2f4e7f0 Mon Sep 17 00:00:00 2001 From: savojovic <74861870+savojovic@users.noreply.github.com> Date: Sat, 13 Jul 2024 22:36:21 +0200 Subject: [PATCH 043/229] Replace ui.py with a Rerun visualizer (#32850) * Replace ui.py with rerun * Visualizing radarpoints * Visualizing all points * Code clean-up * Merging matrices into one * Removing pygame depndency * Replacing ui.py with rp_visualization.py * Minor fix, changing color names * Update README.md --- tools/replay/README.md | 6 +- tools/replay/lib/rp_helpers.py | 108 ++++++++++++++ tools/replay/lib/ui_helpers.py | 231 ------------------------------ tools/replay/rp_visualization.py | 59 ++++++++ tools/replay/ui.py | 238 ------------------------------- 5 files changed, 171 insertions(+), 471 deletions(-) create mode 100644 tools/replay/lib/rp_helpers.py delete mode 100644 tools/replay/lib/ui_helpers.py create mode 100755 tools/replay/rp_visualization.py delete mode 100755 tools/replay/ui.py diff --git a/tools/replay/README.md b/tools/replay/README.md index bf7280ae80..122af71521 100644 --- a/tools/replay/README.md +++ b/tools/replay/README.md @@ -19,8 +19,10 @@ tools/replay/replay --demo # watch the replay with the normal openpilot UI cd selfdrive/ui && ./ui -# or try out a debug visualizer: -python replay/ui.py +# or try out radar point visualization in Rerun: +python replay/rp_visualization.py + +# NOTE: To visualize radar points, make sure tools/replay/replay is running. ``` ## usage diff --git a/tools/replay/lib/rp_helpers.py b/tools/replay/lib/rp_helpers.py new file mode 100644 index 0000000000..95eef9d233 --- /dev/null +++ b/tools/replay/lib/rp_helpers.py @@ -0,0 +1,108 @@ +import numpy as np +from openpilot.selfdrive.controls.radard import RADAR_TO_CAMERA + +# Color palette used for rerun AnnotationContext +rerunColorPalette = [(96, "red", (255, 0, 0)), + (100, "pink", (255, 36, 0)), + (124, "yellow", (255, 255, 0)), + (230, "vibrantpink", (255, 36, 170)), + (240, "orange", (255, 146, 0)), + (255, "white", (255, 255, 255)), + (110, "carColor", (255,0,127))] + + +class UIParams: + lidar_x, lidar_y, lidar_zoom = 384, 960, 6 + lidar_car_x, lidar_car_y = lidar_x / 2., lidar_y / 1.1 + car_hwidth = 1.7272 / 2 * lidar_zoom + car_front = 2.6924 * lidar_zoom + car_back = 1.8796 * lidar_zoom + car_color = rerunColorPalette[6][0] +UP = UIParams + + +def to_topdown_pt(y, x): + px, py = x * UP.lidar_zoom + UP.lidar_car_x, -y * UP.lidar_zoom + UP.lidar_car_y + if px > 0 and py > 0 and px < UP.lidar_x and py < UP.lidar_y: + return int(px), int(py) + return -1, -1 + + +def draw_path(path, lid_overlay, lid_color=None): + x, y = np.asarray(path.x), np.asarray(path.y) + # draw lidar path point on lidar + if lid_color is not None and lid_overlay is not None: + for i in range(len(x)): + px, py = to_topdown_pt(x[i], y[i]) + if px != -1: + lid_overlay[px, py] = lid_color + + +def plot_model(m, lid_overlay): + if lid_overlay is None: + return + for lead in m.leadsV3: + if lead.prob < 0.5: + continue + x, y = lead.x[0], lead.y[0] + x_std = lead.xStd[0] + x -= RADAR_TO_CAMERA + _, py_top = to_topdown_pt(x + x_std, y) + px, py_bottom = to_topdown_pt(x - x_std, y) + lid_overlay[int(round(px - 4)):int(round(px + 4)), py_top:py_bottom] = rerunColorPalette[2][0] + + for path in m.laneLines: + draw_path(path, lid_overlay, rerunColorPalette[2][0]) + for edge in m.roadEdges: + draw_path(edge, lid_overlay, rerunColorPalette[0][0]) + draw_path(m.position, lid_overlay, rerunColorPalette[0][0]) + + +def plot_lead(rs, lid_overlay): + for lead in [rs.leadOne, rs.leadTwo]: + if not lead.status: + continue + x = lead.dRel + px_left, py = to_topdown_pt(x, -10) + px_right, _ = to_topdown_pt(x, 10) + lid_overlay[px_left:px_right, py] = rerunColorPalette[0][0] + + +def maybe_update_radar_points(lt, lid_overlay): + ar_pts = [] + if lt is not None: + ar_pts = {} + for track in lt: + ar_pts[track.trackId] = [track.dRel, track.yRel, track.vRel, track.aRel, track.oncoming, track.stationary] + for ids, pt in ar_pts.items(): + # negative here since radar is left positive + px, py = to_topdown_pt(pt[0], -pt[1]) + if px != -1: + if pt[-1]: + color = rerunColorPalette[4][0] + elif pt[-2]: + color = rerunColorPalette[3][0] + else: + color = rerunColorPalette[5][0] + if int(ids) == 1: + lid_overlay[px - 2:px + 2, py - 10:py + 10] = rerunColorPalette[1][0] + else: + lid_overlay[px - 2:px + 2, py - 2:py + 2] = color + + +def get_blank_lid_overlay(UP): + lid_overlay = np.zeros((UP.lidar_x, UP.lidar_y), 'uint8') + # Draw the car. + lid_overlay[int(round(UP.lidar_car_x - UP.car_hwidth)):int( + round(UP.lidar_car_x + UP.car_hwidth)), int(round(UP.lidar_car_y - + UP.car_front))] = UP.car_color + lid_overlay[int(round(UP.lidar_car_x - UP.car_hwidth)):int( + round(UP.lidar_car_x + UP.car_hwidth)), int(round(UP.lidar_car_y + + UP.car_back))] = UP.car_color + lid_overlay[int(round(UP.lidar_car_x - UP.car_hwidth)), int( + round(UP.lidar_car_y - UP.car_front)):int(round( + UP.lidar_car_y + UP.car_back))] = UP.car_color + lid_overlay[int(round(UP.lidar_car_x + UP.car_hwidth)), int( + round(UP.lidar_car_y - UP.car_front)):int(round( + UP.lidar_car_y + UP.car_back))] = UP.car_color + return lid_overlay diff --git a/tools/replay/lib/ui_helpers.py b/tools/replay/lib/ui_helpers.py deleted file mode 100644 index 11b5182a6b..0000000000 --- a/tools/replay/lib/ui_helpers.py +++ /dev/null @@ -1,231 +0,0 @@ -import itertools -from typing import Any - -import matplotlib.pyplot as plt -import numpy as np -import pygame - -from matplotlib.backends.backend_agg import FigureCanvasAgg - -from openpilot.common.transformations.camera import get_view_frame_from_calib_frame -from openpilot.selfdrive.controls.radard import RADAR_TO_CAMERA - - -RED = (255, 0, 0) -GREEN = (0, 255, 0) -BLUE = (0, 0, 255) -YELLOW = (255, 255, 0) -BLACK = (0, 0, 0) -WHITE = (255, 255, 255) - -class UIParams: - lidar_x, lidar_y, lidar_zoom = 384, 960, 6 - lidar_car_x, lidar_car_y = lidar_x / 2., lidar_y / 1.1 - car_hwidth = 1.7272 / 2 * lidar_zoom - car_front = 2.6924 * lidar_zoom - car_back = 1.8796 * lidar_zoom - car_color = 110 -UP = UIParams - -METER_WIDTH = 20 - -class Calibration: - def __init__(self, num_px, rpy, intrinsic, calib_scale): - self.intrinsic = intrinsic - self.extrinsics_matrix = get_view_frame_from_calib_frame(rpy[0], rpy[1], rpy[2], 0.0)[:,:3] - self.zoom = calib_scale - - def car_space_to_ff(self, x, y, z): - car_space_projective = np.column_stack((x, y, z)).T - - ep = self.extrinsics_matrix.dot(car_space_projective) - kep = self.intrinsic.dot(ep) - return (kep[:-1, :] / kep[-1, :]).T - - def car_space_to_bb(self, x, y, z): - pts = self.car_space_to_ff(x, y, z) - return pts / self.zoom - - -_COLOR_CACHE : dict[tuple[int, int, int], Any] = {} -def find_color(lidar_surface, color): - if color in _COLOR_CACHE: - return _COLOR_CACHE[color] - tcolor = 0 - ret = 255 - for x in lidar_surface.get_palette(): - if x[0:3] == color: - ret = tcolor - break - tcolor += 1 - _COLOR_CACHE[color] = ret - return ret - - -def to_topdown_pt(y, x): - px, py = x * UP.lidar_zoom + UP.lidar_car_x, -y * UP.lidar_zoom + UP.lidar_car_y - if px > 0 and py > 0 and px < UP.lidar_x and py < UP.lidar_y: - return int(px), int(py) - return -1, -1 - - -def draw_path(path, color, img, calibration, top_down, lid_color=None, z_off=0): - x, y, z = np.asarray(path.x), np.asarray(path.y), np.asarray(path.z) + z_off - pts = calibration.car_space_to_bb(x, y, z) - pts = np.round(pts).astype(int) - - # draw lidar path point on lidar - # find color in 8 bit - if lid_color is not None and top_down is not None: - tcolor = find_color(top_down[0], lid_color) - for i in range(len(x)): - px, py = to_topdown_pt(x[i], y[i]) - if px != -1: - top_down[1][px, py] = tcolor - - height, width = img.shape[:2] - for x, y in pts: - if 1 < x < width - 1 and 1 < y < height - 1: - for a, b in itertools.permutations([-1, 0, -1], 2): - img[y + a, x + b] = color - - -def init_plots(arr, name_to_arr_idx, plot_xlims, plot_ylims, plot_names, plot_colors, plot_styles): - color_palette = { "r": (1, 0, 0), - "g": (0, 1, 0), - "b": (0, 0, 1), - "k": (0, 0, 0), - "y": (1, 1, 0), - "p": (0, 1, 1), - "m": (1, 0, 1)} - - dpi = 90 - fig = plt.figure(figsize=(575 / dpi, 600 / dpi), dpi=dpi) - canvas = FigureCanvasAgg(fig) - - fig.set_facecolor((0.2, 0.2, 0.2)) - - axs = [] - for pn in range(len(plot_ylims)): - ax = fig.add_subplot(len(plot_ylims), 1, len(axs)+1) - ax.set_xlim(plot_xlims[pn][0], plot_xlims[pn][1]) - ax.set_ylim(plot_ylims[pn][0], plot_ylims[pn][1]) - ax.patch.set_facecolor((0.4, 0.4, 0.4)) - axs.append(ax) - - plots, idxs, plot_select = [], [], [] - for i, pl_list in enumerate(plot_names): - for j, item in enumerate(pl_list): - plot, = axs[i].plot(arr[:, name_to_arr_idx[item]], - label=item, - color=color_palette[plot_colors[i][j]], - linestyle=plot_styles[i][j]) - plots.append(plot) - idxs.append(name_to_arr_idx[item]) - plot_select.append(i) - axs[i].set_title(", ".join(f"{nm} ({cl})" - for (nm, cl) in zip(pl_list, plot_colors[i], strict=False)), fontsize=10) - axs[i].tick_params(axis="x", colors="white") - axs[i].tick_params(axis="y", colors="white") - axs[i].title.set_color("white") - - if i < len(plot_ylims) - 1: - axs[i].set_xticks([]) - - canvas.draw() - - def draw_plots(arr): - for ax in axs: - ax.draw_artist(ax.patch) - for i in range(len(plots)): - plots[i].set_ydata(arr[:, idxs[i]]) - axs[plot_select[i]].draw_artist(plots[i]) - - raw_data = canvas.buffer_rgba() - plot_surface = pygame.image.frombuffer(raw_data, canvas.get_width_height(), "RGBA").convert() - return plot_surface - - return draw_plots - - -def pygame_modules_have_loaded(): - return pygame.display.get_init() and pygame.font.get_init() - - -def plot_model(m, img, calibration, top_down): - if calibration is None or top_down is None: - return - - for lead in m.leadsV3: - if lead.prob < 0.5: - continue - - x, y = lead.x[0], lead.y[0] - x_std = lead.xStd[0] - x -= RADAR_TO_CAMERA - - _, py_top = to_topdown_pt(x + x_std, y) - px, py_bottom = to_topdown_pt(x - x_std, y) - top_down[1][int(round(px - 4)):int(round(px + 4)), py_top:py_bottom] = find_color(top_down[0], YELLOW) - - for path, prob, _ in zip(m.laneLines, m.laneLineProbs, m.laneLineStds, strict=True): - color = (0, int(255 * prob), 0) - draw_path(path, color, img, calibration, top_down, YELLOW) - - for edge, std in zip(m.roadEdges, m.roadEdgeStds, strict=True): - prob = max(1 - std, 0) - color = (int(255 * prob), 0, 0) - draw_path(edge, color, img, calibration, top_down, RED) - - color = (255, 0, 0) - draw_path(m.position, color, img, calibration, top_down, RED, 1.22) - - -def plot_lead(rs, top_down): - for lead in [rs.leadOne, rs.leadTwo]: - if not lead.status: - continue - - x = lead.dRel - px_left, py = to_topdown_pt(x, -10) - px_right, _ = to_topdown_pt(x, 10) - top_down[1][px_left:px_right, py] = find_color(top_down[0], RED) - - -def maybe_update_radar_points(lt, lid_overlay): - ar_pts = [] - if lt is not None: - ar_pts = {} - for track in lt: - ar_pts[track.trackId] = [track.dRel, track.yRel, track.vRel, track.aRel, track.oncoming, track.stationary] - for ids, pt in ar_pts.items(): - # negative here since radar is left positive - px, py = to_topdown_pt(pt[0], -pt[1]) - if px != -1: - if pt[-1]: - color = 240 - elif pt[-2]: - color = 230 - else: - color = 255 - if int(ids) == 1: - lid_overlay[px - 2:px + 2, py - 10:py + 10] = 100 - else: - lid_overlay[px - 2:px + 2, py - 2:py + 2] = color - -def get_blank_lid_overlay(UP): - lid_overlay = np.zeros((UP.lidar_x, UP.lidar_y), 'uint8') - # Draw the car. - lid_overlay[int(round(UP.lidar_car_x - UP.car_hwidth)):int( - round(UP.lidar_car_x + UP.car_hwidth)), int(round(UP.lidar_car_y - - UP.car_front))] = UP.car_color - lid_overlay[int(round(UP.lidar_car_x - UP.car_hwidth)):int( - round(UP.lidar_car_x + UP.car_hwidth)), int(round(UP.lidar_car_y + - UP.car_back))] = UP.car_color - lid_overlay[int(round(UP.lidar_car_x - UP.car_hwidth)), int( - round(UP.lidar_car_y - UP.car_front)):int(round( - UP.lidar_car_y + UP.car_back))] = UP.car_color - lid_overlay[int(round(UP.lidar_car_x + UP.car_hwidth)), int( - round(UP.lidar_car_y - UP.car_front)):int(round( - UP.lidar_car_y + UP.car_back))] = UP.car_color - return lid_overlay diff --git a/tools/replay/rp_visualization.py b/tools/replay/rp_visualization.py new file mode 100755 index 0000000000..853a83c150 --- /dev/null +++ b/tools/replay/rp_visualization.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +import argparse +import os +import sys +import numpy as np +import rerun as rr +import cereal.messaging as messaging +from openpilot.common.basedir import BASEDIR +from openpilot.tools.replay.lib.rp_helpers import (UP, rerunColorPalette, + get_blank_lid_overlay, + maybe_update_radar_points, plot_lead, + plot_model) +from msgq.visionipc import VisionIpcClient, VisionStreamType + +os.environ['BASEDIR'] = BASEDIR + +UP.lidar_zoom = 6 + +def visualize(addr): + sm = messaging.SubMaster(['radarState', 'liveTracks', 'modelV2'], addr=addr) + vipc_client = VisionIpcClient("camerad", VisionStreamType.VISION_STREAM_ROAD, True) + while True: + if not vipc_client.is_connected(): + vipc_client.connect(True) + new_data = vipc_client.recv() + if new_data is None or not new_data.data.any(): + continue + + sm.update(0) + lid_overlay = get_blank_lid_overlay(UP) + if sm.recv_frame['modelV2']: + plot_model(sm['modelV2'], lid_overlay) + if sm.recv_frame['radarState']: + plot_lead(sm['radarState'], lid_overlay) + liveTracksTime = sm.logMonoTime['liveTracks'] + maybe_update_radar_points(sm['liveTracks'], lid_overlay) + rr.set_time_nanos("TIMELINE", liveTracksTime) + rr.log("tracks", rr.SegmentationImage(np.flip(np.rot90(lid_overlay, k=-1), axis=1))) + + +def get_arg_parser(): + parser = argparse.ArgumentParser( + description="Show replay data in a UI.", + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument("ip_address", nargs="?", default="127.0.0.1", + help="The ip address on which to receive zmq messages.") + parser.add_argument("--frame-address", default=None, + help="The frame address (fully qualified ZMQ endpoint for frames) on which to receive zmq messages.") + return parser + + +if __name__ == "__main__": + args = get_arg_parser().parse_args(sys.argv[1:]) + if args.ip_address != "127.0.0.1": + os.environ["ZMQ"] = "1" + messaging.context = messaging.Context() + rr.init("RadarPoints", spawn= True) + rr.log("tracks", rr.AnnotationContext(rerunColorPalette), static=True) + visualize(args.ip_address) diff --git a/tools/replay/ui.py b/tools/replay/ui.py deleted file mode 100755 index b1fe70ef3c..0000000000 --- a/tools/replay/ui.py +++ /dev/null @@ -1,238 +0,0 @@ -#!/usr/bin/env python3 -import argparse -import os -import sys - -import cv2 -import numpy as np -import pygame - -import cereal.messaging as messaging -from openpilot.common.numpy_fast import clip -from openpilot.common.basedir import BASEDIR -from openpilot.common.transformations.camera import DEVICE_CAMERAS -from openpilot.tools.replay.lib.ui_helpers import (UP, - BLACK, GREEN, - YELLOW, Calibration, - get_blank_lid_overlay, init_plots, - maybe_update_radar_points, plot_lead, - plot_model, - pygame_modules_have_loaded) -from msgq.visionipc import VisionIpcClient, VisionStreamType - -os.environ['BASEDIR'] = BASEDIR - -ANGLE_SCALE = 5.0 - -def ui_thread(addr): - cv2.setNumThreads(1) - pygame.init() - pygame.font.init() - assert pygame_modules_have_loaded() - - disp_info = pygame.display.Info() - max_height = disp_info.current_h - - hor_mode = os.getenv("HORIZONTAL") is not None - hor_mode = True if max_height < 960+300 else hor_mode - - if hor_mode: - size = (640+384+640, 960) - write_x = 5 - write_y = 680 - else: - size = (640+384, 960+300) - write_x = 645 - write_y = 970 - - pygame.display.set_caption("openpilot debug UI") - screen = pygame.display.set_mode(size, pygame.DOUBLEBUF) - - alert1_font = pygame.font.SysFont("arial", 30) - alert2_font = pygame.font.SysFont("arial", 20) - info_font = pygame.font.SysFont("arial", 15) - - camera_surface = pygame.surface.Surface((640, 480), 0, 24).convert() - top_down_surface = pygame.surface.Surface((UP.lidar_x, UP.lidar_y), 0, 8) - - sm = messaging.SubMaster(['carState', 'longitudinalPlan', 'carControl', 'radarState', 'liveCalibration', 'controlsState', - 'liveTracks', 'modelV2', 'liveParameters', 'roadCameraState'], addr=addr) - - img = np.zeros((480, 640, 3), dtype='uint8') - imgff = None - num_px = 0 - calibration = None - - lid_overlay_blank = get_blank_lid_overlay(UP) - - # plots - name_to_arr_idx = { "gas": 0, - "computer_gas": 1, - "user_brake": 2, - "computer_brake": 3, - "v_ego": 4, - "v_pid": 5, - "angle_steers_des": 6, - "angle_steers": 7, - "angle_steers_k": 8, - "steer_torque": 9, - "v_override": 10, - "v_cruise": 11, - "a_ego": 12, - "a_target": 13} - - plot_arr = np.zeros((100, len(name_to_arr_idx.values()))) - - plot_xlims = [(0, plot_arr.shape[0]), (0, plot_arr.shape[0]), (0, plot_arr.shape[0]), (0, plot_arr.shape[0])] - plot_ylims = [(-0.1, 1.1), (-ANGLE_SCALE, ANGLE_SCALE), (0., 75.), (-3.0, 2.0)] - plot_names = [["gas", "computer_gas", "user_brake", "computer_brake"], - ["angle_steers", "angle_steers_des", "angle_steers_k", "steer_torque"], - ["v_ego", "v_override", "v_pid", "v_cruise"], - ["a_ego", "a_target"]] - plot_colors = [["b", "b", "g", "r", "y"], - ["b", "g", "y", "r"], - ["b", "g", "r", "y"], - ["b", "r"]] - plot_styles = [["-", "-", "-", "-", "-"], - ["-", "-", "-", "-"], - ["-", "-", "-", "-"], - ["-", "-"]] - - draw_plots = init_plots(plot_arr, name_to_arr_idx, plot_xlims, plot_ylims, plot_names, plot_colors, plot_styles) - - vipc_client = VisionIpcClient("camerad", VisionStreamType.VISION_STREAM_ROAD, True) - while True: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - pygame.quit() - sys.exit() - - screen.fill((64, 64, 64)) - lid_overlay = lid_overlay_blank.copy() - top_down = top_down_surface, lid_overlay - - # ***** frame ***** - if not vipc_client.is_connected(): - vipc_client.connect(True) - - yuv_img_raw = vipc_client.recv() - if yuv_img_raw is None or not yuv_img_raw.data.any(): - continue - - sm.update(0) - - camera = DEVICE_CAMERAS[("tici", str(sm['roadCameraState'].sensor))] - - imgff = np.frombuffer(yuv_img_raw.data, dtype=np.uint8).reshape((len(yuv_img_raw.data) // vipc_client.stride, vipc_client.stride)) - num_px = vipc_client.width * vipc_client.height - rgb = cv2.cvtColor(imgff[:vipc_client.height * 3 // 2, :vipc_client.width], cv2.COLOR_YUV2RGB_NV12) - - qcam = "QCAM" in os.environ - bb_scale = (528 if qcam else camera.fcam.width) / 640. - calib_scale = camera.fcam.width / 640. - zoom_matrix = np.asarray([ - [bb_scale, 0., 0.], - [0., bb_scale, 0.], - [0., 0., 1.]]) - cv2.warpAffine(rgb, zoom_matrix[:2], (img.shape[1], img.shape[0]), dst=img, flags=cv2.WARP_INVERSE_MAP) - - intrinsic_matrix = camera.fcam.intrinsics - - w = sm['controlsState'].lateralControlState.which() - if w == 'lqrStateDEPRECATED': - angle_steers_k = sm['controlsState'].lateralControlState.lqrStateDEPRECATED.steeringAngleDeg - elif w == 'indiState': - angle_steers_k = sm['controlsState'].lateralControlState.indiState.steeringAngleDeg - else: - angle_steers_k = np.inf - - plot_arr[:-1] = plot_arr[1:] - plot_arr[-1, name_to_arr_idx['angle_steers']] = sm['carState'].steeringAngleDeg - plot_arr[-1, name_to_arr_idx['angle_steers_des']] = sm['carControl'].actuators.steeringAngleDeg - plot_arr[-1, name_to_arr_idx['angle_steers_k']] = angle_steers_k - plot_arr[-1, name_to_arr_idx['gas']] = sm['carState'].gas - # TODO gas is deprecated - plot_arr[-1, name_to_arr_idx['computer_gas']] = clip(sm['carControl'].actuators.accel/4.0, 0.0, 1.0) - plot_arr[-1, name_to_arr_idx['user_brake']] = sm['carState'].brake - plot_arr[-1, name_to_arr_idx['steer_torque']] = sm['carControl'].actuators.steer * ANGLE_SCALE - # TODO brake is deprecated - plot_arr[-1, name_to_arr_idx['computer_brake']] = clip(-sm['carControl'].actuators.accel/4.0, 0.0, 1.0) - plot_arr[-1, name_to_arr_idx['v_ego']] = sm['carState'].vEgo - plot_arr[-1, name_to_arr_idx['v_cruise']] = sm['carState'].cruiseState.speed - plot_arr[-1, name_to_arr_idx['a_ego']] = sm['carState'].aEgo - - if len(sm['longitudinalPlan'].accels): - plot_arr[-1, name_to_arr_idx['a_target']] = sm['longitudinalPlan'].accels[0] - - if sm.recv_frame['modelV2']: - plot_model(sm['modelV2'], img, calibration, top_down) - - if sm.recv_frame['radarState']: - plot_lead(sm['radarState'], top_down) - - # draw all radar points - maybe_update_radar_points(sm['liveTracks'], top_down[1]) - - if sm.updated['liveCalibration'] and num_px: - rpyCalib = np.asarray(sm['liveCalibration'].rpyCalib) - calibration = Calibration(num_px, rpyCalib, intrinsic_matrix, calib_scale) - - # *** blits *** - pygame.surfarray.blit_array(camera_surface, img.swapaxes(0, 1)) - screen.blit(camera_surface, (0, 0)) - - # display alerts - alert_line1 = alert1_font.render(sm['controlsState'].alertText1, True, (255, 0, 0)) - alert_line2 = alert2_font.render(sm['controlsState'].alertText2, True, (255, 0, 0)) - screen.blit(alert_line1, (180, 150)) - screen.blit(alert_line2, (180, 190)) - - if hor_mode: - screen.blit(draw_plots(plot_arr), (640+384, 0)) - else: - screen.blit(draw_plots(plot_arr), (0, 600)) - - pygame.surfarray.blit_array(*top_down) - screen.blit(top_down[0], (640, 0)) - - SPACING = 25 - - lines = [ - info_font.render("ENABLED", True, GREEN if sm['controlsState'].enabled else BLACK), - info_font.render("SPEED: " + str(round(sm['carState'].vEgo, 1)) + " m/s", True, YELLOW), - info_font.render("LONG CONTROL STATE: " + str(sm['controlsState'].longControlState), True, YELLOW), - info_font.render("LONG MPC SOURCE: " + str(sm['longitudinalPlan'].longitudinalPlanSource), True, YELLOW), - None, - info_font.render("ANGLE OFFSET (AVG): " + str(round(sm['liveParameters'].angleOffsetAverageDeg, 2)) + " deg", True, YELLOW), - info_font.render("ANGLE OFFSET (INSTANT): " + str(round(sm['liveParameters'].angleOffsetDeg, 2)) + " deg", True, YELLOW), - info_font.render("STIFFNESS: " + str(round(sm['liveParameters'].stiffnessFactor * 100., 2)) + " %", True, YELLOW), - info_font.render("STEER RATIO: " + str(round(sm['liveParameters'].steerRatio, 2)), True, YELLOW) - ] - - for i, line in enumerate(lines): - if line is not None: - screen.blit(line, (write_x, write_y + i * SPACING)) - - # this takes time...vsync or something - pygame.display.flip() - -def get_arg_parser(): - parser = argparse.ArgumentParser( - description="Show replay data in a UI.", - formatter_class=argparse.ArgumentDefaultsHelpFormatter) - - parser.add_argument("ip_address", nargs="?", default="127.0.0.1", - help="The ip address on which to receive zmq messages.") - - parser.add_argument("--frame-address", default=None, - help="The frame address (fully qualified ZMQ endpoint for frames) on which to receive zmq messages.") - return parser - -if __name__ == "__main__": - args = get_arg_parser().parse_args(sys.argv[1:]) - - if args.ip_address != "127.0.0.1": - os.environ["ZMQ"] = "1" - messaging.context = messaging.Context() - - ui_thread(args.ip_address) From e7388c3743242938d07694864f8db011c00554df Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 13 Jul 2024 13:41:38 -0700 Subject: [PATCH 044/229] remove pygame (#32981) --- pyproject.toml | 1 - uv.lock | 481 ++++++++++++++++++++++++------------------------- 2 files changed, 240 insertions(+), 242 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 82f9c563bd..13800fc1c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -107,7 +107,6 @@ dev = [ "parameterized >=0.8, <0.9", #pprofile = "*" "pyautogui", - "pygame", "pyopencl; platform_machine != 'aarch64'", # broken on arm64 "pywinctl", "pyprof2calltree", diff --git a/uv.lock b/uv.lock index 57f8d9d7ee..873d388808 100644 --- a/uv.lock +++ b/uv.lock @@ -5,7 +5,6 @@ requires-python = ">=3.11" name = "aiohttp" version = "3.9.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/04/a4/e3679773ea7eb5b37a2c998e25b017cc5349edf6ba2739d1f32855cfb11b/aiohttp-3.9.5.tar.gz", hash = "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551", size = 7504841 } dependencies = [ { name = "aiosignal" }, { name = "attrs" }, @@ -13,6 +12,7 @@ dependencies = [ { name = "multidict" }, { name = "yarl" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/04/a4/e3679773ea7eb5b37a2c998e25b017cc5349edf6ba2739d1f32855cfb11b/aiohttp-3.9.5.tar.gz", hash = "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551", size = 7504841 } wheels = [ { url = "https://files.pythonhosted.org/packages/67/f5/aa23d04a1bb57e5f51108a6473964a2618cc83e608e23e3543031aa2bb3a/aiohttp-3.9.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342", size = 599387 }, { url = "https://files.pythonhosted.org/packages/97/e7/575ca16871071313a7a7a03fa055f0c3d52f77eb8583b373ac17fc87ec15/aiohttp-3.9.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d", size = 402427 }, @@ -50,11 +50,11 @@ wheels = [ name = "aioice" version = "0.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/33/b6/e2b0e48ccb5b04fe29265e93f14a0915f416e359c897ae87d570566c430b/aioice-0.9.0.tar.gz", hash = "sha256:fc2401b1c4b6e19372eaaeaa28fd1bd9cbf6b0e412e48625297c53b495eebd1e", size = 40324 } dependencies = [ { name = "dnspython" }, { name = "ifaddr" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/33/b6/e2b0e48ccb5b04fe29265e93f14a0915f416e359c897ae87d570566c430b/aioice-0.9.0.tar.gz", hash = "sha256:fc2401b1c4b6e19372eaaeaa28fd1bd9cbf6b0e412e48625297c53b495eebd1e", size = 40324 } wheels = [ { url = "https://files.pythonhosted.org/packages/b6/35/d21e48d3ba25d32aba5d142d54c4491376c659dd74d052a30dd25198007b/aioice-0.9.0-py3-none-any.whl", hash = "sha256:b609597a3a5a611e0004ff04772e16aceb881d51c25c0afc4ceac05d5e50024e", size = 24177 }, ] @@ -63,7 +63,6 @@ wheels = [ name = "aiortc" version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/71/32/e9b01e2271124643e5dc15c273f2bb8155efebf5bc2115407441ac62f4c5/aiortc-1.9.0.tar.gz", hash = "sha256:03faa76d76ef0e5989ac10386898b029369756102217230e2fcd4b029c50b303", size = 1168973 } dependencies = [ { name = "aioice" }, { name = "av" }, @@ -74,6 +73,7 @@ dependencies = [ { name = "pylibsrtp" }, { name = "pyopenssl" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/71/32/e9b01e2271124643e5dc15c273f2bb8155efebf5bc2115407441ac62f4c5/aiortc-1.9.0.tar.gz", hash = "sha256:03faa76d76ef0e5989ac10386898b029369756102217230e2fcd4b029c50b303", size = 1168973 } wheels = [ { url = "https://files.pythonhosted.org/packages/93/01/db89910fc4dfb72ca25fd9a41326762a490d93d39d2fc4aac3f86c05857d/aiortc-1.9.0-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e3e67c1970c2cffacac53c8f161df264efc62b22721c64a621940935028ee087", size = 1216069 }, { url = "https://files.pythonhosted.org/packages/4c/6d/76ed96521080492c7264eacf73a8cba2202f1ff9f59af1776c5a2532f332/aiortc-1.9.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d893cb3d4ffa0ff4f9bb03a88f0a700cdbcd4c0dc060a46c59a27ccd1c890663", size = 896012 }, @@ -88,10 +88,10 @@ wheels = [ name = "aiosignal" version = "1.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/67/0952ed97a9793b4958e5736f6d2b346b414a2cd63e82d05940032f45b32f/aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", size = 19422 } dependencies = [ { name = "frozenlist" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/ae/67/0952ed97a9793b4958e5736f6d2b346b414a2cd63e82d05940032f45b32f/aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", size = 19422 } wheels = [ { url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17", size = 7617 }, ] @@ -138,12 +138,12 @@ wheels = [ name = "azure-core" version = "1.30.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/99/d4/1f469fa246f554b86fb5cebc30eef1b2a38b7af7a2c2791bce0a4c6e4604/azure-core-1.30.2.tar.gz", hash = "sha256:a14dc210efcd608821aa472d9fb8e8d035d29b68993819147bc290a8ac224472", size = 271104 } dependencies = [ { name = "requests" }, { name = "six" }, { name = "typing-extensions" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/99/d4/1f469fa246f554b86fb5cebc30eef1b2a38b7af7a2c2791bce0a4c6e4604/azure-core-1.30.2.tar.gz", hash = "sha256:a14dc210efcd608821aa472d9fb8e8d035d29b68993819147bc290a8ac224472", size = 271104 } wheels = [ { url = "https://files.pythonhosted.org/packages/ef/d7/69d53f37733f8cb844862781767aef432ff3152bc9b9864dc98c7e286ce9/azure_core-1.30.2-py3-none-any.whl", hash = "sha256:cf019c1ca832e96274ae85abd3d9f752397194d9fea3b41487290562ac8abe4a", size = 194253 }, ] @@ -152,7 +152,6 @@ wheels = [ name = "azure-identity" version = "1.17.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/51/c9/f7e3926686a89670ce641b360bd2da9a2d7a12b3e532403462d99f81e9d5/azure-identity-1.17.1.tar.gz", hash = "sha256:32ecc67cc73f4bd0595e4f64b1ca65cd05186f4fe6f98ed2ae9f1aa32646efea", size = 246652 } dependencies = [ { name = "azure-core" }, { name = "cryptography" }, @@ -160,6 +159,7 @@ dependencies = [ { name = "msal-extensions" }, { name = "typing-extensions" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/51/c9/f7e3926686a89670ce641b360bd2da9a2d7a12b3e532403462d99f81e9d5/azure-identity-1.17.1.tar.gz", hash = "sha256:32ecc67cc73f4bd0595e4f64b1ca65cd05186f4fe6f98ed2ae9f1aa32646efea", size = 246652 } wheels = [ { url = "https://files.pythonhosted.org/packages/49/83/a777861351e7b99e7c84ff3b36bab35e87b6e5d36e50b6905e148c696515/azure_identity-1.17.1-py3-none-any.whl", hash = "sha256:db8d59c183b680e763722bfe8ebc45930e6c57df510620985939f7f3191e0382", size = 173229 }, ] @@ -168,13 +168,13 @@ wheels = [ name = "azure-storage-blob" version = "12.20.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1b/0f/86cdaec4be486d12fd5bd2c56e835492a58d3bcd4915d24473e889b70f2c/azure-storage-blob-12.20.0.tar.gz", hash = "sha256:eeb91256e41d4b5b9bad6a87fd0a8ade07dd58aa52344e2c8d2746e27a017d3b", size = 551196 } dependencies = [ { name = "azure-core" }, { name = "cryptography" }, { name = "isodate" }, { name = "typing-extensions" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/1b/0f/86cdaec4be486d12fd5bd2c56e835492a58d3bcd4915d24473e889b70f2c/azure-storage-blob-12.20.0.tar.gz", hash = "sha256:eeb91256e41d4b5b9bad6a87fd0a8ade07dd58aa52344e2c8d2746e27a017d3b", size = 551196 } wheels = [ { url = "https://files.pythonhosted.org/packages/15/19/2be26569e708cb618feecd7316ee0c5475273f7cdb4f9030a862870c74c8/azure_storage_blob-12.20.0-py3-none-any.whl", hash = "sha256:de6b3bf3a90e9341a6bcb96a2ebe981dffff993e9045818f6549afea827a52a9", size = 392162 }, ] @@ -192,11 +192,11 @@ wheels = [ name = "breathe" version = "4.35.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/9f/0c6f4ae0608d5edbb1df357c2487edfcbda13e75f4e48a898972592e2e48/breathe-4.35.0.tar.gz", hash = "sha256:5165541c3c67b6c7adde8b3ecfe895c6f7844783c4076b6d8d287e4f33d62386", size = 83358 } dependencies = [ { name = "docutils" }, { name = "sphinx" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/a2/9f/0c6f4ae0608d5edbb1df357c2487edfcbda13e75f4e48a898972592e2e48/breathe-4.35.0.tar.gz", hash = "sha256:5165541c3c67b6c7adde8b3ecfe895c6f7844783c4076b6d8d287e4f33d62386", size = 83358 } wheels = [ { url = "https://files.pythonhosted.org/packages/eb/61/faddc25913de74e60e175bcfd962ec83532653c5895c0a06a83a6b5bbf3d/breathe-4.35.0-py3-none-any.whl", hash = "sha256:52c581f42ca4310737f9e435e3851c3d1f15446205a85fbc272f1f97ed74f5be", size = 92955 }, ] @@ -205,10 +205,10 @@ wheels = [ name = "casadi" version = "3.6.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/97/ca40c4d7d36162ddfd0bb96a89206469a95b925faf67046ba6e4b5b78283/casadi-3.6.5.tar.gz", hash = "sha256:409a5f6725eadea40fddfb8ba2321139b5252edac8bc115a72f68e648631d56a", size = 5070590 } dependencies = [ { name = "numpy" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/5a/97/ca40c4d7d36162ddfd0bb96a89206469a95b925faf67046ba6e4b5b78283/casadi-3.6.5.tar.gz", hash = "sha256:409a5f6725eadea40fddfb8ba2321139b5252edac8bc115a72f68e648631d56a", size = 5070590 } wheels = [ { url = "https://files.pythonhosted.org/packages/e5/80/0ba51b24b9db588f02256be00c2a99c6340e703ccfc3cfcb2818c4aea59c/casadi-3.6.5-cp27-none-macosx_10_13_x86_64.macosx_10_13_intel.whl", hash = "sha256:6039081fdd1daf4ef7fa2b52814a954d75bfc03eb0dc62414e02af5d25746e8f", size = 42870004 }, { url = "https://files.pythonhosted.org/packages/9f/a6/edb201c436c820779b1f4e2bf5a74b6fd5e4d7d7b703336e5c0518e1b08f/casadi-3.6.5-cp27-none-manylinux1_i686.whl", hash = "sha256:b5192dfabf6f5266b168b984d124dd3086c1c5a408c0743ff3a82290a8ccf3b5", size = 47956673 }, @@ -272,10 +272,10 @@ wheels = [ name = "cffi" version = "1.16.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/68/ce/95b0bae7968c65473e1298efb042e10cafc7bafc14d9e4f154008241c91d/cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", size = 512873 } dependencies = [ { name = "pycparser" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/68/ce/95b0bae7968c65473e1298efb042e10cafc7bafc14d9e4f154008241c91d/cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", size = 512873 } wheels = [ { url = "https://files.pythonhosted.org/packages/95/c8/ce05a6cba2bec12d4b28285e66c53cc88dd7385b102dea7231da3b74cfef/cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", size = 182415 }, { url = "https://files.pythonhosted.org/packages/18/6c/0406611f3d5aadf4c5b08f6c095d874aed8dfc2d3a19892707d72536d5dc/cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", size = 176745 }, @@ -352,10 +352,10 @@ wheels = [ name = "click" version = "8.1.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } dependencies = [ { name = "colorama", marker = "platform_system == 'Windows'" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } wheels = [ { url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 }, ] @@ -382,10 +382,10 @@ wheels = [ name = "coloredlogs" version = "15.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/c7/eed8f27100517e8c0e6b923d5f0845d0cb99763da6fdee00478f91db7325/coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0", size = 278520 } dependencies = [ { name = "humanfriendly" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/cc/c7/eed8f27100517e8c0e6b923d5f0845d0cb99763da6fdee00478f91db7325/coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0", size = 278520 } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/06/3d6badcf13db419e25b07041d9c7b4a2c331d3f4e7134445ec5df57714cd/coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934", size = 46018 }, ] @@ -394,10 +394,10 @@ wheels = [ name = "contourpy" version = "1.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8d/9e/e4786569b319847ffd98a8326802d5cf8a5500860dbfc2df1f0f4883ed99/contourpy-1.2.1.tar.gz", hash = "sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c", size = 13457196 } dependencies = [ { name = "numpy" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/8d/9e/e4786569b319847ffd98a8326802d5cf8a5500860dbfc2df1f0f4883ed99/contourpy-1.2.1.tar.gz", hash = "sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c", size = 13457196 } wheels = [ { url = "https://files.pythonhosted.org/packages/33/0e/51ff72fac17e2500baf30b6b2a24be423a8d27e1625e5de99f585b852d74/contourpy-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6022cecf8f44e36af10bd9118ca71f371078b4c168b6e0fab43d4a889985dbb5", size = 262121 }, { url = "https://files.pythonhosted.org/packages/9f/6b/8a1ca4b81d426c104fe42b3cfad9488eaaef0a03fcf98eaecc22b628a013/contourpy-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef5adb9a3b1d0c645ff694f9bca7702ec2c70f4d734f9922ea34de02294fdf72", size = 245940 }, @@ -425,12 +425,12 @@ wheels = [ name = "control" version = "0.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/64/02fedcf78b070571f5e446efb55b7ec82b68187323402b99b6f98f769530/control-0.10.0.tar.gz", hash = "sha256:2c18b767537f45c7fd07b2e4afe8fbe5964019499b5f52f888edb5d8560bab53", size = 8956376 } dependencies = [ { name = "matplotlib" }, { name = "numpy" }, { name = "scipy" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/ee/64/02fedcf78b070571f5e446efb55b7ec82b68187323402b99b6f98f769530/control-0.10.0.tar.gz", hash = "sha256:2c18b767537f45c7fd07b2e4afe8fbe5964019499b5f52f888edb5d8560bab53", size = 8956376 } wheels = [ { url = "https://files.pythonhosted.org/packages/4d/de/327ab576657cb6bd5678e5d4fa266f3c4c7094e99df2bb7760e89176772d/control-0.10.0-py3-none-any.whl", hash = "sha256:ed1e0eb73f1e2945fc9af9d7b9121ef328fe980e7903b2a14b149d4f1855a808", size = 513858 }, ] @@ -474,10 +474,10 @@ sdist = { url = "https://files.pythonhosted.org/packages/6b/b0/e595ce2a2527e169c name = "cryptography" version = "42.0.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/93/a7/1498799a2ea06148463a9a2c10ab2f6a921a74fb19e231b27dc412a748e2/cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2", size = 671250 } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/93/a7/1498799a2ea06148463a9a2c10ab2f6a921a74fb19e231b27dc412a748e2/cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2", size = 671250 } wheels = [ { url = "https://files.pythonhosted.org/packages/f9/8b/1b929ba8139430e09e140e6939c2b29c18df1f2fc2149e41bdbdcdaf5d1f/cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e", size = 5899961 }, { url = "https://files.pythonhosted.org/packages/fa/5d/31d833daa800e4fab33209843095df7adb4a78ea536929145534cbc15026/cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d", size = 3114353 }, @@ -708,7 +708,6 @@ wheels = [ name = "geopandas" version = "1.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/39/08/2cf5d85356e45b10b8d066cf4c3ba1e9e3185423c48104eed87e8afd0455/geopandas-1.0.1.tar.gz", hash = "sha256:b8bf70a5534588205b7a56646e2082fb1de9a03599651b3d80c99ea4c2ca08ab", size = 317736 } dependencies = [ { name = "numpy" }, { name = "packaging" }, @@ -717,6 +716,7 @@ dependencies = [ { name = "pyproj" }, { name = "shapely" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/39/08/2cf5d85356e45b10b8d066cf4c3ba1e9e3185423c48104eed87e8afd0455/geopandas-1.0.1.tar.gz", hash = "sha256:b8bf70a5534588205b7a56646e2082fb1de9a03599651b3d80c99ea4c2ca08ab", size = 317736 } wheels = [ { url = "https://files.pythonhosted.org/packages/c4/64/7d344cfcef5efddf9cf32f59af7f855828e9d74b5f862eddf5bfd9f25323/geopandas-1.0.1-py3-none-any.whl", hash = "sha256:01e147d9420cc374d26f51fc23716ac307f32b49406e4bd8462c07e82ed1d3d6", size = 323587 }, ] @@ -725,10 +725,10 @@ wheels = [ name = "ghp-import" version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943 } dependencies = [ { name = "python-dateutil" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943 } wheels = [ { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034 }, ] @@ -755,13 +755,13 @@ wheels = [ name = "gymnasium" version = "0.29.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0d/f8/5699ddb3e1c4f6d97b8930e573074849b921da8374fccd141f0f3a9bd713/gymnasium-0.29.1.tar.gz", hash = "sha256:1a532752efcb7590478b1cc7aa04f608eb7a2fdad5570cd217b66b6a35274bb1", size = 820485 } dependencies = [ { name = "cloudpickle" }, { name = "farama-notifications" }, { name = "numpy" }, { name = "typing-extensions" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/0d/f8/5699ddb3e1c4f6d97b8930e573074849b921da8374fccd141f0f3a9bd713/gymnasium-0.29.1.tar.gz", hash = "sha256:1a532752efcb7590478b1cc7aa04f608eb7a2fdad5570cd217b66b6a35274bb1", size = 820485 } wheels = [ { url = "https://files.pythonhosted.org/packages/a8/4d/3cbfd81ed84db450dbe73a89afcd8bc405273918415649ac6683356afe92/gymnasium-0.29.1-py3-none-any.whl", hash = "sha256:61c3384b5575985bb7f85e43213bcb40f36fcdff388cae6bc229304c71f2843e", size = 953939 }, ] @@ -776,10 +776,10 @@ sdist = { url = "https://files.pythonhosted.org/packages/55/b3/279b1d57fa3681725 name = "humanfriendly" version = "10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/3f/2c29224acb2e2df4d2046e4c73ee2662023c58ff5b113c4c1adac0886c43/humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc", size = 360702 } dependencies = [ - { name = "pyreadline3", marker = "python_version >= '3.8' and sys_platform == 'win32'" }, + { name = "pyreadline3", marker = "sys_platform == 'win32'" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/cc/3f/2c29224acb2e2df4d2046e4c73ee2662023c58ff5b113c4c1adac0886c43/humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc", size = 360702 } wheels = [ { url = "https://files.pythonhosted.org/packages/f0/0f/310fb31e39e2d734ccaa2c0fb981ee41f7bd5056ce9bc29b2248bd569169/humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477", size = 86794 }, ] @@ -788,11 +788,11 @@ wheels = [ name = "hypothesis" version = "6.47.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/45/f2/f77da8271b1abb630cb2090ead2f5aa4acc9639d632e8e68187f52527e4b/hypothesis-6.47.5.tar.gz", hash = "sha256:e0c1e253fc97e7ecdb9e2bbff2cf815d8739e0d1d3d093d67c3af5bb6a7211b0", size = 326641 } dependencies = [ { name = "attrs" }, { name = "sortedcontainers" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/45/f2/f77da8271b1abb630cb2090ead2f5aa4acc9639d632e8e68187f52527e4b/hypothesis-6.47.5.tar.gz", hash = "sha256:e0c1e253fc97e7ecdb9e2bbff2cf815d8739e0d1d3d093d67c3af5bb6a7211b0", size = 326641 } wheels = [ { url = "https://files.pythonhosted.org/packages/d3/a7/389bbaade2cbbb2534cb2715986041ed01c6d792152c527e71f7f68e93b5/hypothesis-6.47.5-py3-none-any.whl", hash = "sha256:87049b781ee11ec1c7948565b889ab02e428a1e32d427ab4de8fdb3649242d06", size = 387311 }, ] @@ -837,10 +837,10 @@ wheels = [ name = "importlib-metadata" version = "8.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/ff/bd28f70283b9cca0cbf0c2a6082acbecd822d1962ae7b2a904861b9965f8/importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812", size = 52667 } dependencies = [ { name = "zipp" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/20/ff/bd28f70283b9cca0cbf0c2a6082acbecd822d1962ae7b2a904861b9965f8/importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812", size = 52667 } wheels = [ { url = "https://files.pythonhosted.org/packages/dc/ef/38766b2edb096260d9b1b6ad35adaa0bce3b0567abb452b21eb074af88c4/importlib_metadata-8.0.0-py3-none-any.whl", hash = "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f", size = 24769 }, ] @@ -867,10 +867,10 @@ wheels = [ name = "isodate" version = "0.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/7a/c0a56c7d56c7fa723988f122fa1f1ccf8c5c4ccc48efad0d214b49e5b1af/isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9", size = 28443 } dependencies = [ { name = "six" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/db/7a/c0a56c7d56c7fa723988f122fa1f1ccf8c5c4ccc48efad0d214b49e5b1af/isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9", size = 28443 } wheels = [ { url = "https://files.pythonhosted.org/packages/b6/85/7882d311924cbcfc70b1890780763e36ff0b140c7e51c110fc59a532f087/isodate-0.6.1-py2.py3-none-any.whl", hash = "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96", size = 41722 }, ] @@ -879,10 +879,10 @@ wheels = [ name = "jinja2" version = "3.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ed/55/39036716d19cab0747a5020fc7e907f362fbf48c984b14e62127f7e68e5d/jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", size = 240245 } dependencies = [ { name = "markupsafe" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/ed/55/39036716d19cab0747a5020fc7e907f362fbf48c984b14e62127f7e68e5d/jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", size = 240245 } wheels = [ { url = "https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d", size = 133271 }, ] @@ -1042,10 +1042,10 @@ wheels = [ name = "markdown-it-py" version = "3.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } dependencies = [ { name = "mdurl" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } wheels = [ { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, ] @@ -1082,7 +1082,6 @@ wheels = [ name = "matplotlib" version = "3.9.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/22/06/9e8ba6ec8b716a215404a5d1938b61f5a28001be493cf35344dda9a4072a/matplotlib-3.9.1.tar.gz", hash = "sha256:de06b19b8db95dd33d0dc17c926c7c9ebed9f572074b6fac4f65068a6814d010", size = 36084124 } dependencies = [ { name = "contourpy" }, { name = "cycler" }, @@ -1094,6 +1093,7 @@ dependencies = [ { name = "pyparsing" }, { name = "python-dateutil" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/22/06/9e8ba6ec8b716a215404a5d1938b61f5a28001be493cf35344dda9a4072a/matplotlib-3.9.1.tar.gz", hash = "sha256:de06b19b8db95dd33d0dc17c926c7c9ebed9f572074b6fac4f65068a6814d010", size = 36084124 } wheels = [ { url = "https://files.pythonhosted.org/packages/ce/f5/22d0f294a76cc65c431fb7f2146a96a4e12233c09cbce6285f74bb75db96/matplotlib-3.9.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b3fce58971b465e01b5c538f9d44915640c20ec5ff31346e963c9e1cd66fa812", size = 7902698 }, { url = "https://files.pythonhosted.org/packages/46/81/38bc95cf20ce6ed9dd5e7aec805bf1efc931e3fdeb9c5b593d00634a4747/matplotlib-3.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a973c53ad0668c53e0ed76b27d2eeeae8799836fd0d0caaa4ecc66bf4e6676c0", size = 7781109 }, @@ -1113,10 +1113,10 @@ wheels = [ name = "mdit-py-plugins" version = "0.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/6c/79c52651b22b64dba5c7bbabd7a294cc410bfb2353250dc8ade44d7d8ad8/mdit_py_plugins-0.4.1.tar.gz", hash = "sha256:834b8ac23d1cd60cec703646ffd22ae97b7955a6d596eb1d304be1e251ae499c", size = 42713 } dependencies = [ { name = "markdown-it-py" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/00/6c/79c52651b22b64dba5c7bbabd7a294cc410bfb2353250dc8ade44d7d8ad8/mdit_py_plugins-0.4.1.tar.gz", hash = "sha256:834b8ac23d1cd60cec703646ffd22ae97b7955a6d596eb1d304be1e251ae499c", size = 42713 } wheels = [ { url = "https://files.pythonhosted.org/packages/ef/f7/8a4dcea720a581e69ac8c5a38524baf0e3e2bb5f3819a9ff661464fe7d10/mdit_py_plugins-0.4.1-py3-none-any.whl", hash = "sha256:1020dfe4e6bfc2c79fb49ae4e3f5b297f5ccd20f010187acc52af2921e27dc6a", size = 54794 }, ] @@ -1172,7 +1172,6 @@ dependencies = [ name = "mkdocs" version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/6b/26b33cc8ad54e8bc0345cddc061c2c5c23e364de0ecd97969df23f95a673/mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512", size = 3888392 } dependencies = [ { name = "click" }, { name = "colorama", marker = "platform_system == 'Windows'" }, @@ -1188,6 +1187,7 @@ dependencies = [ { name = "pyyaml-env-tag" }, { name = "watchdog" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/cc/6b/26b33cc8ad54e8bc0345cddc061c2c5c23e364de0ecd97969df23f95a673/mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512", size = 3888392 } wheels = [ { url = "https://files.pythonhosted.org/packages/b8/c0/930dcf5a3e96b9c8e7ad15502603fc61d495479699e2d2c381e3d37294d1/mkdocs-1.6.0-py3-none-any.whl", hash = "sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7", size = 3862264 }, ] @@ -1196,12 +1196,12 @@ wheels = [ name = "mkdocs-get-deps" version = "0.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239 } dependencies = [ { name = "mergedeep" }, { name = "platformdirs" }, { name = "pyyaml" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239 } wheels = [ { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521 }, ] @@ -1210,7 +1210,6 @@ wheels = [ name = "mkdocs-terminal" version = "4.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/a4/afa8826c3d6971f3e93cb3669936b25579314fef2a4d648fe72729c9675f/mkdocs_terminal-4.4.0.tar.gz", hash = "sha256:d72b87b3d0edf470695811cb56c440a43b0387212590a5dfb2f26861c6e518d7", size = 619482 } dependencies = [ { name = "jinja2" }, { name = "markdown" }, @@ -1218,6 +1217,7 @@ dependencies = [ { name = "pygments" }, { name = "pymdown-extensions" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/b3/a4/afa8826c3d6971f3e93cb3669936b25579314fef2a4d648fe72729c9675f/mkdocs_terminal-4.4.0.tar.gz", hash = "sha256:d72b87b3d0edf470695811cb56c440a43b0387212590a5dfb2f26861c6e518d7", size = 619482 } wheels = [ { url = "https://files.pythonhosted.org/packages/93/65/7973dfe5ae03dd83a5a4e203b542ebacb16fd0c796e3f93f3cb98c3ffcc2/mkdocs_terminal-4.4.0-py3-none-any.whl", hash = "sha256:b2c94dc651c840e9762a1040d39371a31cc7482f7768e619e317419ebae4e40e", size = 641788 }, ] @@ -1226,22 +1226,22 @@ wheels = [ name = "mouseinfo" version = "0.1.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/28/fa/b2ba8229b9381e8f6381c1dcae6f4159a7f72349e414ed19cfbbd1817173/MouseInfo-0.1.3.tar.gz", hash = "sha256:2c62fb8885062b8e520a3cce0a297c657adcc08c60952eb05bc8256ef6f7f6e7", size = 10850 } dependencies = [ { name = "pyperclip" }, - { name = "python3-xlib", marker = "python_version >= '3.0' and platform_system == 'Linux'" }, + { name = "python3-xlib", marker = "platform_system == 'Linux'" }, { name = "rubicon-objc", marker = "platform_system == 'Darwin'" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/28/fa/b2ba8229b9381e8f6381c1dcae6f4159a7f72349e414ed19cfbbd1817173/MouseInfo-0.1.3.tar.gz", hash = "sha256:2c62fb8885062b8e520a3cce0a297c657adcc08c60952eb05bc8256ef6f7f6e7", size = 10850 } [[distribution]] name = "mpld3" version = "0.5.10" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/58/19378f4189a034eb3efc17b133426b8551af1d3b2c70d641a63124579629/mpld3-0.5.10.tar.gz", hash = "sha256:a478eb404fa5212505c59133cf272cd9a94105872e605597720e7f84de38fbc7", size = 1027709 } dependencies = [ { name = "jinja2" }, { name = "matplotlib" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/90/58/19378f4189a034eb3efc17b133426b8551af1d3b2c70d641a63124579629/mpld3-0.5.10.tar.gz", hash = "sha256:a478eb404fa5212505c59133cf272cd9a94105872e605597720e7f84de38fbc7", size = 1027709 } wheels = [ { url = "https://files.pythonhosted.org/packages/95/6a/e3691bcc47485f38b09853207c928130571821d187cf174eed5418d45e82/mpld3-0.5.10-py3-none-any.whl", hash = "sha256:80877acce87ea447380fad7374668737505c8c0684aab05238e7c5dc1fab38c1", size = 202561 }, ] @@ -1259,13 +1259,13 @@ wheels = [ name = "msal" version = "1.29.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/39/d8/438af3c52f48bab135edbd47f24447c4985ec81c122ebf36e027621f6742/msal-1.29.0.tar.gz", hash = "sha256:8f6725f099752553f9b2fe84125e2a5ebe47b49f92eacca33ebedd3a9ebaae25", size = 140817 } dependencies = [ { name = "cryptography" }, { name = "pyjwt" }, { name = "pyjwt", extra = "crypto" }, { name = "requests" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/39/d8/438af3c52f48bab135edbd47f24447c4985ec81c122ebf36e027621f6742/msal-1.29.0.tar.gz", hash = "sha256:8f6725f099752553f9b2fe84125e2a5ebe47b49f92eacca33ebedd3a9ebaae25", size = 140817 } wheels = [ { url = "https://files.pythonhosted.org/packages/c3/a7/5b51016902118052a1342e073138a319b758020cd66f3ee79a7e98e56d62/msal-1.29.0-py3-none-any.whl", hash = "sha256:6b301e63f967481f0cc1a3a3bac0cf322b276855bc1b0955468d9deb3f33d511", size = 110860 }, ] @@ -1274,11 +1274,11 @@ wheels = [ name = "msal-extensions" version = "1.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2d/38/ad49272d0a5af95f7a0cb64a79bbd75c9c187f3b789385a143d8d537a5eb/msal_extensions-1.2.0.tar.gz", hash = "sha256:6f41b320bfd2933d631a215c91ca0dd3e67d84bd1a2f50ce917d5874ec646bef", size = 22391 } dependencies = [ { name = "msal" }, { name = "portalocker" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/2d/38/ad49272d0a5af95f7a0cb64a79bbd75c9c187f3b789385a143d8d537a5eb/msal_extensions-1.2.0.tar.gz", hash = "sha256:6f41b320bfd2933d631a215c91ca0dd3e67d84bd1a2f50ce917d5874ec646bef", size = 22391 } wheels = [ { url = "https://files.pythonhosted.org/packages/2c/69/314d887a01599669fb330da14e5c6ff5f138609e322812a942a74ef9b765/msal_extensions-1.2.0-py3-none-any.whl", hash = "sha256:cf5ba83a2113fa6dc011a254a72f1c223c88d7dfad74cc30617c4679a417704d", size = 19254 }, ] @@ -1326,11 +1326,11 @@ wheels = [ name = "mypy" version = "1.10.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/b9/81e4c6dbb1ec1e72503de3ff2c5fe4b7f224e04613b670f8b9004cd8a4dd/mypy-1.10.1.tar.gz", hash = "sha256:1f8f492d7db9e3593ef42d4f115f04e556130f2819ad33ab84551403e97dd4c0", size = 3022304 } dependencies = [ { name = "mypy-extensions" }, { name = "typing-extensions" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/c7/b9/81e4c6dbb1ec1e72503de3ff2c5fe4b7f224e04613b670f8b9004cd8a4dd/mypy-1.10.1.tar.gz", hash = "sha256:1f8f492d7db9e3593ef42d4f115f04e556130f2819ad33ab84551403e97dd4c0", size = 3022304 } wheels = [ { url = "https://files.pythonhosted.org/packages/38/cf/0645128c6edf70eb9b9687ad42fcb61ea344a7927ed2b78ce2275282fe87/mypy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd6f629b67bb43dc0d9211ee98b96d8dabc97b1ad38b9b25f5e4c4d7569a0c6a", size = 10740526 }, { url = "https://files.pythonhosted.org/packages/19/c9/10842953066265e6063c41a85bbee3b877501947c970ea84a1db5f11d32e/mypy-1.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1bbb3a6f5ff319d2b9d40b4080d46cd639abe3516d5a62c070cf0114a457d84", size = 9898375 }, @@ -1358,7 +1358,6 @@ wheels = [ name = "myst-parser" version = "3.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/64/e2f13dac02f599980798c01156393b781aec983b52a6e4057ee58f07c43a/myst_parser-3.0.1.tar.gz", hash = "sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87", size = 92392 } dependencies = [ { name = "docutils" }, { name = "jinja2" }, @@ -1367,6 +1366,7 @@ dependencies = [ { name = "pyyaml" }, { name = "sphinx" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/49/64/e2f13dac02f599980798c01156393b781aec983b52a6e4057ee58f07c43a/myst_parser-3.0.1.tar.gz", hash = "sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87", size = 92392 } wheels = [ { url = "https://files.pythonhosted.org/packages/e2/de/21aa8394f16add8f7427f0a1326ccd2b3a2a8a3245c9252bc5ac034c6155/myst_parser-3.0.1-py3-none-any.whl", hash = "sha256:6457aaa33a5d474aca678b8ead9b3dc298e89c68e67012e73146ea6fd54babf1", size = 83163 }, ] @@ -1417,11 +1417,11 @@ wheels = [ name = "onnx" version = "1.16.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/74/be/242d02ebf7fe115bd695166eeea58b2206c9fa62de22cf9cbf8986fa8d27/onnx-1.16.1.tar.gz", hash = "sha256:8299193f0f2a3849bfc069641aa8e4f93696602da8d165632af8ee48ec7556b6", size = 12306956 } dependencies = [ { name = "numpy" }, { name = "protobuf" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/74/be/242d02ebf7fe115bd695166eeea58b2206c9fa62de22cf9cbf8986fa8d27/onnx-1.16.1.tar.gz", hash = "sha256:8299193f0f2a3849bfc069641aa8e4f93696602da8d165632af8ee48ec7556b6", size = 12306956 } wheels = [ { url = "https://files.pythonhosted.org/packages/17/ab/cea6c47f05b51046f4e7b523b817a99c736f9569c60613b53c03f5fff355/onnx-1.16.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:006ba5059c85ce43e89a1486cc0276d0f1a8ec9c6efd1a9334fd3fa0f6e33b64", size = 16504005 }, { url = "https://files.pythonhosted.org/packages/55/f8/fd7078f3c976209ff19e027eaabf1d1b0e35ffcdd48e37f9148767480bd1/onnx-1.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1521ea7cd3497ecaf57d3b5e72d637ca5ebca632122a0806a9df99bedbeecdf8", size = 15793779 }, @@ -1483,10 +1483,10 @@ wheels = [ name = "opencv-python-headless" version = "4.10.0.84" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2f/7e/d20f68a5f1487adf19d74378d349932a386b1ece3be9be9915e5986db468/opencv-python-headless-4.10.0.84.tar.gz", hash = "sha256:f2017c6101d7c2ef8d7bc3b414c37ff7f54d64413a1847d89970b6b7069b4e1a", size = 95117755 } dependencies = [ - { name = "numpy", marker = "python_version >= '3.7' or (python_version >= '3.6' and platform_machine == 'aarch64' and platform_system == 'Linux') or (python_version >= '3.10' and platform_system == 'Darwin')" }, + { name = "numpy" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/2f/7e/d20f68a5f1487adf19d74378d349932a386b1ece3be9be9915e5986db468/opencv-python-headless-4.10.0.84.tar.gz", hash = "sha256:f2017c6101d7c2ef8d7bc3b414c37ff7f54d64413a1847d89970b6b7069b4e1a", size = 95117755 } wheels = [ { url = "https://files.pythonhosted.org/packages/1c/9b/583c8d9259f6fc19413f83fd18dd8e6cbc8eefb0b4dc6da52dd151fe3272/opencv_python_headless-4.10.0.84-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a4f4bcb07d8f8a7704d9c8564c224c8b064c63f430e95b61ac0bffaa374d330e", size = 54835657 }, { url = "https://files.pythonhosted.org/packages/c0/7b/b4c67f5dad7a9a61c47f7a39e4050e8a4628bd64b3c3daaeb755d759f928/opencv_python_headless-4.10.0.84-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:5ae454ebac0eb0a0b932e3406370aaf4212e6a3fdb5038cc86c7aea15a6851da", size = 56475470 }, @@ -1554,7 +1554,6 @@ dev = [ { name = "opencv-python-headless" }, { name = "parameterized" }, { name = "pyautogui" }, - { name = "pygame" }, { name = "pyopencl", marker = "platform_machine != 'aarch64'" }, { name = "pyprof2calltree" }, { name = "pyqt5", marker = "platform_machine == 'x86_64'" }, @@ -1618,11 +1617,11 @@ wheels = [ name = "panda3d-gltf" version = "0.13" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/07/7f/9f18fc3fa843a080acb891af6bcc12262e7bdf1d194a530f7042bebfc81f/panda3d-gltf-0.13.tar.gz", hash = "sha256:d06d373bdd91cf530909b669f43080e599463bbf6d3ef00c3558bad6c6b19675", size = 25573 } dependencies = [ { name = "panda3d" }, { name = "panda3d-simplepbr" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/07/7f/9f18fc3fa843a080acb891af6bcc12262e7bdf1d194a530f7042bebfc81f/panda3d-gltf-0.13.tar.gz", hash = "sha256:d06d373bdd91cf530909b669f43080e599463bbf6d3ef00c3558bad6c6b19675", size = 25573 } wheels = [ { url = "https://files.pythonhosted.org/packages/70/94/98ed1f81ca0f5daf6de80533805cc1e98ac162abe4e3e1d382caa7ba5c3c/panda3d_gltf-0.13-py3-none-any.whl", hash = "sha256:02d1a980f447bb1895ff4b48c667f289ba78f07a28ef308d8839b665a621efe2", size = 25568 }, ] @@ -1631,11 +1630,11 @@ wheels = [ name = "panda3d-simplepbr" version = "0.12.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b1/af/505608eef09d7f9b822e69dc7631cd14102650b8fe1b6f60d9562d2788d9/panda3d-simplepbr-0.12.0.tar.gz", hash = "sha256:c71d490afeeb3a90455dcfde1d30c41f321a38742a97d18834e5c31016331ed5", size = 1929980 } dependencies = [ { name = "panda3d" }, { name = "typing-extensions" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/b1/af/505608eef09d7f9b822e69dc7631cd14102650b8fe1b6f60d9562d2788d9/panda3d-simplepbr-0.12.0.tar.gz", hash = "sha256:c71d490afeeb3a90455dcfde1d30c41f321a38742a97d18834e5c31016331ed5", size = 1929980 } wheels = [ { url = "https://files.pythonhosted.org/packages/46/4c/926e1cf17abfb1d91e12bf38e653cacf10e30c5030e37f9078f0f41aaf40/panda3d_simplepbr-0.12.0-py3-none-any.whl", hash = "sha256:6c43d1990ff07840cf1c557561d6122fd1250d8e76aacf227b61c3789149bcf9", size = 2458121 }, ] @@ -1644,13 +1643,13 @@ wheels = [ name = "pandas" version = "2.2.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/d9/ecf715f34c73ccb1d8ceb82fc01cd1028a65a5f6dbc57bfa6ea155119058/pandas-2.2.2.tar.gz", hash = "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54", size = 4398391 } dependencies = [ { name = "numpy", marker = "python_version == '3.11' or python_version >= '3.12'" }, { name = "python-dateutil" }, { name = "pytz" }, { name = "tzdata" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/88/d9/ecf715f34c73ccb1d8ceb82fc01cd1028a65a5f6dbc57bfa6ea155119058/pandas-2.2.2.tar.gz", hash = "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54", size = 4398391 } wheels = [ { url = "https://files.pythonhosted.org/packages/1b/70/61704497903d43043e288017cb2b82155c0d41e15f5c17807920877b45c2/pandas-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288", size = 12574808 }, { url = "https://files.pythonhosted.org/packages/16/c6/75231fd47afd6b3f89011e7077f1a3958441264aca7ae9ff596e3276a5d0/pandas-2.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151", size = 11304876 }, @@ -1749,10 +1748,10 @@ wheels = [ name = "portalocker" version = "2.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d5/2c/b565d42be77be6e642e9c193930258f25660a93900caca07c37ec107dd01/portalocker-2.10.0.tar.gz", hash = "sha256:49de8bc0a2f68ca98bf9e219c81a3e6b27097c7bf505a87c5a112ce1aaeb9b81", size = 40825 } dependencies = [ { name = "pywin32", marker = "platform_system == 'Windows'" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/d5/2c/b565d42be77be6e642e9c193930258f25660a93900caca07c37ec107dd01/portalocker-2.10.0.tar.gz", hash = "sha256:49de8bc0a2f68ca98bf9e219c81a3e6b27097c7bf505a87c5a112ce1aaeb9b81", size = 40825 } wheels = [ { url = "https://files.pythonhosted.org/packages/07/ff/52080172c7fdfa7c62f8cab014997178c19be9948607e977184dafc76522/portalocker-2.10.0-py3-none-any.whl", hash = "sha256:48944147b2cd42520549bc1bb8fe44e220296e56f7c3d551bc6ecce69d9b0de1", size = 18430 }, ] @@ -1761,7 +1760,6 @@ wheels = [ name = "pre-commit" version = "3.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/46/cc214ef6514270328910083d0119d0a80a6d2c4ec8c6608c0219db0b74cf/pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a", size = 177317 } dependencies = [ { name = "cfgv" }, { name = "identify" }, @@ -1769,6 +1767,7 @@ dependencies = [ { name = "pyyaml" }, { name = "virtualenv" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/aa/46/cc214ef6514270328910083d0119d0a80a6d2c4ec8c6608c0219db0b74cf/pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a", size = 177317 } wheels = [ { url = "https://files.pythonhosted.org/packages/b9/0f/d6d0b4e2f5b2933a557087fc0560371aa545a18232d4d3427eb3bb3af12e/pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5", size = 204268 }, ] @@ -1814,10 +1813,10 @@ wheels = [ name = "pyarrow" version = "16.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1a/f2/67533f116deb6dae7a0ac04681695fe06135912253a115c5ecdc714a32d4/pyarrow-16.1.0.tar.gz", hash = "sha256:15fbb22ea96d11f0b5768504a3f961edab25eaf4197c341720c4a387f6c60315", size = 1080280 } dependencies = [ { name = "numpy" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/1a/f2/67533f116deb6dae7a0ac04681695fe06135912253a115c5ecdc714a32d4/pyarrow-16.1.0.tar.gz", hash = "sha256:15fbb22ea96d11f0b5768504a3f961edab25eaf4197c341720c4a387f6c60315", size = 1080280 } wheels = [ { url = "https://files.pythonhosted.org/packages/28/17/a12aaddb818b7b73d17f3304afc22bce32ccb26723b507cc9c267aa809f3/pyarrow-16.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:d0ebea336b535b37eee9eee31761813086d33ed06de9ab6fc6aaa0bace7b250c", size = 28380406 }, { url = "https://files.pythonhosted.org/packages/f3/94/4e2a579bbac1adb19e63b054b300f6f7fa04f32f212ce86c18727bdda698/pyarrow-16.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e73cfc4a99e796727919c5541c65bb88b973377501e39b9842ea71401ca6c1c", size = 26040531 }, @@ -1851,7 +1850,6 @@ wheels = [ name = "pyautogui" version = "0.9.54" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/ff/cdae0a8c2118a0de74b6cf4cbcdcaf8fd25857e6c3f205ce4b1794b27814/PyAutoGUI-0.9.54.tar.gz", hash = "sha256:dd1d29e8fd118941cb193f74df57e5c6ff8e9253b99c7b04f39cfc69f3ae04b2", size = 61236 } dependencies = [ { name = "mouseinfo" }, { name = "pygetwindow" }, @@ -1859,9 +1857,10 @@ dependencies = [ { name = "pyobjc-core", marker = "platform_system == 'Darwin'" }, { name = "pyobjc-framework-quartz", marker = "platform_system == 'Darwin'" }, { name = "pyscreeze" }, - { name = "python3-xlib", marker = "python_version >= '3.0' and platform_system == 'Linux'" }, + { name = "python3-xlib", marker = "platform_system == 'Linux'" }, { name = "pytweening" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/65/ff/cdae0a8c2118a0de74b6cf4cbcdcaf8fd25857e6c3f205ce4b1794b27814/PyAutoGUI-0.9.54.tar.gz", hash = "sha256:dd1d29e8fd118941cb193f74df57e5c6ff8e9253b99c7b04f39cfc69f3ae04b2", size = 61236 } [[distribution]] name = "pycapnp" @@ -1932,10 +1931,10 @@ wheels = [ name = "pyee" version = "11.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/22/b4c7f3d9579204a014c4eda0e019e6bfe56af52a96cacc82004b60eec079/pyee-11.1.0.tar.gz", hash = "sha256:b53af98f6990c810edd9b56b87791021a8f54fd13db4edd1142438d44ba2263f", size = 29806 } dependencies = [ { name = "typing-extensions" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/f7/22/b4c7f3d9579204a014c4eda0e019e6bfe56af52a96cacc82004b60eec079/pyee-11.1.0.tar.gz", hash = "sha256:b53af98f6990c810edd9b56b87791021a8f54fd13db4edd1142438d44ba2263f", size = 29806 } wheels = [ { url = "https://files.pythonhosted.org/packages/16/cc/5cea8a0a0d3deb90b5a0d39ad1a6a1ccaa40a9ea86d793eb8a49d32a6ed0/pyee-11.1.0-py3-none-any.whl", hash = "sha256:5d346a7d0f861a4b2e6c47960295bd895f816725b27d656181947346be98d7c1", size = 15263 }, ] @@ -1966,10 +1965,10 @@ wheels = [ name = "pygetwindow" version = "0.0.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e1/70/c7a4f46dbf06048c6d57d9489b8e0f9c4c3d36b7479f03c5ca97eaa2541d/PyGetWindow-0.0.9.tar.gz", hash = "sha256:17894355e7d2b305cd832d717708384017c1698a90ce24f6f7fbf0242dd0a688", size = 9699 } dependencies = [ { name = "pyrect" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/e1/70/c7a4f46dbf06048c6d57d9489b8e0f9c4c3d36b7479f03c5ca97eaa2541d/PyGetWindow-0.0.9.tar.gz", hash = "sha256:17894355e7d2b305cd832d717708384017c1698a90ce24f6f7fbf0242dd0a688", size = 9699 } [[distribution]] name = "pygments" @@ -1998,10 +1997,10 @@ crypto = [ name = "pylibsrtp" version = "0.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6b/ae/c95199144eed954976223bdce3f94564eb6c43567111aff8048a26a429bd/pylibsrtp-0.10.0.tar.gz", hash = "sha256:d8001912d7f51bd05b4ea3551747930631777fd37892cf3bfe0e541a742e699f", size = 10557 } dependencies = [ { name = "cffi" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/6b/ae/c95199144eed954976223bdce3f94564eb6c43567111aff8048a26a429bd/pylibsrtp-0.10.0.tar.gz", hash = "sha256:d8001912d7f51bd05b4ea3551747930631777fd37892cf3bfe0e541a742e699f", size = 10557 } wheels = [ { url = "https://files.pythonhosted.org/packages/1c/d2/ffc24f80e83a54d9b309cdae6b31cf9294b4f3a85ab107827fd272d1e687/pylibsrtp-0.10.0-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6a1121ceea3339e0a84842a4a9da0fcf57cc8f99eb60dbf31a46d978b4170e7c", size = 1704188 }, { url = "https://files.pythonhosted.org/packages/66/3e/db86a09a5cb290a274f76ce25f4fae3a7e3c4a4dbc64baf7e2aaa57a32bb/pylibsrtp-0.10.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ca1994e73c6857b0a695fdde94cc5ac846c1b0d5d8766255a1dc2db40857f667", size = 2028580 }, @@ -2016,11 +2015,11 @@ wheels = [ name = "pymdown-extensions" version = "10.8.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/09/11/0a1da270c1011194a6efee7ec1ac07d8b75a9706eed4a80675403f6a9d70/pymdown_extensions-10.8.1.tar.gz", hash = "sha256:3ab1db5c9e21728dabf75192d71471f8e50f216627e9a1fa9535ecb0231b9940", size = 812097 } dependencies = [ { name = "markdown" }, { name = "pyyaml" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/09/11/0a1da270c1011194a6efee7ec1ac07d8b75a9706eed4a80675403f6a9d70/pymdown_extensions-10.8.1.tar.gz", hash = "sha256:3ab1db5c9e21728dabf75192d71471f8e50f216627e9a1fa9535ecb0231b9940", size = 812097 } wheels = [ { url = "https://files.pythonhosted.org/packages/c6/d7/e19f9bee2729a8d65b9bf822bb69ac364bf782bac8d761c62b4252769ae0/pymdown_extensions-10.8.1-py3-none-any.whl", hash = "sha256:f938326115884f48c6059c67377c46cf631c733ef3629b6eed1349989d1b30cb", size = 250833 }, ] @@ -2050,7 +2049,6 @@ sdist = { url = "https://files.pythonhosted.org/packages/7d/ff/4c6f31a4f08979f12 name = "pyobjc" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/20/722e33f62631370c1475d773cadf4290d3c6f3a0e9d025fa6e2528270eaa/pyobjc-10.3.1.tar.gz", hash = "sha256:476dd5c72394e4cfcdac6dfd756839011a0159353247f45e3e07cc0b3536c9d4", size = 10975 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-accessibility", marker = "platform_release >= '20.0'" }, @@ -2207,6 +2205,7 @@ dependencies = [ { name = "pyobjc-framework-vision", marker = "platform_release >= '17.0'" }, { name = "pyobjc-framework-webkit" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/e0/20/722e33f62631370c1475d773cadf4290d3c6f3a0e9d025fa6e2528270eaa/pyobjc-10.3.1.tar.gz", hash = "sha256:476dd5c72394e4cfcdac6dfd756839011a0159353247f45e3e07cc0b3536c9d4", size = 10975 } wheels = [ { url = "https://files.pythonhosted.org/packages/cb/a5/4b9ed66894d804dc57c13b7fdb8f65ed831f13514216ce736e1455dfe214/pyobjc-10.3.1-py3-none-any.whl", hash = "sha256:dfa9ff44a353b9d0bf1245c25c94d1eee6d0cb26d9c5433bbcd67a265f7654ae", size = 4050 }, ] @@ -2226,12 +2225,12 @@ wheels = [ name = "pyobjc-framework-accessibility" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/20/18a45998ae8bf9ce532a29f8eaebdaa7f15a7f77b3c34a8304714b393166/pyobjc_framework_accessibility-10.3.1.tar.gz", hash = "sha256:c973306417441e6bed5f9be6154e6399aa7f38fa9b6bcf3368fa42d92ef3030b", size = 29349 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/24/20/18a45998ae8bf9ce532a29f8eaebdaa7f15a7f77b3c34a8304714b393166/pyobjc_framework_accessibility-10.3.1.tar.gz", hash = "sha256:c973306417441e6bed5f9be6154e6399aa7f38fa9b6bcf3368fa42d92ef3030b", size = 29349 } wheels = [ { url = "https://files.pythonhosted.org/packages/1f/be/f20998cbba98386a47784ea9b7738c6b6d106f1dd30a7f99387e7ee5bb53/pyobjc_framework_Accessibility-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:4a1b10d2098b5e3887d4e52b13c2d7619f248ceeaa4e78bb21c51c25c7d391c3", size = 10723 }, { url = "https://files.pythonhosted.org/packages/50/36/6afe05e0ebf8b194d7d26730fa39b09279e7f819945c909875cbc7435b6d/pyobjc_framework_Accessibility-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4926eeef40d750215f0787d2124407a4c65bc03407e402ea47901b713e8765e5", size = 10781 }, @@ -2243,11 +2242,11 @@ wheels = [ name = "pyobjc-framework-accounts" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cf/be/a4e4eeebfa140f0e00fe2fb882802cc4a5fa7f12c7fea01e35314fcf276c/pyobjc_framework_accounts-10.3.1.tar.gz", hash = "sha256:3d55738e7b3290af8cd4993fd2b670242a952deb995a69911be2a1be4c509a86", size = 16180 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/cf/be/a4e4eeebfa140f0e00fe2fb882802cc4a5fa7f12c7fea01e35314fcf276c/pyobjc_framework_accounts-10.3.1.tar.gz", hash = "sha256:3d55738e7b3290af8cd4993fd2b670242a952deb995a69911be2a1be4c509a86", size = 16180 } wheels = [ { url = "https://files.pythonhosted.org/packages/27/8c/23a9128a0252d6ef7643edd5c90d18699fb7a8ae9849e47806408d3d15d2/pyobjc_framework_Accounts-10.3.1-py2.py3-none-any.whl", hash = "sha256:451488f91263afd23233287f223ba00c0ee5c93d64cd10e133d72bc6a0fc48aa", size = 4727 }, ] @@ -2256,11 +2255,11 @@ wheels = [ name = "pyobjc-framework-addressbook" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/0a/68769f71cbf9f46070059def94a5c7b0b218626652d7aa589e15f4e8b876/pyobjc_framework_addressbook-10.3.1.tar.gz", hash = "sha256:cde99b855c39b56ca52479b0a1e2daa3ef5de12cebfe780c3c802a5f59a484cc", size = 84696 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/21/0a/68769f71cbf9f46070059def94a5c7b0b218626652d7aa589e15f4e8b876/pyobjc_framework_addressbook-10.3.1.tar.gz", hash = "sha256:cde99b855c39b56ca52479b0a1e2daa3ef5de12cebfe780c3c802a5f59a484cc", size = 84696 } wheels = [ { url = "https://files.pythonhosted.org/packages/1b/11/7843baf1041c7c42e272178eb0f1f6b19bd1460e59a4515741b8e553375d/pyobjc_framework_AddressBook-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:02ab8cb2300d55beaddee4f113a5c4a78ef737eda6c704678487529e391062e2", size = 13244 }, { url = "https://files.pythonhosted.org/packages/e3/29/d1ccc5aaf041d68f35f64df1ba0acd5c3d8b13f3deaf4b3ac94b8f67e792/pyobjc_framework_AddressBook-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:1cfa893c21920f5420f3e57da314315e92c855a83f0718482dc33bdb859b9f24", size = 13302 }, @@ -2272,11 +2271,11 @@ wheels = [ name = "pyobjc-framework-adservices" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ab/9b/eaeb7c8f30899979113b91d8317efd30743d335bdaaa8fb88434e7bf7616/pyobjc_framework_adservices-10.3.1.tar.gz", hash = "sha256:28123eb111d023f708e1d86f5f3f76bd4f6bb0d932466863f84b3e322b11537a", size = 11838 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/ab/9b/eaeb7c8f30899979113b91d8317efd30743d335bdaaa8fb88434e7bf7616/pyobjc_framework_adservices-10.3.1.tar.gz", hash = "sha256:28123eb111d023f708e1d86f5f3f76bd4f6bb0d932466863f84b3e322b11537a", size = 11838 } wheels = [ { url = "https://files.pythonhosted.org/packages/c7/85/bfd64830a47b363ae31e2366ec68da065c35abd9fc08adaa4cd6daa48d42/pyobjc_framework_AdServices-10.3.1-py2.py3-none-any.whl", hash = "sha256:c839c4267ad8443393e4d138396026764ee43776164da8a8ed9ac248b7d9c0d9", size = 3105 }, ] @@ -2285,11 +2284,11 @@ wheels = [ name = "pyobjc-framework-adsupport" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/87/cf/9b40ef87f1315858e3dce9f807b359e43a6183616a6a8d2caab533d49a3e/pyobjc_framework_adsupport-10.3.1.tar.gz", hash = "sha256:ba85a00cf20c42501d8083092f7ca0fcd1e616b1725e6512e75bcb60a6d58528", size = 11991 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/87/cf/9b40ef87f1315858e3dce9f807b359e43a6183616a6a8d2caab533d49a3e/pyobjc_framework_adsupport-10.3.1.tar.gz", hash = "sha256:ba85a00cf20c42501d8083092f7ca0fcd1e616b1725e6512e75bcb60a6d58528", size = 11991 } wheels = [ { url = "https://files.pythonhosted.org/packages/20/3e/3d43c0a398390c358a777fec7ccf9cf94523cc41618a59fcf72dc2172990/pyobjc_framework_AdSupport-10.3.1-py2.py3-none-any.whl", hash = "sha256:0e403ec206ada472b2c0b129ed656342a97c20110ca8398ab907100516b0e48c", size = 3018 }, ] @@ -2298,11 +2297,11 @@ wheels = [ name = "pyobjc-framework-applescriptkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/c4/42e37476f31dddecb3d7b83b076d5e94b754837e2326b0218227b20f96ec/pyobjc_framework_applescriptkit-10.3.1.tar.gz", hash = "sha256:add2e63598b699666bcf00ac59f6f1046266df1665bec71b142cd21b89037064", size = 11779 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/5c/c4/42e37476f31dddecb3d7b83b076d5e94b754837e2326b0218227b20f96ec/pyobjc_framework_applescriptkit-10.3.1.tar.gz", hash = "sha256:add2e63598b699666bcf00ac59f6f1046266df1665bec71b142cd21b89037064", size = 11779 } wheels = [ { url = "https://files.pythonhosted.org/packages/0c/0b/6638a036e5e4b8451d9c5e96da5ec1bfcf4bee68b09b2e28158445d767e4/pyobjc_framework_AppleScriptKit-10.3.1-py2.py3-none-any.whl", hash = "sha256:97ce878ff334b6853405a62e164debb9e6695110e64db5ed596008c0fde84970", size = 3930 }, ] @@ -2311,11 +2310,11 @@ wheels = [ name = "pyobjc-framework-applescriptobjc" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/80/9e/db9d93764db336ed53da548cd7b52b6fbd7d493101b801b164f5c1f5fce8/pyobjc_framework_applescriptobjc-10.3.1.tar.gz", hash = "sha256:a87101d86b08e06e2c0e51630ac76d4c70f01cf1ed7af281f3138e63146e279b", size = 11797 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/80/9e/db9d93764db336ed53da548cd7b52b6fbd7d493101b801b164f5c1f5fce8/pyobjc_framework_applescriptobjc-10.3.1.tar.gz", hash = "sha256:a87101d86b08e06e2c0e51630ac76d4c70f01cf1ed7af281f3138e63146e279b", size = 11797 } wheels = [ { url = "https://files.pythonhosted.org/packages/94/1f/700ba04ece5f7c654cd58617a26427a0337e21003f1efd38132af48e0427/pyobjc_framework_AppleScriptObjC-10.3.1-py2.py3-none-any.whl", hash = "sha256:2d64c74a4af48656bb407eb177fe5f1d3c0f7bd9c578e5583dffde8e3d55f5df", size = 4027 }, ] @@ -2324,13 +2323,13 @@ wheels = [ name = "pyobjc-framework-applicationservices" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/a6/3704b63c6e844739e3b7e324d1268fb6f7cb485550267719660779266c60/pyobjc_framework_applicationservices-10.3.1.tar.gz", hash = "sha256:f27cb64aa4d129ce671fd42638c985eb2a56d544214a95fe3214a007eacc4790", size = 182738 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-coretext" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/66/a6/3704b63c6e844739e3b7e324d1268fb6f7cb485550267719660779266c60/pyobjc_framework_applicationservices-10.3.1.tar.gz", hash = "sha256:f27cb64aa4d129ce671fd42638c985eb2a56d544214a95fe3214a007eacc4790", size = 182738 } wheels = [ { url = "https://files.pythonhosted.org/packages/78/24/31fdd15f88d3a0a88ba88b27d1f134c7819221886bf56644af12fe672c6d/pyobjc_framework_ApplicationServices-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d886ba1f65df47b77ff7546f3fc9bc7d08cfb6b3c04433b719f6b0689a2c0d1f", size = 31029 }, { url = "https://files.pythonhosted.org/packages/af/01/bf2d335e3f176227a142f466419a9400dd752e7f02f03674a276f39c1d78/pyobjc_framework_ApplicationServices-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:be157f2c3ffb254064ef38249670af8cada5e519a714d2aa5da3740934d89bc8", size = 31072 }, @@ -2341,11 +2340,11 @@ wheels = [ name = "pyobjc-framework-apptrackingtransparency" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/75/63/b7039473d92211938645c44069b2e8bc65eefc229a3aac1ff8ccf0f13415/pyobjc_framework_apptrackingtransparency-10.3.1.tar.gz", hash = "sha256:2e381db5f7d3985207b5ff2975e41bf0f9147080345b2e1b4b242f8799290d04", size = 12547 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/75/63/b7039473d92211938645c44069b2e8bc65eefc229a3aac1ff8ccf0f13415/pyobjc_framework_apptrackingtransparency-10.3.1.tar.gz", hash = "sha256:2e381db5f7d3985207b5ff2975e41bf0f9147080345b2e1b4b242f8799290d04", size = 12547 } wheels = [ { url = "https://files.pythonhosted.org/packages/f2/ab/7be81bd560ea539f5fa39c81c55af759d69a667ad9bb81efb2094e8a7b1c/pyobjc_framework_AppTrackingTransparency-10.3.1-py2.py3-none-any.whl", hash = "sha256:7c0e3a5cad402e8c3c5da1f070be0f49bb827e6d9e5165744f64e082633a4b45", size = 3459 }, ] @@ -2354,11 +2353,11 @@ wheels = [ name = "pyobjc-framework-audiovideobridging" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/f8/437666f24f295986ad9ea77a694f7db98889a8367fad46d93b84ae028e28/pyobjc_framework_audiovideobridging-10.3.1.tar.gz", hash = "sha256:b2c1d5977a92915f6af2203e3b4c9b8a8392bc51e0fc13ccb393589419387119", size = 59209 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/f9/f8/437666f24f295986ad9ea77a694f7db98889a8367fad46d93b84ae028e28/pyobjc_framework_audiovideobridging-10.3.1.tar.gz", hash = "sha256:b2c1d5977a92915f6af2203e3b4c9b8a8392bc51e0fc13ccb393589419387119", size = 59209 } wheels = [ { url = "https://files.pythonhosted.org/packages/82/ec/da418b96f03e5dd7d0bf0974843292756d89dd9e2604384e5da802332ffd/pyobjc_framework_AudioVideoBridging-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4f6067b2f50fb48c9ecb521b8865d93dfbd46510a4322cc2041b1e917678f39b", size = 11124 }, { url = "https://files.pythonhosted.org/packages/2f/5b/f03579fb2c77b72981beab1cbb58d9f02ea6a7d0309a9fb4e859a6ede73b/pyobjc_framework_AudioVideoBridging-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1aebc6c1aafb3cdfc5f9fad2dfe2dfccfbab159dc8dbfe54cfea777108e80e44", size = 11152 }, @@ -2369,11 +2368,11 @@ wheels = [ name = "pyobjc-framework-authenticationservices" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/3b/12082a13266fed356222a5c6c3eaf6ddcf21099f7a5b76b3fff58568042a/pyobjc_framework_authenticationservices-10.3.1.tar.gz", hash = "sha256:0ac834f4a5cbe3cf20acd4f6a96df77bc643a1ae248e394d06964db9fe0d6310", size = 86405 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/35/3b/12082a13266fed356222a5c6c3eaf6ddcf21099f7a5b76b3fff58568042a/pyobjc_framework_authenticationservices-10.3.1.tar.gz", hash = "sha256:0ac834f4a5cbe3cf20acd4f6a96df77bc643a1ae248e394d06964db9fe0d6310", size = 86405 } wheels = [ { url = "https://files.pythonhosted.org/packages/ce/f3/7e2ed16674d77f7f124d9aed88e44d420c1de9bf405fe3a020fa4550ffc5/pyobjc_framework_AuthenticationServices-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:fa0a11fb64e30f14f01ec2d3a2a89a3e1a554db62111b0612f1782722b6dd534", size = 19963 }, { url = "https://files.pythonhosted.org/packages/87/8c/51425897927005f8d42b26fd1c5ce6b934dcff287f3d643b21cba2a8fcd2/pyobjc_framework_AuthenticationServices-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:e2753cdd5480f97753dc32d9f41d7e6cb75b09f7ce950b2eea4a9851e0a437db", size = 19902 }, @@ -2385,11 +2384,11 @@ wheels = [ name = "pyobjc-framework-automaticassessmentconfiguration" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/67/0d/19f8aee86e91da5a9f6954870f21d839b835a20e84eb2221b839797be705/pyobjc_framework_automaticassessmentconfiguration-10.3.1.tar.gz", hash = "sha256:f7846d04493e90eddbacfb7cffebc11b3f76f0800d3dc2bec39441732a20ac56", size = 22477 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/67/0d/19f8aee86e91da5a9f6954870f21d839b835a20e84eb2221b839797be705/pyobjc_framework_automaticassessmentconfiguration-10.3.1.tar.gz", hash = "sha256:f7846d04493e90eddbacfb7cffebc11b3f76f0800d3dc2bec39441732a20ac56", size = 22477 } wheels = [ { url = "https://files.pythonhosted.org/packages/c4/ce/ebe221179d1e860ade2128f8a5bce3da22df1db4f4abe567197620abda7a/pyobjc_framework_AutomaticAssessmentConfiguration-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:f717f6df5886123a55584f8dd85626c42387f5b55edcd3d68ff306b3fe56a206", size = 8590 }, { url = "https://files.pythonhosted.org/packages/6a/14/c929d3ef97471462292072011e2ad228516892b6e0077f0b6ea62adc0c27/pyobjc_framework_AutomaticAssessmentConfiguration-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:ab84a771835f346e8a45d19e05f0c2ef8bb3dca81461fb2acc6c9f031794ec63", size = 8637 }, @@ -2401,11 +2400,11 @@ wheels = [ name = "pyobjc-framework-automator" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/ca/fe39648043bf7ab2e5f09707cca9254277555c1a09973ade71fc029f7dff/pyobjc_framework_automator-10.3.1.tar.gz", hash = "sha256:330042475479f054ac98abd568b523fc0165c39eeefffc23bd65d35780939316", size = 195097 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/88/ca/fe39648043bf7ab2e5f09707cca9254277555c1a09973ade71fc029f7dff/pyobjc_framework_automator-10.3.1.tar.gz", hash = "sha256:330042475479f054ac98abd568b523fc0165c39eeefffc23bd65d35780939316", size = 195097 } wheels = [ { url = "https://files.pythonhosted.org/packages/46/d9/129cbbf10c38b8a9f907cbfbb44dc9746861c3a2d306d49963e401016480/pyobjc_framework_Automator-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:63632d2c1d069ca29a077b15ab20a0a0acc0a5f33ee322c9c8cc854702c66549", size = 10019 }, { url = "https://files.pythonhosted.org/packages/41/a7/745ae406ed296d4503556a5e8697bdad6ac9004e01a55a598aef660915fb/pyobjc_framework_Automator-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4bc8afe0a52bee09f7f99bdfc62100654f08113de47e74488c0af2afcd646e23", size = 10077 }, @@ -2417,7 +2416,6 @@ wheels = [ name = "pyobjc-framework-avfoundation" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5b/4f/0f509c925c28d4b0ea709ccb9fd9a229c6552187f7506aa1e583d66cf658/pyobjc_framework_avfoundation-10.3.1.tar.gz", hash = "sha256:2f94bee3a4217b46d9416cad066e4f357bf0f344079c328736114451ae19ae94", size = 695146 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, @@ -2425,6 +2423,7 @@ dependencies = [ { name = "pyobjc-framework-coremedia" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/5b/4f/0f509c925c28d4b0ea709ccb9fd9a229c6552187f7506aa1e583d66cf658/pyobjc_framework_avfoundation-10.3.1.tar.gz", hash = "sha256:2f94bee3a4217b46d9416cad066e4f357bf0f344079c328736114451ae19ae94", size = 695146 } wheels = [ { url = "https://files.pythonhosted.org/packages/a9/62/5b7cfc6ea3d5df7d61b29eb6572ef4abc8027af5538ceff4f2582f672bcb/pyobjc_framework_AVFoundation-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:0896f6650df35f0229d1fb3aa3fbf632647dd815d4921cb61d9eb7fa26be6237", size = 67777 }, { url = "https://files.pythonhosted.org/packages/0c/34/2f0e42bfedf3d15381944940bded10266d25f8843f2aed85ac731d880dd5/pyobjc_framework_AVFoundation-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:0cb27cc95288d95df7504adf474596f8855de7fa7798bbc1bbfbdfbbcb940952", size = 67973 }, @@ -2436,12 +2435,12 @@ wheels = [ name = "pyobjc-framework-avkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/de/7de605cea8176d69a41503dd544c0af02760c4518be3049b877563cc0c36/pyobjc_framework_avkit-10.3.1.tar.gz", hash = "sha256:97ca35b5f0cec98f5c8521fedb8537bb23d82739b7102e4ac732d3c3944c8ccc", size = 38986 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/b5/de/7de605cea8176d69a41503dd544c0af02760c4518be3049b877563cc0c36/pyobjc_framework_avkit-10.3.1.tar.gz", hash = "sha256:97ca35b5f0cec98f5c8521fedb8537bb23d82739b7102e4ac732d3c3944c8ccc", size = 38986 } wheels = [ { url = "https://files.pythonhosted.org/packages/22/b3/76c4c4a6455928f130aa08d121ef717536e77d58fb6013f7d3fd609bbc8a/pyobjc_framework_AVKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:bb6025331e5ed493d5ca0a35fab14026820e0d8b0a091fc6010b4ef77aa4bf16", size = 12368 }, { url = "https://files.pythonhosted.org/packages/3a/42/d683ad96e4b51cccbd99109c7fa5350a841015844fe0e042df040d4f8ad6/pyobjc_framework_AVKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:675832ec9c088c2010bd9cd9f912ff5c45ff608d7d94233347d49f1b91f690ca", size = 12418 }, @@ -2453,11 +2452,11 @@ wheels = [ name = "pyobjc-framework-avrouting" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/d5/b3012c90b18722b9d8e27f6a570ac534da89e4902bf5805f0bb39e340891/pyobjc_framework_avrouting-10.3.1.tar.gz", hash = "sha256:7026059b24daf8e1da05d7867f450e82abe412fe5c438faf9344f46e3b83da39", size = 18663 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/66/d5/b3012c90b18722b9d8e27f6a570ac534da89e4902bf5805f0bb39e340891/pyobjc_framework_avrouting-10.3.1.tar.gz", hash = "sha256:7026059b24daf8e1da05d7867f450e82abe412fe5c438faf9344f46e3b83da39", size = 18663 } wheels = [ { url = "https://files.pythonhosted.org/packages/d0/58/b01ddd24cb808eca3ef0254cc6e00fb47c53ce41c18f37ac23ea64db4cd7/pyobjc_framework_AVRouting-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:30b05ea44f21d481e39905684c79176c04060e0e92c1ad31756fed6aa39b07df", size = 8260 }, { url = "https://files.pythonhosted.org/packages/9f/e3/d814c295e9a4f4cf8c8f283371a42c992b0996b96a99bbda7e2e8efa2976/pyobjc_framework_AVRouting-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:af940e322cb9ce9d79b47b829c5df41ac4980aca2cda1fbe1ead4ed0f9f589a4", size = 8314 }, @@ -2469,11 +2468,11 @@ wheels = [ name = "pyobjc-framework-backgroundassets" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bb/be/6a0039ac75e7d9b84f7250d2301e0fe6529c0db6c137e398e31d04f65629/pyobjc_framework_backgroundassets-10.3.1.tar.gz", hash = "sha256:5e1198f81db6f30ead2a55e8ea39264f9fce83dcf8e31a68e5f0ea08c5cfe9b5", size = 21762 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/bb/be/6a0039ac75e7d9b84f7250d2301e0fe6529c0db6c137e398e31d04f65629/pyobjc_framework_backgroundassets-10.3.1.tar.gz", hash = "sha256:5e1198f81db6f30ead2a55e8ea39264f9fce83dcf8e31a68e5f0ea08c5cfe9b5", size = 21762 } wheels = [ { url = "https://files.pythonhosted.org/packages/53/b0/8de66724de73e39c00ccddfd4f8d56eac4ea9da810fc79a86ef59b522621/pyobjc_framework_BackgroundAssets-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:f725d33a5d633c514e4973489e1bdca391976a5c04443451acaaacc5ccd4095e", size = 9684 }, { url = "https://files.pythonhosted.org/packages/cd/bb/d3de8275de550fae2bb0263252fb784859f5ed07cf43783f1a243d5e9766/pyobjc_framework_BackgroundAssets-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:14cc84ad7bef64986fe240d23205870fc40dd7b1d2a1819d3dd7924c4898b5c2", size = 9743 }, @@ -2485,7 +2484,6 @@ wheels = [ name = "pyobjc-framework-browserenginekit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/48/09/61f1688824a500f74e4fee94cec3ec3bef87e58a5205026761e4d292f027/pyobjc_framework_browserenginekit-10.3.1.tar.gz", hash = "sha256:0f6ea100bcf06f2b3f915dab27cf2f038698b39510fb47d3769f72ff62c1e80b", size = 21016 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, @@ -2493,6 +2491,7 @@ dependencies = [ { name = "pyobjc-framework-coremedia" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/48/09/61f1688824a500f74e4fee94cec3ec3bef87e58a5205026761e4d292f027/pyobjc_framework_browserenginekit-10.3.1.tar.gz", hash = "sha256:0f6ea100bcf06f2b3f915dab27cf2f038698b39510fb47d3769f72ff62c1e80b", size = 21016 } wheels = [ { url = "https://files.pythonhosted.org/packages/e7/fa/fb104e8dba10800982d499da02d2422a9faef685438a12c9e899385693c1/pyobjc_framework_BrowserEngineKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:86c92ef4e79db4066f7887426e99cfec8902fc8949fb666359cf2a9e519106fc", size = 10579 }, { url = "https://files.pythonhosted.org/packages/68/a4/85deec80d0b26a31ddf830039448ef4d98a74f21ce9c817fb88147fc275c/pyobjc_framework_BrowserEngineKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:69766ba235976e0a1961d3925228d2ef12808298acd0cd66fe9e883424f0f9a4", size = 10639 }, @@ -2504,11 +2503,11 @@ wheels = [ name = "pyobjc-framework-businesschat" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/19/7414a07489dbeef3b1bd40845cb9bd0e035062da3879ca20fb01a7901302/pyobjc_framework_businesschat-10.3.1.tar.gz", hash = "sha256:53e52981f9da336fcaf6783e82509e06faf8868931213ac70e6bd7395a5859a4", size = 12088 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/a5/19/7414a07489dbeef3b1bd40845cb9bd0e035062da3879ca20fb01a7901302/pyobjc_framework_businesschat-10.3.1.tar.gz", hash = "sha256:53e52981f9da336fcaf6783e82509e06faf8868931213ac70e6bd7395a5859a4", size = 12088 } wheels = [ { url = "https://files.pythonhosted.org/packages/85/0e/b3f16873394b9d88c3217a5fe3e736e36af049f813c18af5a1bf38279cd8/pyobjc_framework_BusinessChat-10.3.1-py2.py3-none-any.whl", hash = "sha256:952b60f558e3d3498e6191d717bf62c1803f4e1ad040ae29d130090671ec004f", size = 3088 }, ] @@ -2517,11 +2516,11 @@ wheels = [ name = "pyobjc-framework-calendarstore" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/10/85/c4bb713e7e4d3f197ac975f5425ecf5469c1ea91d7b80d32eb4437b004f4/pyobjc_framework_calendarstore-10.3.1.tar.gz", hash = "sha256:21f627b0afb9a667794b451dd3a03f12ea3f74358dc5977c33b8ecc8b9736c27", size = 62920 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/10/85/c4bb713e7e4d3f197ac975f5425ecf5469c1ea91d7b80d32eb4437b004f4/pyobjc_framework_calendarstore-10.3.1.tar.gz", hash = "sha256:21f627b0afb9a667794b451dd3a03f12ea3f74358dc5977c33b8ecc8b9736c27", size = 62920 } wheels = [ { url = "https://files.pythonhosted.org/packages/e3/7f/2e3325244afa35fa610757a7f0488965b6fe89504d13ad2325527f515139/pyobjc_framework_CalendarStore-10.3.1-py2.py3-none-any.whl", hash = "sha256:7afb59e793ea6d28706423faa50bb1f25532d8ed7388c8540596ce41891445ca", size = 4865 }, ] @@ -2530,11 +2529,11 @@ wheels = [ name = "pyobjc-framework-callkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d3/b2/be5cf42e2b288073fa5d693d869ac2fbfb091a34e8edd5aa67f50fa6982f/pyobjc_framework_callkit-10.3.1.tar.gz", hash = "sha256:350390023e9ac98ff6c91b1f51da2489eef2e23aa649d0f63c13cf1d8be1e0df", size = 31907 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/d3/b2/be5cf42e2b288073fa5d693d869ac2fbfb091a34e8edd5aa67f50fa6982f/pyobjc_framework_callkit-10.3.1.tar.gz", hash = "sha256:350390023e9ac98ff6c91b1f51da2489eef2e23aa649d0f63c13cf1d8be1e0df", size = 31907 } wheels = [ { url = "https://files.pythonhosted.org/packages/92/01/4e419642221949f459459633be2e0ef456c7cdb8fb02644a805b31008e86/pyobjc_framework_CallKit-10.3.1-py2.py3-none-any.whl", hash = "sha256:495354bea298efdc81c970154083b83aff985f2c294d4883a62de3cc4129e34e", size = 4916 }, ] @@ -2543,11 +2542,11 @@ wheels = [ name = "pyobjc-framework-cfnetwork" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fb/e6/e1d6b0d0b21ba5241712389aea46dba4ee9d5c955738076f5ec9d75b5f29/pyobjc_framework_cfnetwork-10.3.1.tar.gz", hash = "sha256:0e4c51a75dbf4e2b1c0d4ee60a363f9d31d682d2dd2f6b74aded769d2d883aa8", size = 66882 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/fb/e6/e1d6b0d0b21ba5241712389aea46dba4ee9d5c955738076f5ec9d75b5f29/pyobjc_framework_cfnetwork-10.3.1.tar.gz", hash = "sha256:0e4c51a75dbf4e2b1c0d4ee60a363f9d31d682d2dd2f6b74aded769d2d883aa8", size = 66882 } wheels = [ { url = "https://files.pythonhosted.org/packages/2b/0a/1e8ecd8604952650c38b53469c2a383c341e99e0a559cb8a6a8c9a178826/pyobjc_framework_CFNetwork-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:e6027a90c5442e36a4ef91c9e10896efb5bc1bb4743d732adf3422112922f6cf", size = 18955 }, { url = "https://files.pythonhosted.org/packages/cf/25/90a071f9ca9dd35bbb0d86246be3a99e71386aa7ee8ed7a31ba151110e89/pyobjc_framework_CFNetwork-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:dff41296378029f1a5e9cedbc133b243f096a93fcc8d6985c555459328cfe11e", size = 19011 }, @@ -2559,7 +2558,6 @@ wheels = [ name = "pyobjc-framework-cinematic" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2a/83/90a5f31fd89bfa030c812c869ab69cf0e333e13ee2e3c1e4877ed883d6d3/pyobjc_framework_cinematic-10.3.1.tar.gz", hash = "sha256:7edaaa7e325aeb39cd0c33329c25783dd54af294229884556daad36d1d1b9d72", size = 19342 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-avfoundation" }, @@ -2567,6 +2565,7 @@ dependencies = [ { name = "pyobjc-framework-coremedia" }, { name = "pyobjc-framework-metal" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/2a/83/90a5f31fd89bfa030c812c869ab69cf0e333e13ee2e3c1e4877ed883d6d3/pyobjc_framework_cinematic-10.3.1.tar.gz", hash = "sha256:7edaaa7e325aeb39cd0c33329c25783dd54af294229884556daad36d1d1b9d72", size = 19342 } wheels = [ { url = "https://files.pythonhosted.org/packages/8f/d1/cc9c887e748d172fc0928f0d80cf03f598daba9757ea08187e6295d6dc4c/pyobjc_framework_Cinematic-10.3.1-py2.py3-none-any.whl", hash = "sha256:48bf35d594f4f010266a028bbf93bd953cc78db7658d3c614e219b482c8d73b2", size = 4193 }, ] @@ -2575,11 +2574,11 @@ wheels = [ name = "pyobjc-framework-classkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/b8/cc33b734656f6617394b410a9805d05511aecdb665591936acfd66060dfd/pyobjc_framework_classkit-10.3.1.tar.gz", hash = "sha256:e15700d32007bf77c5c740bc9931c864bb7739cdfcd2b0595377c3ed35ecfe25", size = 32503 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/a9/b8/cc33b734656f6617394b410a9805d05511aecdb665591936acfd66060dfd/pyobjc_framework_classkit-10.3.1.tar.gz", hash = "sha256:e15700d32007bf77c5c740bc9931c864bb7739cdfcd2b0595377c3ed35ecfe25", size = 32503 } wheels = [ { url = "https://files.pythonhosted.org/packages/2b/a1/b18ea640218aaa4e3005b02eaa68eb10cd8e5036a38eb15cedff2055a380/pyobjc_framework_ClassKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:980d2605296428d177b0111af914d0dd4a0c5116da5ae944cdd8b6bba733e758", size = 8390 }, { url = "https://files.pythonhosted.org/packages/93/ae/e15dbc7c011b6c047754a4638baa9c870006544b66f792534e60403decf3/pyobjc_framework_ClassKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:17dec45d5ec7db663bc87ddf80b8185d2134177f265a12a9a6df778901183412", size = 8442 }, @@ -2591,7 +2590,6 @@ wheels = [ name = "pyobjc-framework-cloudkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/84/2d/22c51450dddeb9d851529f90ebd4f15fc12a4f3c9b2ceae4df8841fde64e/pyobjc_framework_cloudkit-10.3.1.tar.gz", hash = "sha256:4c7db72c2bb2fcf63365df91bf2eefa83cee4004606b901e1da89b75da652309", size = 98916 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-accounts" }, @@ -2599,6 +2597,7 @@ dependencies = [ { name = "pyobjc-framework-coredata" }, { name = "pyobjc-framework-corelocation" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/84/2d/22c51450dddeb9d851529f90ebd4f15fc12a4f3c9b2ceae4df8841fde64e/pyobjc_framework_cloudkit-10.3.1.tar.gz", hash = "sha256:4c7db72c2bb2fcf63365df91bf2eefa83cee4004606b901e1da89b75da652309", size = 98916 } wheels = [ { url = "https://files.pythonhosted.org/packages/a1/68/49c0dac7cf069a13352e9bb7092aa0a0caeb5646e2c3a7b9eabfb07279ce/pyobjc_framework_CloudKit-10.3.1-py2.py3-none-any.whl", hash = "sha256:53670f47320063b80aa60edd2d813308dce85dfd2112461dd13c060aa9e5b47a", size = 10475 }, ] @@ -2607,10 +2606,10 @@ wheels = [ name = "pyobjc-framework-cocoa" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/6c/b62e31e6e00f24e70b62f680e35a0d663ba14ff7601ae591b5d20e251161/pyobjc_framework_cocoa-10.3.1.tar.gz", hash = "sha256:1cf20714daaa986b488fb62d69713049f635c9d41a60c8da97d835710445281a", size = 4941542 } dependencies = [ { name = "pyobjc-core" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/a7/6c/b62e31e6e00f24e70b62f680e35a0d663ba14ff7601ae591b5d20e251161/pyobjc_framework_cocoa-10.3.1.tar.gz", hash = "sha256:1cf20714daaa986b488fb62d69713049f635c9d41a60c8da97d835710445281a", size = 4941542 } wheels = [ { url = "https://files.pythonhosted.org/packages/d4/ad/436c3619d1a84f83d55ff9c709b122e4d1ac2ee9af467b68fcb60e5ad3a6/pyobjc_framework_Cocoa-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5f31021f4f8fdf873b57a97ee1f3c1620dbe285e0b4eaed73dd0005eb72fd773", size = 396142 }, { url = "https://files.pythonhosted.org/packages/29/73/9a913537d6d63758243f76a3d3acbae8eb77705c278eceaf37198e58dcf5/pyobjc_framework_Cocoa-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:11b4e0bad4bbb44a4edda128612f03cdeab38644bbf174de0c13129715497296", size = 396183 }, @@ -2621,11 +2620,11 @@ wheels = [ name = "pyobjc-framework-collaboration" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0d/cd/8bc8e3c4cf93b1044d5e582904ec5c55656f4385bd25f86f924b4ed25ae3/pyobjc_framework_collaboration-10.3.1.tar.gz", hash = "sha256:bbca3de3679b058cbb89ad911e3bdfe491a02b4fa219d5f9219c022774ba237a", size = 15830 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/0d/cd/8bc8e3c4cf93b1044d5e582904ec5c55656f4385bd25f86f924b4ed25ae3/pyobjc_framework_collaboration-10.3.1.tar.gz", hash = "sha256:bbca3de3679b058cbb89ad911e3bdfe491a02b4fa219d5f9219c022774ba237a", size = 15830 } wheels = [ { url = "https://files.pythonhosted.org/packages/a0/c0/b26f50c0669f49fa652a96b6496deba5c9181ddec5ac59c4de8251666857/pyobjc_framework_Collaboration-10.3.1-py2.py3-none-any.whl", hash = "sha256:889b1e00bdea09c2423e9b8d493492ec45a70787ddc533bf67d060c7ec0e1f78", size = 4490 }, ] @@ -2634,11 +2633,11 @@ wheels = [ name = "pyobjc-framework-colorsync" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/16/b5cf65d3cdae2127a868e06b21e9c59e2ef531e65c4ee58afcaef2c4fe69/pyobjc_framework_colorsync-10.3.1.tar.gz", hash = "sha256:180960ed6f76084b35073eff49fcca41a8fa883c3236949a40f75daa28ee8f94", size = 31940 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/43/16/b5cf65d3cdae2127a868e06b21e9c59e2ef531e65c4ee58afcaef2c4fe69/pyobjc_framework_colorsync-10.3.1.tar.gz", hash = "sha256:180960ed6f76084b35073eff49fcca41a8fa883c3236949a40f75daa28ee8f94", size = 31940 } wheels = [ { url = "https://files.pythonhosted.org/packages/2c/3e/273fcd5803daf481ecc3d76adafd455040375acd63582e501cb3e2717de3/pyobjc_framework_ColorSync-10.3.1-py2.py3-none-any.whl", hash = "sha256:0c37075e9b0f1dabc0aa1755687e1a5dada08ae0914ebb593c7810bf8090cf83", size = 5599 }, ] @@ -2647,11 +2646,11 @@ wheels = [ name = "pyobjc-framework-contacts" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/a9/112ee53259220322f6729c446fd7b779d3bae7b24804bd342f51764dc6bc/pyobjc_framework_contacts-10.3.1.tar.gz", hash = "sha256:7120b5593a20e936cb5589b93ef7fd5558c86bd6ec8003f427afb87c04bbea20", size = 68431 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/eb/a9/112ee53259220322f6729c446fd7b779d3bae7b24804bd342f51764dc6bc/pyobjc_framework_contacts-10.3.1.tar.gz", hash = "sha256:7120b5593a20e936cb5589b93ef7fd5558c86bd6ec8003f427afb87c04bbea20", size = 68431 } wheels = [ { url = "https://files.pythonhosted.org/packages/c5/f9/7efe17e729ed96aac2618c24513c95bdf61762d2f7e9a288f4c290e32e3d/pyobjc_framework_Contacts-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:401e40ff638712d011fe54c7b1e9929af994e87cb03d129cd95df2fb90439e4e", size = 12768 }, { url = "https://files.pythonhosted.org/packages/6f/e9/b13466931afbe95b5acd368ad0f177e530e458a76f8a7a2f1fb54f58b465/pyobjc_framework_Contacts-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:83de186cd4037171c63899987caa66cc01527688b15176e899cf1a06e6baab09", size = 12769 }, @@ -2663,12 +2662,12 @@ wheels = [ name = "pyobjc-framework-contactsui" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ad/17/ce9b512e29ca92eb519328d0fc1e12b6b048ac379447c7f4f2be4266599e/pyobjc_framework_contactsui-10.3.1.tar.gz", hash = "sha256:51601501d5bc94c59ad458c7bb1d1994c497b373307dad8bd2ea2aa348f66c4a", size = 17921 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-contacts" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/ad/17/ce9b512e29ca92eb519328d0fc1e12b6b048ac379447c7f4f2be4266599e/pyobjc_framework_contactsui-10.3.1.tar.gz", hash = "sha256:51601501d5bc94c59ad458c7bb1d1994c497b373307dad8bd2ea2aa348f66c4a", size = 17921 } wheels = [ { url = "https://files.pythonhosted.org/packages/9b/d0/67150306b40068d05cb7794ed5762fe85c5d9eb0a6148b1860d7fab3cab1/pyobjc_framework_ContactsUI-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:0e939e46ccff1e07e7fa6768a35d646b7302886a99b9efe6b31dea4ea67674ad", size = 7906 }, { url = "https://files.pythonhosted.org/packages/48/7e/2a9b1e4ae673406bad4278126491a818e2a55e4791c7cec62487947f1096/pyobjc_framework_ContactsUI-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4adc77f2fb7ae4e2999cfd72f5d3b8e0e039880f9d60cb8e15050607b249c730", size = 7965 }, @@ -2680,11 +2679,11 @@ wheels = [ name = "pyobjc-framework-coreaudio" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c5/fe/39351e6a58f4a9b1fce5a5e982830612277233084fe72b1d84b4de890f3b/pyobjc_framework_coreaudio-10.3.1.tar.gz", hash = "sha256:c81c709bf955aea474a4de380b187f3c2e56c864ca7de520b08362b73070c795", size = 125676 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/c5/fe/39351e6a58f4a9b1fce5a5e982830612277233084fe72b1d84b4de890f3b/pyobjc_framework_coreaudio-10.3.1.tar.gz", hash = "sha256:c81c709bf955aea474a4de380b187f3c2e56c864ca7de520b08362b73070c795", size = 125676 } wheels = [ { url = "https://files.pythonhosted.org/packages/6f/dd/e4be148694e5e73885aaf00a92720293674fd510d87369cf5ba300f24660/pyobjc_framework_CoreAudio-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bd58e69cabbc987d0c2854ab2d13516889cfe4a2094b80296591ad7df0f30e40", size = 35672 }, { url = "https://files.pythonhosted.org/packages/21/1c/af5e88a24dc7f437852a9605949c5eeaedb7bba9883b2c3cd275dea3729b/pyobjc_framework_CoreAudio-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e0aeca61a425d846afc92350ffba970e1e503469182f5f0ea436de98cfd00d96", size = 36444 }, @@ -2695,12 +2694,12 @@ wheels = [ name = "pyobjc-framework-coreaudiokit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1f/4e/79a20d1ab459467de5695f96057e034d6457b061da68951b41af211b1fe3/pyobjc_framework_coreaudiokit-10.3.1.tar.gz", hash = "sha256:81f35d5dc45cda043e01f0ca045311f4aebc36c51cb71e859b30ea0edf90b3db", size = 19761 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-coreaudio" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/1f/4e/79a20d1ab459467de5695f96057e034d6457b061da68951b41af211b1fe3/pyobjc_framework_coreaudiokit-10.3.1.tar.gz", hash = "sha256:81f35d5dc45cda043e01f0ca045311f4aebc36c51cb71e859b30ea0edf90b3db", size = 19761 } wheels = [ { url = "https://files.pythonhosted.org/packages/13/d3/6cc3624b3dfc5f5d25221e8b46d456c5f3f1bbefe9fc1a9a030406a31ddf/pyobjc_framework_CoreAudioKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:dfc967bc448cc0a1fce932e6af15ad42f5ea3eb2f793396e364cf39005c812eb", size = 7331 }, { url = "https://files.pythonhosted.org/packages/e6/2e/45509db91d9fcb0df6e1a24884596e2e560f20d6083a06f6bf9e72e42b84/pyobjc_framework_CoreAudioKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:6634f3f15d257e93cad4644eb08f5b32376e8a8a7ae2e95d99d36d935b5e9ba2", size = 7395 }, @@ -2712,11 +2711,11 @@ wheels = [ name = "pyobjc-framework-corebluetooth" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/69/89afd7747f42d2eb1e8f4b7f2ba2739d98ccf36f6b5c72474802962494de/pyobjc_framework_corebluetooth-10.3.1.tar.gz", hash = "sha256:dc5d326ab5541b8b68e7e920aa8363851e779cb8c33842f6cfeef4674cc62f94", size = 50210 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/f7/69/89afd7747f42d2eb1e8f4b7f2ba2739d98ccf36f6b5c72474802962494de/pyobjc_framework_corebluetooth-10.3.1.tar.gz", hash = "sha256:dc5d326ab5541b8b68e7e920aa8363851e779cb8c33842f6cfeef4674cc62f94", size = 50210 } wheels = [ { url = "https://files.pythonhosted.org/packages/33/2f/b34311bc453472e34c7a9473b1da21d79f7126d61f95d85e7d679cbd98c1/pyobjc_framework_CoreBluetooth-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:c89ee6fba0ed359c46b4908a7d01f88f133be025bd534cbbf4fb9c183e62fc97", size = 14052 }, { url = "https://files.pythonhosted.org/packages/af/a2/946a7099d5181ebfa59eb390471b30b51f04da935f8ef8d9a9ac3a102e13/pyobjc_framework_CoreBluetooth-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2f261a386aa6906f9d4601d35ff71a13315dbca1a0698bf1f1ecfe3971de4648", size = 14102 }, @@ -2728,11 +2727,11 @@ wheels = [ name = "pyobjc-framework-coredata" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/17/1929fabc88d265373ce2b5e5c3136aae03c30ee42df66bd0810fa71328da/pyobjc_framework_coredata-10.3.1.tar.gz", hash = "sha256:8a75094942c8f3ddc1bcbde920c87658d7bb4c7534a4652e60db42d17f4b4a4a", size = 229850 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/cc/17/1929fabc88d265373ce2b5e5c3136aae03c30ee42df66bd0810fa71328da/pyobjc_framework_coredata-10.3.1.tar.gz", hash = "sha256:8a75094942c8f3ddc1bcbde920c87658d7bb4c7534a4652e60db42d17f4b4a4a", size = 229850 } wheels = [ { url = "https://files.pythonhosted.org/packages/e6/18/5662deb09d3bff1390f6eab760f0e806a91d604d867960978245304a44ca/pyobjc_framework_CoreData-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:2313aba4236f3a909d2747f4327da83be884adadb734a602ed4319addf88edd7", size = 16618 }, { url = "https://files.pythonhosted.org/packages/51/69/d07e0b235e22dbe33cf5fc7b377828a0965ca4eb156ba7db1ba380c79a20/pyobjc_framework_CoreData-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:065ff3058f4bc8544422ad1f10dff037bdeed25263cc8ec5c609e54231bf9347", size = 16675 }, @@ -2744,11 +2743,11 @@ wheels = [ name = "pyobjc-framework-corehaptics" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6b/04/ef530d0c30cf81a772ddee64cbfeb7cafd9428d87df96bbc6eb41b77d80f/pyobjc_framework_corehaptics-10.3.1.tar.gz", hash = "sha256:5a7cc117c0b64428e1f08dc9c8b76dbc5d8f61f80dc41e911d11ddee4e0e2059", size = 36854 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/6b/04/ef530d0c30cf81a772ddee64cbfeb7cafd9428d87df96bbc6eb41b77d80f/pyobjc_framework_corehaptics-10.3.1.tar.gz", hash = "sha256:5a7cc117c0b64428e1f08dc9c8b76dbc5d8f61f80dc41e911d11ddee4e0e2059", size = 36854 } wheels = [ { url = "https://files.pythonhosted.org/packages/2b/70/b41b0423b1dce4c98e87787c5af254275ad88db1a781eca5d8d440a4c882/pyobjc_framework_CoreHaptics-10.3.1-py2.py3-none-any.whl", hash = "sha256:163b83ea727cbac5c0963d16ffda89c9f1626ed633d5e52830c7918b8599a693", size = 4987 }, ] @@ -2757,11 +2756,11 @@ wheels = [ name = "pyobjc-framework-corelocation" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/06/35/8cf7ab8f9b7be5b81deac4d74fdc89607a3eeb901f785cc7d50332eaa275/pyobjc_framework_corelocation-10.3.1.tar.gz", hash = "sha256:8ae54e5bd4c07f7224639d815f7a6537fadee17c11cb35dd99c2804bac1825ab", size = 89219 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/06/35/8cf7ab8f9b7be5b81deac4d74fdc89607a3eeb901f785cc7d50332eaa275/pyobjc_framework_corelocation-10.3.1.tar.gz", hash = "sha256:8ae54e5bd4c07f7224639d815f7a6537fadee17c11cb35dd99c2804bac1825ab", size = 89219 } wheels = [ { url = "https://files.pythonhosted.org/packages/7a/a0/9268f18f0daec40460590a724eef778f6012d81da3e4c668b478486288f4/pyobjc_framework_CoreLocation-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:4cc83a730db7f78ca5ceef45ea4c992084d8c90bed189939fa3f51f8e9ea83ae", size = 12928 }, { url = "https://files.pythonhosted.org/packages/e9/e3/16b8d53786cee07c496d614ca29aeb1e110a93fea501983b54158d23622e/pyobjc_framework_CoreLocation-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:97d5aa35214e417c9a03ac7209630dc445b98652932642dd0497f1ec52624bfe", size = 12978 }, @@ -2773,11 +2772,11 @@ wheels = [ name = "pyobjc-framework-coremedia" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/68/9f/5e500c16472053db65dc917b7ea9cdc0fa8fde140ea4c38500a4c341b0a4/pyobjc_framework_coremedia-10.3.1.tar.gz", hash = "sha256:bc3e0cddf5f546b5d8407d8f46b203f1bd4396ad5dbfdc0d064a560b3fe31221", size = 180773 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/68/9f/5e500c16472053db65dc917b7ea9cdc0fa8fde140ea4c38500a4c341b0a4/pyobjc_framework_coremedia-10.3.1.tar.gz", hash = "sha256:bc3e0cddf5f546b5d8407d8f46b203f1bd4396ad5dbfdc0d064a560b3fe31221", size = 180773 } wheels = [ { url = "https://files.pythonhosted.org/packages/3b/99/5ca053be93f30cb8420b72a1e7eefb778677e072f86ea2525dd6d848ae88/pyobjc_framework_CoreMedia-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e63b002cf5e34540cba3f3a1704603ea0fb076ffc1ea42c2393a0679f40846de", size = 29040 }, { url = "https://files.pythonhosted.org/packages/9e/2f/2b118b5f3c8fe955efd466398d519ffeb2e02e2957ae61953f8f4df0c798/pyobjc_framework_CoreMedia-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c6eaf48f202becab10679e3b5dd62607ddec2739495db45882524592cabf3997", size = 29052 }, @@ -2788,11 +2787,11 @@ wheels = [ name = "pyobjc-framework-coremediaio" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/08/67/1c22ff55baf5018d3ca4979f8c319e055ecff8b51ea91d53b8654503cc35/pyobjc_framework_coremediaio-10.3.1.tar.gz", hash = "sha256:5da3ed78475223dd3400fdb55fb97d543a248086f5cf8b77bf4aceac3df1513c", size = 88655 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/08/67/1c22ff55baf5018d3ca4979f8c319e055ecff8b51ea91d53b8654503cc35/pyobjc_framework_coremediaio-10.3.1.tar.gz", hash = "sha256:5da3ed78475223dd3400fdb55fb97d543a248086f5cf8b77bf4aceac3df1513c", size = 88655 } wheels = [ { url = "https://files.pythonhosted.org/packages/9b/0b/80fcc75ecd8afb2f3966146985716e165321bbbcf00bdce2119feaf3be9e/pyobjc_framework_CoreMediaIO-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:07e19e89489a372ebea9e8a5cfaf1ec03fd570e65ed3fa2dfa44719d1e337a36", size = 17233 }, { url = "https://files.pythonhosted.org/packages/92/5d/14312b4d3f8108124bdf69d2f5aa49d73a9c537e2ae44da698c618e66ab9/pyobjc_framework_CoreMediaIO-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c3bc3d8f3648b6a4126983119d9fc4e21d2c7ec06beb284c57039ca1033ceb03", size = 17284 }, @@ -2804,11 +2803,11 @@ wheels = [ name = "pyobjc-framework-coremidi" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bf/9f/38d8668499e0c590e51b3f3091d972e09a1f45e4efba94373c22d23d2b88/pyobjc_framework_coremidi-10.3.1.tar.gz", hash = "sha256:818454b56edae082a3a4b4366a7e93b8bb54856be01ee21bb8527a22a4732efc", size = 78441 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/bf/9f/38d8668499e0c590e51b3f3091d972e09a1f45e4efba94373c22d23d2b88/pyobjc_framework_coremidi-10.3.1.tar.gz", hash = "sha256:818454b56edae082a3a4b4366a7e93b8bb54856be01ee21bb8527a22a4732efc", size = 78441 } wheels = [ { url = "https://files.pythonhosted.org/packages/1d/67/9800fbbfec104699c2d03adde3fa26ec5c60505f2005abb9fc37c841096a/pyobjc_framework_CoreMIDI-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:00a6869c2365b90cdf6e1ed0bbde6d87fe4daaa40ed243ee810e3cc3945f185a", size = 17489 }, { url = "https://files.pythonhosted.org/packages/3c/0d/d8adf38ed03bf331934635dc1dc6e9c636b08df5bccdaa55db6d1e85a789/pyobjc_framework_CoreMIDI-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:92d04962f7ea63be03127880d4659f718f5b44b6a57a0e619a96d9def619bddb", size = 17870 }, @@ -2820,11 +2819,11 @@ wheels = [ name = "pyobjc-framework-coreml" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5b/a2/08a73df17f344700f48444e3000ebdf0ca78765bf0816387de7392380255/pyobjc_framework_coreml-10.3.1.tar.gz", hash = "sha256:6b7091142cfaafee76f1a804329e7a4e3aeca921eea8644e9ceba4cc2751f705", size = 66750 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/5b/a2/08a73df17f344700f48444e3000ebdf0ca78765bf0816387de7392380255/pyobjc_framework_coreml-10.3.1.tar.gz", hash = "sha256:6b7091142cfaafee76f1a804329e7a4e3aeca921eea8644e9ceba4cc2751f705", size = 66750 } wheels = [ { url = "https://files.pythonhosted.org/packages/a9/93/fd46439a3d974e4c9bde868b056410abfcb897d30ddb58a0ebf31116fa5d/pyobjc_framework_CoreML-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:c1fdcc0487807afa9cd0f88f25697e0e2e093d0219e8e1aa42aa3674dd78c2cb", size = 11647 }, { url = "https://files.pythonhosted.org/packages/d5/7d/b875857b4116e68ecead251e53ef9f456650d4e740903e73775bea459bd0/pyobjc_framework_CoreML-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:21c87e84c807b5dbe61e0f016d9aefa32d3212f175cc4b976b5c08770be7a58c", size = 11707 }, @@ -2836,11 +2835,11 @@ wheels = [ name = "pyobjc-framework-coremotion" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/77/cef3cee6010e926754cc80faa455b5a7530d740f9b5a83a94fd4bd34484a/pyobjc_framework_coremotion-10.3.1.tar.gz", hash = "sha256:6ba61ffd360473b018702b9ae025eb16b8aaa45c6e533121522f26eef93a9f71", size = 54459 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/6c/77/cef3cee6010e926754cc80faa455b5a7530d740f9b5a83a94fd4bd34484a/pyobjc_framework_coremotion-10.3.1.tar.gz", hash = "sha256:6ba61ffd360473b018702b9ae025eb16b8aaa45c6e533121522f26eef93a9f71", size = 54459 } wheels = [ { url = "https://files.pythonhosted.org/packages/c9/7a/c208726685a2bae7edd597d6209f275d5052e3244ebed3d8c0f9b2e3de5a/pyobjc_framework_CoreMotion-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a003478eeb520c7f28be4d9dc8f9e02df6ffa8921d46c8879e2b298c9fbc6926", size = 9805 }, { url = "https://files.pythonhosted.org/packages/d3/2c/dda7dbf8ffd5ae61986b2201ded7c600da7d6e3edab967065317a5b233e1/pyobjc_framework_CoreMotion-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:63c8f831ad522212627f99ae8d6f34161628230afd544203646e7d66596d6437", size = 9835 }, @@ -2851,12 +2850,12 @@ wheels = [ name = "pyobjc-framework-coreservices" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/c6/9214c4e64a22e92233f67f6518dc60269b30b317a169861f8cb8150adaef/pyobjc_framework_coreservices-10.3.1.tar.gz", hash = "sha256:2e46d008ee4ff586420175888c45f8eb0f002ed5b840c8f7893c560af01b2d72", size = 859909 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-fsevents" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/18/c6/9214c4e64a22e92233f67f6518dc60269b30b317a169861f8cb8150adaef/pyobjc_framework_coreservices-10.3.1.tar.gz", hash = "sha256:2e46d008ee4ff586420175888c45f8eb0f002ed5b840c8f7893c560af01b2d72", size = 859909 } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/a5/63364d45385f91a8026130d32b64e8b5a392865e4bde54a6acb7a7124a2e/pyobjc_framework_CoreServices-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:58d5708ee0a2ad7eea180864fe68123a2464b987ea089d0646ce69e2002500b0", size = 29708 }, { url = "https://files.pythonhosted.org/packages/81/d8/d657d510b9655ab5a6b8ab4b45727f7164288a57dd20ced9f5a4ee5a98a9/pyobjc_framework_CoreServices-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:9d43b77fa11af139ba39d94921e695cf804226737f68167f8bdb8f1c449c932e", size = 29825 }, @@ -2868,11 +2867,11 @@ wheels = [ name = "pyobjc-framework-corespotlight" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9f/fa/e0ef8d255265a2aaa575244df3d629c46a4eda6c64a210a9faf62fd70772/pyobjc_framework_corespotlight-10.3.1.tar.gz", hash = "sha256:6b8ad243a65943d631434a9ff4696458cdd3d0cb631cfeb501a967fe29445c30", size = 69476 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/9f/fa/e0ef8d255265a2aaa575244df3d629c46a4eda6c64a210a9faf62fd70772/pyobjc_framework_corespotlight-10.3.1.tar.gz", hash = "sha256:6b8ad243a65943d631434a9ff4696458cdd3d0cb631cfeb501a967fe29445c30", size = 69476 } wheels = [ { url = "https://files.pythonhosted.org/packages/8b/80/d84bc74e1feca7d54ff3fe18d28abe2304a0eb01eb1e6df540d176fdc51e/pyobjc_framework_CoreSpotlight-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:4aa9b01b8d722ba9e803ec4a2329ee8da0bdecb9a004a668b793b957544a6d81", size = 9615 }, { url = "https://files.pythonhosted.org/packages/b2/b5/706eea1e71054177e2e7cd3a48eb40471a8b48b7199453b05a0239eb388f/pyobjc_framework_CoreSpotlight-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:9684f735fd3d3e8fae447e90a2c246bf6a8d4ca37f619174208d65daa86d9ca0", size = 9675 }, @@ -2884,12 +2883,12 @@ wheels = [ name = "pyobjc-framework-coretext" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9e/9f/d363cb1548808f538d7ae267a9fcb999dfb5693056fdaa5bc93de089cfef/pyobjc_framework_coretext-10.3.1.tar.gz", hash = "sha256:b8fa2d5078ed774431ae64ba886156e319aec0b8c6cc23dabfd86778265b416f", size = 233428 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/9e/9f/d363cb1548808f538d7ae267a9fcb999dfb5693056fdaa5bc93de089cfef/pyobjc_framework_coretext-10.3.1.tar.gz", hash = "sha256:b8fa2d5078ed774431ae64ba886156e319aec0b8c6cc23dabfd86778265b416f", size = 233428 } wheels = [ { url = "https://files.pythonhosted.org/packages/0e/f6/ccc934adf50fa77c7d7d8bdb13ede25d1a0a62c67fec571ae2bd8557c41d/pyobjc_framework_CoreText-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:834142a14235bd80edaef8d3a28d1e203ed3c988810a9b78005df7c561390288", size = 30266 }, { url = "https://files.pythonhosted.org/packages/66/8e/4341253c550d6cf4da1a8c33d8d310b6ddbbaaea09eca26ea5eaff176e4b/pyobjc_framework_CoreText-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ae6c09d29eeaf30a67aa70e08a465b1f1e47d12e22b3a34ae8bc8fdb7e2e7342", size = 30404 }, @@ -2900,11 +2899,11 @@ wheels = [ name = "pyobjc-framework-corewlan" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9f/b0/6e708d931e85db91de439c080d3af77422d7935b7527ce81888f8ff6ed8b/pyobjc_framework_corewlan-10.3.1.tar.gz", hash = "sha256:d340d976b5d072b917c6d3de130cb4e7a944ee0fdf4e1335b2aa6b1d4d6b4e14", size = 57781 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/9f/b0/6e708d931e85db91de439c080d3af77422d7935b7527ce81888f8ff6ed8b/pyobjc_framework_corewlan-10.3.1.tar.gz", hash = "sha256:d340d976b5d072b917c6d3de130cb4e7a944ee0fdf4e1335b2aa6b1d4d6b4e14", size = 57781 } wheels = [ { url = "https://files.pythonhosted.org/packages/1b/a3/4afc5aaae025cd2367ecf267a9dbe68c5e62290c70046063658972f5699b/pyobjc_framework_CoreWLAN-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:0b9b9a6f54c11b6adcb04eb07686c8a8372140619876073d6355498da7ecd074", size = 10060 }, { url = "https://files.pythonhosted.org/packages/9f/fa/8be58eaab2a6c3159f3a048394ee9d85910e03ebb3e9e03630cc76baf1f0/pyobjc_framework_CoreWLAN-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:8d68dabd2fdb74e5263f1e05fa039621c197907347e045cd672a54b3ac537140", size = 10110 }, @@ -2916,11 +2915,11 @@ wheels = [ name = "pyobjc-framework-cryptotokenkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/07/15/49981d93f8402c655cbda9181a55e0f5879715d3f6c344070ba41d2511f1/pyobjc_framework_cryptotokenkit-10.3.1.tar.gz", hash = "sha256:ef1c4a3b9bc5429eceda59724279428e1f8740df2c5a511d061b244113b6fd97", size = 48548 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/07/15/49981d93f8402c655cbda9181a55e0f5879715d3f6c344070ba41d2511f1/pyobjc_framework_cryptotokenkit-10.3.1.tar.gz", hash = "sha256:ef1c4a3b9bc5429eceda59724279428e1f8740df2c5a511d061b244113b6fd97", size = 48548 } wheels = [ { url = "https://files.pythonhosted.org/packages/b0/8c/6d12957ca129241a992932dd6387bd188f9c0523370b1a286ae8f7093617/pyobjc_framework_CryptoTokenKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:6c88948bc8d30cd125ae29ffe551315e08c0fb49654d4f36ba4b3f0fe2f85259", size = 13332 }, { url = "https://files.pythonhosted.org/packages/87/b4/afaf21d0d993c98f293d72c1985ff687b4e87db4110f31599d5d4c1181fd/pyobjc_framework_CryptoTokenKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf0735d5d8e3ff61650deaa9670df62032dc218b865f21cd6b36b0d4c00b88ae", size = 13388 }, @@ -2932,11 +2931,11 @@ wheels = [ name = "pyobjc-framework-datadetection" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/28/9b/8b3a633ef4a215095bf1e008f4921bb9647a61a1f5b24e8ab94e89473df9/pyobjc_framework_datadetection-10.3.1.tar.gz", hash = "sha256:5394350cd7e7f40562dc0777f26dd9ddf4a595d20cb6e3cd601938e9490c963e", size = 12682 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/28/9b/8b3a633ef4a215095bf1e008f4921bb9647a61a1f5b24e8ab94e89473df9/pyobjc_framework_datadetection-10.3.1.tar.gz", hash = "sha256:5394350cd7e7f40562dc0777f26dd9ddf4a595d20cb6e3cd601938e9490c963e", size = 12682 } wheels = [ { url = "https://files.pythonhosted.org/packages/4e/1e/bc1dde224086ad91e2eedcebdb698f3d9a3c81b4b7da3b0548bd9c6a42ef/pyobjc_framework_DataDetection-10.3.1-py2.py3-none-any.whl", hash = "sha256:618ea90267fd4b83d09b557b67342ad5f3ac579090020e081dca6c664f1ae598", size = 3106 }, ] @@ -2945,11 +2944,11 @@ wheels = [ name = "pyobjc-framework-devicecheck" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/23/40/51f5e655f4d003227df3077151d20e8490e17e28043e0c4152cec9fcdfac/pyobjc_framework_devicecheck-10.3.1.tar.gz", hash = "sha256:7f6f95c84dc3d1f62aa07061f79b47d19463390d977e5afb444ef9fdd9177a9d", size = 13134 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/23/40/51f5e655f4d003227df3077151d20e8490e17e28043e0c4152cec9fcdfac/pyobjc_framework_devicecheck-10.3.1.tar.gz", hash = "sha256:7f6f95c84dc3d1f62aa07061f79b47d19463390d977e5afb444ef9fdd9177a9d", size = 13134 } wheels = [ { url = "https://files.pythonhosted.org/packages/2c/2b/9f22fc10b09daa6283ee5e9273aa6f25c61a1aee6afc44ce55fd353dfed0/pyobjc_framework_DeviceCheck-10.3.1-py2.py3-none-any.whl", hash = "sha256:9a3b291a2583bac2b65ff902c4b7872c1068736e249765906f530ae5a6eb8085", size = 3293 }, ] @@ -2958,11 +2957,11 @@ wheels = [ name = "pyobjc-framework-dictionaryservices" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/ee/ecf4fc40acfdc71a42f6efb7de6cd12b43ee73b3a2397872145584157aef/pyobjc_framework_dictionaryservices-10.3.1.tar.gz", hash = "sha256:c9fb8ed1b92f63c6f568bcdbadf628baab1cb8bb4cd01dbd65424d59c236a552", size = 10131 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-coreservices" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/a9/ee/ecf4fc40acfdc71a42f6efb7de6cd12b43ee73b3a2397872145584157aef/pyobjc_framework_dictionaryservices-10.3.1.tar.gz", hash = "sha256:c9fb8ed1b92f63c6f568bcdbadf628baab1cb8bb4cd01dbd65424d59c236a552", size = 10131 } wheels = [ { url = "https://files.pythonhosted.org/packages/57/2c/ded526049d60a7863bc08244454a4ae02250b15d2c07c16ad695bb4a71f6/pyobjc_framework_DictionaryServices-10.3.1-py2.py3-none-any.whl", hash = "sha256:e40933bc96764450dff16cd8ca8080ec83157a93ed43574441848ea52f24918d", size = 3505 }, ] @@ -2971,11 +2970,11 @@ wheels = [ name = "pyobjc-framework-discrecording" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e3/0a/07b7871e9bbfb59676be857046c8285549edaf285e8c1508b67db62ddf9c/pyobjc_framework_discrecording-10.3.1.tar.gz", hash = "sha256:47865c9a0d24366b6ede01d326d57404346c3d01e249f417bd2b0b3de00d6c54", size = 101624 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/e3/0a/07b7871e9bbfb59676be857046c8285549edaf285e8c1508b67db62ddf9c/pyobjc_framework_discrecording-10.3.1.tar.gz", hash = "sha256:47865c9a0d24366b6ede01d326d57404346c3d01e249f417bd2b0b3de00d6c54", size = 101624 } wheels = [ { url = "https://files.pythonhosted.org/packages/a0/7c/9754edfb2144025245309e7433d55feb736ddf03855b9c9f974191544657/pyobjc_framework_DiscRecording-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:99ee7b1762c7e2a4e0b74c36416f4095695ea33505c7de03875a4f46a5729af7", size = 14642 }, { url = "https://files.pythonhosted.org/packages/c6/bb/841c9452714e028486bd11f189038e91b72e0b9490307e59e4061dcd9574/pyobjc_framework_DiscRecording-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c4233f2649e34be2dd158752f0f0180c7db4ee705cc14aa62bc03c1f77318ca3", size = 14704 }, @@ -2987,12 +2986,12 @@ wheels = [ name = "pyobjc-framework-discrecordingui" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e6/5e/12669a09410b9707bd27ba93274cd9e817acc6d43ff358299974a52fa624/pyobjc_framework_discrecordingui-10.3.1.tar.gz", hash = "sha256:4b9c804a97c89001feddb58106cdc3e099e241314f7c4de062842d27b1318b68", size = 18181 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-discrecording" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/e6/5e/12669a09410b9707bd27ba93274cd9e817acc6d43ff358299974a52fa624/pyobjc_framework_discrecordingui-10.3.1.tar.gz", hash = "sha256:4b9c804a97c89001feddb58106cdc3e099e241314f7c4de062842d27b1318b68", size = 18181 } wheels = [ { url = "https://files.pythonhosted.org/packages/9a/78/57528e38d638bfb618f3d16b684b85a74c24e9443e3e986cc5dc1dc3ffda/pyobjc_framework_DiscRecordingUI-10.3.1-py2.py3-none-any.whl", hash = "sha256:cb25c70117a5c5eeb4ef74a96da48e2da171f01b7e92d1b7bbd7808068e8960c", size = 4344 }, ] @@ -3001,11 +3000,11 @@ wheels = [ name = "pyobjc-framework-diskarbitration" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/e8/9f1929c51bcfd78bde9763cc08200eb498528534664701730077beea31d3/pyobjc_framework_diskarbitration-10.3.1.tar.gz", hash = "sha256:0776318cb56f8e095066a880812c4fc5db2071687846e23a000a947a079f6c6c", size = 18667 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/4e/e8/9f1929c51bcfd78bde9763cc08200eb498528534664701730077beea31d3/pyobjc_framework_diskarbitration-10.3.1.tar.gz", hash = "sha256:0776318cb56f8e095066a880812c4fc5db2071687846e23a000a947a079f6c6c", size = 18667 } wheels = [ { url = "https://files.pythonhosted.org/packages/4e/e8/9670d42e001ad2577b7526fa1cb400328c4b3851e0b7171875fe43459a4f/pyobjc_framework_DiskArbitration-10.3.1-py2.py3-none-any.whl", hash = "sha256:f0f727435da388efd035bdd510607a5f5769b22be2361afc5b8d4ee081c70cce", size = 4432 }, ] @@ -3014,11 +3013,11 @@ wheels = [ name = "pyobjc-framework-dvdplayback" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/b6/7f7d140ce091b9813e11f1b980956e607b552ead399abed5a70662f721c0/pyobjc_framework_dvdplayback-10.3.1.tar.gz", hash = "sha256:1f7c22624dee9b1b54def15f12a3f7cacb28052cd864a845eb24b7f59de12257", size = 53047 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/72/b6/7f7d140ce091b9813e11f1b980956e607b552ead399abed5a70662f721c0/pyobjc_framework_dvdplayback-10.3.1.tar.gz", hash = "sha256:1f7c22624dee9b1b54def15f12a3f7cacb28052cd864a845eb24b7f59de12257", size = 53047 } wheels = [ { url = "https://files.pythonhosted.org/packages/b6/32/62882a136a3f17eef51cf81e13d69159e448c51cc9b136cf2b32375426ce/pyobjc_framework_DVDPlayback-10.3.1-py2.py3-none-any.whl", hash = "sha256:c0fb2e96ce4eae8def642f1c4beaec2da3cdf61db1562d4b5199d1334d1a10fe", size = 7836 }, ] @@ -3027,11 +3026,11 @@ wheels = [ name = "pyobjc-framework-eventkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ac/c4/995108bba1fb40eac108501038ae44c57099310982d1a6339b6a5fa47d82/pyobjc_framework_eventkit-10.3.1.tar.gz", hash = "sha256:3eef14ba439be1c5bc47da561ccea3941daba663577efac7a58e3031d27e056b", size = 64043 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/ac/c4/995108bba1fb40eac108501038ae44c57099310982d1a6339b6a5fa47d82/pyobjc_framework_eventkit-10.3.1.tar.gz", hash = "sha256:3eef14ba439be1c5bc47da561ccea3941daba663577efac7a58e3031d27e056b", size = 64043 } wheels = [ { url = "https://files.pythonhosted.org/packages/29/7f/1edbb57ab0cb591aa924279aabedf3fe508f62de136465adc44d77ab17a9/pyobjc_framework_EventKit-10.3.1-py2.py3-none-any.whl", hash = "sha256:ad9f42431bd058ff72feba3bbce6fbd88b2a278c3b2c1cdb4625ea5f60f1ecda", size = 6413 }, ] @@ -3040,11 +3039,11 @@ wheels = [ name = "pyobjc-framework-exceptionhandling" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/88/1328bdac98aa75de421ffea4e16f0b894e39b4ea6569b3a109b531798d20/pyobjc_framework_exceptionhandling-10.3.1.tar.gz", hash = "sha256:ff6208777739f8a886d0cbfe20692b41cc4e5e0607419c47d2c5d405b6b4c6ee", size = 17129 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/00/88/1328bdac98aa75de421ffea4e16f0b894e39b4ea6569b3a109b531798d20/pyobjc_framework_exceptionhandling-10.3.1.tar.gz", hash = "sha256:ff6208777739f8a886d0cbfe20692b41cc4e5e0607419c47d2c5d405b6b4c6ee", size = 17129 } wheels = [ { url = "https://files.pythonhosted.org/packages/90/05/da9e1a8dce6d333d7b9e714c5c228b01b9208b827aaf2862e7c993541eb6/pyobjc_framework_ExceptionHandling-10.3.1-py2.py3-none-any.whl", hash = "sha256:79843a681a1d0f9ee2b7014dcf7e1182c99c83e49cf6cea81df934ebbdf4050b", size = 6670 }, ] @@ -3053,11 +3052,11 @@ wheels = [ name = "pyobjc-framework-executionpolicy" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/8e/e5a3c06123a4ec3b845dac82450f4f1b4e5b80c0863881fb538f900762b0/pyobjc_framework_executionpolicy-10.3.1.tar.gz", hash = "sha256:cc066dc8378fc2a1a4e6129c4d09e2076dc9a5b09925f8dd959aad591cbf9a44", size = 12825 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/54/8e/e5a3c06123a4ec3b845dac82450f4f1b4e5b80c0863881fb538f900762b0/pyobjc_framework_executionpolicy-10.3.1.tar.gz", hash = "sha256:cc066dc8378fc2a1a4e6129c4d09e2076dc9a5b09925f8dd959aad591cbf9a44", size = 12825 } wheels = [ { url = "https://files.pythonhosted.org/packages/b3/45/559ddb59ce80f07c8c2ed81a3dd2b3ce7eb9399076cb556c8544dd444ead/pyobjc_framework_ExecutionPolicy-10.3.1-py2.py3-none-any.whl", hash = "sha256:f2eb203fa4c7dcf18a0ab3a4a94cb30a9f82cf888c237994dbbdb15adf01c8d2", size = 3343 }, ] @@ -3066,11 +3065,11 @@ wheels = [ name = "pyobjc-framework-extensionkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/6a/2803c373283c66eb0d38f139aa1bfa7eb9dc909bc470856ae2308f064e39/pyobjc_framework_extensionkit-10.3.1.tar.gz", hash = "sha256:91946030195fa17c5248655b10786ea60b9aee7d83a4627ba56768600b4e7674", size = 17592 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/e7/6a/2803c373283c66eb0d38f139aa1bfa7eb9dc909bc470856ae2308f064e39/pyobjc_framework_extensionkit-10.3.1.tar.gz", hash = "sha256:91946030195fa17c5248655b10786ea60b9aee7d83a4627ba56768600b4e7674", size = 17592 } wheels = [ { url = "https://files.pythonhosted.org/packages/f1/a0/927202bf17e502e9e5e44821666e21158d6f251bd770d8478148ad66b0da/pyobjc_framework_ExtensionKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:e2b54a5b32c959fc1500936b73c7ebd6d7ffcad23d74b9a6ff3db4ea5660f731", size = 7953 }, { url = "https://files.pythonhosted.org/packages/2a/af/5db1176b6ddf9319054cff45550a32d60a6339918cc1f9e5c65717624c54/pyobjc_framework_ExtensionKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f5b1e9c7e3a64224acae7b4c2d26d2a654edc54382e9e88aa3b056f4033508f8", size = 8010 }, @@ -3082,11 +3081,11 @@ wheels = [ name = "pyobjc-framework-externalaccessory" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/51/61ed6de7d4950f3810e0b5f95cad1a225a1fff8eef13223ebcbc659a4888/pyobjc_framework_externalaccessory-10.3.1.tar.gz", hash = "sha256:3ba1a7242448126b4af0fb93963790d0066766bcba2770d935111093e87b7b83", size = 20735 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/db/51/61ed6de7d4950f3810e0b5f95cad1a225a1fff8eef13223ebcbc659a4888/pyobjc_framework_externalaccessory-10.3.1.tar.gz", hash = "sha256:3ba1a7242448126b4af0fb93963790d0066766bcba2770d935111093e87b7b83", size = 20735 } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/52/4606f684f4ab1708c5506813aadad620563cbf3dac16e40ef55e0febc511/pyobjc_framework_ExternalAccessory-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:4395607570f1dd91abd786422fc516f83b4b2a5185321e6581d33dbe74a52c63", size = 8945 }, { url = "https://files.pythonhosted.org/packages/d8/b2/81b6d4046e658fc1da5d041d7303cc6a0c1b336c30b29de84260b10c7472/pyobjc_framework_ExternalAccessory-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:3fcdbb2338e7bd0fb66e9074dc95f2f989146ae92c66eb4282cfc1a6533cbe6c", size = 9006 }, @@ -3098,11 +3097,11 @@ wheels = [ name = "pyobjc-framework-fileprovider" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2e/69/c4ebc6738e8a3f5e0c9394791434813fa2656dbe2356fdf4c611a57e7391/pyobjc_framework_fileprovider-10.3.1.tar.gz", hash = "sha256:63a4160e6cbede0f682145f4303ed889bd9f3c9fccfecdc32636a8d95aeceeab", size = 63649 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/2e/69/c4ebc6738e8a3f5e0c9394791434813fa2656dbe2356fdf4c611a57e7391/pyobjc_framework_fileprovider-10.3.1.tar.gz", hash = "sha256:63a4160e6cbede0f682145f4303ed889bd9f3c9fccfecdc32636a8d95aeceeab", size = 63649 } wheels = [ { url = "https://files.pythonhosted.org/packages/00/39/5e4358e76d1285607166b623a8e0222b75e1560142907b8ff18b4ba9b0f2/pyobjc_framework_FileProvider-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b44bcbf3d826fd8a0cbc53142c65655433d553205fb36811486757e2089e6c5f", size = 18163 }, { url = "https://files.pythonhosted.org/packages/d2/87/3925b479aac490f3e96c5d56da813bfddcb75dca5597526d958eb0b3484b/pyobjc_framework_FileProvider-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b28294768dc71190019c2b2638e27b7ebf6edb65a90721b86613083bd86f6b2d", size = 18140 }, @@ -3113,11 +3112,11 @@ wheels = [ name = "pyobjc-framework-fileproviderui" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bf/5c/b130db2b86ff41da6422cd9ed54959202052c0b7401992b467c6cc29ec16/pyobjc_framework_fileproviderui-10.3.1.tar.gz", hash = "sha256:2a3f3b9b81aff216df76bc72c8e8730d7ba7f3b2412720f68b722bae58f82797", size = 12546 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-fileprovider" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/bf/5c/b130db2b86ff41da6422cd9ed54959202052c0b7401992b467c6cc29ec16/pyobjc_framework_fileproviderui-10.3.1.tar.gz", hash = "sha256:2a3f3b9b81aff216df76bc72c8e8730d7ba7f3b2412720f68b722bae58f82797", size = 12546 } wheels = [ { url = "https://files.pythonhosted.org/packages/ea/f2/1ddd3a5866a596daa4def91c3cb6e07f0a395232e49865f4e16c6929fb95/pyobjc_framework_FileProviderUI-10.3.1-py2.py3-none-any.whl", hash = "sha256:14be680a7fc78def5174ec5a6d890d407678cff723d6b359bba66bc0a78bd31a", size = 3317 }, ] @@ -3126,11 +3125,11 @@ wheels = [ name = "pyobjc-framework-findersync" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/67/70/0a2d490c88541912cab2d245093460190ddeed3bcde9faa3bc5e987c2247/pyobjc_framework_findersync-10.3.1.tar.gz", hash = "sha256:b4a08e0a87c54f62623038de1929fab018fe44fca5372a455bb524b9f90e9196", size = 14228 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/67/70/0a2d490c88541912cab2d245093460190ddeed3bcde9faa3bc5e987c2247/pyobjc_framework_findersync-10.3.1.tar.gz", hash = "sha256:b4a08e0a87c54f62623038de1929fab018fe44fca5372a455bb524b9f90e9196", size = 14228 } wheels = [ { url = "https://files.pythonhosted.org/packages/ba/b5/bd7cd2bb1ac4c13da19309ce5db976f5b533ab8ec44744ec15963de7b131/pyobjc_framework_FinderSync-10.3.1-py2.py3-none-any.whl", hash = "sha256:d4778de8a9b386c16812d470d1ad44d7370970d1dbc75d8bea390d4f5cd12be4", size = 4478 }, ] @@ -3139,11 +3138,11 @@ wheels = [ name = "pyobjc-framework-fsevents" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/fe/53eb4883293b4920544570feb1d8290e937df706ee063a26061f3aebfa72/pyobjc_framework_fsevents-10.3.1.tar.gz", hash = "sha256:6269fd8aa3f62d8a6312e316043aca6d7d792812bff09b617bbd6ca9f0f6e440", size = 27274 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/a6/fe/53eb4883293b4920544570feb1d8290e937df706ee063a26061f3aebfa72/pyobjc_framework_fsevents-10.3.1.tar.gz", hash = "sha256:6269fd8aa3f62d8a6312e316043aca6d7d792812bff09b617bbd6ca9f0f6e440", size = 27274 } wheels = [ { url = "https://files.pythonhosted.org/packages/38/29/84087044fbc34b60920cb921c03b69033d73ef713b98df05f35fcbef4b57/pyobjc_framework_FSEvents-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:7348e1aa268819b005e1ab648b5bac348052d3513aacf768c2c3999d6ffbf81e", size = 13056 }, { url = "https://files.pythonhosted.org/packages/76/2c/1624ca745f6aad9fe1a1784487a1354a2324a7fdc262f8fca44fcf7498c2/pyobjc_framework_FSEvents-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:420736c645e15006c1ed962767bfd164b1d5dba7d9dc3cd9730e4c9922b05c27", size = 13138 }, @@ -3155,11 +3154,11 @@ wheels = [ name = "pyobjc-framework-gamecenter" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/46/2f/82cea539bd5a3c764c7acb065face9d1176011f58643323fde30f05997cd/pyobjc_framework_gamecenter-10.3.1.tar.gz", hash = "sha256:221ae88ee69816b95861b1a0dc781c1c17775d38fcf0388327620535479b6a07", size = 30111 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/46/2f/82cea539bd5a3c764c7acb065face9d1176011f58643323fde30f05997cd/pyobjc_framework_gamecenter-10.3.1.tar.gz", hash = "sha256:221ae88ee69816b95861b1a0dc781c1c17775d38fcf0388327620535479b6a07", size = 30111 } wheels = [ { url = "https://files.pythonhosted.org/packages/c0/0c/4d598091446f6df9b425b3c9d754d29a69b14a7662a3b19e3c47e482b23c/pyobjc_framework_GameCenter-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:eba1058859fb30bef8227ce649dcf7531545aeff81c3cfd3e3b80ef8fe87bf70", size = 19192 }, { url = "https://files.pythonhosted.org/packages/40/26/47ed05bc86f1fb24ce9261facfe23d6ea264d7af93a22ab6d831dfce6560/pyobjc_framework_GameCenter-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:3329261e8a6a3b0df3abd4a7a3cc66cc8e47be919279a08249e08f94a0e4448f", size = 19226 }, @@ -3171,11 +3170,11 @@ wheels = [ name = "pyobjc-framework-gamecontroller" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/6e/1ee46fe9870ce020529ce883c04291a7c7f43adad2b6fbc9b0c44d2549c0/pyobjc_framework_gamecontroller-10.3.1.tar.gz", hash = "sha256:f9f252b5fed5de2a8c7fdd2e302b6ed6e0b82015d7da75b28984c5ea5909345e", size = 94100 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/49/6e/1ee46fe9870ce020529ce883c04291a7c7f43adad2b6fbc9b0c44d2549c0/pyobjc_framework_gamecontroller-10.3.1.tar.gz", hash = "sha256:f9f252b5fed5de2a8c7fdd2e302b6ed6e0b82015d7da75b28984c5ea5909345e", size = 94100 } wheels = [ { url = "https://files.pythonhosted.org/packages/dc/8c/d307f5ce6d03f552f66fb178d8da11bee59b410ff58538a5a4801195d606/pyobjc_framework_GameController-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:cfb754d29660e90f295ba443cc84fb189e5ca9d1f019c35a382cb24dd4e08bf8", size = 20409 }, { url = "https://files.pythonhosted.org/packages/21/77/279da82f58d551fde28594a26180245b373a52c8b77fb0430e8099e69575/pyobjc_framework_GameController-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:a7a1e34a4ebcf9f653bc4a066b7d08d9124d462bc7e1c434ead983a6ae093382", size = 20424 }, @@ -3187,12 +3186,12 @@ wheels = [ name = "pyobjc-framework-gamekit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/84/aa/897e74e41c80f0eaec994c4b0852e680e5eb22868d3a4681b46f06cf4032/pyobjc_framework_gamekit-10.3.1.tar.gz", hash = "sha256:7d21a8f45c32ac94ce0e70b6c6fe72928fe75cb1a6bd6d7715e2bf39b291b70b", size = 137591 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/84/aa/897e74e41c80f0eaec994c4b0852e680e5eb22868d3a4681b46f06cf4032/pyobjc_framework_gamekit-10.3.1.tar.gz", hash = "sha256:7d21a8f45c32ac94ce0e70b6c6fe72928fe75cb1a6bd6d7715e2bf39b291b70b", size = 137591 } wheels = [ { url = "https://files.pythonhosted.org/packages/1a/b0/c0818f700b2df034e2b3b43643e7c73dbba3c72e1ce0a1494753d8591847/pyobjc_framework_GameKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:57930e2b65296719b2998c9816ab844983460f3358c57a120f09ebe78013b64c", size = 22352 }, { url = "https://files.pythonhosted.org/packages/8e/93/cd9ad8514ec750da969eefc1466ce0d43b14fd4c51bf10daf5d5396513df/pyobjc_framework_GameKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:5634ac5f8b3569355f4fe8b2e6a06450d8aee555119607f7d738f5c85900c1b6", size = 22385 }, @@ -3204,12 +3203,12 @@ wheels = [ name = "pyobjc-framework-gameplaykit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/02/df/3a6e19a496dec873d26f255458a3e557f6e3aa004f04ca83f9de4e85e9e8/pyobjc_framework_gameplaykit-10.3.1.tar.gz", hash = "sha256:2035b81f7bc34b93636753cc3f9b06cd08171afc5c95bb2327a82fd3195f3c36", size = 55768 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-spritekit" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/02/df/3a6e19a496dec873d26f255458a3e557f6e3aa004f04ca83f9de4e85e9e8/pyobjc_framework_gameplaykit-10.3.1.tar.gz", hash = "sha256:2035b81f7bc34b93636753cc3f9b06cd08171afc5c95bb2327a82fd3195f3c36", size = 55768 } wheels = [ { url = "https://files.pythonhosted.org/packages/1a/7a/d9ed333da4ec5a6dfeb2ec4634aaeb37208e71eb58475dcc15508d39233d/pyobjc_framework_GameplayKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:cb54cfc4dbc69f1888c59ddce9da97ddc03f5003794fe47d56942a89c478e138", size = 13800 }, { url = "https://files.pythonhosted.org/packages/c6/09/ab7746307ba028d8921022d0d54950e3c232fa01003f31bb7ee392b1873f/pyobjc_framework_GameplayKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:eb49a732c82b17ff66f6e878b2cb9ba27e2222be303a337f2af4ed1a34a404bf", size = 13848 }, @@ -3221,11 +3220,11 @@ wheels = [ name = "pyobjc-framework-healthkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c0/68/fdda86963c5b3f86941623176acc2d7df03183ea9d3bbfff9088283d2bd2/pyobjc_framework_healthkit-10.3.1.tar.gz", hash = "sha256:45622fedb42bbd95dcc096248bbc41dacd857d9db120ff7310f74f3bad4b23e1", size = 113769 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/c0/68/fdda86963c5b3f86941623176acc2d7df03183ea9d3bbfff9088283d2bd2/pyobjc_framework_healthkit-10.3.1.tar.gz", hash = "sha256:45622fedb42bbd95dcc096248bbc41dacd857d9db120ff7310f74f3bad4b23e1", size = 113769 } wheels = [ { url = "https://files.pythonhosted.org/packages/a6/b7/532df1501af543fa78383d440818c07badf6911931da7b79da5fc33ed590/pyobjc_framework_HealthKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:80aee8bf0e7af6e434e9023c2d2050c2a2fe8e53abbf0e1f2285a932836fdd17", size = 18910 }, { url = "https://files.pythonhosted.org/packages/f9/d5/33b2e71ac4089a96031da4e079c79545d09b2acfa720987ee08d34f73e4f/pyobjc_framework_HealthKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac9abec44c02edfe7f2151f529bac1c9544fb99ee1caffff55b331281b374463", size = 18964 }, @@ -3237,11 +3236,11 @@ wheels = [ name = "pyobjc-framework-imagecapturecore" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2f/32/36b2b34e2ae902552854c1e5d24cb4d587875f4400791a30740213f57178/pyobjc_framework_imagecapturecore-10.3.1.tar.gz", hash = "sha256:9ce83c38b8ccee6b022faadb9cd7b8716119092cd41b6c2cabce3670101119bf", size = 81896 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/2f/32/36b2b34e2ae902552854c1e5d24cb4d587875f4400791a30740213f57178/pyobjc_framework_imagecapturecore-10.3.1.tar.gz", hash = "sha256:9ce83c38b8ccee6b022faadb9cd7b8716119092cd41b6c2cabce3670101119bf", size = 81896 } wheels = [ { url = "https://files.pythonhosted.org/packages/3b/2e/416250b77c56389059d9456a214d7c9e64c64e2f25d22d3f30a29dd4f327/pyobjc_framework_ImageCaptureCore-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:649e0b7bf428ad3fe90faaf63dbd09d234563a32b3cee5a6f2d28ab31927bd54", size = 16958 }, { url = "https://files.pythonhosted.org/packages/62/cc/4e3a24a111197c29c863432ed5d5eb80a347f8e63a035e45d8d4691f6692/pyobjc_framework_ImageCaptureCore-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:5bab844c665b3ac07b191e94130f543eb23c5cfd014035f025efacb7a48aa68c", size = 17018 }, @@ -3253,11 +3252,11 @@ wheels = [ name = "pyobjc-framework-inputmethodkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3b/1b/28c9e10640e0b73dcd7b4693c9ee1fb5519443bd8fd5debb0066261a0abd/pyobjc_framework_inputmethodkit-10.3.1.tar.gz", hash = "sha256:637ba2da38da5f558443b4529b33bab276380336e977807347ee9dad81d42109", size = 24489 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/3b/1b/28c9e10640e0b73dcd7b4693c9ee1fb5519443bd8fd5debb0066261a0abd/pyobjc_framework_inputmethodkit-10.3.1.tar.gz", hash = "sha256:637ba2da38da5f558443b4529b33bab276380336e977807347ee9dad81d42109", size = 24489 } wheels = [ { url = "https://files.pythonhosted.org/packages/b3/b3/9e04e21ce92cb822dabdd30fda046ac1ba17015cb12e8902bcd4acfd1a93/pyobjc_framework_InputMethodKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:d1c3beb88f94eb6b0bdc458ef49f331d064c0260758134cef1cf941684f46c83", size = 9532 }, { url = "https://files.pythonhosted.org/packages/30/66/7480b6ca7654be7964783a1195b2b928c0cc2b22e34d8f225bcdfe9ee7ad/pyobjc_framework_InputMethodKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:d0f7538ac549b61afc93df895375114464f778e06a66a4c2684cbbf247a8f4c7", size = 9592 }, @@ -3269,11 +3268,11 @@ wheels = [ name = "pyobjc-framework-installerplugins" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/cd/a9594b8200b1460630d21af18c9fc38741ff748c5457bf5958c5599795c7/pyobjc_framework_installerplugins-10.3.1.tar.gz", hash = "sha256:280808bbce36090b59197756fdb56c19838845a5fc25966a435dbc5fc4ddbbf0", size = 26514 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/a2/cd/a9594b8200b1460630d21af18c9fc38741ff748c5457bf5958c5599795c7/pyobjc_framework_installerplugins-10.3.1.tar.gz", hash = "sha256:280808bbce36090b59197756fdb56c19838845a5fc25966a435dbc5fc4ddbbf0", size = 26514 } wheels = [ { url = "https://files.pythonhosted.org/packages/52/1a/06a5d257d20dcb64f9f20c4fb7cc518016add734a70c9547676af0d4131b/pyobjc_framework_InstallerPlugins-10.3.1-py2.py3-none-any.whl", hash = "sha256:2b32cde6fb8bbb3e1ffd04d7acbe3132291ad5937fc7af5820062e8aece7b5cc", size = 4392 }, ] @@ -3282,12 +3281,12 @@ wheels = [ name = "pyobjc-framework-instantmessage" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/fc/51a0707b48507ca4963333452fd17119cc325bbbefdac460bd960f6a935e/pyobjc_framework_instantmessage-10.3.1.tar.gz", hash = "sha256:bb1560a2f92a2def179b6381c17d406331b7818fa0fd1ba98f09ed94415f8a7b", size = 32767 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/c7/fc/51a0707b48507ca4963333452fd17119cc325bbbefdac460bd960f6a935e/pyobjc_framework_instantmessage-10.3.1.tar.gz", hash = "sha256:bb1560a2f92a2def179b6381c17d406331b7818fa0fd1ba98f09ed94415f8a7b", size = 32767 } wheels = [ { url = "https://files.pythonhosted.org/packages/0d/04/089eee187804a418167d901c38cc4bb7cfb7045b53756fe3404011161a5a/pyobjc_framework_InstantMessage-10.3.1-py2.py3-none-any.whl", hash = "sha256:51a096e55a423423dbfbf19cc976a49915987ce68b9038f8ce3db9c3cde11718", size = 5016 }, ] @@ -3296,11 +3295,11 @@ wheels = [ name = "pyobjc-framework-intents" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/64/dc/120a1891de4ea2c4c5fa382100ac9706dda75a64dd6185367ddc8d89710e/pyobjc_framework_intents-10.3.1.tar.gz", hash = "sha256:89f0ed49c515b75c8811d9f6771ac635e799dfaf11921172729f8e0857c8c0e9", size = 361884 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/64/dc/120a1891de4ea2c4c5fa382100ac9706dda75a64dd6185367ddc8d89710e/pyobjc_framework_intents-10.3.1.tar.gz", hash = "sha256:89f0ed49c515b75c8811d9f6771ac635e799dfaf11921172729f8e0857c8c0e9", size = 361884 } wheels = [ { url = "https://files.pythonhosted.org/packages/82/32/4050983e2d7a6d7ecb5eefd49e76f173b293862b27ae5e8850aa1c8d6fd1/pyobjc_framework_Intents-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:4d5a899e8cffd63096aec69edafac78e76d591afd07059a96377d6893ba56649", size = 32440 }, { url = "https://files.pythonhosted.org/packages/49/30/71306e19f0f52658474a6325387b384459137b4a5ea302f41d7eafa7f508/pyobjc_framework_Intents-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:b6da33ba8a1e6ae169eb67c1c83bf4e0aeb365fb368162ba002ef26cdc9f853f", size = 32474 }, @@ -3312,11 +3311,11 @@ wheels = [ name = "pyobjc-framework-intentsui" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/51/3cff5de2db25fb516eba66480e90ceea293fc12d715d51a16ebb242c0893/pyobjc_framework_intentsui-10.3.1.tar.gz", hash = "sha256:68f42cabbd36889060d07b21f156f1dae78243d42b34c652448c687d07cbca62", size = 18822 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-intents" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/df/51/3cff5de2db25fb516eba66480e90ceea293fc12d715d51a16ebb242c0893/pyobjc_framework_intentsui-10.3.1.tar.gz", hash = "sha256:68f42cabbd36889060d07b21f156f1dae78243d42b34c652448c687d07cbca62", size = 18822 } wheels = [ { url = "https://files.pythonhosted.org/packages/8a/ed/adbe8714da27be1056a936e51cfbba36bed6046ba1fedc3f54b006f7f0cf/pyobjc_framework_IntentsUI-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bd2fed37c96f1d97abcbd6d98b2da90ba2c744f968e2c4e0735dce77bbbc95f4", size = 9607 }, { url = "https://files.pythonhosted.org/packages/6b/fc/97bf965283261206b971f329a7d02180cdf14ad5a30d5cae2f9962b0153a/pyobjc_framework_IntentsUI-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e9fe0ba78c9dd500ef9c13227dd1a60e39df460c84180d8325f5022edd80178b", size = 9642 }, @@ -3327,11 +3326,11 @@ wheels = [ name = "pyobjc-framework-iobluetooth" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e9/98/b6aade04f7e07de0e81f0312c19bbd21ea61986ab8158a0986aec6c5efd5/pyobjc_framework_iobluetooth-10.3.1.tar.gz", hash = "sha256:bca424889d7fdd5bcb728d312e91ee681e73c0c2ac16ba37068603d699043d39", size = 226060 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/e9/98/b6aade04f7e07de0e81f0312c19bbd21ea61986ab8158a0986aec6c5efd5/pyobjc_framework_iobluetooth-10.3.1.tar.gz", hash = "sha256:bca424889d7fdd5bcb728d312e91ee681e73c0c2ac16ba37068603d699043d39", size = 226060 } wheels = [ { url = "https://files.pythonhosted.org/packages/a6/4f/d75da040aca8563c56e2a7b5322ee236e2bfdb71181f761e846a5b759c88/pyobjc_framework_IOBluetooth-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:cdd8bd3da07c6935657bbcf47e6fc6b3b7a2ed9bd7e8ef83bbbd5f4a0e8884f3", size = 41473 }, { url = "https://files.pythonhosted.org/packages/31/0e/bede89b5275ad1af549f86de3ec9395d01b1bb6db5592e2c4d69fa242776/pyobjc_framework_IOBluetooth-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:d5c7ca666050b63c5dd87ede54beebdba7fc12a60bd754d77155da9f7e60618c", size = 41527 }, @@ -3343,11 +3342,11 @@ wheels = [ name = "pyobjc-framework-iobluetoothui" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/e2/3793269efe06505b1b4224ea395912c697896054bdc0bddcc3889796ceac/pyobjc_framework_iobluetoothui-10.3.1.tar.gz", hash = "sha256:6db82aeb360641b878f8ed73c2074db0425664d9411317b2e01962e0929fa29c", size = 19226 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-iobluetooth" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/d4/e2/3793269efe06505b1b4224ea395912c697896054bdc0bddcc3889796ceac/pyobjc_framework_iobluetoothui-10.3.1.tar.gz", hash = "sha256:6db82aeb360641b878f8ed73c2074db0425664d9411317b2e01962e0929fa29c", size = 19226 } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/b4/47b9746727a7a199d674bb864525016bf2d22aae7e58021e96cbeb70c048/pyobjc_framework_IOBluetoothUI-10.3.1-py2.py3-none-any.whl", hash = "sha256:ae283c3fecbeb99adba9b3c3d5d06caaad741da726fc7a1dd50ecc0376e03ae8", size = 3653 }, ] @@ -3356,11 +3355,11 @@ wheels = [ name = "pyobjc-framework-iosurface" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b1/45/8cc7def9b73ec0c3423b7c4878ee3e02fd27e72085574f4c5b7b284bebc5/pyobjc_framework_iosurface-10.3.1.tar.gz", hash = "sha256:94e4a109a94f0e365bd60ce68aab6ff166fef6f30a40f7682c76902f5fc3aa34", size = 19262 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/b1/45/8cc7def9b73ec0c3423b7c4878ee3e02fd27e72085574f4c5b7b284bebc5/pyobjc_framework_iosurface-10.3.1.tar.gz", hash = "sha256:94e4a109a94f0e365bd60ce68aab6ff166fef6f30a40f7682c76902f5fc3aa34", size = 19262 } wheels = [ { url = "https://files.pythonhosted.org/packages/36/2d/c2519d5d8e78d60245d7336d2f44a48041b5ffee9b8f2bac9f5672033e6d/pyobjc_framework_IOSurface-10.3.1-py2.py3-none-any.whl", hash = "sha256:4171a33a09ee006ad28ba29e6d12cee821e2c0ba09b4beddae8db16580fb9bc7", size = 4572 }, ] @@ -3369,11 +3368,11 @@ wheels = [ name = "pyobjc-framework-ituneslibrary" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/53/a8/63766d37cc93e2a92a53bb3b5dc769fed0ac27509bfb251cb94878792432/pyobjc_framework_ituneslibrary-10.3.1.tar.gz", hash = "sha256:3899f8555ae02f6441a711892cdc6537404215b3d5f8a7ea4594f7460c58c9b2", size = 40017 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/53/a8/63766d37cc93e2a92a53bb3b5dc769fed0ac27509bfb251cb94878792432/pyobjc_framework_ituneslibrary-10.3.1.tar.gz", hash = "sha256:3899f8555ae02f6441a711892cdc6537404215b3d5f8a7ea4594f7460c58c9b2", size = 40017 } wheels = [ { url = "https://files.pythonhosted.org/packages/f0/c7/05cf8de68b85c574cf5929a4771cbdbd4ae2448d3381d4ef7f5066e510fe/pyobjc_framework_iTunesLibrary-10.3.1-py2.py3-none-any.whl", hash = "sha256:9485e986f6075d04e10c196e5dc36e4c3b60116a45849683a61c876e5fb45fde", size = 4821 }, ] @@ -3382,11 +3381,11 @@ wheels = [ name = "pyobjc-framework-kernelmanagement" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2a/b2/0c894451b949023e00b76e17e46ce65dfa30e5005c5500958d6f90a20fcd/pyobjc_framework_kernelmanagement-10.3.1.tar.gz", hash = "sha256:04c41bc0d0ce014318acf9e333aba302092d2698ec408cbf0b022f3a507ecfa1", size = 11933 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/2a/b2/0c894451b949023e00b76e17e46ce65dfa30e5005c5500958d6f90a20fcd/pyobjc_framework_kernelmanagement-10.3.1.tar.gz", hash = "sha256:04c41bc0d0ce014318acf9e333aba302092d2698ec408cbf0b022f3a507ecfa1", size = 11933 } wheels = [ { url = "https://files.pythonhosted.org/packages/d6/75/140a6075df7c97c4e70014e696066d5b077d4116b9228287d87f63f1c1ca/pyobjc_framework_KernelManagement-10.3.1-py2.py3-none-any.whl", hash = "sha256:e07134bf3815370d3d9c37f9813edec12758f86fdbbbc67036ab72e8b767ddee", size = 3279 }, ] @@ -3395,11 +3394,11 @@ wheels = [ name = "pyobjc-framework-latentsemanticmapping" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6e/17/435b483033f21fa1d95132e93c0cedbf93567f00e6ffb579989e0c070f9c/pyobjc_framework_latentsemanticmapping-10.3.1.tar.gz", hash = "sha256:0bca94fd00f59f49874c8266bfacb09a7c56ad13b4d405c241421cef201f8943", size = 16630 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/6e/17/435b483033f21fa1d95132e93c0cedbf93567f00e6ffb579989e0c070f9c/pyobjc_framework_latentsemanticmapping-10.3.1.tar.gz", hash = "sha256:0bca94fd00f59f49874c8266bfacb09a7c56ad13b4d405c241421cef201f8943", size = 16630 } wheels = [ { url = "https://files.pythonhosted.org/packages/8c/ee/af2199401d4a6ce71b195338a2fa63bba0d33d9402622146906b741ec601/pyobjc_framework_LatentSemanticMapping-10.3.1-py2.py3-none-any.whl", hash = "sha256:c80c709b983273c8f29e86a04c52e98e8e6b0e723a400f7d6036fcabfd850367", size = 5035 }, ] @@ -3408,11 +3407,11 @@ wheels = [ name = "pyobjc-framework-launchservices" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/34/dd/53ff73cc0fbf1ad21d3acdd387830f793541dd023150866853e4f00d8dc1/pyobjc_framework_launchservices-10.3.1.tar.gz", hash = "sha256:7f16af2acabca0c2953eb7333bfe652bf853bb9d9e59b771f9d228468bccdea3", size = 20012 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-coreservices" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/34/dd/53ff73cc0fbf1ad21d3acdd387830f793541dd023150866853e4f00d8dc1/pyobjc_framework_launchservices-10.3.1.tar.gz", hash = "sha256:7f16af2acabca0c2953eb7333bfe652bf853bb9d9e59b771f9d228468bccdea3", size = 20012 } wheels = [ { url = "https://files.pythonhosted.org/packages/56/77/848cc9be87327fed05e46a67ffa5abcc0edd5c0777c4b98b6e2e6537882c/pyobjc_framework_LaunchServices-10.3.1-py2.py3-none-any.whl", hash = "sha256:3ce840027b43c4bd95dc31aaa9b4bfff1d431e782669b4c95e2b12d386c05000", size = 3489 }, ] @@ -3421,11 +3420,11 @@ wheels = [ name = "pyobjc-framework-libdispatch" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b7/37/1a7d9e5a04ab42aa8186f3493478c055601503ac7f8d58b8501d23db8b21/pyobjc_framework_libdispatch-10.3.1.tar.gz", hash = "sha256:f5c3475498cb32f54d75e21952670e4a32c8517fb2db2e90869f634edc942446", size = 44771 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/b7/37/1a7d9e5a04ab42aa8186f3493478c055601503ac7f8d58b8501d23db8b21/pyobjc_framework_libdispatch-10.3.1.tar.gz", hash = "sha256:f5c3475498cb32f54d75e21952670e4a32c8517fb2db2e90869f634edc942446", size = 44771 } wheels = [ { url = "https://files.pythonhosted.org/packages/5b/8b/44d0a44bfb68ead2481f95516f1d791e6e72667a9514c36d8d7df87a58bc/pyobjc_framework_libdispatch-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3e0db3138aae333f0b87b42586bc016430a76638af169aab9cef6afee4e5f887", size = 20491 }, { url = "https://files.pythonhosted.org/packages/40/1c/4d16cbe1d41462184e908d757537349cebddc7444950ea24dfbaf2a957ca/pyobjc_framework_libdispatch-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b209dbc9338cd87e053ede4d782b8c445bcc0b9a3d0365a6ffa1f9cd5143c301", size = 20542 }, @@ -3436,11 +3435,11 @@ wheels = [ name = "pyobjc-framework-libxpc" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/9d/8a7eb8d3570f2f41fd265513655fbf28e2ab93155a0053f46277fd61b097/pyobjc_framework_libxpc-10.3.1.tar.gz", hash = "sha256:b3c9e9fd281b5610e3bef486e91570b0afa8ab8eb0c01c0baa5e2ec49ccb7329", size = 39868 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/8e/9d/8a7eb8d3570f2f41fd265513655fbf28e2ab93155a0053f46277fd61b097/pyobjc_framework_libxpc-10.3.1.tar.gz", hash = "sha256:b3c9e9fd281b5610e3bef486e91570b0afa8ab8eb0c01c0baa5e2ec49ccb7329", size = 39868 } wheels = [ { url = "https://files.pythonhosted.org/packages/14/58/70effee80f0f0f840b6e6639252cdc749a4f7ee043d2ad66528ce354b507/pyobjc_framework_libxpc-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0afba29b6bf5c3de3ef51f60e06c026ab7be7ce44600047dece5d3bf4e758af", size = 19484 }, { url = "https://files.pythonhosted.org/packages/2c/5f/bd9bcd9d13a1ccb61c906b68f998556b3319ea83ce722be7ee5559103ce5/pyobjc_framework_libxpc-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:123b72dff148a56d48120448bd9742190326f87661f4ae6f5363e112de0e554f", size = 19582 }, @@ -3451,12 +3450,12 @@ wheels = [ name = "pyobjc-framework-linkpresentation" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/f2/8317cff954187875cc82dd8a08de69adbd1efb48451cd2b6836f347392db/pyobjc_framework_linkpresentation-10.3.1.tar.gz", hash = "sha256:535d452cc33d61074ba9bad7707d6c0a23d474fb045ed4322e5f87bfb0b7e865", size = 14174 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/b3/f2/8317cff954187875cc82dd8a08de69adbd1efb48451cd2b6836f347392db/pyobjc_framework_linkpresentation-10.3.1.tar.gz", hash = "sha256:535d452cc33d61074ba9bad7707d6c0a23d474fb045ed4322e5f87bfb0b7e865", size = 14174 } wheels = [ { url = "https://files.pythonhosted.org/packages/a4/6a/6347826cc12c01bfd2f6c804af1d99d4df8cd74440a412562b72cbbd97f5/pyobjc_framework_LinkPresentation-10.3.1-py2.py3-none-any.whl", hash = "sha256:e49ac094eb3a60a87f37edc24657feb051614a4d4464ad2580831288ead521f9", size = 3467 }, ] @@ -3465,12 +3464,12 @@ wheels = [ name = "pyobjc-framework-localauthentication" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/a9/bb2c2c3171a600dad5c7db509cdeef5a1a3cd7a22266a515145ebd5497b0/pyobjc_framework_localauthentication-10.3.1.tar.gz", hash = "sha256:ad85411f1899a2ba89349df6a92db99fcaa80a4232a4934a1a176c60698d46b1", size = 26240 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-security" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/d7/a9/bb2c2c3171a600dad5c7db509cdeef5a1a3cd7a22266a515145ebd5497b0/pyobjc_framework_localauthentication-10.3.1.tar.gz", hash = "sha256:ad85411f1899a2ba89349df6a92db99fcaa80a4232a4934a1a176c60698d46b1", size = 26240 } wheels = [ { url = "https://files.pythonhosted.org/packages/98/d5/3d5290b829f1f722b7593e01cc06406d6de404a35d91640241d885e2c01e/pyobjc_framework_LocalAuthentication-10.3.1-py2.py3-none-any.whl", hash = "sha256:565910d7d2075cd53c6d4ffdbb15d9b93267f1b1ba4c502d354778865d0dc2ec", size = 5678 }, ] @@ -3479,12 +3478,12 @@ wheels = [ name = "pyobjc-framework-localauthenticationembeddedui" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/36/ba89365d6bdbed5db435e0b4e2dc310a977dab5a306453c4f7ef8de745f2/pyobjc_framework_localauthenticationembeddedui-10.3.1.tar.gz", hash = "sha256:f915190f6106b9f9234750abf48f87445c364ccbca8f8dd565bba1b66ddd55a3", size = 13305 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-localauthentication" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/00/36/ba89365d6bdbed5db435e0b4e2dc310a977dab5a306453c4f7ef8de745f2/pyobjc_framework_localauthenticationembeddedui-10.3.1.tar.gz", hash = "sha256:f915190f6106b9f9234750abf48f87445c364ccbca8f8dd565bba1b66ddd55a3", size = 13305 } wheels = [ { url = "https://files.pythonhosted.org/packages/bd/e5/a393e16847f7605b80c643e961f60bed3c6c3b4758693907cdf88058a9bd/pyobjc_framework_LocalAuthenticationEmbeddedUI-10.3.1-py2.py3-none-any.whl", hash = "sha256:d69ef723f4525e6476e51bd166d56e97c9274500f98aa209a659e7567793dc01", size = 3559 }, ] @@ -3493,11 +3492,11 @@ wheels = [ name = "pyobjc-framework-mailkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d3/1a/683f99e9af1966de9173c1696946ec52b7d45d346aee8a638d1104eade95/pyobjc_framework_mailkit-10.3.1.tar.gz", hash = "sha256:90ad82786ae01a275aeec842e73b1fef12d9f91a67edcde8ff6a145859dc9f92", size = 26043 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/d3/1a/683f99e9af1966de9173c1696946ec52b7d45d346aee8a638d1104eade95/pyobjc_framework_mailkit-10.3.1.tar.gz", hash = "sha256:90ad82786ae01a275aeec842e73b1fef12d9f91a67edcde8ff6a145859dc9f92", size = 26043 } wheels = [ { url = "https://files.pythonhosted.org/packages/21/99/b91c7329119c9ab2397307cb5e37f0e27a8a31fefbf8376cdc1b07b76ba6/pyobjc_framework_MailKit-10.3.1-py2.py3-none-any.whl", hash = "sha256:7c403525e01bed0888946552e512ca4d1b018c3f6ef3d293fff85b90dc02a411", size = 4494 }, ] @@ -3506,13 +3505,13 @@ wheels = [ name = "pyobjc-framework-mapkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/53/f3/1f711e0311ddf3a838d1fe2ec1ab7c52cdb52d4a6144edcd2bd49becbe6c/pyobjc_framework_mapkit-10.3.1.tar.gz", hash = "sha256:f433228c404b9ef4a66e808995daccc1306f7123296317651078a6a734ac1ab0", size = 135465 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-corelocation" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/53/f3/1f711e0311ddf3a838d1fe2ec1ab7c52cdb52d4a6144edcd2bd49becbe6c/pyobjc_framework_mapkit-10.3.1.tar.gz", hash = "sha256:f433228c404b9ef4a66e808995daccc1306f7123296317651078a6a734ac1ab0", size = 135465 } wheels = [ { url = "https://files.pythonhosted.org/packages/4d/b8/03c9b2de80e18a53df9d0f0881fd08015beb4cdf8e4d28d76f25c6315089/pyobjc_framework_MapKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:cfee94ad82e673eaebc3159732b5cff1fc4f7e3bee6f17cc4fabd641c260b769", size = 22766 }, { url = "https://files.pythonhosted.org/packages/48/76/e957f714814e21c25b579d4bb98f13b92c8f17f8666f8b4be89705a0a3c0/pyobjc_framework_MapKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:dd65d6eff1397afc0b2108b0e9387a6c2390b1387731a8e0dd8298b8d0641635", size = 22999 }, @@ -3524,11 +3523,11 @@ wheels = [ name = "pyobjc-framework-mediaaccessibility" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c1/d9/e82531ed727311b54bbbeb9da0bec5c098b8cf8017d541fc77175f4bf322/pyobjc_framework_mediaaccessibility-10.3.1.tar.gz", hash = "sha256:c249e1eee636e77b5f00db3bf85174cb3e0cb53ca991a17e53a1f200377f4289", size = 16607 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/c1/d9/e82531ed727311b54bbbeb9da0bec5c098b8cf8017d541fc77175f4bf322/pyobjc_framework_mediaaccessibility-10.3.1.tar.gz", hash = "sha256:c249e1eee636e77b5f00db3bf85174cb3e0cb53ca991a17e53a1f200377f4289", size = 16607 } wheels = [ { url = "https://files.pythonhosted.org/packages/87/01/0adc256ed71a620be9fd357ac72b51a5b08af175104778201e0873de651f/pyobjc_framework_MediaAccessibility-10.3.1-py2.py3-none-any.whl", hash = "sha256:c4304ea53c7e85320b58d773cce2288f62dcb5b9c5a295be1ecfaa6645a9fea6", size = 4113 }, ] @@ -3537,12 +3536,12 @@ wheels = [ name = "pyobjc-framework-medialibrary" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/1c/c8355ad906e2051a3d73bef221ce559f417cd58e94dc5af1163bd3669c09/pyobjc_framework_medialibrary-10.3.1.tar.gz", hash = "sha256:703ffd0904fc86d4fbfbbd4952be43e91a6d477c53ce2868e4c18c3eb295f5c6", size = 17661 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/01/1c/c8355ad906e2051a3d73bef221ce559f417cd58e94dc5af1163bd3669c09/pyobjc_framework_medialibrary-10.3.1.tar.gz", hash = "sha256:703ffd0904fc86d4fbfbbd4952be43e91a6d477c53ce2868e4c18c3eb295f5c6", size = 17661 } wheels = [ { url = "https://files.pythonhosted.org/packages/d7/f8/d4afc0ccb1506ba85a873a238db934a83c349440f09c64d9ed287d5c5a88/pyobjc_framework_MediaLibrary-10.3.1-py2.py3-none-any.whl", hash = "sha256:25f16d610e3ea5d983175a6c07351596bd5dd2fcca194f1eac5686c670bbdb3b", size = 3974 }, ] @@ -3551,11 +3550,11 @@ wheels = [ name = "pyobjc-framework-mediaplayer" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/10/00/6d991d13624e8e9288ee289945737bd7e48cce6df7497ee25f2c39c4d173/pyobjc_framework_mediaplayer-10.3.1.tar.gz", hash = "sha256:97043df5ef89d4fbe217813e8f4ee1e226d8a43dee4eac00fff95e6b8a7772be", size = 77337 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-avfoundation" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/10/00/6d991d13624e8e9288ee289945737bd7e48cce6df7497ee25f2c39c4d173/pyobjc_framework_mediaplayer-10.3.1.tar.gz", hash = "sha256:97043df5ef89d4fbe217813e8f4ee1e226d8a43dee4eac00fff95e6b8a7772be", size = 77337 } wheels = [ { url = "https://files.pythonhosted.org/packages/b2/40/92912923eabb827ad6d97205d6091575118e312d58efd190766b38bb3b55/pyobjc_framework_MediaPlayer-10.3.1-py2.py3-none-any.whl", hash = "sha256:5b428cc28e57c1778bd431156c3adb948650f7503f266689559d0ece94b34e8a", size = 6548 }, ] @@ -3564,11 +3563,11 @@ wheels = [ name = "pyobjc-framework-mediatoolbox" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/8e/a4abb578ad0207ef723fac1255738ea2a3fab3c5b0b0c49a3bb30463257f/pyobjc_framework_mediatoolbox-10.3.1.tar.gz", hash = "sha256:f141056dce0dc16ec21be596fea58acb4a668045f53e12a0f250990d936b44f2", size = 21516 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/a6/8e/a4abb578ad0207ef723fac1255738ea2a3fab3c5b0b0c49a3bb30463257f/pyobjc_framework_mediatoolbox-10.3.1.tar.gz", hash = "sha256:f141056dce0dc16ec21be596fea58acb4a668045f53e12a0f250990d936b44f2", size = 21516 } wheels = [ { url = "https://files.pythonhosted.org/packages/60/13/6e20282c95f86912f7883cfba346366eaef41148fd1f3de150bbca72b132/pyobjc_framework_MediaToolbox-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:d4ef616e233c40fcac99298ee4ab95a9b6439cffe28e96ce07b66c00f598bd30", size = 13236 }, { url = "https://files.pythonhosted.org/packages/67/dc/e05fbf599d579a6a77b150ee764bf7d3012bbe02dc386c11e7a45cf08d92/pyobjc_framework_MediaToolbox-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:a8acfa377b593b043e8c9ff1aa6cbbde92b7feaea60578ea2d0b61ac3edd15dc", size = 13297 }, @@ -3580,11 +3579,11 @@ wheels = [ name = "pyobjc-framework-metal" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/5e/2df5fdb85a5753ebe6e1a1b1905da565a408a4f090f7c1d89f3a3143d18b/pyobjc_framework_metal-10.3.1.tar.gz", hash = "sha256:495307db0bfd2063f28b7c8fa350af71afcfbf5f5f2186a6a751b4cb2ef46a1a", size = 299751 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/8c/5e/2df5fdb85a5753ebe6e1a1b1905da565a408a4f090f7c1d89f3a3143d18b/pyobjc_framework_metal-10.3.1.tar.gz", hash = "sha256:495307db0bfd2063f28b7c8fa350af71afcfbf5f5f2186a6a751b4cb2ef46a1a", size = 299751 } wheels = [ { url = "https://files.pythonhosted.org/packages/07/40/405b6d09b646756b450dfe9b47f9fb4c6a8cfc93dd94bccf2e4469c03ab3/pyobjc_framework_Metal-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:4a42f3aa47eb5e0d3f29bf07f239c2ba33725701546ea6d3c5d019133e0fbce1", size = 55675 }, { url = "https://files.pythonhosted.org/packages/2d/09/3bcf777771e3db8cf692d64395e78555dc158098eb6a49ebf8d55168941b/pyobjc_framework_Metal-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:cc33d05e376d3a2f42da24b397f6353d9cb8e5990c79c9255a82637b7b8f256c", size = 56186 }, @@ -3596,11 +3595,11 @@ wheels = [ name = "pyobjc-framework-metalfx" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5f/b0/a479ef7219d4176806e6f49718da59feb1dc222605f45f5e06777a6c6a3c/pyobjc_framework_metalfx-10.3.1.tar.gz", hash = "sha256:3ea0f259397523a84a320b3925dcaaa5c039494accc3cb412b63e6f7f66f9513", size = 21547 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-metal" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/5f/b0/a479ef7219d4176806e6f49718da59feb1dc222605f45f5e06777a6c6a3c/pyobjc_framework_metalfx-10.3.1.tar.gz", hash = "sha256:3ea0f259397523a84a320b3925dcaaa5c039494accc3cb412b63e6f7f66f9513", size = 21547 } wheels = [ { url = "https://files.pythonhosted.org/packages/b6/4a/0490ead36e933453bf7de321a38831c5379753b8f748efd1eb2a1eb649fc/pyobjc_framework_MetalFX-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:ea4bed69e6a9ab4cd4fa6160554cb7df72316e849a34b839bf8d9c69ab445b24", size = 10514 }, { url = "https://files.pythonhosted.org/packages/a1/f7/f4734b1d4fce902c6c5b57e095924f7eee03d960ff77e7f4067c16da5165/pyobjc_framework_MetalFX-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f3ecae357688a4730191d57ffbc3db6abb950b756e8b98f23689d4bf08f34c20", size = 10566 }, @@ -3612,12 +3611,12 @@ wheels = [ name = "pyobjc-framework-metalkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/6d/c5a782ee9def0feda16cf41c7326680f306293f4446185f3b0040e3e956c/pyobjc_framework_metalkit-10.3.1.tar.gz", hash = "sha256:905eaad9dce29082efd5cc56195337d2e8bff86ccfad36ec5127f818155ec038", size = 38269 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-metal" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/f0/6d/c5a782ee9def0feda16cf41c7326680f306293f4446185f3b0040e3e956c/pyobjc_framework_metalkit-10.3.1.tar.gz", hash = "sha256:905eaad9dce29082efd5cc56195337d2e8bff86ccfad36ec5127f818155ec038", size = 38269 } wheels = [ { url = "https://files.pythonhosted.org/packages/5d/aa/3ec47cb09ae256e118f4f54f1759503714ff2a47474ba3f0fd7a83c3b5bf/pyobjc_framework_MetalKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:c198c61d967812837538a793b1ff862bbd868d954abcd6ee558662c45c4dbf12", size = 8782 }, { url = "https://files.pythonhosted.org/packages/9c/1b/d8fc542e7ca1c296439fbe17d96c45943ad265c63727e1d03f988a931246/pyobjc_framework_MetalKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:7c0155d731766be52cf18de6ad61339c16217bde330e17ef50808366856c1b85", size = 8840 }, @@ -3629,11 +3628,11 @@ wheels = [ name = "pyobjc-framework-metalperformanceshaders" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4a/f5/d6b25e063691ab304ed39b3d8121262f661b2e56630bf3b07476134e08a4/pyobjc_framework_metalperformanceshaders-10.3.1.tar.gz", hash = "sha256:1a9e91dc9e748834c95b7a596b943203761f6533352631c7abe612f804b23d50", size = 215419 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-metal" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/4a/f5/d6b25e063691ab304ed39b3d8121262f661b2e56630bf3b07476134e08a4/pyobjc_framework_metalperformanceshaders-10.3.1.tar.gz", hash = "sha256:1a9e91dc9e748834c95b7a596b943203761f6533352631c7abe612f804b23d50", size = 215419 } wheels = [ { url = "https://files.pythonhosted.org/packages/b9/9f/ca54b26d1fbaa3589f00d3e55107b499017ec7f4972b46f808513f45bddb/pyobjc_framework_MetalPerformanceShaders-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:a6f72fd528033ff0b176e909394edfc34f90b711fc6dcb225ba41b042929b71a", size = 33033 }, { url = "https://files.pythonhosted.org/packages/1d/93/58b86080d4008854fd071f4d46589d394133a4a61795ee55959beec762f2/pyobjc_framework_MetalPerformanceShaders-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:59c971d79c0d02a451571cd0122296aba05b46d7eecedea75ed8ce892d1119a1", size = 32981 }, @@ -3645,11 +3644,11 @@ wheels = [ name = "pyobjc-framework-metalperformanceshadersgraph" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e6/0c/c00edcdc19f692d0d261d2a0c43f296f240c236704666e287e60dea23edd/pyobjc_framework_metalperformanceshadersgraph-10.3.1.tar.gz", hash = "sha256:4bf2045036f97dcaabbf16ee8527f1787c7e9366611b9b9ed4bfabc81c19343f", size = 81585 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-metalperformanceshaders" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/e6/0c/c00edcdc19f692d0d261d2a0c43f296f240c236704666e287e60dea23edd/pyobjc_framework_metalperformanceshadersgraph-10.3.1.tar.gz", hash = "sha256:4bf2045036f97dcaabbf16ee8527f1787c7e9366611b9b9ed4bfabc81c19343f", size = 81585 } wheels = [ { url = "https://files.pythonhosted.org/packages/19/71/0dbf9660d2a31470bb6e5d5338aed82c1906c4624e8629e24cf612fa4e14/pyobjc_framework_MetalPerformanceShadersGraph-10.3.1-py2.py3-none-any.whl", hash = "sha256:a0288c53a024bc47348da2ccd8dc980d389dacc9d1d33b3412614e88732dc424", size = 6045 }, ] @@ -3658,11 +3657,11 @@ wheels = [ name = "pyobjc-framework-metrickit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/71/82f14e24708d44eb0c53b4fc57224bf5db8fa268c0632974abd6ea4b2e7f/pyobjc_framework_metrickit-10.3.1.tar.gz", hash = "sha256:f0b96fe9da0e26759f38d9e4cdf7d9c8be9c6ba35403bc8e675183a6f81dd0b3", size = 31749 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/b2/71/82f14e24708d44eb0c53b4fc57224bf5db8fa268c0632974abd6ea4b2e7f/pyobjc_framework_metrickit-10.3.1.tar.gz", hash = "sha256:f0b96fe9da0e26759f38d9e4cdf7d9c8be9c6ba35403bc8e675183a6f81dd0b3", size = 31749 } wheels = [ { url = "https://files.pythonhosted.org/packages/d5/7e/f940ff748d257d0c44415a4f7d1dfad1fa0fabb4d76f77bec62e780abf3d/pyobjc_framework_MetricKit-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:59b6959d6f79f71080d386ad08665c19e52d0cc57943716da180bbb3369c9569", size = 8165 }, { url = "https://files.pythonhosted.org/packages/a5/c3/0308e5941f509f84b0026dd56329941d4a7bb3859028ddcf4acaede186e9/pyobjc_framework_MetricKit-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f73d240b5e8f2351d6c2258b71a6d06b45ec964523f54acf05af50dc4ffac821", size = 8179 }, @@ -3673,11 +3672,11 @@ wheels = [ name = "pyobjc-framework-mlcompute" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/9a/405b3091a514670d36d21a9f1a9441555ae3b6cc0e6913765484af1cf52f/pyobjc_framework_mlcompute-10.3.1.tar.gz", hash = "sha256:9ac94b0a9511fedceacda846865daa05358eec5a4bf62be534b69eb4d7aced9b", size = 68347 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/db/9a/405b3091a514670d36d21a9f1a9441555ae3b6cc0e6913765484af1cf52f/pyobjc_framework_mlcompute-10.3.1.tar.gz", hash = "sha256:9ac94b0a9511fedceacda846865daa05358eec5a4bf62be534b69eb4d7aced9b", size = 68347 } wheels = [ { url = "https://files.pythonhosted.org/packages/07/82/1d9ad402910d9def7622c2b85a147364ecb31ad1add4a3ddb64c98f5abaf/pyobjc_framework_MLCompute-10.3.1-py2.py3-none-any.whl", hash = "sha256:e5f8d98ee43fc795f44dab322299cf8957d7e6acb54139cecebfc7f4b2562b6c", size = 6410 }, ] @@ -3686,12 +3685,12 @@ wheels = [ name = "pyobjc-framework-modelio" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/d1/3020a89e0e1145b831351b1e0b34b89b3af7055843384c2a138d3ef4979a/pyobjc_framework_modelio-10.3.1.tar.gz", hash = "sha256:b1da37d10c38c63006d5173b49d18891b2db2c9acdbb6dbd21c73f17c0ccab7e", size = 93075 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/98/d1/3020a89e0e1145b831351b1e0b34b89b3af7055843384c2a138d3ef4979a/pyobjc_framework_modelio-10.3.1.tar.gz", hash = "sha256:b1da37d10c38c63006d5173b49d18891b2db2c9acdbb6dbd21c73f17c0ccab7e", size = 93075 } wheels = [ { url = "https://files.pythonhosted.org/packages/ba/fb/cd67b4b488f9c7463dfd9ddf4ed10796ecf9e20037b11143700e75b8568c/pyobjc_framework_ModelIO-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:e841be15f1847ffe1d30e0efdbc57d3c6f1a2db7553946bc15dde0d8f57b620d", size = 21656 }, { url = "https://files.pythonhosted.org/packages/d7/1d/b403003258b758287c515e40895806e0dd60af7329714d0267db7add00a0/pyobjc_framework_ModelIO-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:53d4cc794e0dbc94e622ed164556f82db723f9c3b2d9dbf72bdf44468eb4efa5", size = 21690 }, @@ -3703,11 +3702,11 @@ wheels = [ name = "pyobjc-framework-multipeerconnectivity" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/bf/14b2e58b3462ab15fba8fb07fa493da6531d6c8da07382ef2b63e429be4a/pyobjc_framework_multipeerconnectivity-10.3.1.tar.gz", hash = "sha256:eb801d44194eb7eafcb0a21094c4ce78bcf41ed727125b048755838b59de3271", size = 23441 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/a6/bf/14b2e58b3462ab15fba8fb07fa493da6531d6c8da07382ef2b63e429be4a/pyobjc_framework_multipeerconnectivity-10.3.1.tar.gz", hash = "sha256:eb801d44194eb7eafcb0a21094c4ce78bcf41ed727125b048755838b59de3271", size = 23441 } wheels = [ { url = "https://files.pythonhosted.org/packages/51/50/54225bb1e4f98f469531090efb98a5771c4696558f41ceea385194e0c272/pyobjc_framework_MultipeerConnectivity-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:1c0b65734f1e9b907c6198b035ad47c49819711c49694fe73cdf475be37db82e", size = 12779 }, { url = "https://files.pythonhosted.org/packages/8e/e7/09d67a41a11c0c005200149cfa92e69a9c92f80381622f1f50f3936175e5/pyobjc_framework_MultipeerConnectivity-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f0e466da15a3daf2c140be66da99ac0526b584fbd6dc08ed82e542e706964449", size = 12833 }, @@ -3719,11 +3718,11 @@ wheels = [ name = "pyobjc-framework-naturallanguage" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1f/37/a0af80f8bb4ce27b5d6ab5d6bb8a71ea950cbdf81ec73c03b03388d8c572/pyobjc_framework_naturallanguage-10.3.1.tar.gz", hash = "sha256:49f19d0dba34802696a270d690db310ff03f1c85d6fb411734cb13667db90dd9", size = 39154 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/1f/37/a0af80f8bb4ce27b5d6ab5d6bb8a71ea950cbdf81ec73c03b03388d8c572/pyobjc_framework_naturallanguage-10.3.1.tar.gz", hash = "sha256:49f19d0dba34802696a270d690db310ff03f1c85d6fb411734cb13667db90dd9", size = 39154 } wheels = [ { url = "https://files.pythonhosted.org/packages/81/37/7aabe277c3cfd6dc756959e6fa2bacf8e8e1c435b67e33f6a0c799e2a5ae/pyobjc_framework_NaturalLanguage-10.3.1-py2.py3-none-any.whl", hash = "sha256:d0e47fad66bb74fa68b50093500f5cb49d8a772b522f8c92e725f2e65942dd9c", size = 4923 }, ] @@ -3732,11 +3731,11 @@ wheels = [ name = "pyobjc-framework-netfs" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/94/d467f7bc9efdf633f6cb40b83357f1cb91308efea2738f37b7c682e6619a/pyobjc_framework_netfs-10.3.1.tar.gz", hash = "sha256:46466917f7b0aca3772bf4dfd586b583992c60ecd71c39f7d28ff7665d057637", size = 15212 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/90/94/d467f7bc9efdf633f6cb40b83357f1cb91308efea2738f37b7c682e6619a/pyobjc_framework_netfs-10.3.1.tar.gz", hash = "sha256:46466917f7b0aca3772bf4dfd586b583992c60ecd71c39f7d28ff7665d057637", size = 15212 } wheels = [ { url = "https://files.pythonhosted.org/packages/ec/08/1a6effdc97f3eede536e66a7c7e1c50cce644e8d4d5e258a243985997b2a/pyobjc_framework_NetFS-10.3.1-py2.py3-none-any.whl", hash = "sha256:84faa7325c4ecc2f4ad199d8c52cebcb520ad2e7713f356c7a5a849839398d77", size = 3791 }, ] @@ -3745,11 +3744,11 @@ wheels = [ name = "pyobjc-framework-network" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b7/a2/547e786e3ff87e4facf038b0375d8fd4a48a8f6c69762efc7aac87b2d379/pyobjc_framework_network-10.3.1.tar.gz", hash = "sha256:87a5839d4ab2ae452b4e563bd7a00569557ede4b8cd1eb77c973cdf45fb8f5ab", size = 104030 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/b7/a2/547e786e3ff87e4facf038b0375d8fd4a48a8f6c69762efc7aac87b2d379/pyobjc_framework_network-10.3.1.tar.gz", hash = "sha256:87a5839d4ab2ae452b4e563bd7a00569557ede4b8cd1eb77c973cdf45fb8f5ab", size = 104030 } wheels = [ { url = "https://files.pythonhosted.org/packages/a1/83/d8799253ebf55496dd0725d9ba4cd03260fc161dee6f128fd3e78ae6a79f/pyobjc_framework_Network-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:56df88c10b948b3b09dd6d0e9061da33683e294d0450efd9076354f41e214f58", size = 19084 }, { url = "https://files.pythonhosted.org/packages/43/ce/d5e00d0dcf234a0269c079948c855467f5af0464d4d1d44148c20c69f602/pyobjc_framework_Network-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:0336fc0b80a2481d3a032b94e7dfddbb8d0f1ec10e36e80ad424a028b00679ac", size = 19128 }, @@ -3761,11 +3760,11 @@ wheels = [ name = "pyobjc-framework-networkextension" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/46/1af5ad27f16af7ef97cced31dc70d92cf85c08d1e15a32997f9e40496601/pyobjc_framework_networkextension-10.3.1.tar.gz", hash = "sha256:c5a094862061565ca6d37457db42f55f344ec24dd7604ddf5d72e20ae7f63fdd", size = 130653 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/dc/46/1af5ad27f16af7ef97cced31dc70d92cf85c08d1e15a32997f9e40496601/pyobjc_framework_networkextension-10.3.1.tar.gz", hash = "sha256:c5a094862061565ca6d37457db42f55f344ec24dd7604ddf5d72e20ae7f63fdd", size = 130653 } wheels = [ { url = "https://files.pythonhosted.org/packages/35/fd/085d7b5ab96a5eec797933246e268773728d58ce4cccfbb06bc210590c4f/pyobjc_framework_NetworkExtension-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:baacdb4ad595d5c5ce9660e10ea476fab9bfd1a1def2357eae7918f5019bb8c0", size = 13808 }, { url = "https://files.pythonhosted.org/packages/4d/e3/3afdc6ec7c8ecf596b35b3e32f95fc23d755ce42af40375cd96041eeb587/pyobjc_framework_NetworkExtension-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c1efc35dc4ddced3f0e5400e8ae9b28b7585f0cf5701023dd957f3cbd58d361f", size = 13864 }, @@ -3777,11 +3776,11 @@ wheels = [ name = "pyobjc-framework-notificationcenter" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/11/a4/105abbec54e815ab9de653bba08db37524589c369badab6e1a5e3bd598a3/pyobjc_framework_notificationcenter-10.3.1.tar.gz", hash = "sha256:3e6efe0fe6389601bb87086f5585fa7e74b2143236b7d5afd02b617a73656419", size = 21039 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/11/a4/105abbec54e815ab9de653bba08db37524589c369badab6e1a5e3bd598a3/pyobjc_framework_notificationcenter-10.3.1.tar.gz", hash = "sha256:3e6efe0fe6389601bb87086f5585fa7e74b2143236b7d5afd02b617a73656419", size = 21039 } wheels = [ { url = "https://files.pythonhosted.org/packages/cd/f8/eb4a4703d3b91d91ed050411ac129612d11ce34f3f01cca8c7912cc08ea1/pyobjc_framework_NotificationCenter-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:2818922c2c3f45721515733b452d20a507368a87b793fa976c21945773582abc", size = 10603 }, { url = "https://files.pythonhosted.org/packages/0a/6e/3be21a76248fcfb4c703bda266f2b289bb0df07ad1ea551209d71ede808b/pyobjc_framework_NotificationCenter-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:e08264759b84a21631e143afce1696920207d418be7f8853dbde18dbc7881667", size = 10668 }, @@ -3793,11 +3792,11 @@ wheels = [ name = "pyobjc-framework-opendirectory" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/32/1e/85e8d9ea9ee43a111a6d278c5006a3a58c4573af60ba7932402cb3ca5e84/pyobjc_framework_opendirectory-10.3.1.tar.gz", hash = "sha256:cddc25632eebeb6bf0d886ae0fc919d574e458c597691226ba15bbf134ab51a6", size = 159659 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/32/1e/85e8d9ea9ee43a111a6d278c5006a3a58c4573af60ba7932402cb3ca5e84/pyobjc_framework_opendirectory-10.3.1.tar.gz", hash = "sha256:cddc25632eebeb6bf0d886ae0fc919d574e458c597691226ba15bbf134ab51a6", size = 159659 } wheels = [ { url = "https://files.pythonhosted.org/packages/ca/17/74c8d815ddd43d206311baf00237c8a14c4c3cb7ad656ef33afcfe370655/pyobjc_framework_OpenDirectory-10.3.1-py2.py3-none-any.whl", hash = "sha256:7e787e65409aad082faed2ed0c2cd52cccea61702d9c83b6acdcac3fa50a562f", size = 11425 }, ] @@ -3806,11 +3805,11 @@ wheels = [ name = "pyobjc-framework-osakit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ce/db/2ee141472cb30079b8881d4839f4d46d38bed2e78e04d5ecf44885d05cd7/pyobjc_framework_osakit-10.3.1.tar.gz", hash = "sha256:0af326b831fa29fca11ffe2b641807ad3c233be9eb403e62328fa784528da4ab", size = 18286 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/ce/db/2ee141472cb30079b8881d4839f4d46d38bed2e78e04d5ecf44885d05cd7/pyobjc_framework_osakit-10.3.1.tar.gz", hash = "sha256:0af326b831fa29fca11ffe2b641807ad3c233be9eb403e62328fa784528da4ab", size = 18286 } wheels = [ { url = "https://files.pythonhosted.org/packages/f3/37/f644ff0e1013ee25a3c543f4240687f7ab79580df401cafff8e5dfea278c/pyobjc_framework_OSAKit-10.3.1-py2.py3-none-any.whl", hash = "sha256:aaa60e6f455febe45f9be6487c59f11450de81bd7f49a6e4db576a38bcaf1c68", size = 3784 }, ] @@ -3819,13 +3818,13 @@ wheels = [ name = "pyobjc-framework-oslog" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/11/ba/45a84a9a26608c8dd2d909f8ad8183434c17b1d4071ce910388c80a07637/pyobjc_framework_oslog-10.3.1.tar.gz", hash = "sha256:592c3e50cf824c2c07779771aa0065de2dbb4c615de43e8949b39d19ba04d744", size = 22288 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-coremedia" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/11/ba/45a84a9a26608c8dd2d909f8ad8183434c17b1d4071ce910388c80a07637/pyobjc_framework_oslog-10.3.1.tar.gz", hash = "sha256:592c3e50cf824c2c07779771aa0065de2dbb4c615de43e8949b39d19ba04d744", size = 22288 } wheels = [ { url = "https://files.pythonhosted.org/packages/79/ef/1d18049de4f5d459107e1703cb42d3e159dffa988bc9968ec43c7cef3742/pyobjc_framework_OSLog-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:4799619f9ae12287923e2bc39fc021c75ea4e8bcb0e8ff44201f1018d017db98", size = 7898 }, { url = "https://files.pythonhosted.org/packages/08/94/609913d615527e891fadf4b3c319ce6df143c5c160ba5e69904fa4d2a666/pyobjc_framework_OSLog-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:7ff719367249c09318a87df47ef8e1c8d18ab5f4b9e94862e7ca9c8fad21ed9a", size = 7958 }, @@ -3837,11 +3836,11 @@ wheels = [ name = "pyobjc-framework-passkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/5a/8336d8fe6371e7696235d131d042572156299d6a0c566a5854f127270adc/pyobjc_framework_passkit-10.3.1.tar.gz", hash = "sha256:4c3eea19c1ae3edf6e7858ab815bcd8ecf517a146928ce6a843910729372f010", size = 94853 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/a5/5a/8336d8fe6371e7696235d131d042572156299d6a0c566a5854f127270adc/pyobjc_framework_passkit-10.3.1.tar.gz", hash = "sha256:4c3eea19c1ae3edf6e7858ab815bcd8ecf517a146928ce6a843910729372f010", size = 94853 } wheels = [ { url = "https://files.pythonhosted.org/packages/f0/ba/9e247686f64ee75840104d4e85a2c21316ce6abaa0697b0fa826edd69442/pyobjc_framework_PassKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:ce09205aae4e15d3639d76a558c072ae106e8c7dafe9a451c5e27967498b74cd", size = 13868 }, { url = "https://files.pythonhosted.org/packages/6a/af/081c1c6fd9bbcd93ea983e5ea2111011c669c96cc6d6146e07f570aeb136/pyobjc_framework_PassKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:79ff6fa8ad4c0f9b4a992122b22e2b2b4200534221eb1bfe86bf473fb3c7ca23", size = 13907 }, @@ -3853,11 +3852,11 @@ wheels = [ name = "pyobjc-framework-pencilkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d2/8e/9152ecf82135f5f6ec94f4b407948cdee9b8f01ead2896613422dbfe8ef1/pyobjc_framework_pencilkit-10.3.1.tar.gz", hash = "sha256:4dfd8e0179be5ecf67b768317a88d86d93df1c8674d422afa14957cf80e6e01f", size = 18784 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/d2/8e/9152ecf82135f5f6ec94f4b407948cdee9b8f01ead2896613422dbfe8ef1/pyobjc_framework_pencilkit-10.3.1.tar.gz", hash = "sha256:4dfd8e0179be5ecf67b768317a88d86d93df1c8674d422afa14957cf80e6e01f", size = 18784 } wheels = [ { url = "https://files.pythonhosted.org/packages/1b/41/a15fd222e8f9b28ab18440ac3d4c2aca98c640f2e1456dbc018c451c7556/pyobjc_framework_PencilKit-10.3.1-py2.py3-none-any.whl", hash = "sha256:dc05376fbc5887391ff4e778b6f4b2fa20264aac58cd5fe5f47e4930186c1674", size = 3653 }, ] @@ -3866,11 +3865,11 @@ wheels = [ name = "pyobjc-framework-phase" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/7c/57e7a130932027f11ce8bfb68e8a6a910b9ec11c8bd4647605d0c6ff1ade/pyobjc_framework_phase-10.3.1.tar.gz", hash = "sha256:5be2ea5d36ea9620f5278f5ad3b02cc243511be3b137aa28b1523e8f6da54f99", size = 43938 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-avfoundation" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/f8/7c/57e7a130932027f11ce8bfb68e8a6a910b9ec11c8bd4647605d0c6ff1ade/pyobjc_framework_phase-10.3.1.tar.gz", hash = "sha256:5be2ea5d36ea9620f5278f5ad3b02cc243511be3b137aa28b1523e8f6da54f99", size = 43938 } wheels = [ { url = "https://files.pythonhosted.org/packages/82/5b/948fcead87fc9badb4de137829423ce53f1d03a5f8d873e4d0cea01745da/pyobjc_framework_PHASE-10.3.1-py2.py3-none-any.whl", hash = "sha256:eec5a38983d65a4cf022dd01dc6f290ec163399e79592203443b4115ea3c8510", size = 6233 }, ] @@ -3879,11 +3878,11 @@ wheels = [ name = "pyobjc-framework-photos" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4f/e3/764707657dc2ee986510ac137dfcb98ca3498fa21ed7c79e711df3b85736/pyobjc_framework_photos-10.3.1.tar.gz", hash = "sha256:8d538c399720062523694f7669aa82dcb75a7b192fb4aca93cf782d04e4c39be", size = 74176 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/4f/e3/764707657dc2ee986510ac137dfcb98ca3498fa21ed7c79e711df3b85736/pyobjc_framework_photos-10.3.1.tar.gz", hash = "sha256:8d538c399720062523694f7669aa82dcb75a7b192fb4aca93cf782d04e4c39be", size = 74176 } wheels = [ { url = "https://files.pythonhosted.org/packages/03/e2/7e46258b4c0f75a48e639bc1423830c34067b101bd5512c80db4a6554b1f/pyobjc_framework_Photos-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:9a382201dd14a3f3076d8689267d63520803a1ad1716fb66df5c1bb578bc6384", size = 12793 }, { url = "https://files.pythonhosted.org/packages/ef/20/3fcc8803c0503bfd7e7f2fb81889d1f41f12cc1660a1b37f31743d271821/pyobjc_framework_Photos-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:9c72efff52bed483b0dfaa569a21355f7620f25672a0245c5db8c1df86abc7b8", size = 12850 }, @@ -3895,11 +3894,11 @@ wheels = [ name = "pyobjc-framework-photosui" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/34/6ee322114383d37c4921fc15e41ba4595347f0b108e14d6232e540d77c5e/pyobjc_framework_photosui-10.3.1.tar.gz", hash = "sha256:e9eb961c6be1f3e00d76cc0a8ec15b50ac0692bd5b5c86268ad08f6d09cf390d", size = 38914 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/aa/34/6ee322114383d37c4921fc15e41ba4595347f0b108e14d6232e540d77c5e/pyobjc_framework_photosui-10.3.1.tar.gz", hash = "sha256:e9eb961c6be1f3e00d76cc0a8ec15b50ac0692bd5b5c86268ad08f6d09cf390d", size = 38914 } wheels = [ { url = "https://files.pythonhosted.org/packages/b4/69/422c3f59a3d9f632aaa2440d2cf7f80cd22b6930ef965a0892923bf8b879/pyobjc_framework_PhotosUI-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:88665561d9ef7e9fd2ceb4e7e5da0fc3412a397d4c48a2121250462781106d30", size = 12574 }, { url = "https://files.pythonhosted.org/packages/09/69/5de76149d57fd1a22cfa8be06e8f7bf76a334e488abafbac6e39773942ac/pyobjc_framework_PhotosUI-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:3254605c33e090742d0303a3b5b8ddab5489dbf28ea8a287566106e6887ee561", size = 12626 }, @@ -3911,11 +3910,11 @@ wheels = [ name = "pyobjc-framework-preferencepanes" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/56/da2d75cf4900a62cafde27d875bbe0dc0e9c3624b6d4c08adc69d9336033/pyobjc_framework_preferencepanes-10.3.1.tar.gz", hash = "sha256:eef150416a39a0109a8a37e9978ac4a55ad0b125ef6053a7431524ede5c69783", size = 25330 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/8a/56/da2d75cf4900a62cafde27d875bbe0dc0e9c3624b6d4c08adc69d9336033/pyobjc_framework_preferencepanes-10.3.1.tar.gz", hash = "sha256:eef150416a39a0109a8a37e9978ac4a55ad0b125ef6053a7431524ede5c69783", size = 25330 } wheels = [ { url = "https://files.pythonhosted.org/packages/78/54/e2d55873233287481d11f9d92254e0fc8a86d2c37c062186c1867d41c7a6/pyobjc_framework_PreferencePanes-10.3.1-py2.py3-none-any.whl", hash = "sha256:319b58b6c8f876f67e879b3a4f74afd6d892aa43a7f9ef4320819265b281c9e5", size = 4384 }, ] @@ -3924,11 +3923,11 @@ wheels = [ name = "pyobjc-framework-pubsub" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ad/94/7126b622790d16a422589938b97f8c7c13a0724d9b9c8bed7badd8016d01/pyobjc_framework_pubsub-10.3.1.tar.gz", hash = "sha256:d123e75288c2f9d785ed1c4d92a96e5118c4b6f1cd9c55605eb4b4a74c2e36f4", size = 15716 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/ad/94/7126b622790d16a422589938b97f8c7c13a0724d9b9c8bed7badd8016d01/pyobjc_framework_pubsub-10.3.1.tar.gz", hash = "sha256:d123e75288c2f9d785ed1c4d92a96e5118c4b6f1cd9c55605eb4b4a74c2e36f4", size = 15716 } wheels = [ { url = "https://files.pythonhosted.org/packages/91/ad/87b0141019472292be66bfe2d867c8aae2324e3eedde95312a39689e6b50/pyobjc_framework_PubSub-10.3.1-py2.py3-none-any.whl", hash = "sha256:dd8bc334b3acbdd82163d511bc71af7addc98dfaf473736545487f3168836dcd", size = 4793 }, ] @@ -3937,11 +3936,11 @@ wheels = [ name = "pyobjc-framework-pushkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/d6/2fec9c42a76466902b14afeea7a9c8cc2c90aeafd3f3dbe72af474681dc5/pyobjc_framework_pushkit-10.3.1.tar.gz", hash = "sha256:cc4da5382cf48c29637af1c633490203358a6ab0c76f0c006079cf144eeb9568", size = 19167 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/30/d6/2fec9c42a76466902b14afeea7a9c8cc2c90aeafd3f3dbe72af474681dc5/pyobjc_framework_pushkit-10.3.1.tar.gz", hash = "sha256:cc4da5382cf48c29637af1c633490203358a6ab0c76f0c006079cf144eeb9568", size = 19167 } wheels = [ { url = "https://files.pythonhosted.org/packages/37/33/0b2cf5dadd448498490a31e52dbbbc6015a62402128fb4e7aac90f3d3889/pyobjc_framework_PushKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:39e21ac2b9a529e99d6d33c439c96d4d2bb97d2c56bd6d92b2c5bd497e925851", size = 8204 }, { url = "https://files.pythonhosted.org/packages/3d/cd/51e1ac0bd23813b6e11a7e1363a104096adc6d56bd2a5f9180014e110d8b/pyobjc_framework_PushKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:e20f94ad3fbebf34c613c880e655d0f918d891b0a70763f99bb5d11e0af65c73", size = 8256 }, @@ -3953,11 +3952,11 @@ wheels = [ name = "pyobjc-framework-quartz" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/a2/f488d801197b9b4d28d0b8d85947f9e2c8a6e89c5e6d4a828fc7cccfb57a/pyobjc_framework_quartz-10.3.1.tar.gz", hash = "sha256:b6d7e346d735c9a7f147cd78e6da79eeae416a0b7d3874644c83a23786c6f886", size = 3775947 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/f7/a2/f488d801197b9b4d28d0b8d85947f9e2c8a6e89c5e6d4a828fc7cccfb57a/pyobjc_framework_quartz-10.3.1.tar.gz", hash = "sha256:b6d7e346d735c9a7f147cd78e6da79eeae416a0b7d3874644c83a23786c6f886", size = 3775947 } wheels = [ { url = "https://files.pythonhosted.org/packages/62/b3/ba33c4a3406fec862a5107da03d8daacbc11daa355f446a8849e1bf2c73e/pyobjc_framework_Quartz-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:96578d4a3e70164efe44ad7dc320ecd4e211758ffcde5dcd694de1bbdfe090a4", size = 227260 }, { url = "https://files.pythonhosted.org/packages/0f/08/215f38dbebfca74f49276a9471531f360b4fb7888106f78953909919ca53/pyobjc_framework_Quartz-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ca35f92486869a41847a1703bb176aab8a53dbfd8e678d1f4d68d8e6e1581c71", size = 227195 }, @@ -3968,12 +3967,12 @@ wheels = [ name = "pyobjc-framework-quicklookthumbnailing" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/29/04/ef2db0a73af5b2530de728529f5d637bbe5f09bf4165493db0ab3df2018b/pyobjc_framework_quicklookthumbnailing-10.3.1.tar.gz", hash = "sha256:ee26be78df9ce46ffa6f971f4ce167a0e98f38167aeb86cfc1b41270f15c96a3", size = 15534 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/29/04/ef2db0a73af5b2530de728529f5d637bbe5f09bf4165493db0ab3df2018b/pyobjc_framework_quicklookthumbnailing-10.3.1.tar.gz", hash = "sha256:ee26be78df9ce46ffa6f971f4ce167a0e98f38167aeb86cfc1b41270f15c96a3", size = 15534 } wheels = [ { url = "https://files.pythonhosted.org/packages/bb/d2/6c199cf69d5402cd4317600e7a4f925964a2eb9df44e4a09437af5dbf037/pyobjc_framework_QuickLookThumbnailing-10.3.1-py2.py3-none-any.whl", hash = "sha256:e5095c0ad8cf1f91a6ed9aa5c4fb7c9b1da122d495ce131bae8d7faa06da9505", size = 3814 }, ] @@ -3982,11 +3981,11 @@ wheels = [ name = "pyobjc-framework-replaykit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5b/37/dbadcb487150f4ea1a691c83d09f1ed58463bed6b4fa54dca6aeb1584d06/pyobjc_framework_replaykit-10.3.1.tar.gz", hash = "sha256:21762c8674b629fb670c3cbd515c593f1b5f98ee24ee4834a09055cb08849068", size = 23417 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/5b/37/dbadcb487150f4ea1a691c83d09f1ed58463bed6b4fa54dca6aeb1584d06/pyobjc_framework_replaykit-10.3.1.tar.gz", hash = "sha256:21762c8674b629fb670c3cbd515c593f1b5f98ee24ee4834a09055cb08849068", size = 23417 } wheels = [ { url = "https://files.pythonhosted.org/packages/de/0a/173ad3f0ae54f172b59a351244a7b049cedca96d2b9b88d2609ea611dd1d/pyobjc_framework_ReplayKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:1d89020e770763947c0e3e3a201b541b81b455656e574d390ad0b0e32a67640a", size = 10127 }, { url = "https://files.pythonhosted.org/packages/36/c9/493a621107b3d2540140acfa70e72fb9f340485d38b475f1590d57608bc9/pyobjc_framework_ReplayKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:b753658337d25964acb83f5edc465b772f276b4c88fc8bd03ad633b4466f6bd4", size = 10163 }, @@ -3998,11 +3997,11 @@ wheels = [ name = "pyobjc-framework-safariservices" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/69/63/c12192ed8b5a08cc5313aef6d4e6d86d9d17171d4325a7f6e2f8c0da7a19/pyobjc_framework_safariservices-10.3.1.tar.gz", hash = "sha256:9c5278576e7c28c3d93e74ebe5d39d07c5c91572ddf03ea01cc45d9a06dc8d0a", size = 29436 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/69/63/c12192ed8b5a08cc5313aef6d4e6d86d9d17171d4325a7f6e2f8c0da7a19/pyobjc_framework_safariservices-10.3.1.tar.gz", hash = "sha256:9c5278576e7c28c3d93e74ebe5d39d07c5c91572ddf03ea01cc45d9a06dc8d0a", size = 29436 } wheels = [ { url = "https://files.pythonhosted.org/packages/6c/43/e7fd640b320252360e5777b4544dd18a7b507ecd4e31e8a54b877dff761d/pyobjc_framework_SafariServices-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:c8afb977b5858d3fd27136146db46a9f2ec43c35f5af269dbcb51c46a422dd7e", size = 7405 }, { url = "https://files.pythonhosted.org/packages/af/ef/5a28fa9b7e9aea7e011e58f461b60f0fab27488859b1f83b556fcc4c5151/pyobjc_framework_SafariServices-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:adb0332cbfa086892524efa253c873ecc4a8b00c60db45be3362759c4b4ae87d", size = 7461 }, @@ -4014,12 +4013,12 @@ wheels = [ name = "pyobjc-framework-safetykit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/db/1d099ed2b3655caacad70315a6789b47277f9939f73d4f13810bf27f9e29/pyobjc_framework_safetykit-10.3.1.tar.gz", hash = "sha256:8421be801ce29053e67a2c91673913562c3ad9d4bb1fbaa934a3a365d8bff12d", size = 19035 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/d8/db/1d099ed2b3655caacad70315a6789b47277f9939f73d4f13810bf27f9e29/pyobjc_framework_safetykit-10.3.1.tar.gz", hash = "sha256:8421be801ce29053e67a2c91673913562c3ad9d4bb1fbaa934a3a365d8bff12d", size = 19035 } wheels = [ { url = "https://files.pythonhosted.org/packages/c1/13/35bfd2d99a20f035d8c1e0c266b2c5d90c64f8f075d6d70743c8b1fa4118/pyobjc_framework_SafetyKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:e554cb94bc2f89f525ccaa4ed827390d188eba8bb24049acdc764f3dfee9af08", size = 8039 }, { url = "https://files.pythonhosted.org/packages/9c/86/7f33005e00824520fa611bcc63ecbbe55979b94dc1599df44d1c8a7ab92c/pyobjc_framework_SafetyKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:8eb160cc4f3b7e6d58f2eecc205f016afd5f4278b9641e49d5ef9c4df7b6df8c", size = 8089 }, @@ -4031,12 +4030,12 @@ wheels = [ name = "pyobjc-framework-scenekit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/23/cb/0451b9463cc1d19eef523dfc6098c5d774cbd5f4cae9fbc6884b17cd5cd9/pyobjc_framework_scenekit-10.3.1.tar.gz", hash = "sha256:99cf0db3055d9bae0a8643400e528a8c012235db8ee6a1864ea0b03a0854c9d0", size = 155276 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/23/cb/0451b9463cc1d19eef523dfc6098c5d774cbd5f4cae9fbc6884b17cd5cd9/pyobjc_framework_scenekit-10.3.1.tar.gz", hash = "sha256:99cf0db3055d9bae0a8643400e528a8c012235db8ee6a1864ea0b03a0854c9d0", size = 155276 } wheels = [ { url = "https://files.pythonhosted.org/packages/46/37/d10538c3547f8aac05fd8d7b519ce46f54ed1eda6f77686e319f0191a0ee/pyobjc_framework_SceneKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:7a108ef1a660a7928d1d44e415c84f544d296745d5350235addaab82777b080a", size = 32978 }, { url = "https://files.pythonhosted.org/packages/cf/73/79c969fe840aede23074ba229c077653e778c7a6735709a642c17c870862/pyobjc_framework_SceneKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:08fb5dd8c10a5624a0bf3dd9f448b2fe4c8b9c7c3c98708d28b0b4c72dd2a107", size = 33193 }, @@ -4048,12 +4047,12 @@ wheels = [ name = "pyobjc-framework-screencapturekit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/20/51dbb697dc5d3bc522771afa375e05370e6357b49dacf1bafe7dae37908f/pyobjc_framework_screencapturekit-10.3.1.tar.gz", hash = "sha256:cb1a2e746e0f98ea14a11ea35d059d38587340beeeb905812085e2c7ceb14e0c", size = 34829 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-coremedia" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/d4/20/51dbb697dc5d3bc522771afa375e05370e6357b49dacf1bafe7dae37908f/pyobjc_framework_screencapturekit-10.3.1.tar.gz", hash = "sha256:cb1a2e746e0f98ea14a11ea35d059d38587340beeeb905812085e2c7ceb14e0c", size = 34829 } wheels = [ { url = "https://files.pythonhosted.org/packages/1a/67/ff55c30ac3508f3c1214a084f321d2268c56d15fe5be436591a5ee24eb7e/pyobjc_framework_ScreenCaptureKit-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0953f8d43bd7f0012decebe34401d361c4a64472190960204b3214e4850e4ef2", size = 11398 }, { url = "https://files.pythonhosted.org/packages/b2/c7/25af6462a4f161dca7ffb375348716b6cb271c29e356bbfd4e4693f87b69/pyobjc_framework_ScreenCaptureKit-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a80928dc483046ac72294fd576c53f793045aad700b740ec9591b23a3ccc011d", size = 11435 }, @@ -4064,11 +4063,11 @@ wheels = [ name = "pyobjc-framework-screensaver" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/7c/55374bae0be8632e2c76b911af3bcdfd5b5ea417c125d8268f8207c77516/pyobjc_framework_screensaver-10.3.1.tar.gz", hash = "sha256:0bbc5b574f12e95f6f6e48ced40b601e46e560ef6786845c15c57d78e6cd083e", size = 22037 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/dc/7c/55374bae0be8632e2c76b911af3bcdfd5b5ea417c125d8268f8207c77516/pyobjc_framework_screensaver-10.3.1.tar.gz", hash = "sha256:0bbc5b574f12e95f6f6e48ced40b601e46e560ef6786845c15c57d78e6cd083e", size = 22037 } wheels = [ { url = "https://files.pythonhosted.org/packages/63/26/d9db1199855e3b3227bfe3c156750786f23d600055732eea2be28314b4c3/pyobjc_framework_ScreenSaver-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:31bffb17ec131509c4cc584e98328497310ea644c764b50fb6bf7850617ec5a5", size = 7961 }, { url = "https://files.pythonhosted.org/packages/b5/0a/0eac07594070e89c796fb56858fa75f2a39dbc407e02ded06624d26120ed/pyobjc_framework_ScreenSaver-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:ff25ad7cfffa116feaa117989f0a4b68dd6b7318aea4320ece6f75caf0092cfa", size = 8166 }, @@ -4080,11 +4079,11 @@ wheels = [ name = "pyobjc-framework-screentime" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/38/a5/b2b9c57eb364ccc1074442ce956b0052f71e903b7b944a93bc4888deb94d/pyobjc_framework_screentime-10.3.1.tar.gz", hash = "sha256:351179d5bf951aa754c72f50ba8785212adf1b26abe10149c750fafd0a3108ae", size = 13365 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/38/a5/b2b9c57eb364ccc1074442ce956b0052f71e903b7b944a93bc4888deb94d/pyobjc_framework_screentime-10.3.1.tar.gz", hash = "sha256:351179d5bf951aa754c72f50ba8785212adf1b26abe10149c750fafd0a3108ae", size = 13365 } wheels = [ { url = "https://files.pythonhosted.org/packages/b5/00/475bee668c55ca6d39464bb80ffb7e8c3012b027183e6d91c675b4b5e5aa/pyobjc_framework_ScreenTime-10.3.1-py2.py3-none-any.whl", hash = "sha256:d4f8a0784dc7d7060dadae2e4b5aae5e1afe8bbf453ce49cbb1860b8920114c3", size = 3403 }, ] @@ -4093,11 +4092,11 @@ wheels = [ name = "pyobjc-framework-scriptingbridge" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/10/45/ef1ae83f84555c3cf7ba18e53be9ace9f4225e56b852d7f5d79b5c516d4f/pyobjc_framework_scriptingbridge-10.3.1.tar.gz", hash = "sha256:6bfb45efd0a1cda38a37154afe69f86ea086d5cbdfbc33b3e31c0bda97537fe9", size = 20828 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/10/45/ef1ae83f84555c3cf7ba18e53be9ace9f4225e56b852d7f5d79b5c516d4f/pyobjc_framework_scriptingbridge-10.3.1.tar.gz", hash = "sha256:6bfb45efd0a1cda38a37154afe69f86ea086d5cbdfbc33b3e31c0bda97537fe9", size = 20828 } wheels = [ { url = "https://files.pythonhosted.org/packages/d8/4f/33f9ddb57f3cfc88d878e2bfbe99ecc10f775bd62a0bbc3b53ec4fad709c/pyobjc_framework_ScriptingBridge-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:3a88e1a6c6b7d8935ab4baa9dcdeccb9cb08a44906bdd69b77302f48c88408d9", size = 8365 }, { url = "https://files.pythonhosted.org/packages/10/bb/f692b524f4ff77535f6d7b4f9e54f8fa2ed5e82e01bea9506f5a78bbf9f8/pyobjc_framework_ScriptingBridge-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:66b55a9c12572f9bd6c00fd0a5aa5353354e7b717e37ffd1e843614d2fbde3d5", size = 8424 }, @@ -4109,11 +4108,11 @@ wheels = [ name = "pyobjc-framework-searchkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/85/74/1ee0012987c203f6776b7ca3da12b68623d9861c96ddc9575809c38864bc/pyobjc_framework_searchkit-10.3.1.tar.gz", hash = "sha256:7efb76b7af9d8f0f08efb91543f4dba0b00261ed41abb121ada80175cc82d65d", size = 30449 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-coreservices" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/85/74/1ee0012987c203f6776b7ca3da12b68623d9861c96ddc9575809c38864bc/pyobjc_framework_searchkit-10.3.1.tar.gz", hash = "sha256:7efb76b7af9d8f0f08efb91543f4dba0b00261ed41abb121ada80175cc82d65d", size = 30449 } wheels = [ { url = "https://files.pythonhosted.org/packages/a8/40/9c3231a96b55776338005ec60f278488111f4093af8bc9f1c7f17696406e/pyobjc_framework_SearchKit-10.3.1-py2.py3-none-any.whl", hash = "sha256:48ec776603e350405c7311f29d5941e0e9d6b6a75e2aec69e0acd28be0979905", size = 3320 }, ] @@ -4122,11 +4121,11 @@ wheels = [ name = "pyobjc-framework-security" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/db/3fa2a151c53f2d87d9da725948d33f8bb4c7f36d6cb468411ae4b46ad474/pyobjc_framework_security-10.3.1.tar.gz", hash = "sha256:0d4e679a8aebaef9b54bd24e2fe2794ad5c28d601b6d140ed38370594bcb6fa0", size = 252496 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/20/db/3fa2a151c53f2d87d9da725948d33f8bb4c7f36d6cb468411ae4b46ad474/pyobjc_framework_security-10.3.1.tar.gz", hash = "sha256:0d4e679a8aebaef9b54bd24e2fe2794ad5c28d601b6d140ed38370594bcb6fa0", size = 252496 } wheels = [ { url = "https://files.pythonhosted.org/packages/6f/d2/c8e65fd0d5905883bfae7c087645bba247e109570d5c55f814cdaa027eea/pyobjc_framework_Security-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:499372b4b87de0198601e0c6b3d3e43d48605218149a5808c6567b601147a9bf", size = 41023 }, { url = "https://files.pythonhosted.org/packages/36/96/f8f714d8eaa7e7741475a53c3e6a06cc550cd996153e5076fe2276e00ad2/pyobjc_framework_Security-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b3daed9661bd80245dd8dbc738a17870226969db27f6dbb3424ec0ebdbb6ba83", size = 41069 }, @@ -4137,12 +4136,12 @@ wheels = [ name = "pyobjc-framework-securityfoundation" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/40/d6/908dcceb7cd5dcfa3ff265dfcb945a8707256f7ab09ee709d86cb26ae1d4/pyobjc_framework_securityfoundation-10.3.1.tar.gz", hash = "sha256:414b13acabfae584729cd614e27247d250ec225d31140e8d971aa08536d6150c", size = 12595 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-security" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/40/d6/908dcceb7cd5dcfa3ff265dfcb945a8707256f7ab09ee709d86cb26ae1d4/pyobjc_framework_securityfoundation-10.3.1.tar.gz", hash = "sha256:414b13acabfae584729cd614e27247d250ec225d31140e8d971aa08536d6150c", size = 12595 } wheels = [ { url = "https://files.pythonhosted.org/packages/93/43/3f0b77bc72a9c419b355cbdaaa4a289ae838f6593421292b790b58512888/pyobjc_framework_SecurityFoundation-10.3.1-py2.py3-none-any.whl", hash = "sha256:c352cde672c9c2afa89575c362a0714e589c118485cec49ba230327e92c8a9a6", size = 3383 }, ] @@ -4151,12 +4150,12 @@ wheels = [ name = "pyobjc-framework-securityinterface" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b6/8b/d2dfd658f279fe6d3416b45c5030a65342ded0150ba56e028f6dcc9b38e1/pyobjc_framework_securityinterface-10.3.1.tar.gz", hash = "sha256:cd25f342a2b53cbffd134443506d5e75c96ba7145135debb8932c1252d57269a", size = 31921 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-security" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/b6/8b/d2dfd658f279fe6d3416b45c5030a65342ded0150ba56e028f6dcc9b38e1/pyobjc_framework_securityinterface-10.3.1.tar.gz", hash = "sha256:cd25f342a2b53cbffd134443506d5e75c96ba7145135debb8932c1252d57269a", size = 31921 } wheels = [ { url = "https://files.pythonhosted.org/packages/05/17/ba99db445a991ecba87f82d190756fb9c9943c68000e2e7d093e830f1051/pyobjc_framework_SecurityInterface-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:7a9bbca70e8a27bd79a0b8846f7d08b693dd309ff780f92f713fee57ff9d3ddf", size = 10731 }, { url = "https://files.pythonhosted.org/packages/b6/e3/281084dfecb61453da2ccf36c8cbf3c6db24191c973a0c4f14397a1ec186/pyobjc_framework_SecurityInterface-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:b964ecbde276611c14fd70884ab9c08c4aae75633deda1a29813dbe42dc83dd6", size = 10780 }, @@ -4168,12 +4167,12 @@ wheels = [ name = "pyobjc-framework-sensitivecontentanalysis" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ef/3d/7b50fb510374640c7562fc3cc83a75d91bd23f3f53a15579bd0061ffc3bd/pyobjc_framework_sensitivecontentanalysis-10.3.1.tar.gz", hash = "sha256:ac8dd18d77ccc0bb4eb24839cf39da9981db64e53f52b09636e47bd7b3066f84", size = 12006 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/ef/3d/7b50fb510374640c7562fc3cc83a75d91bd23f3f53a15579bd0061ffc3bd/pyobjc_framework_sensitivecontentanalysis-10.3.1.tar.gz", hash = "sha256:ac8dd18d77ccc0bb4eb24839cf39da9981db64e53f52b09636e47bd7b3066f84", size = 12006 } wheels = [ { url = "https://files.pythonhosted.org/packages/fc/bc/09d3c469f63366eff7caf148e53bf38a3752178a62a99881a0ef11453549/pyobjc_framework_SensitiveContentAnalysis-10.3.1-py2.py3-none-any.whl", hash = "sha256:6b5cfe771a28300d766ff14ff81313fda946943d54a039d5574478a070933e03", size = 3451 }, ] @@ -4182,11 +4181,11 @@ wheels = [ name = "pyobjc-framework-servicemanagement" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/de/f60506eef312ea3cbd5eacd1308bfb7e68f8d1a032573840f46b7de3a122/pyobjc_framework_servicemanagement-10.3.1.tar.gz", hash = "sha256:d048a803ad34c997dcc99ba778fca9d91cc5adfa1d115202e4bf22d9b04fd92c", size = 15746 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/ec/de/f60506eef312ea3cbd5eacd1308bfb7e68f8d1a032573840f46b7de3a122/pyobjc_framework_servicemanagement-10.3.1.tar.gz", hash = "sha256:d048a803ad34c997dcc99ba778fca9d91cc5adfa1d115202e4bf22d9b04fd92c", size = 15746 } wheels = [ { url = "https://files.pythonhosted.org/packages/09/ed/72cbba493d3e6d17127f39f1436b12248a812ca9714fdcf02f6834e7bb93/pyobjc_framework_ServiceManagement-10.3.1-py2.py3-none-any.whl", hash = "sha256:6b7ca0de9cf74439df0947aae29f5f31d58eeacb0ff55e1465faed540d31de4b", size = 4927 }, ] @@ -4195,11 +4194,11 @@ wheels = [ name = "pyobjc-framework-sharedwithyou" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/c8/261b3ae7063550b157fd33e9931c53007e4b7ff209a6d5a393b301af67c3/pyobjc_framework_sharedwithyou-10.3.1.tar.gz", hash = "sha256:7e35b631bc77b040151515e4fee9c8f47bc313924fc3e5970e940f1343db039b", size = 27924 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-sharedwithyoucore" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/a2/c8/261b3ae7063550b157fd33e9931c53007e4b7ff209a6d5a393b301af67c3/pyobjc_framework_sharedwithyou-10.3.1.tar.gz", hash = "sha256:7e35b631bc77b040151515e4fee9c8f47bc313924fc3e5970e940f1343db039b", size = 27924 } wheels = [ { url = "https://files.pythonhosted.org/packages/f9/94/e54dfbdb57e82d65cc78a881ed02240e7bd6f12b4b8da5d003ff18acaf07/pyobjc_framework_SharedWithYou-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:175cb32c93c55511f86ccf02b1da2fdcbc2a0f92422d451ff5dd4a864b3f3faf", size = 8782 }, { url = "https://files.pythonhosted.org/packages/e8/35/ccb26fa87164b6616f208b87fc255cce06bb23443473f1fa3ab2f89fa59d/pyobjc_framework_SharedWithYou-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:8a1ee78d6220e02e073c5fe6fea8f223ef870086c1afe60f346e7bb3dbdcb165", size = 8831 }, @@ -4211,11 +4210,11 @@ wheels = [ name = "pyobjc-framework-sharedwithyoucore" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/ba/09d6cfb51167b14711d2a2526d69994566eec101578af0e39b84a4794e5b/pyobjc_framework_sharedwithyoucore-10.3.1.tar.gz", hash = "sha256:e4768b7fdb18730e225bbebc9c9f9acfa7e44e648875816aff8c7e7f0e82afbf", size = 24331 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/58/ba/09d6cfb51167b14711d2a2526d69994566eec101578af0e39b84a4794e5b/pyobjc_framework_sharedwithyoucore-10.3.1.tar.gz", hash = "sha256:e4768b7fdb18730e225bbebc9c9f9acfa7e44e648875816aff8c7e7f0e82afbf", size = 24331 } wheels = [ { url = "https://files.pythonhosted.org/packages/f3/4f/7d1f125b94f5fd88d66c4d5969b54fd2902e9c683a6ad6092e8b8638856e/pyobjc_framework_SharedWithYouCore-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:b0fb4e84e15765d913d5383b61004b7ff9a637f198ec7c3dee07632f3a4e2b4c", size = 8540 }, { url = "https://files.pythonhosted.org/packages/ba/d7/06cc06c15fa69500c9f321e575cc296913e560b04ab448b477f7bec012d3/pyobjc_framework_SharedWithYouCore-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:9b480058016216e5a3715e3ff50f5430159ec4235dcd110141f53637f5dbb51d", size = 8589 }, @@ -4227,11 +4226,11 @@ wheels = [ name = "pyobjc-framework-shazamkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/07/d7/5cf2157fd163084d75d1cf9cf2de774d373387162a7b03c19cbcd193f22f/pyobjc_framework_shazamkit-10.3.1.tar.gz", hash = "sha256:deef11a43e773b876df31eeadbfc447892fda0607e314ca2afb2c012284cfa32", size = 22923 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/07/d7/5cf2157fd163084d75d1cf9cf2de774d373387162a7b03c19cbcd193f22f/pyobjc_framework_shazamkit-10.3.1.tar.gz", hash = "sha256:deef11a43e773b876df31eeadbfc447892fda0607e314ca2afb2c012284cfa32", size = 22923 } wheels = [ { url = "https://files.pythonhosted.org/packages/05/05/ac965959bfd2261bbcc590e1db7f9b7b59a39736db6b7398a20a8d510d38/pyobjc_framework_ShazamKit-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cc77fde1503ec1f96d7b9a05ad784d29d94065732f0cfe089321be423e5045f3", size = 8628 }, { url = "https://files.pythonhosted.org/packages/77/03/470f30e129d93faee2cc418a38acabd16b331b403cb201d3cefe380ae9a4/pyobjc_framework_ShazamKit-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:012560cab1997c1da6e19388b5192f68dcdf806c2f8d7bd1e66da37512d18b30", size = 8652 }, @@ -4242,11 +4241,11 @@ wheels = [ name = "pyobjc-framework-social" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/a8/c5a8ea9eea5ec096e03fcda22f3bf5077710a988dbcdbc543afed7478d34/pyobjc_framework_social-10.3.1.tar.gz", hash = "sha256:d1303cf3860ad02a8795c099e17888923505a9c45be407da50721a9a8a5b2efd", size = 13749 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/94/a8/c5a8ea9eea5ec096e03fcda22f3bf5077710a988dbcdbc543afed7478d34/pyobjc_framework_social-10.3.1.tar.gz", hash = "sha256:d1303cf3860ad02a8795c099e17888923505a9c45be407da50721a9a8a5b2efd", size = 13749 } wheels = [ { url = "https://files.pythonhosted.org/packages/89/bc/aa8ad14fc35f7a08fdc78757bfb341f3f4da9c6c8036201777d5f17b5ca7/pyobjc_framework_Social-10.3.1-py2.py3-none-any.whl", hash = "sha256:f83617c07db7c8bd15b3b9e0878ab2b6a286dcbd9a8c7f451da204f75db880e9", size = 4065 }, ] @@ -4255,11 +4254,11 @@ wheels = [ name = "pyobjc-framework-soundanalysis" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/23/bb9bc28f3d96e1316ac257b6b0605bcefb4b38879b9594272bbc9505e341/pyobjc_framework_soundanalysis-10.3.1.tar.gz", hash = "sha256:faa533644231f99dbdc2fcc3ecb9181c5df4f4dc68d42856729214021c83c881", size = 15578 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/cc/23/bb9bc28f3d96e1316ac257b6b0605bcefb4b38879b9594272bbc9505e341/pyobjc_framework_soundanalysis-10.3.1.tar.gz", hash = "sha256:faa533644231f99dbdc2fcc3ecb9181c5df4f4dc68d42856729214021c83c881", size = 15578 } wheels = [ { url = "https://files.pythonhosted.org/packages/5a/f6/350c7b3e9ceba976a4669c87b86cf378918cb6938a6083cc16aeb271c81b/pyobjc_framework_SoundAnalysis-10.3.1-py2.py3-none-any.whl", hash = "sha256:ef67207ff4045e5db37f017bdcd07d4b42464c86fe6c3b56524f6f22a9cde216", size = 3789 }, ] @@ -4268,11 +4267,11 @@ wheels = [ name = "pyobjc-framework-speech" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e6/8c/cc25b4267f884139b9677ea3fed8a8b99c423ef3f72dcc35eae6a01e4007/pyobjc_framework_speech-10.3.1.tar.gz", hash = "sha256:5b77b1d1ced0d1ad7244037b865dda2b83e8f9562d76d1e9fa4fea3b89e437b8", size = 29979 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/e6/8c/cc25b4267f884139b9677ea3fed8a8b99c423ef3f72dcc35eae6a01e4007/pyobjc_framework_speech-10.3.1.tar.gz", hash = "sha256:5b77b1d1ced0d1ad7244037b865dda2b83e8f9562d76d1e9fa4fea3b89e437b8", size = 29979 } wheels = [ { url = "https://files.pythonhosted.org/packages/4c/13/112143807eae621c4237bdc75e6275af9915313ea64cffe3fd6e255ca6ae/pyobjc_framework_Speech-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:07afd82d76b98b67a78c07098a814a0b862bcf00fc072d49d8da435202008a18", size = 9135 }, { url = "https://files.pythonhosted.org/packages/14/f1/6902241407b59de5c889e72fe05a329d107e97e50c6829023b9adfbab7e7/pyobjc_framework_Speech-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:444994d062286ff2769e07425d511503b2047b381afad1d64c8517ef4e44d01f", size = 9190 }, @@ -4284,12 +4283,12 @@ wheels = [ name = "pyobjc-framework-spritekit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/a3/037c63ce21d3a01d1d3c891b17979c5c1ce13a0893c97848bf2eb3e30442/pyobjc_framework_spritekit-10.3.1.tar.gz", hash = "sha256:2c11f35f48302f487c51ba8030f5cf79493a9dc0993dd901016ae4b8d8047c8b", size = 95557 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/fc/a3/037c63ce21d3a01d1d3c891b17979c5c1ce13a0893c97848bf2eb3e30442/pyobjc_framework_spritekit-10.3.1.tar.gz", hash = "sha256:2c11f35f48302f487c51ba8030f5cf79493a9dc0993dd901016ae4b8d8047c8b", size = 95557 } wheels = [ { url = "https://files.pythonhosted.org/packages/cd/15/df384944ae0699ff3dffe20e0f9f3d64f09d58d2ee33dbc4beff2e359e38/pyobjc_framework_SpriteKit-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:af355eccc18437e0932e1b327817e8f50d194bfa471b65b4733185ba606ab792", size = 17827 }, { url = "https://files.pythonhosted.org/packages/78/19/60a5a3da996744095234e01445e93cbfdedb44dd0b0e01b661bb6618de7b/pyobjc_framework_SpriteKit-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c3fd6aaecd7abd6ebc83d4c37a22950d55b75911fdb99628b2677f44085a0212", size = 17881 }, @@ -4300,11 +4299,11 @@ wheels = [ name = "pyobjc-framework-storekit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bb/42/e0ebe600ca0572fea164c2308bdd8866cb09167ef1617ed66d5c9a9a6026/pyobjc_framework_storekit-10.3.1.tar.gz", hash = "sha256:913b4aad7dc31df7d8011c54a695da65cc57819f4b48c98abaed4e6d9ff7d323", size = 63667 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/bb/42/e0ebe600ca0572fea164c2308bdd8866cb09167ef1617ed66d5c9a9a6026/pyobjc_framework_storekit-10.3.1.tar.gz", hash = "sha256:913b4aad7dc31df7d8011c54a695da65cc57819f4b48c98abaed4e6d9ff7d323", size = 63667 } wheels = [ { url = "https://files.pythonhosted.org/packages/04/dd/a10721d0d7634deff95a2e5d514269fa89b8d1754a7c724d85eab155286b/pyobjc_framework_StoreKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:f9c50a980846b236884504ad42690d49935bda3de5d779fca3cdfb16d43fa8d1", size = 12630 }, { url = "https://files.pythonhosted.org/packages/d7/45/06593054fa5ac13701e1571f1560b0b9418e47b0a8f98dcd8521ca748804/pyobjc_framework_StoreKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:b3846b249a6fc5d26c80320098858978e0a16f46e98fc998075f16f539ac89fc", size = 12682 }, @@ -4316,11 +4315,11 @@ wheels = [ name = "pyobjc-framework-symbols" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/2b/e32921c7f2e00ba41fdd6befc0f7aabf17bc4c136f2b6a0cf4f44939940e/pyobjc_framework_symbols-10.3.1.tar.gz", hash = "sha256:3e3f35ef3646b5f9c0653d9dbf5693cf87de3df04420cb2679dad74c75965d18", size = 11785 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/d7/2b/e32921c7f2e00ba41fdd6befc0f7aabf17bc4c136f2b6a0cf4f44939940e/pyobjc_framework_symbols-10.3.1.tar.gz", hash = "sha256:3e3f35ef3646b5f9c0653d9dbf5693cf87de3df04420cb2679dad74c75965d18", size = 11785 } wheels = [ { url = "https://files.pythonhosted.org/packages/97/bb/f4a01bec12bc1c9dfe86b0428d39a5e9d5614e0f433b5eda42af43d3d1c0/pyobjc_framework_Symbols-10.3.1-py2.py3-none-any.whl", hash = "sha256:6e171da5af2612e186cc4cf896ad7f2672c021a1fc18bc8ef49b79c4c831202d", size = 2958 }, ] @@ -4329,12 +4328,12 @@ wheels = [ name = "pyobjc-framework-syncservices" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/77/eb/6b73844bc7a4f964128cde7fffbe4243b62c691626b4b101337b6ac7caff/pyobjc_framework_syncservices-10.3.1.tar.gz", hash = "sha256:1cd5e3eaf85a11996184afad1da47037cd921e302ccb35fe388b19f91a685669", size = 49572 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-coredata" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/77/eb/6b73844bc7a4f964128cde7fffbe4243b62c691626b4b101337b6ac7caff/pyobjc_framework_syncservices-10.3.1.tar.gz", hash = "sha256:1cd5e3eaf85a11996184afad1da47037cd921e302ccb35fe388b19f91a685669", size = 49572 } wheels = [ { url = "https://files.pythonhosted.org/packages/da/cf/bf62d8583436bad00a8b0bf59a6f0b1009b25229f51522a22f2164beeff5/pyobjc_framework_SyncServices-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:aa98a38f59f230da7817dc08055c8049fa961193af16caa262c51e4ec8b5de20", size = 14394 }, { url = "https://files.pythonhosted.org/packages/ca/ed/3a406dde3ec505c5650ce8b379e566f146a84a22efca1b7a12a10e61e613/pyobjc_framework_SyncServices-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:9d3798cc745143d44da101bb0eb9d482326b761f48c3699251191e9c3656ee6c", size = 14450 }, @@ -4346,11 +4345,11 @@ wheels = [ name = "pyobjc-framework-systemconfiguration" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1f/34/4a8a79ae382296533cf0aa51377f53d9157aa41484c83a506d9dc43fc9e1/pyobjc_framework_systemconfiguration-10.3.1.tar.gz", hash = "sha256:1bf6ffe98faa4e208bf594c857ba23cd56fe404bc579188ff53b704844d9c402", size = 124143 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/1f/34/4a8a79ae382296533cf0aa51377f53d9157aa41484c83a506d9dc43fc9e1/pyobjc_framework_systemconfiguration-10.3.1.tar.gz", hash = "sha256:1bf6ffe98faa4e208bf594c857ba23cd56fe404bc579188ff53b704844d9c402", size = 124143 } wheels = [ { url = "https://files.pythonhosted.org/packages/fc/23/4986e3f009493910f552e74cf239e09802d1df059075b021611959f22c5f/pyobjc_framework_SystemConfiguration-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:200c4b7d3483e5ccb86d4d5783ace8c26d4b3f9130684280f30080d53f62d4c5", size = 21723 }, { url = "https://files.pythonhosted.org/packages/9c/65/c2db36889167836e1d26134c650e638cbf0667ceb815b2cc6d8bb9ed1ced/pyobjc_framework_SystemConfiguration-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:403392b0e2085cf528547d468bc523fbee418381bb61446eb4aa1f9a1c8a8494", size = 21800 }, @@ -4362,11 +4361,11 @@ wheels = [ name = "pyobjc-framework-systemextensions" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dd/d2/eab93a69f95c757104112cb0bce3e1fc70de59ca47ff0c60d180f306819f/pyobjc_framework_systemextensions-10.3.1.tar.gz", hash = "sha256:34412e75c95a585d222ea23efc3eba436210ec0345cec6c7dc78d16e027d03e1", size = 19844 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/dd/d2/eab93a69f95c757104112cb0bce3e1fc70de59ca47ff0c60d180f306819f/pyobjc_framework_systemextensions-10.3.1.tar.gz", hash = "sha256:34412e75c95a585d222ea23efc3eba436210ec0345cec6c7dc78d16e027d03e1", size = 19844 } wheels = [ { url = "https://files.pythonhosted.org/packages/0e/a9/5c97bbf22f792fd4beb01dc2bad894eab5f62687122fd9b156c743c04f8f/pyobjc_framework_SystemExtensions-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:b24edd33c71cb02a16bdd9b26d3a229a6b2a815c26a4c908b1b8b6cdf4f6c84a", size = 8672 }, { url = "https://files.pythonhosted.org/packages/d5/bd/caf73e19fb2b4bae267df4cef98debfad7db265228337c4ab84540507561/pyobjc_framework_SystemExtensions-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:e2a24501a782d2b6f7fa339619eb5c988db6b31a6043d029f40f67c54fd9399e", size = 8739 }, @@ -4378,11 +4377,11 @@ wheels = [ name = "pyobjc-framework-threadnetwork" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/6c/c502594ac550436bb8d989b18734eeabd5ce189c2ebb1f4895e3e00d424d/pyobjc_framework_threadnetwork-10.3.1.tar.gz", hash = "sha256:1038210a8e5dfa86aefd10894563913e767e95d1c1bd4333ae5f9c6cabbb3ce9", size = 12639 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/dc/6c/c502594ac550436bb8d989b18734eeabd5ce189c2ebb1f4895e3e00d424d/pyobjc_framework_threadnetwork-10.3.1.tar.gz", hash = "sha256:1038210a8e5dfa86aefd10894563913e767e95d1c1bd4333ae5f9c6cabbb3ce9", size = 12639 } wheels = [ { url = "https://files.pythonhosted.org/packages/21/d0/bcc8756d01a1d4f400148f67123a7238429be7c2ddb95f94d15beec8372f/pyobjc_framework_ThreadNetwork-10.3.1-py2.py3-none-any.whl", hash = "sha256:95ddbed8a114cc1f05db613bb53247465ec48ccaad2b56f5da466317808fc32b", size = 3377 }, ] @@ -4391,11 +4390,11 @@ wheels = [ name = "pyobjc-framework-uniformtypeidentifiers" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1f/54/10c56c741e7c95ee4dd8db06afac5e59722e5372e35f3c5a3e7c2954c746/pyobjc_framework_uniformtypeidentifiers-10.3.1.tar.gz", hash = "sha256:1985fee7e1f1157db36f3c19ee0ad273677eeff10467f575086246bbeffcdf50", size = 18476 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/1f/54/10c56c741e7c95ee4dd8db06afac5e59722e5372e35f3c5a3e7c2954c746/pyobjc_framework_uniformtypeidentifiers-10.3.1.tar.gz", hash = "sha256:1985fee7e1f1157db36f3c19ee0ad273677eeff10467f575086246bbeffcdf50", size = 18476 } wheels = [ { url = "https://files.pythonhosted.org/packages/37/5c/48f1c942fa870439598e296eb2136fc5cec3f4a6e08bff25f727dc5e9bb8/pyobjc_framework_UniformTypeIdentifiers-10.3.1-py2.py3-none-any.whl", hash = "sha256:8bd1516ccec1807e2ad92a071242d83e9d1eda08ddbfae04dacc30d76c3d734c", size = 4467 }, ] @@ -4404,11 +4403,11 @@ wheels = [ name = "pyobjc-framework-usernotifications" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/d2/32432d2b579ca393f65f7ae7b53cf887f2efda861c4e1b372428f65dd4bf/pyobjc_framework_usernotifications-10.3.1.tar.gz", hash = "sha256:ddb5de88fb659c2241429b6408ddcabbfc0c2c9e4a7f5f543a6fab1c4953403b", size = 45987 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/12/d2/32432d2b579ca393f65f7ae7b53cf887f2efda861c4e1b372428f65dd4bf/pyobjc_framework_usernotifications-10.3.1.tar.gz", hash = "sha256:ddb5de88fb659c2241429b6408ddcabbfc0c2c9e4a7f5f543a6fab1c4953403b", size = 45987 } wheels = [ { url = "https://files.pythonhosted.org/packages/e6/63/3d1151dd355936977c3a713d0952f384d0f175e2d8ed29352ba374f17c80/pyobjc_framework_UserNotifications-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:d85c293e0520530ac7152b3f293c5606f0495b7727de331ef4e198278bf40e98", size = 9677 }, { url = "https://files.pythonhosted.org/packages/32/4d/631dd68f95261db9acd8488519bf9afd9359686cd5a027ba653f64b60f04/pyobjc_framework_UserNotifications-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:0001bb25f15e6f8cac81bcb58cab8161a15a6fe41f6c475e8da364c913bdb090", size = 9721 }, @@ -4420,12 +4419,12 @@ wheels = [ name = "pyobjc-framework-usernotificationsui" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/10/a525f13919955d653fd431f527974e2604b0b8727c886de1ec7e2bf34189/pyobjc_framework_usernotificationsui-10.3.1.tar.gz", hash = "sha256:80390b5361bb6014dc32d0afbf581280e7762a4f67460a736f461f613d397094", size = 13288 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-usernotifications" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/df/10/a525f13919955d653fd431f527974e2604b0b8727c886de1ec7e2bf34189/pyobjc_framework_usernotificationsui-10.3.1.tar.gz", hash = "sha256:80390b5361bb6014dc32d0afbf581280e7762a4f67460a736f461f613d397094", size = 13288 } wheels = [ { url = "https://files.pythonhosted.org/packages/17/4b/1a198d4d8907d83f4334d34dae76572e18362391ee0644c9a5bc002980e7/pyobjc_framework_UserNotificationsUI-10.3.1-py2.py3-none-any.whl", hash = "sha256:bc6cb92a6ac947e8fe9685f3c1964c5a9f98e576b936b0bbff8c528f47f976d2", size = 3522 }, ] @@ -4434,11 +4433,11 @@ wheels = [ name = "pyobjc-framework-videosubscriberaccount" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c8/a6/41d6afaa800bf8839c45642b60d7fa13a0e292d477762c33ce22ba1c0aa6/pyobjc_framework_videosubscriberaccount-10.3.1.tar.gz", hash = "sha256:f62509e976b805bc76ff5928444677ac542b52dd9f7781ac0731d7c4b22bed96", size = 23793 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/c8/a6/41d6afaa800bf8839c45642b60d7fa13a0e292d477762c33ce22ba1c0aa6/pyobjc_framework_videosubscriberaccount-10.3.1.tar.gz", hash = "sha256:f62509e976b805bc76ff5928444677ac542b52dd9f7781ac0731d7c4b22bed96", size = 23793 } wheels = [ { url = "https://files.pythonhosted.org/packages/88/38/a9e721db0fa383eeabaadd6c6762ea33d6f50a25c22b70ee82c31d536e66/pyobjc_framework_VideoSubscriberAccount-10.3.1-py2.py3-none-any.whl", hash = "sha256:4b489f0007dce8ea17f37316175dac2768cd173a4d4c7a1d5f87fb3991c1e518", size = 4295 }, ] @@ -4447,13 +4446,13 @@ wheels = [ name = "pyobjc-framework-videotoolbox" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/e4/435561672801cb29a398b208e75e6823e6c369027cd51f0774f3b24f2baf/pyobjc_framework_videotoolbox-10.3.1.tar.gz", hash = "sha256:7ebc281523b2b37aff17ce6eabd0c81081864b3e3e4a83ae72b18fd70c57c521", size = 66253 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-coremedia" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/65/e4/435561672801cb29a398b208e75e6823e6c369027cd51f0774f3b24f2baf/pyobjc_framework_videotoolbox-10.3.1.tar.gz", hash = "sha256:7ebc281523b2b37aff17ce6eabd0c81081864b3e3e4a83ae72b18fd70c57c521", size = 66253 } wheels = [ { url = "https://files.pythonhosted.org/packages/f7/98/96be1155746ad418400628191c9dd5e8354bb9f7f842c3c134a04d47efa5/pyobjc_framework_VideoToolbox-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:bc52aa91f568060e0087762f2a4d876bf7b683e5396779e93925252e26f0330b", size = 12471 }, { url = "https://files.pythonhosted.org/packages/3b/e1/dbe5951097e627f6a7be79ee9a662beba8fb4eb20cebabab1d810f4aa881/pyobjc_framework_VideoToolbox-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:3d20ea92b597f4758f24ed8e19f7a7a372faf6478d739e7cb7f7cd73d3e8617a", size = 12527 }, @@ -4465,11 +4464,11 @@ wheels = [ name = "pyobjc-framework-virtualization" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2e/d1/427065aab5570855228fe0bc3d387fcc4c76e18538c28c5fc2497b0f75f2/pyobjc_framework_virtualization-10.3.1.tar.gz", hash = "sha256:8348ddef18eb943d151e5b5977e4d410012ee2e3f6048c16f7cfe0c1a73536cb", size = 61591 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/2e/d1/427065aab5570855228fe0bc3d387fcc4c76e18538c28c5fc2497b0f75f2/pyobjc_framework_virtualization-10.3.1.tar.gz", hash = "sha256:8348ddef18eb943d151e5b5977e4d410012ee2e3f6048c16f7cfe0c1a73536cb", size = 61591 } wheels = [ { url = "https://files.pythonhosted.org/packages/6a/3f/5e11618a50c525bd89b8219360f1782dc6aff52cae6548cd767dc32af74c/pyobjc_framework_Virtualization-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:c046abcebf6a64a47ea50311f3e4aaae424dbac719e847cd15b375ebe99a51ed", size = 12300 }, { url = "https://files.pythonhosted.org/packages/2f/41/9ef6d54da4bbc517ca5132a01e385b0ec3e329f9437a12fea608016a89a1/pyobjc_framework_Virtualization-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:dc14f6c3deaf367adff18b509e766dc78c4695a4cd76e4aad3ff4b1e207a4635", size = 12343 }, @@ -4481,13 +4480,13 @@ wheels = [ name = "pyobjc-framework-vision" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/55/ff278351cb47f939a932dc5d9d80a8a0d51a427e27e0419833d49219e757/pyobjc_framework_vision-10.3.1.tar.gz", hash = "sha256:aa071656d395afc2d624600a9f30d6a3344aa747bf37f613ff3972158c40881c", size = 108532 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, { name = "pyobjc-framework-coreml" }, { name = "pyobjc-framework-quartz" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/7c/55/ff278351cb47f939a932dc5d9d80a8a0d51a427e27e0419833d49219e757/pyobjc_framework_vision-10.3.1.tar.gz", hash = "sha256:aa071656d395afc2d624600a9f30d6a3344aa747bf37f613ff3972158c40881c", size = 108532 } wheels = [ { url = "https://files.pythonhosted.org/packages/24/4a/c6e7e1aaa2e095be007c82fa4861fae9496737a6a446b0671e12d39bd1fd/pyobjc_framework_Vision-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:dff3582678930461a0bb11bf070854d49f6944a851dc89edc63fac93c75ddf39", size = 17706 }, { url = "https://files.pythonhosted.org/packages/63/a0/aa85feda6dc7d3a516f4d5059e421a7692d1f4d43e9d3f66e4f56f1281cb/pyobjc_framework_Vision-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:32626183c51674efb3b5738e2884c3fea37edca010117cf71bd72cb3c49c869a", size = 22423 }, @@ -4499,11 +4498,11 @@ wheels = [ name = "pyobjc-framework-webkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/6b/50c1000354e9de966a150b4a41c291c83517eec9bd162f43ea4e55444d64/pyobjc_framework_webkit-10.3.1.tar.gz", hash = "sha256:7ad9f4eb91a6dff39848d9c2ab71f170aeab4b6396bcec8e5a780739f9be4222", size = 610874 } dependencies = [ { name = "pyobjc-core" }, { name = "pyobjc-framework-cocoa" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/15/6b/50c1000354e9de966a150b4a41c291c83517eec9bd162f43ea4e55444d64/pyobjc_framework_webkit-10.3.1.tar.gz", hash = "sha256:7ad9f4eb91a6dff39848d9c2ab71f170aeab4b6396bcec8e5a780739f9be4222", size = 610874 } wheels = [ { url = "https://files.pythonhosted.org/packages/3b/8b/bddff1733fb4da9b23039b1a51f755a446a127fbab08a6e4fbaae0445510/pyobjc_framework_WebKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:df52913e4c3cb77d4551d9848e30be01b82cace54cede850c88a7e0ab41a20a9", size = 44518 }, { url = "https://files.pythonhosted.org/packages/fa/e9/304f8cc6e3a5ac7062c77134e14579ad33941a761b43c97f1be8aa16ad0a/pyobjc_framework_WebKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:207a7aa57817d3ab3fa033e42ab612f8c00521f13ff2871547c92cd94ed51f85", size = 44626 }, @@ -4515,12 +4514,12 @@ wheels = [ name = "pyogrio" version = "0.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/09/a13ffa71f617f3c76f31984bc4fc237aede9988d89056b278efcb97f6fb0/pyogrio-0.9.0.tar.gz", hash = "sha256:6a6fa2e8cf95b3d4a7c0fac48bce6e5037579e28d3eb33b53349d6e11f15e5a8", size = 352526 } dependencies = [ { name = "certifi" }, { name = "numpy" }, { name = "packaging" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/4e/09/a13ffa71f617f3c76f31984bc4fc237aede9988d89056b278efcb97f6fb0/pyogrio-0.9.0.tar.gz", hash = "sha256:6a6fa2e8cf95b3d4a7c0fac48bce6e5037579e28d3eb33b53349d6e11f15e5a8", size = 352526 } wheels = [ { url = "https://files.pythonhosted.org/packages/21/c2/f4ce7e004550a1ff74c83465fb9d11507f2d77dfab54203320e68fcd3c90/pyogrio-0.9.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f5d80eb846be4fc4e642cbedc1ed0c143e8d241653382ecc76a7620bbd2a5c3a", size = 14750921 }, { url = "https://files.pythonhosted.org/packages/70/b1/d04cdfe873f79fdf166c6bc8d774788bc9b981a1da61a24cb37d477f9c4e/pyogrio-0.9.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:2f2ec57ab74785db9c2bf47c0a6731e5175595a13f8253f06fa84136adb310a9", size = 16084054 }, @@ -4538,12 +4537,12 @@ wheels = [ name = "pyopencl" version = "2024.2.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/92/68/a26269be1ba101b740a7b47d81032cf71c50a8700cc71ab2c49f0fcccec9/pyopencl-2024.2.7.tar.gz", hash = "sha256:6ae4458a959b6ad9c138fb711a52c4d57c2c2f798eb3aecc4c26830cb2726140", size = 470964 } dependencies = [ { name = "numpy" }, { name = "platformdirs" }, { name = "pytools" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/92/68/a26269be1ba101b740a7b47d81032cf71c50a8700cc71ab2c49f0fcccec9/pyopencl-2024.2.7.tar.gz", hash = "sha256:6ae4458a959b6ad9c138fb711a52c4d57c2c2f798eb3aecc4c26830cb2726140", size = 470964 } wheels = [ { url = "https://files.pythonhosted.org/packages/04/2b/0c830171d30de73c76a3ff92989959278d88d50e50e03b1ce5f1ffb04169/pyopencl-2024.2.7-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:31cc3907adb4d88e4b2cc05270054598a4544ed59539547a7eba11bb2304ea17", size = 450436 }, { url = "https://files.pythonhosted.org/packages/12/fc/db5f1a1c4251b8bc7ece6e55664b84de30d5fc71f4d505b5974082e366b3/pyopencl-2024.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a65049fa87b461fe35a28a35f63f33f7e8e5a9f2862c401a3dfaddf2597c6954", size = 442814 }, @@ -4561,10 +4560,10 @@ wheels = [ name = "pyopenssl" version = "24.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/91/a8/cbeec652549e30103b9e6147ad433405fdd18807ac2d54e6dbb73184d8a1/pyOpenSSL-24.1.0.tar.gz", hash = "sha256:cabed4bfaa5df9f1a16c0ef64a0cb65318b5cd077a7eda7d6970131ca2f41a6f", size = 179671 } dependencies = [ { name = "cryptography" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/91/a8/cbeec652549e30103b9e6147ad433405fdd18807ac2d54e6dbb73184d8a1/pyOpenSSL-24.1.0.tar.gz", hash = "sha256:cabed4bfaa5df9f1a16c0ef64a0cb65318b5cd077a7eda7d6970131ca2f41a6f", size = 179671 } wheels = [ { url = "https://files.pythonhosted.org/packages/54/a7/2104f674a5a6845b04c8ff01659becc6b8978ca410b82b94287e0b1e018b/pyOpenSSL-24.1.0-py3-none-any.whl", hash = "sha256:17ed5be5936449c5418d1cd269a1a9e9081bc54c17aed272b45856a3d3dc86ad", size = 56945 }, ] @@ -4594,10 +4593,10 @@ sdist = { url = "https://files.pythonhosted.org/packages/ca/2a/e9a76261183b4b5e0 name = "pyproj" version = "3.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/84/2b39bbf888c753ea48b40d47511548c77aa03445465c35cc4c4e9649b643/pyproj-3.6.1.tar.gz", hash = "sha256:44aa7c704c2b7d8fb3d483bbf75af6cb2350d30a63b144279a09b75fead501bf", size = 225131 } dependencies = [ { name = "certifi" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/7d/84/2b39bbf888c753ea48b40d47511548c77aa03445465c35cc4c4e9649b643/pyproj-3.6.1.tar.gz", hash = "sha256:44aa7c704c2b7d8fb3d483bbf75af6cb2350d30a63b144279a09b75fead501bf", size = 225131 } wheels = [ { url = "https://files.pythonhosted.org/packages/84/a6/a300c1b14b2112e966e9f90b18f9c13b586bdcf417207cee913ae9005da3/pyproj-3.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ebfbdbd0936e178091309f6cd4fcb4decd9eab12aa513cdd9add89efa3ec2882", size = 6147442 }, { url = "https://files.pythonhosted.org/packages/30/bd/b9bd3761f08754e8dbb34c5a647db2099b348ab5da338e90980caf280e37/pyproj-3.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:447db19c7efad70ff161e5e46a54ab9cc2399acebb656b6ccf63e4bc4a04b97a", size = 4880331 }, @@ -4617,10 +4616,10 @@ wheels = [ name = "pyqt5" version = "5.15.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/28/6c/640e3f5c734c296a7193079a86842a789edb7988dca39eab44579088a1d1/PyQt5-5.15.2.tar.gz", hash = "sha256:372b08dc9321d1201e4690182697c5e7ffb2e0770e6b4a45519025134b12e4fc", size = 3265445 } dependencies = [ { name = "pyqt5-sip" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/28/6c/640e3f5c734c296a7193079a86842a789edb7988dca39eab44579088a1d1/PyQt5-5.15.2.tar.gz", hash = "sha256:372b08dc9321d1201e4690182697c5e7ffb2e0770e6b4a45519025134b12e4fc", size = 3265445 } wheels = [ { url = "https://files.pythonhosted.org/packages/0f/28/fcaf2aeede42456538d1543aefa253d70282bf326f5f795c99233366b66f/PyQt5-5.15.2-5.15.2-cp35.cp36.cp37.cp38.cp39-abi3-macosx_10_13_intel.whl", hash = "sha256:894ca4ae767a8d6cf5903784b71f755073c78cb8c167eecf6e4ed6b3b055ac6a", size = 47599356 }, { url = "https://files.pythonhosted.org/packages/91/cf/cc705497cdae04c3c0bc34f94b91e31b6585bb65eb561f18473c998caae1/PyQt5-5.15.2-5.15.2-cp35.cp36.cp37.cp38.cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:29889845688a54d62820585ad5b2e0200a36b304ff3d7a555e95599f110ba4ce", size = 68328841 }, @@ -4663,10 +4662,10 @@ sdist = { url = "https://files.pythonhosted.org/packages/cb/04/2ba023d5f771b645f name = "pyscreeze" version = "0.1.30" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/f5/754a6f29a25c7ec375a2e2468ceb83926856b1f0532abd9ec7720ab26b30/PyScreeze-0.1.30.tar.gz", hash = "sha256:74098ad048e76a6231dcfa6243343af94459b8c829f9ccb7a44a5d3b147a67d1", size = 27789 } dependencies = [ { name = "pillow", marker = "python_version == '3.11'" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/88/f5/754a6f29a25c7ec375a2e2468ceb83926856b1f0532abd9ec7720ab26b30/PyScreeze-0.1.30.tar.gz", hash = "sha256:74098ad048e76a6231dcfa6243343af94459b8c829f9ccb7a44a5d3b147a67d1", size = 27789 } [[distribution]] name = "pyserial" @@ -4681,13 +4680,13 @@ wheels = [ name = "pytest" version = "8.2.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/58/e993ca5357553c966b9e73cb3475d9c935fe9488746e13ebdf9b80fae508/pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977", size = 1427980 } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/a6/58/e993ca5357553c966b9e73cb3475d9c935fe9488746e13ebdf9b80fae508/pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977", size = 1427980 } wheels = [ { url = "https://files.pythonhosted.org/packages/4e/e7/81ebdd666d3bff6670d27349b5053605d83d55548e6bd5711f3b0ae7dd23/pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", size = 339873 }, ] @@ -4696,10 +4695,10 @@ wheels = [ name = "pytest-asyncio" version = "0.23.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/d9/1dcac9b3fc6eccf8f1e3a657439c11ffc5cf762edd20f65577f832ba248b/pytest_asyncio-0.23.7.tar.gz", hash = "sha256:5f5c72948f4c49e7db4f29f2521d4031f1c27f86e57b046126654083d4770268", size = 46296 } dependencies = [ { name = "pytest" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/13/d9/1dcac9b3fc6eccf8f1e3a657439c11ffc5cf762edd20f65577f832ba248b/pytest_asyncio-0.23.7.tar.gz", hash = "sha256:5f5c72948f4c49e7db4f29f2521d4031f1c27f86e57b046126654083d4770268", size = 46296 } wheels = [ { url = "https://files.pythonhosted.org/packages/e5/98/947690b1a79af83e584143cb904497caff05bb6016614b38326a81076357/pytest_asyncio-0.23.7-py3-none-any.whl", hash = "sha256:009b48127fbe44518a547bddd25611551b0e43ccdbf1e67d12479f569832c20b", size = 17585 }, ] @@ -4708,11 +4707,11 @@ wheels = [ name = "pytest-cov" version = "5.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/74/67/00efc8d11b630c56f15f4ad9c7f9223f1e5ec275aaae3fa9118c6a223ad2/pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857", size = 63042 } dependencies = [ { name = "coverage" }, { name = "pytest" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/74/67/00efc8d11b630c56f15f4ad9c7f9223f1e5ec275aaae3fa9118c6a223ad2/pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857", size = 63042 } wheels = [ { url = "https://files.pythonhosted.org/packages/78/3a/af5b4fa5961d9a1e6237b530eb87dd04aea6eb83da09d2a4073d81b54ccf/pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652", size = 21990 }, ] @@ -4721,11 +4720,11 @@ wheels = [ name = "pytest-cpp" version = "2.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/72/6da4fd6ea5afd44e10dbed76ef666c0732e27317a753099bc163f3330a91/pytest-cpp-2.5.0.tar.gz", hash = "sha256:695604baa21bc95291bb4ea7263a7aa960753de57c2d17d224c4652fbcf65cdc", size = 465039 } dependencies = [ { name = "colorama" }, { name = "pytest" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/0f/72/6da4fd6ea5afd44e10dbed76ef666c0732e27317a753099bc163f3330a91/pytest-cpp-2.5.0.tar.gz", hash = "sha256:695604baa21bc95291bb4ea7263a7aa960753de57c2d17d224c4652fbcf65cdc", size = 465039 } wheels = [ { url = "https://files.pythonhosted.org/packages/32/d5/b7b5c75dc2e11555898fbec78f88970c43f27439436ac83e65de6afcd2c6/pytest_cpp-2.5.0-py3-none-any.whl", hash = "sha256:137bcaa6487307b4c362245fcd4abf35de64ee85e6375f4d06cd31e6a64f9701", size = 15064 }, ] @@ -4734,10 +4733,10 @@ wheels = [ name = "pytest-mock" version = "3.14.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c6/90/a955c3ab35ccd41ad4de556596fa86685bf4fc5ffcc62d22d856cfd4e29a/pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0", size = 32814 } dependencies = [ { name = "pytest" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/c6/90/a955c3ab35ccd41ad4de556596fa86685bf4fc5ffcc62d22d856cfd4e29a/pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0", size = 32814 } wheels = [ { url = "https://files.pythonhosted.org/packages/f2/3b/b26f90f74e2986a82df6e7ac7e319b8ea7ccece1caec9f8ab6104dc70603/pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f", size = 9863 }, ] @@ -4746,10 +4745,10 @@ wheels = [ name = "pytest-randomly" version = "3.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/d4/6e924a0b2855736d942703dec88dfc98b4fe0881c8fa849b6b0fbb9182fa/pytest_randomly-3.15.0.tar.gz", hash = "sha256:b908529648667ba5e54723088edd6f82252f540cc340d748d1fa985539687047", size = 21743 } dependencies = [ { name = "pytest" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/c9/d4/6e924a0b2855736d942703dec88dfc98b4fe0881c8fa849b6b0fbb9182fa/pytest_randomly-3.15.0.tar.gz", hash = "sha256:b908529648667ba5e54723088edd6f82252f540cc340d748d1fa985539687047", size = 21743 } wheels = [ { url = "https://files.pythonhosted.org/packages/24/d3/00e575657422055c4ea220b2f80e8cc6026ab7130372b7067444d1b0ac10/pytest_randomly-3.15.0-py3-none-any.whl", hash = "sha256:0516f4344b29f4e9cdae8bce31c4aeebf59d0b9ef05927c33354ff3859eeeca6", size = 8685 }, ] @@ -4758,10 +4757,10 @@ wheels = [ name = "pytest-repeat" version = "0.9.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/86/5e/99365eb229efff0b1bd475886150fc6db9937ab7e1bd21f6f65c1279e0eb/pytest_repeat-0.9.3.tar.gz", hash = "sha256:ffd3836dfcd67bb270bec648b330e20be37d2966448c4148c4092d1e8aba8185", size = 6272 } dependencies = [ { name = "pytest" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/86/5e/99365eb229efff0b1bd475886150fc6db9937ab7e1bd21f6f65c1279e0eb/pytest_repeat-0.9.3.tar.gz", hash = "sha256:ffd3836dfcd67bb270bec648b330e20be37d2966448c4148c4092d1e8aba8185", size = 6272 } wheels = [ { url = "https://files.pythonhosted.org/packages/49/a8/0a0aec0c2541b8baf4a0b95af2ba99abce217ee43534adf9cb7c908cf184/pytest_repeat-0.9.3-py3-none-any.whl", hash = "sha256:26ab2df18226af9d5ce441c858f273121e92ff55f5bb311d25755b8d7abdd8ed", size = 4196 }, ] @@ -4770,11 +4769,11 @@ wheels = [ name = "pytest-subtests" version = "0.13.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/95/be/cebc1b9f6358d174443f46737979e244048a385fe2b0be6fab2b96771dc5/pytest_subtests-0.13.0.tar.gz", hash = "sha256:9e02b9d243c0379b02abf3e0887da122bcb2714b021c3608a37f17ce210adce5", size = 15842 } dependencies = [ { name = "attrs" }, { name = "pytest" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/95/be/cebc1b9f6358d174443f46737979e244048a385fe2b0be6fab2b96771dc5/pytest_subtests-0.13.0.tar.gz", hash = "sha256:9e02b9d243c0379b02abf3e0887da122bcb2714b021c3608a37f17ce210adce5", size = 15842 } wheels = [ { url = "https://files.pythonhosted.org/packages/74/19/9fd9ff6e8827983bcfc74a39c4a98ab6b4c32b3f3403b917f352f7b83777/pytest_subtests-0.13.0-py3-none-any.whl", hash = "sha256:5a142064218df37a52299ddb393b1a6b2c1161ca19e71ca60c3a8040eb17e811", size = 8038 }, ] @@ -4783,10 +4782,10 @@ wheels = [ name = "pytest-timeout" version = "2.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/93/0d/04719abc7a4bdb3a7a1f968f24b0f5253d698c9cc94975330e9d3145befb/pytest-timeout-2.3.1.tar.gz", hash = "sha256:12397729125c6ecbdaca01035b9e5239d4db97352320af155b3f5de1ba5165d9", size = 17697 } dependencies = [ { name = "pytest" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/93/0d/04719abc7a4bdb3a7a1f968f24b0f5253d698c9cc94975330e9d3145befb/pytest-timeout-2.3.1.tar.gz", hash = "sha256:12397729125c6ecbdaca01035b9e5239d4db97352320af155b3f5de1ba5165d9", size = 17697 } wheels = [ { url = "https://files.pythonhosted.org/packages/03/27/14af9ef8321f5edc7527e47def2a21d8118c6f329a9342cc61387a0c0599/pytest_timeout-2.3.1-py3-none-any.whl", hash = "sha256:68188cb703edfc6a18fad98dc25a3c61e9f24d644b0b70f33af545219fc7813e", size = 14148 }, ] @@ -4795,11 +4794,11 @@ wheels = [ name = "pytest-xdist" version = "3.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/41/c4/3c310a19bc1f1e9ef50075582652673ef2bfc8cd62afef9585683821902f/pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d", size = 84060 } dependencies = [ { name = "execnet" }, { name = "pytest" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/41/c4/3c310a19bc1f1e9ef50075582652673ef2bfc8cd62afef9585683821902f/pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d", size = 84060 } wheels = [ { url = "https://files.pythonhosted.org/packages/6d/82/1d96bf03ee4c0fdc3c0cbe61470070e659ca78dc0086fb88b66c185e2449/pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7", size = 46108 }, ] @@ -4808,10 +4807,10 @@ wheels = [ name = "python-dateutil" version = "2.9.0.post0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } dependencies = [ { name = "six" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, ] @@ -4820,10 +4819,10 @@ wheels = [ name = "python-xlib" version = "0.33" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/86/f5/8c0653e5bb54e0cbdfe27bf32d41f27bc4e12faa8742778c17f2a71be2c0/python-xlib-0.33.tar.gz", hash = "sha256:55af7906a2c75ce6cb280a584776080602444f75815a7aff4d287bb2d7018b32", size = 269068 } dependencies = [ { name = "six" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/86/f5/8c0653e5bb54e0cbdfe27bf32d41f27bc4e12faa8742778c17f2a71be2c0/python-xlib-0.33.tar.gz", hash = "sha256:55af7906a2c75ce6cb280a584776080602444f75815a7aff4d287bb2d7018b32", size = 269068 } wheels = [ { url = "https://files.pythonhosted.org/packages/fc/b8/ff33610932e0ee81ae7f1269c890f697d56ff74b9f5b2ee5d9b7fa2c5355/python_xlib-0.33-py2.py3-none-any.whl", hash = "sha256:c3534038d42e0df2f1392a1b30a15a4ff5fdc2b86cfa94f072bf11b10a164398", size = 182185 }, ] @@ -4838,10 +4837,10 @@ sdist = { url = "https://files.pythonhosted.org/packages/ef/c6/2c5999de3bb153352 name = "pytools" version = "2024.1.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/c7/8268b500d2d80ae4232e978877fe8779dea7671066288a10776476e8ebc8/pytools-2024.1.6.tar.gz", hash = "sha256:bbdb7506b0966a44a177c5e555675bece1e65e15bbb1114f370b223e069322b9", size = 81344 } dependencies = [ { name = "platformdirs" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/72/c7/8268b500d2d80ae4232e978877fe8779dea7671066288a10776476e8ebc8/pytools-2024.1.6.tar.gz", hash = "sha256:bbdb7506b0966a44a177c5e555675bece1e65e15bbb1114f370b223e069322b9", size = 81344 } wheels = [ { url = "https://files.pythonhosted.org/packages/b7/41/f96b6e0181d1452413bfd15bb208b715551eb847cb35eba3c2bf3be9bab6/pytools-2024.1.6-py2.py3-none-any.whl", hash = "sha256:02825046c4a59a98cbb9fcb02eba6551ee3cbba08932d5474e19a37e910dfcd3", size = 88596 }, ] @@ -4933,10 +4932,10 @@ wheels = [ name = "pyyaml-env-tag" version = "0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fb/8e/da1c6c58f751b70f8ceb1eb25bc25d524e8f14fe16edcce3f4e3ba08629c/pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", size = 5631 } dependencies = [ { name = "pyyaml" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/fb/8e/da1c6c58f751b70f8ceb1eb25bc25d524e8f14fe16edcce3f4e3ba08629c/pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", size = 5631 } wheels = [ { url = "https://files.pythonhosted.org/packages/5a/66/bbb1dd374f5c870f59c5bb1db0e18cbe7fa739415a24cbd95b2d1f5ae0c4/pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069", size = 3911 }, ] @@ -4945,10 +4944,10 @@ wheels = [ name = "pyzmq" version = "26.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c4/9a/0e2ab500fd5a5a41e7d003e4a49faa7a0333db13e54498a3cf749b9eedd0/pyzmq-26.0.3.tar.gz", hash = "sha256:dba7d9f2e047dfa2bca3b01f4f84aa5246725203d6284e3790f2ca15fba6b40a", size = 267708 } dependencies = [ { name = "cffi", marker = "implementation_name == 'pypy'" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/c4/9a/0e2ab500fd5a5a41e7d003e4a49faa7a0333db13e54498a3cf749b9eedd0/pyzmq-26.0.3.tar.gz", hash = "sha256:dba7d9f2e047dfa2bca3b01f4f84aa5246725203d6284e3790f2ca15fba6b40a", size = 267708 } wheels = [ { url = "https://files.pythonhosted.org/packages/4b/60/4e5170ffdf1720791752f09261a813efd5e59ec8ccf3e909d50d62a13b7d/pyzmq-26.0.3-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:a72a84570f84c374b4c287183debc776dc319d3e8ce6b6a0041ce2e400de3f32", size = 1393498 }, { url = "https://files.pythonhosted.org/packages/33/fa/e35e8c9e677604bbaa15e0f5887a5c0b031361ae25c6a3577c4720e106c2/pyzmq-26.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ca684ee649b55fd8f378127ac8462fb6c85f251c2fb027eb3c887e8ee347bcd", size = 1060015 }, @@ -4980,13 +4979,13 @@ wheels = [ name = "requests" version = "2.32.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } dependencies = [ { name = "certifi" }, { name = "charset-normalizer" }, { name = "idna" }, { name = "urllib3" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } wheels = [ { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, ] @@ -5048,10 +5047,10 @@ wheels = [ name = "scipy" version = "1.14.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/e5/0230da034a2e1b1feb32621d7cd57c59484091d6dccc9e6b855b0d309fc9/scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b", size = 58618870 } dependencies = [ { name = "numpy" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/4e/e5/0230da034a2e1b1feb32621d7cd57c59484091d6dccc9e6b855b0d309fc9/scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b", size = 58618870 } wheels = [ { url = "https://files.pythonhosted.org/packages/10/55/d6096721c0f0d7e7369da9660a854c14e6379ab7aba603ea5d492d77fa23/scipy-1.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6d056a8709ccda6cf36cdd2eac597d13bc03dba38360f418560a93050c76a16e", size = 39129318 }, { url = "https://files.pythonhosted.org/packages/56/95/1a3a04b5facab8287325ad2335dbb6b78b98d73690c832099c9c498f7a4d/scipy-1.14.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f0a50da861a7ec4573b7c716b2ebdcdf142b66b756a0d392c236ae568b3a93fb", size = 29880413 }, @@ -5084,12 +5083,12 @@ wheels = [ name = "seaborn" version = "0.13.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696 } dependencies = [ { name = "matplotlib" }, { name = "numpy" }, { name = "pandas" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696 } wheels = [ { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914 }, ] @@ -5098,11 +5097,11 @@ wheels = [ name = "sentry-sdk" version = "2.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/9d/d61d64819ecb0481647229c3ee8ddc00887552acc23745fd65d0d4d066f3/sentry_sdk-2.8.0.tar.gz", hash = "sha256:aa4314f877d9cd9add5a0c9ba18e3f27f99f7de835ce36bd150e48a41c7c646f", size = 273663 } dependencies = [ { name = "certifi" }, { name = "urllib3" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/c9/9d/d61d64819ecb0481647229c3ee8ddc00887552acc23745fd65d0d4d066f3/sentry_sdk-2.8.0.tar.gz", hash = "sha256:aa4314f877d9cd9add5a0c9ba18e3f27f99f7de835ce36bd150e48a41c7c646f", size = 273663 } wheels = [ { url = "https://files.pythonhosted.org/packages/80/f4/8e1be145ce63c4ef4e126ee362992ae1ada5e716723883912b74829583e7/sentry_sdk-2.8.0-py2.py3-none-any.whl", hash = "sha256:6051562d2cfa8087bb8b4b8b79dc44690f8a054762a29c07e22588b1f619bfb5", size = 300617 }, ] @@ -5120,10 +5119,10 @@ wheels = [ name = "shapely" version = "2.0.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/7e/816fd1c135b062c80b72e17b7330d9a719cd413158afa580f4aaccf59aa9/shapely-2.0.4.tar.gz", hash = "sha256:5dc736127fac70009b8d309a0eeb74f3e08979e530cf7017f2f507ef62e6cfb8", size = 280935 } dependencies = [ { name = "numpy" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/49/7e/816fd1c135b062c80b72e17b7330d9a719cd413158afa580f4aaccf59aa9/shapely-2.0.4.tar.gz", hash = "sha256:5dc736127fac70009b8d309a0eeb74f3e08979e530cf7017f2f507ef62e6cfb8", size = 280935 } wheels = [ { url = "https://files.pythonhosted.org/packages/12/f6/b1b54fd7749e9cde332d8f55dd417cba189839b9a8a295ea4dbbab8a5fa3/shapely-2.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:de0205cb21ad5ddaef607cda9a3191eadd1e7a62a756ea3a356369675230ac35", size = 2503648 }, { url = "https://files.pythonhosted.org/packages/93/fd/b205661ed60294a344406fb04227042fcede9501e81ee1e7018e9159455a/shapely-2.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7d56ce3e2a6a556b59a288771cf9d091470116867e578bebced8bfc4147fbfd7", size = 1434573 }, @@ -5181,10 +5180,10 @@ wheels = [ name = "sounddevice" version = "0.4.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0d/88/5832219fa90595932d5f6d1b5125bfd8a55e95b19ad866e265c9bbb7cde4/sounddevice-0.4.7.tar.gz", hash = "sha256:69b386818d50a2d518607d4b973442e8d524760c7cd6c8b8be03d8c98fc4bce7", size = 52244 } dependencies = [ { name = "cffi" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/0d/88/5832219fa90595932d5f6d1b5125bfd8a55e95b19ad866e265c9bbb7cde4/sounddevice-0.4.7.tar.gz", hash = "sha256:69b386818d50a2d518607d4b973442e8d524760c7cd6c8b8be03d8c98fc4bce7", size = 52244 } wheels = [ { url = "https://files.pythonhosted.org/packages/46/ea/e9196f01ec3c5ad537e1bb83fe08da3bacfbdfee8a872c461e491f489801/sounddevice-0.4.7-py3-none-any.whl", hash = "sha256:1c3f18bfa4d9a257f5715f2ab83f2c0eb412a09f3e6a9fa73720886ca88f6bc7", size = 32092 }, { url = "https://files.pythonhosted.org/packages/1c/9c/d8de668a462b7a326d9f697dfa2adb6fbde07cc468cc7cdcf51cbe975d56/sounddevice-0.4.7-py3-none-macosx_10_6_x86_64.macosx_10_6_universal2.whl", hash = "sha256:d6ddfd341ad7412b14ca001f2c4dbf5fa2503bdc9eb15ad2c3105f6c260b698a", size = 108360 }, @@ -5196,7 +5195,6 @@ wheels = [ name = "sphinx" version = "7.3.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b7/0a/b88033900b1582f5ed8f880263363daef968d1cd064175e32abfd9714410/sphinx-7.3.7.tar.gz", hash = "sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc", size = 7094808 } dependencies = [ { name = "alabaster" }, { name = "babel" }, @@ -5215,6 +5213,7 @@ dependencies = [ { name = "sphinxcontrib-qthelp" }, { name = "sphinxcontrib-serializinghtml" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/b7/0a/b88033900b1582f5ed8f880263363daef968d1cd064175e32abfd9714410/sphinx-7.3.7.tar.gz", hash = "sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc", size = 7094808 } wheels = [ { url = "https://files.pythonhosted.org/packages/b4/fa/130c32ed94cf270e3d0b9ded16fb7b2c8fea86fa7263c29a696a30c1dde7/sphinx-7.3.7-py3-none-any.whl", hash = "sha256:413f75440be4cacf328f580b4274ada4565fb2187d696a84970c23f77b64d8c3", size = 3335650 }, ] @@ -5283,10 +5282,10 @@ sdist = { url = "https://files.pythonhosted.org/packages/c7/d9/401c0a7be089e0282 name = "sympy" version = "1.12.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/41/8a/0d1bbd33cd3091c913d298746e56f40586fa954788f51b816c6336424675/sympy-1.12.1.tar.gz", hash = "sha256:2877b03f998cd8c08f07cd0de5b767119cd3ef40d09f41c30d722f6686b0fb88", size = 6722359 } dependencies = [ { name = "mpmath" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/41/8a/0d1bbd33cd3091c913d298746e56f40586fa954788f51b816c6336424675/sympy-1.12.1.tar.gz", hash = "sha256:2877b03f998cd8c08f07cd0de5b767119cd3ef40d09f41c30d722f6686b0fb88", size = 6722359 } wheels = [ { url = "https://files.pythonhosted.org/packages/61/53/e18c8c97d0b2724d85c9830477e3ebea3acf1dcdc6deb344d5d9c93a9946/sympy-1.12.1-py3-none-any.whl", hash = "sha256:9b2cbc7f1a640289430e13d2a56f02f867a1da0190f2f99d8968c2f74da0e515", size = 5743129 }, ] @@ -5313,10 +5312,10 @@ wheels = [ name = "tqdm" version = "4.66.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/c0/b7599d6e13fe0844b0cda01b9aaef9a0e87dbb10b06e4ee255d3fa1c79a2/tqdm-4.66.4.tar.gz", hash = "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb", size = 169392 } dependencies = [ { name = "colorama", marker = "platform_system == 'Windows'" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/5a/c0/b7599d6e13fe0844b0cda01b9aaef9a0e87dbb10b06e4ee255d3fa1c79a2/tqdm-4.66.4.tar.gz", hash = "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb", size = 169392 } wheels = [ { url = "https://files.pythonhosted.org/packages/18/eb/fdb7eb9e48b7b02554e1664afd3bd3f117f6b6d6c5881438a0b055554f9b/tqdm-4.66.4-py3-none-any.whl", hash = "sha256:b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644", size = 78275 }, ] @@ -5325,10 +5324,10 @@ wheels = [ name = "types-requests" version = "2.32.0.20240622" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cf/99/ab96b7a68b26bbcff2865d0aa71bf6a895f04397a303dc027f96c58c4a58/types-requests-2.32.0.20240622.tar.gz", hash = "sha256:ed5e8a412fcc39159d6319385c009d642845f250c63902718f605cd90faade31", size = 17675 } dependencies = [ { name = "urllib3" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/cf/99/ab96b7a68b26bbcff2865d0aa71bf6a895f04397a303dc027f96c58c4a58/types-requests-2.32.0.20240622.tar.gz", hash = "sha256:ed5e8a412fcc39159d6319385c009d642845f250c63902718f605cd90faade31", size = 17675 } wheels = [ { url = "https://files.pythonhosted.org/packages/8f/d0/409f7b40f9c34896b153c911d442c6e8d0f78035ddbfa387183aec5aa8c5/types_requests-2.32.0.20240622-py3-none-any.whl", hash = "sha256:97bac6b54b5bd4cf91d407e62f0932a74821bc2211f22116d9ee1dd643826caf", size = 15784 }, ] @@ -5373,12 +5372,12 @@ wheels = [ name = "virtualenv" version = "20.26.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/68/60/db9f95e6ad456f1872486769c55628c7901fb4de5a72c2f7bdd912abf0c1/virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a", size = 9057588 } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/68/60/db9f95e6ad456f1872486769c55628c7901fb4de5a72c2f7bdd912abf0c1/virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a", size = 9057588 } wheels = [ { url = "https://files.pythonhosted.org/packages/07/4d/410156100224c5e2f0011d435e477b57aed9576fc7fe137abcf14ec16e11/virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589", size = 5684792 }, ] @@ -5420,12 +5419,12 @@ wheels = [ name = "yapf" version = "0.40.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b9/14/c1f0ebd083fddd38a7c832d5ffde343150bd465689d12c549c303fbcd0f5/yapf-0.40.2.tar.gz", hash = "sha256:4dab8a5ed7134e26d57c1647c7483afb3f136878b579062b786c9ba16b94637b", size = 252068 } dependencies = [ { name = "importlib-metadata" }, { name = "platformdirs" }, { name = "tomli" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/b9/14/c1f0ebd083fddd38a7c832d5ffde343150bd465689d12c549c303fbcd0f5/yapf-0.40.2.tar.gz", hash = "sha256:4dab8a5ed7134e26d57c1647c7483afb3f136878b579062b786c9ba16b94637b", size = 252068 } wheels = [ { url = "https://files.pythonhosted.org/packages/66/c9/d4b03b2490107f13ebd68fe9496d41ae41a7de6275ead56d0d4621b11ffd/yapf-0.40.2-py3-none-any.whl", hash = "sha256:adc8b5dd02c0143108878c499284205adb258aad6db6634e5b869e7ee2bd548b", size = 254707 }, ] @@ -5434,11 +5433,11 @@ wheels = [ name = "yarl" version = "1.9.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/ad/bedcdccbcbf91363fd425a948994f3340924145c2bc8ccb296f4a1e52c28/yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf", size = 141869 } dependencies = [ { name = "idna" }, { name = "multidict" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/e0/ad/bedcdccbcbf91363fd425a948994f3340924145c2bc8ccb296f4a1e52c28/yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf", size = 141869 } wheels = [ { url = "https://files.pythonhosted.org/packages/12/65/4c7f3676209a569405c9f0f492df2bc3a387c253f5d906e36944fdd12277/yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099", size = 132836 }, { url = "https://files.pythonhosted.org/packages/3b/c5/81e3dbf5271ab1510860d2ae7a704ef43f93f7cb9326bf7ebb1949a7260b/yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c", size = 83215 }, From 7ed3f62f0c4fcd43f8f8251e3aec47e77da3f6c7 Mon Sep 17 00:00:00 2001 From: pantew869 <173707415+pantew869@users.noreply.github.com> Date: Sun, 14 Jul 2024 17:35:24 +0300 Subject: [PATCH 045/229] Bump submodules that used numpy-stubs in pre-commit config (#32983) update submodules that used numpy-stubs in pre-commit config --- body | 2 +- panda | 2 +- rednose_repo | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/body b/body index 0e74db67ae..c433da944f 160000 --- a/body +++ b/body @@ -1 +1 @@ -Subproject commit 0e74db67ae6aaa7c30054bd4335dcafe69a5aa72 +Subproject commit c433da944f0e4d974cd66601effa66a06355debe diff --git a/panda b/panda index 376408bb4f..481d2bec59 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 376408bb4f6706b682eb6d607bedd14958665084 +Subproject commit 481d2bec595b64bb44ad70455b69fd3dd148ed4b diff --git a/rednose_repo b/rednose_repo index 72b3479bab..023a6195db 160000 --- a/rednose_repo +++ b/rednose_repo @@ -1 +1 @@ -Subproject commit 72b3479bababc658f24cc7aa0dc8bb550f0474fc +Subproject commit 023a6195dbfc2fa37dedc7383ed271fe639287c0 From cbee4421da690fa7b260f62c4a2c72ccacc6c902 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 14 Jul 2024 15:56:44 -0700 Subject: [PATCH 046/229] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 481d2bec59..b4e3d5cdd2 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 481d2bec595b64bb44ad70455b69fd3dd148ed4b +Subproject commit b4e3d5cdd2dec2a58807b0d710a5d3561a59529d From c759fe900276a6e622b51302fb9897e590edf3fd Mon Sep 17 00:00:00 2001 From: signed-long <38993953+signed-long@users.noreply.github.com> Date: Mon, 15 Jul 2024 09:01:51 -0600 Subject: [PATCH 047/229] CI: fix ui report directory (#32991) fix report artifact name --- .github/workflows/selfdrive_tests.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 419c472084..8968b493cf 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -335,8 +335,8 @@ jobs: - name: Upload Test Report uses: actions/upload-artifact@v4 with: - name: report-${{ inputs.run_number }} - path: selfdrive/ui/tests/test_ui/report_${{ inputs.run_number }} + name: report-${{ inputs.run_number || '1' }} + path: selfdrive/ui/tests/test_ui/report_${{ inputs.run_number || '1' }} - name: Get changes to selfdrive/ui if: ${{ github.event_name == 'pull_request' }} id: changed-files @@ -359,7 +359,7 @@ jobs: git checkout -b openpilot/pr-${{ github.event.pull_request.number }} git config user.name "GitHub Actions Bot" git config user.email "<>" - sudo mv ${{ github.workspace }}/selfdrive/ui/tests/test_ui/report/screenshots/* . + sudo mv ${{ github.workspace }}/selfdrive/ui/tests/test_ui/report_1/screenshots/* . git add . git commit -m "screenshots for PR #${{ github.event.pull_request.number }}" git push origin openpilot/pr-${{ github.event.pull_request.number }} --force From dd2787b7a1f2ebb6f71eb3a667848db6caa9963c Mon Sep 17 00:00:00 2001 From: commaci-public <60409688+commaci-public@users.noreply.github.com> Date: Mon, 15 Jul 2024 10:29:57 -0700 Subject: [PATCH 048/229] [bot] Update Python packages and pre-commit hooks (#32990) * Update Python packages and pre-commit hooks * fix ruff --------- Co-authored-by: Vehicle Researcher Co-authored-by: Maxime Desroches --- .pre-commit-config.yaml | 4 +- .../sim/bridge/metadrive/metadrive_process.py | 2 +- uv.lock | 209 ++++++++++-------- 3 files changed, 117 insertions(+), 98 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fd27ad4852..6aa2a065ac 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,7 +33,7 @@ repos: - -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn - --builtins clear,rare,informal,usage,code,names,en-GB_to_en-US - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.1 + rev: v0.5.2 hooks: - id: ruff exclude: '^(third_party/)|(msgq/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)' @@ -93,6 +93,6 @@ repos: pass_filenames: false files: '^selfdrive/ui/translations/' - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.28.6 + rev: 0.29.0 hooks: - id: check-github-workflows diff --git a/tools/sim/bridge/metadrive/metadrive_process.py b/tools/sim/bridge/metadrive/metadrive_process.py index 38c13a1434..2486d87ff9 100644 --- a/tools/sim/bridge/metadrive/metadrive_process.py +++ b/tools/sim/bridge/metadrive/metadrive_process.py @@ -89,7 +89,7 @@ def metadrive_process(dual_camera: bool, config: dict, camera_array, wide_camera cam.get_cam().setPos(C3_POSITION) cam.get_cam().setHpr(C3_HPR) img = cam.perceive(to_float=False) - if type(img) != np.ndarray: + if not isinstance(img, np.ndarray): img = img.get() # convert cupy array to numpy return img diff --git a/uv.lock b/uv.lock index 873d388808..b0ba09ca3c 100644 --- a/uv.lock +++ b/uv.lock @@ -437,31 +437,31 @@ wheels = [ [[distribution]] name = "coverage" -version = "7.5.4" +version = "7.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ef/05/31553dc038667012853d0a248b57987d8d70b2d67ea885605f87bcb1baba/coverage-7.5.4.tar.gz", hash = "sha256:a44963520b069e12789d0faea4e9fdb1e410cdc4aab89d94f7f55cbb7fef0353", size = 793238 } +sdist = { url = "https://files.pythonhosted.org/packages/64/c8/a94ce9e17756aed521085ae716d627623374d34f92c1daf7162272ecb030/coverage-7.6.0.tar.gz", hash = "sha256:289cc803fa1dc901f84701ac10c9ee873619320f2f9aff38794db4a4a0268d51", size = 797590 } wheels = [ - { url = "https://files.pythonhosted.org/packages/48/92/f56bf17b10efdb21311b7aa6853afc39eb962af0f9595a24408f7df3f694/coverage-7.5.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:db14f552ac38f10758ad14dd7b983dbab424e731588d300c7db25b6f89e335b5", size = 205211 }, - { url = "https://files.pythonhosted.org/packages/b8/69/a3bdace4d667f592b7730c0d636ac9ff9195f678fb4e61b5469b91e49919/coverage-7.5.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3257fdd8e574805f27bb5342b77bc65578e98cbc004a92232106344053f319ba", size = 205664 }, - { url = "https://files.pythonhosted.org/packages/cd/bd/8515e955724baab11e8220a3872dc3d1c895b841b281ac8865834257ae2e/coverage-7.5.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a6612c99081d8d6134005b1354191e103ec9705d7ba2754e848211ac8cacc6b", size = 237695 }, - { url = "https://files.pythonhosted.org/packages/41/d5/f4f9d2d86e3bd0c3ae761e2511c4033abcdce1de8f1926f8e7c98952540d/coverage-7.5.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d45d3cbd94159c468b9b8c5a556e3f6b81a8d1af2a92b77320e887c3e7a5d080", size = 235270 }, - { url = "https://files.pythonhosted.org/packages/1e/62/e33595d35c9fa7cbcca5df2c3745b595532ec94b68c49ca2877629c4aca1/coverage-7.5.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed550e7442f278af76d9d65af48069f1fb84c9f745ae249c1a183c1e9d1b025c", size = 236966 }, - { url = "https://files.pythonhosted.org/packages/62/ea/e5ae9c845bef94369a3b9b66eb1e0857289c0a769b20078fcf5a5e6021be/coverage-7.5.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7a892be37ca35eb5019ec85402c3371b0f7cda5ab5056023a7f13da0961e60da", size = 235891 }, - { url = "https://files.pythonhosted.org/packages/33/7f/068a5d05ca6c89295bc8b7ae7ad5ed9d7b0286305a2444eb4d1eb42cb902/coverage-7.5.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8192794d120167e2a64721d88dbd688584675e86e15d0569599257566dec9bf0", size = 234548 }, - { url = "https://files.pythonhosted.org/packages/15/a6/bbeeb4c0447a0ae8993e7d9b7ac8c8538ffb1a4210d106573238233f58c8/coverage-7.5.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:820bc841faa502e727a48311948e0461132a9c8baa42f6b2b84a29ced24cc078", size = 235329 }, - { url = "https://files.pythonhosted.org/packages/01/54/e009827b234225815743303d002a146183ea25e011c088dfa7a87f895fdf/coverage-7.5.4-cp311-cp311-win32.whl", hash = "sha256:6aae5cce399a0f065da65c7bb1e8abd5c7a3043da9dceb429ebe1b289bc07806", size = 207728 }, - { url = "https://files.pythonhosted.org/packages/cd/48/8b929edd540634d8e7ed50d78e86790613e8733edf7eb21c2c217bf25176/coverage-7.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:d2e344d6adc8ef81c5a233d3a57b3c7d5181f40e79e05e1c143da143ccb6377d", size = 208614 }, - { url = "https://files.pythonhosted.org/packages/6d/96/58bcb3417c2fd38fae862704599f7088451bb6c8786f5cec6887366e78d9/coverage-7.5.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:54317c2b806354cbb2dc7ac27e2b93f97096912cc16b18289c5d4e44fc663233", size = 205392 }, - { url = "https://files.pythonhosted.org/packages/2c/63/4f781db529b585a6ef3860ea01390951b006dbea9ada4ea3a3d830e325f4/coverage-7.5.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:042183de01f8b6d531e10c197f7f0315a61e8d805ab29c5f7b51a01d62782747", size = 205634 }, - { url = "https://files.pythonhosted.org/packages/57/50/c5aadf036078072f31d8f1ae1a6000cc70f3f6cf652939c2d77551174d77/coverage-7.5.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6bb74ed465d5fb204b2ec41d79bcd28afccf817de721e8a807d5141c3426638", size = 238754 }, - { url = "https://files.pythonhosted.org/packages/eb/a6/57c42994b1686461c7b0b29de3b6d3d60c5f23a656f96460f9c755a31506/coverage-7.5.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3d45ff86efb129c599a3b287ae2e44c1e281ae0f9a9bad0edc202179bcc3a2e", size = 235783 }, - { url = "https://files.pythonhosted.org/packages/88/52/7054710a881b09d295e93b9889ac204c241a6847a8c05555fc6e1d8799d5/coverage-7.5.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5013ed890dc917cef2c9f765c4c6a8ae9df983cd60dbb635df8ed9f4ebc9f555", size = 237865 }, - { url = "https://files.pythonhosted.org/packages/a0/c3/57ef08c70483b83feb4e0d22345010aaf0afbe442dba015da3b173076c36/coverage-7.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1014fbf665fef86cdfd6cb5b7371496ce35e4d2a00cda501cf9f5b9e6fced69f", size = 237340 }, - { url = "https://files.pythonhosted.org/packages/d8/44/465fa8f8edc11a18cbb83673f29b1af20ccf5139a66fbe2768ff67527ff0/coverage-7.5.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3684bc2ff328f935981847082ba4fdc950d58906a40eafa93510d1b54c08a66c", size = 235663 }, - { url = "https://files.pythonhosted.org/packages/ef/e5/829ddcfb29ad41661ba8e9cac7dc52100fd2c4853bb93d668a3ebde64862/coverage-7.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:581ea96f92bf71a5ec0974001f900db495488434a6928a2ca7f01eee20c23805", size = 237309 }, - { url = "https://files.pythonhosted.org/packages/98/f6/f9c96fbf9b36be3f4d8c252ab2b4944420d99425f235f492784498804182/coverage-7.5.4-cp312-cp312-win32.whl", hash = "sha256:73ca8fbc5bc622e54627314c1a6f1dfdd8db69788f3443e752c215f29fa87a0b", size = 207988 }, - { url = "https://files.pythonhosted.org/packages/0e/c1/2b7c7dcf4c273aac7676f12fb2b5524b133671d731ab91bd9a41c21675b9/coverage-7.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:cef4649ec906ea7ea5e9e796e68b987f83fa9a718514fe147f538cfeda76d7a7", size = 208756 }, - { url = "https://files.pythonhosted.org/packages/7a/c3/a5b06a07b68795018f47b5d69b523ad473ac9ee66be3c22c4d3e5eadd91e/coverage-7.5.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:79b356f3dd5b26f3ad23b35c75dbdaf1f9e2450b6bcefc6d0825ea0aa3f86ca5", size = 197342 }, + { url = "https://files.pythonhosted.org/packages/1b/03/a5140e4f336f0b71023435d7e1564da8e2ff5552e91dfd3ec26424b72c47/coverage-7.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7b525ab52ce18c57ae232ba6f7010297a87ced82a2383b1afd238849c1ff933", size = 205898 }, + { url = "https://files.pythonhosted.org/packages/a2/d3/1f839af6d6cbaee2c50a0bf2d51964b56272e8b94a6504b6ab7c7ecd66c9/coverage-7.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bea27c4269234e06f621f3fac3925f56ff34bc14521484b8f66a580aacc2e7d", size = 206345 }, + { url = "https://files.pythonhosted.org/packages/f9/cf/77b3fb7e132cbae1f112458399157f67f69d5264a9e5a6eae3b91e580b79/coverage-7.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed8d1d1821ba5fc88d4a4f45387b65de52382fa3ef1f0115a4f7a20cdfab0e94", size = 238389 }, + { url = "https://files.pythonhosted.org/packages/a8/aa/da317fae6b6057428c72f1023a61d57a79a049f03bc4cbe6ffb7cb61e698/coverage-7.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c322ef2bbe15057bc4bf132b525b7e3f7206f071799eb8aa6ad1940bcf5fb1", size = 235967 }, + { url = "https://files.pythonhosted.org/packages/39/33/da23d8bfdfdc5c221d2c9a2f169f63a4e04b9a0327c1c67777157155e4d6/coverage-7.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03cafe82c1b32b770a29fd6de923625ccac3185a54a5e66606da26d105f37dac", size = 237659 }, + { url = "https://files.pythonhosted.org/packages/4d/d7/acea77ab27215da6afff2d5228a64cc4af7db83c481c7b14f47f34cad100/coverage-7.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0d1b923fc4a40c5832be4f35a5dab0e5ff89cddf83bb4174499e02ea089daf57", size = 236585 }, + { url = "https://files.pythonhosted.org/packages/e5/b5/fc782807b3e984d0bb0472da8c7aa820ed2827ed95b9fc95c63ccb88f1f9/coverage-7.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4b03741e70fb811d1a9a1d75355cf391f274ed85847f4b78e35459899f57af4d", size = 235238 }, + { url = "https://files.pythonhosted.org/packages/80/88/649d1047bfcbf51227726bfa47073e3b5b94310acbd66f6457c274f74391/coverage-7.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a73d18625f6a8a1cbb11eadc1d03929f9510f4131879288e3f7922097a429f63", size = 236022 }, + { url = "https://files.pythonhosted.org/packages/91/41/eeba3fca0f4b6820184572c50d911959f5d108ec5f8e55fd30f0981d5209/coverage-7.6.0-cp311-cp311-win32.whl", hash = "sha256:65fa405b837060db569a61ec368b74688f429b32fa47a8929a7a2f9b47183713", size = 208431 }, + { url = "https://files.pythonhosted.org/packages/54/bb/9f2d3303441e87d27221fc9de4de63994a9570c899726a4f10ac16f79824/coverage-7.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:6379688fb4cfa921ae349c76eb1a9ab26b65f32b03d46bb0eed841fd4cb6afb1", size = 209314 }, + { url = "https://files.pythonhosted.org/packages/57/3a/287ea47cca84c92528b5f9b34b971f845b637d37c3eead9f10aede3531da/coverage-7.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f7db0b6ae1f96ae41afe626095149ecd1b212b424626175a6633c2999eaad45b", size = 206079 }, + { url = "https://files.pythonhosted.org/packages/7b/14/3432bbdabeaa79de25421d24161ab472578ffe73fc56b0aa9411bea66335/coverage-7.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bbdf9a72403110a3bdae77948b8011f644571311c2fb35ee15f0f10a8fc082e8", size = 206320 }, + { url = "https://files.pythonhosted.org/packages/0e/2a/f62d42a48449b26cfdf940661cf28bccc27e199dc0e956c738a6b1c942af/coverage-7.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc44bf0315268e253bf563f3560e6c004efe38f76db03a1558274a6e04bf5d5", size = 239454 }, + { url = "https://files.pythonhosted.org/packages/0c/a2/d7c0988df525298b2c19c482cec27f76bbeba6c3ed7f85d9f79d8996e509/coverage-7.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da8549d17489cd52f85a9829d0e1d91059359b3c54a26f28bec2c5d369524807", size = 236478 }, + { url = "https://files.pythonhosted.org/packages/f2/aa/0419103c357bfd95a65d7b2e2249f9f1d79194241c5e87819cd81d36b96c/coverage-7.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0086cd4fc71b7d485ac93ca4239c8f75732c2ae3ba83f6be1c9be59d9e2c6382", size = 238563 }, + { url = "https://files.pythonhosted.org/packages/2a/ce/375f8fbbabc51e3dfce91355460912c930a4e241ffbafc1f3a35f43ac90b/coverage-7.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fad32ee9b27350687035cb5fdf9145bc9cf0a094a9577d43e909948ebcfa27b", size = 238039 }, + { url = "https://files.pythonhosted.org/packages/fd/ca/5eb0004e0bf66db1d4a18c67e4aece76ff409b061d85f31843c28c9a531c/coverage-7.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:044a0985a4f25b335882b0966625270a8d9db3d3409ddc49a4eb00b0ef5e8cee", size = 236357 }, + { url = "https://files.pythonhosted.org/packages/64/ea/848f064727fe172e80f8a7abc77664c593b6bece14d5acab7d7087f1244e/coverage-7.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:76d5f82213aa78098b9b964ea89de4617e70e0d43e97900c2778a50856dac605", size = 238003 }, + { url = "https://files.pythonhosted.org/packages/c2/b1/8f54a56789aecc930e227fc5900d18628d6efae4a8ad24981d58fc14b1e3/coverage-7.6.0-cp312-cp312-win32.whl", hash = "sha256:3c59105f8d58ce500f348c5b56163a4113a440dad6daa2294b5052a10db866da", size = 208686 }, + { url = "https://files.pythonhosted.org/packages/cb/db/242c44433c5d342c8bf83864131e56af8c1c1ea5645a825b1800c19ad9bf/coverage-7.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca5d79cfdae420a1d52bf177de4bc2289c321d6c961ae321503b2ca59c17ae67", size = 209455 }, + { url = "https://files.pythonhosted.org/packages/ea/69/2b79b6b37c57cd05c85b76ec5ceabf7e091ab0f4986dfefaddbb468881c0/coverage-7.6.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:6fe885135c8a479d3e37a7aae61cbd3a0fb2deccb4dda3c25f92a49189f766d6", size = 198032 }, ] [[distribution]] @@ -1746,14 +1746,14 @@ wheels = [ [[distribution]] name = "portalocker" -version = "2.10.0" +version = "2.10.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pywin32", marker = "platform_system == 'Windows'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d5/2c/b565d42be77be6e642e9c193930258f25660a93900caca07c37ec107dd01/portalocker-2.10.0.tar.gz", hash = "sha256:49de8bc0a2f68ca98bf9e219c81a3e6b27097c7bf505a87c5a112ce1aaeb9b81", size = 40825 } +sdist = { url = "https://files.pythonhosted.org/packages/ed/d3/c6c64067759e87af98cc668c1cc75171347d0f1577fab7ca3749134e3cd4/portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f", size = 40891 } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/ff/52080172c7fdfa7c62f8cab014997178c19be9948607e977184dafc76522/portalocker-2.10.0-py3-none-any.whl", hash = "sha256:48944147b2cd42520549bc1bb8fe44e220296e56f7c3d551bc6ecce69d9b0de1", size = 18430 }, + { url = "https://files.pythonhosted.org/packages/9b/fb/a70a4214956182e0d7a9099ab17d50bfcba1056188e9b14f35b9e2b62a0d/portalocker-2.10.1-py3-none-any.whl", hash = "sha256:53a5984ebc86a025552264b459b46a2086e269b21823cb572f8f28ee759e45bf", size = 18423 }, ] [[distribution]] @@ -4629,18 +4629,18 @@ wheels = [ [[distribution]] name = "pyqt5-sip" -version = "12.13.0" +version = "12.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/81/fce2a475aa56c1f49707d9306b930695b6ff078c2242c9f2fd72a3214e1f/PyQt5_sip-12.13.0.tar.gz", hash = "sha256:7f321daf84b9c9dbca61b80e1ef37bdaffc0e93312edae2cd7da25b953971d91", size = 123225 } +sdist = { url = "https://files.pythonhosted.org/packages/1b/15/78318d50f10062c428e97e7ce387e772616a4673c356018b905f247a6a85/PyQt5_sip-12.15.0.tar.gz", hash = "sha256:d23fdfcf363b5cedd9d39f8a9c5710e7d52804f5b08a58e91c638b36eafcb702", size = 104024 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/de/fff654a38821e42beb914ecca72c4ac0ae3dab1f94666ae8015a152a197f/PyQt5_sip-12.13.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0f85fb633a522f04e48008de49dce1ff1d947011b48885b8428838973fbca412", size = 144454 }, - { url = "https://files.pythonhosted.org/packages/ca/b0/5af957d148693e1d1b1e2e33c51dd9c8a3c29f7ac21008684d612c0b86c3/PyQt5_sip-12.13.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ec60162e034c42fb99859206d62b83b74f987d58937b3a82bdc07b5c3d190dec", size = 346673 }, - { url = "https://files.pythonhosted.org/packages/d8/04/8682c882bb0adbc73dd5cf191c486cc2680acb53ffca312f254a806baf15/PyQt5_sip-12.13.0-cp311-cp311-win32.whl", hash = "sha256:205cd449d08a2b024a468fb6100cd7ed03e946b4f49706f508944006f955ae1a", size = 68704 }, - { url = "https://files.pythonhosted.org/packages/8e/e2/d296cb17bae19ba49137a2649934a70d5f48cc99b7daa6ce9cf1aecddfeb/PyQt5_sip-12.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:1c8371682f77852256f1f2d38c41e2e684029f43330f0635870895ab01c02f6c", size = 78476 }, - { url = "https://files.pythonhosted.org/packages/37/75/02e2f850b0e7c8987da526ed4a2bf579c231b2bb2731860798bb1a1752ea/PyQt5_sip-12.13.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7fe3375b508c5bc657d73b9896bba8a768791f1f426c68053311b046bcebdddf", size = 146399 }, - { url = "https://files.pythonhosted.org/packages/3c/ab/f8f1e970768fcb4ab118d4aabbfcb9b7f781088b71e1f26d813fd51c4701/PyQt5_sip-12.13.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:773731b1b5ab1a7cf5621249f2379c95e3d2905e9bd96ff3611b119586daa876", size = 360986 }, - { url = "https://files.pythonhosted.org/packages/46/e1/70222aac7ed23f85b54e69507fb5256e53be1205bdc4f678463f2ed74aa2/PyQt5_sip-12.13.0-cp312-cp312-win32.whl", hash = "sha256:fb4a5271fa3f6bc2feb303269a837a95a6d8dd16be553aa40e530de7fb81bfdf", size = 69214 }, - { url = "https://files.pythonhosted.org/packages/dd/88/41bab90e8cde04220d9fb688750d69441633a8c570638e7b204ebf63ab01/PyQt5_sip-12.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:3a4498f3b1b15f43f5d12963accdce0fd652b0bcaae6baf8008663365827444c", size = 77706 }, + { url = "https://files.pythonhosted.org/packages/e9/7e/4b87c65adf9cb74895acc129043d04bb300436cab1e39469f4a9fc40b602/PyQt5_sip-12.15.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:855563d4d3b59ce7438bbf2dd32fed2707787defa40f3efe94f204a19ef92b25", size = 122436 }, + { url = "https://files.pythonhosted.org/packages/ec/90/8bf505a096553a253e1a65078ca1aeb6de8a83f27afa3a43bb89ae29da31/PyQt5_sip-12.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0b718a362f4392430903bbb2a4b9bbff9841a16a52f0cfdd5b5bbd9d11457980", size = 276022 }, + { url = "https://files.pythonhosted.org/packages/6b/80/ed1a360df9128e0e26e28c6341174a7e02efc57816799af5e3a3cb865fc8/PyQt5_sip-12.15.0-cp311-cp311-win32.whl", hash = "sha256:2575f428de584a12009fd29d00c89df16ed101a3b38beba818dfdcbc4a10709c", size = 49065 }, + { url = "https://files.pythonhosted.org/packages/4e/d6/ea034ad64290c541042dc4c349d5aa854c8a0b54802a0759ec37671f0939/PyQt5_sip-12.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c85be433fbafcb3d417581c0e1b67c8198d23858166e4f938e971c2262c13cdb", size = 59009 }, + { url = "https://files.pythonhosted.org/packages/90/47/de48934a0d692c65b0833924a618786146c0869910c707a5e508351d5b91/PyQt5_sip-12.15.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:852b75cf208825602480e95ab63314108f872d0da251e9ad3deaaff5a183a6f5", size = 124312 }, + { url = "https://files.pythonhosted.org/packages/d1/6c/9a2fe24f8970e092613f709283a2101403490a209a30de3de89a413d9915/PyQt5_sip-12.15.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0cd21c3215e3c47fdd5fa7a2dc3dd1e07a7230b0626e905a7217925068c788b9", size = 281431 }, + { url = "https://files.pythonhosted.org/packages/90/53/0a4dc2d448619f2a51849e124d375ec7a8e95c938eccfaf8711bb77a62b6/PyQt5_sip-12.15.0-cp312-cp312-win32.whl", hash = "sha256:b58eeedc9b2a3037b136bf96915196c391a33be470ed1c0723d7163ef0b727a2", size = 49408 }, + { url = "https://files.pythonhosted.org/packages/aa/c2/c07c531fe5a6124d91942c48a85ff4e14918766cd37819f7841cf2debabb/PyQt5_sip-12.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:24a1d4937332bf0a38dd95bb2ce4d89723df449f6e912b52ef0e107e11fefac1", size = 57922 }, ] [[distribution]] @@ -4835,14 +4835,15 @@ sdist = { url = "https://files.pythonhosted.org/packages/ef/c6/2c5999de3bb153352 [[distribution]] name = "pytools" -version = "2024.1.6" +version = "2024.1.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "platformdirs" }, + { name = "siphash24" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/c7/8268b500d2d80ae4232e978877fe8779dea7671066288a10776476e8ebc8/pytools-2024.1.6.tar.gz", hash = "sha256:bbdb7506b0966a44a177c5e555675bece1e65e15bbb1114f370b223e069322b9", size = 81344 } +sdist = { url = "https://files.pythonhosted.org/packages/c0/0a/33961bdb345c0621f2883e6c192f05116fe7e4871700eb2100d3e37d152a/pytools-2024.1.8.tar.gz", hash = "sha256:cccc184a10af56dabab3077af82ab0cf7a5b06625313cae0b2f06a3c4b126001", size = 82220 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/41/f96b6e0181d1452413bfd15bb208b715551eb847cb35eba3c2bf3be9bab6/pytools-2024.1.6-py2.py3-none-any.whl", hash = "sha256:02825046c4a59a98cbb9fcb02eba6551ee3cbba08932d5474e19a37e910dfcd3", size = 88596 }, + { url = "https://files.pythonhosted.org/packages/d2/ea/fa3124d613e07ee93aaf1ec38b846c712a25eda3035af20ae2e7cd5927e5/pytools-2024.1.8-py3-none-any.whl", hash = "sha256:3fe89cf182e97d16842de78f2b08c009030c895c4e1496e96e3679664cf2bd3b", size = 88527 }, ] [[distribution]] @@ -4992,7 +4993,7 @@ wheels = [ [[distribution]] name = "rerun-sdk" -version = "0.16.1" +version = "0.17.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, @@ -5002,11 +5003,11 @@ dependencies = [ { name = "typing-extensions" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/62/97/4f61141d7dcadc30f5e4f6279823068b3a96e42acb3245544dd4e156c8cc/rerun_sdk-0.16.1-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:170c6976634008611753e10dfef8cdc395ce8180e634c169e7c61cef2f89a277", size = 31232677 }, - { url = "https://files.pythonhosted.org/packages/2a/b3/1fdad82b064d8bab5f06f5baa33a7e4db475514c14f876d72182404df0ff/rerun_sdk-0.16.1-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c9a76eab7eb5559276737dad655200e9350df0837158dbc5a896970ab4201454", size = 30514076 }, - { url = "https://files.pythonhosted.org/packages/a2/32/5c220f61c72215e686bffcce1a7273e56a05109ea42d425dacbd9997300e/rerun_sdk-0.16.1-cp38-abi3-manylinux_2_31_aarch64.whl", hash = "sha256:4d6436752d57e8b8038489a0e7e37f0c760b088e96db5fb81667d3a376d63fea", size = 36762084 }, - { url = "https://files.pythonhosted.org/packages/34/cd/2165450a91cdaac5a9a09862e81f2f44a61fc902751954b3f6ddc113c729/rerun_sdk-0.16.1-cp38-abi3-manylinux_2_31_x86_64.whl", hash = "sha256:37b7b47948471873e84f224b16f417a94a91c7cbd6c72c68281eeff1ba414b8f", size = 37042093 }, - { url = "https://files.pythonhosted.org/packages/08/69/be7810460a7b739034c951ab7c2d89f5648cf55d61e468fb3cb2260f5bb8/rerun_sdk-0.16.1-cp38-abi3-win_amd64.whl", hash = "sha256:be88799c8afdf68eafa99e64e2e4f0a484e187e017a180219abbe6bb988acd4e", size = 28013117 }, + { url = "https://files.pythonhosted.org/packages/30/5f/ce02381b9d7e1e14f60c421c76dce12b7d823690181784780b30266017b1/rerun_sdk-0.17.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:abd34f746eada83b8bb0bc50007183151981d7ccf18306f3d42165819a3f6fcb", size = 33166544 }, + { url = "https://files.pythonhosted.org/packages/b7/c5/d47ba7b774bc563aa3c07ba500dd304ea24b31fe438e10ea9ad5e10ffe17/rerun_sdk-0.17.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:8b0a8a6feab3f8e679801d158216a71d88a81480021587719330f50d083c4d26", size = 32237860 }, + { url = "https://files.pythonhosted.org/packages/87/0a/b5fe1ffea700eeaa8d28817a92ad3cb4a7d56dc4af45de76ea412cfc5cd5/rerun_sdk-0.17.0-cp38-abi3-manylinux_2_31_aarch64.whl", hash = "sha256:ad55807abafb01e527846742e087819aac8e103f1ec15aadc563a4038bb44e1d", size = 38608604 }, + { url = "https://files.pythonhosted.org/packages/d9/74/6c1ff0c8dbe6da09ceb5ea838a72382fa3131ef6bb9377a30003299743fa/rerun_sdk-0.17.0-cp38-abi3-manylinux_2_31_x86_64.whl", hash = "sha256:9d41f1f475270b1e0d50ddb8cb62e0d828988f0c371ac8457af25c8be5aa1dc0", size = 38917319 }, + { url = "https://files.pythonhosted.org/packages/8c/28/92423fe9673b738c180fb5b6b8ea4203fe4b02c1d20b06b7fae79d11cc24/rerun_sdk-0.17.0-cp38-abi3-win_amd64.whl", hash = "sha256:34e5595a326cbdddfebdf00b08e877358c564fce74cc8c6d617fc89ef3a6aa70", size = 29490986 }, ] [[distribution]] @@ -5020,27 +5021,27 @@ wheels = [ [[distribution]] name = "ruff" -version = "0.5.1" +version = "0.5.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/dc/8d95ce5e15f0f25dc1fb6e9a11d6f33379e092d528a3b0535de246e07182/ruff-0.5.1.tar.gz", hash = "sha256:3164488aebd89b1745b47fd00604fb4358d774465f20d1fcd907f9c0fc1b0655", size = 2594019 } +sdist = { url = "https://files.pythonhosted.org/packages/79/6c/147f04f6a799f659cc810352742994e51441b14c7a5621e285d021261388/ruff-0.5.2.tar.gz", hash = "sha256:2c0df2d2de685433794a14d8d2e240df619b748fbe3367346baa519d8e6f1ca2", size = 2596910 } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/36/c4684f20bc0f6e4725177fbed8557a1d4c8dd118584112313ee03876f4dd/ruff-0.5.1-py3-none-linux_armv6l.whl", hash = "sha256:6ecf968fcf94d942d42b700af18ede94b07521bd188aaf2cd7bc898dd8cb63b6", size = 9506184 }, - { url = "https://files.pythonhosted.org/packages/40/98/80295e661ba1219c584a2d6103277bce16c6ff7cd0d9e3597bb16c115113/ruff-0.5.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:204fb0a472f00f2e6280a7c8c7c066e11e20e23a37557d63045bf27a616ba61c", size = 8606624 }, - { url = "https://files.pythonhosted.org/packages/a9/64/b0356632574dea983e2d718f064d95f8a45f8f381d094c917685f1d6fc26/ruff-0.5.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d235968460e8758d1e1297e1de59a38d94102f60cafb4d5382033c324404ee9d", size = 8184772 }, - { url = "https://files.pythonhosted.org/packages/34/57/db0df86298aa6082c396b44d4ad12a16ee891f61513849e5bdaeab0a4c7a/ruff-0.5.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38beace10b8d5f9b6bdc91619310af6d63dd2019f3fb2d17a2da26360d7962fa", size = 9981131 }, - { url = "https://files.pythonhosted.org/packages/bb/b1/63211390db6afa0e24bdd5b1d5053693074759ce940c0669576834fc6026/ruff-0.5.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e478d2f09cf06add143cf8c4540ef77b6599191e0c50ed976582f06e588c994", size = 9297773 }, - { url = "https://files.pythonhosted.org/packages/ac/7f/5824713ffcb5ce055dc7e509cb2d5d5ef405af73cd1615d27e475114dc89/ruff-0.5.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f0368d765eec8247b8550251c49ebb20554cc4e812f383ff9f5bf0d5d94190b0", size = 10087567 }, - { url = "https://files.pythonhosted.org/packages/75/3b/1ada2a113e1899e215e7542a42e59e5143d7ce4e9b04b7f9f03217414139/ruff-0.5.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3a9a9a1b582e37669b0138b7c1d9d60b9edac880b80eb2baba6d0e566bdeca4d", size = 10863472 }, - { url = "https://files.pythonhosted.org/packages/b2/f9/11ca13d8040830140d4385af241d435e1b1b1387a987df707c969c5bbfb9/ruff-0.5.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bdd9f723e16003623423affabcc0a807a66552ee6a29f90eddad87a40c750b78", size = 10448311 }, - { url = "https://files.pythonhosted.org/packages/b7/43/8546df86010041ab9f7e80f1a85cd4b8042a55338d7a30561ef835cba9e2/ruff-0.5.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:be9fd62c1e99539da05fcdc1e90d20f74aec1b7a1613463ed77870057cd6bd96", size = 11368918 }, - { url = "https://files.pythonhosted.org/packages/8a/d5/8271d42dd239b7c2d163615b3b01b1acfb187f5114bfca6d5a85e1d6a1eb/ruff-0.5.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e216fc75a80ea1fbd96af94a6233d90190d5b65cc3d5dfacf2bd48c3e067d3e1", size = 10144007 }, - { url = "https://files.pythonhosted.org/packages/39/38/c480773c22012535ca121c9488323943406c1780f22f9bb5ca51e830c2b1/ruff-0.5.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c4c2112e9883a40967827d5c24803525145e7dab315497fae149764979ac7929", size = 9940919 }, - { url = "https://files.pythonhosted.org/packages/5f/ea/6d96bd900cfe2a2401de733c4bd9ee3e5811cb27584ade3bbcdee638afc8/ruff-0.5.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dfaf11c8a116394da3b65cd4b36de30d8552fa45b8119b9ef5ca6638ab964fa3", size = 9361679 }, - { url = "https://files.pythonhosted.org/packages/7d/7c/b4ab2d5d90bab6e16ea79c261aeb437cb804b436d376c70f37f37086907c/ruff-0.5.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d7ceb9b2fe700ee09a0c6b192c5ef03c56eb82a0514218d8ff700f6ade004108", size = 9717533 }, - { url = "https://files.pythonhosted.org/packages/6d/a3/fb5a4ee18cee7b44e9309a9b8d7b8d76a12ee7f3ef53f6c0dcc71c080f2d/ruff-0.5.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:bac6288e82f6296f82ed5285f597713acb2a6ae26618ffc6b429c597b392535c", size = 10204312 }, - { url = "https://files.pythonhosted.org/packages/9c/39/da2a5cc52fd239e291c0ff473137d6733778e481b8e4469fd1c4c891c7f7/ruff-0.5.1-py3-none-win32.whl", hash = "sha256:5c441d9c24ec09e1cb190a04535c5379b36b73c4bc20aa180c54812c27d1cca4", size = 7775009 }, - { url = "https://files.pythonhosted.org/packages/a8/9f/e236acf3b95b383a5241da0f758fc8688d1796837b6bec8ee528130c3dba/ruff-0.5.1-py3-none-win_amd64.whl", hash = "sha256:b1789bf2cd3d1b5a7d38397cac1398ddf3ad7f73f4de01b1e913e2abc7dfc51d", size = 8597783 }, - { url = "https://files.pythonhosted.org/packages/f6/b1/fd215876543ac2a3ddd477487f574ca2d91973d0ecd87664095e6b249017/ruff-0.5.1-py3-none-win_arm64.whl", hash = "sha256:2875b7596a740cbbd492f32d24be73e545a4ce0a3daf51e4f4e609962bfd3cd2", size = 7998017 }, + { url = "https://files.pythonhosted.org/packages/3b/05/9ec81c397be41596e4329b340780d56bfa9ad1cb95247148bf9859edf575/ruff-0.5.2-py3-none-linux_armv6l.whl", hash = "sha256:7bab8345df60f9368d5f4594bfb8b71157496b44c30ff035d1d01972e764d3be", size = 9482764 }, + { url = "https://files.pythonhosted.org/packages/f3/ea/ebf3ea51ad48abfc6e0bbb762e71b0ffc6220a6fb8735cb09bd5aca7c52e/ruff-0.5.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1aa7acad382ada0189dbe76095cf0a36cd0036779607c397ffdea16517f535b1", size = 8612665 }, + { url = "https://files.pythonhosted.org/packages/0f/52/9e7868770615c16be60549746ad6f48f483320f7ecf5a294f4f051f4e7d4/ruff-0.5.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:aec618d5a0cdba5592c60c2dee7d9c865180627f1a4a691257dea14ac1aa264d", size = 8191223 }, + { url = "https://files.pythonhosted.org/packages/7a/9d/c880e41895b9bc48bf7051c81bcf270d2f6eebdce3c8f02c72fdef582d20/ruff-0.5.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b62adc5ce81780ff04077e88bac0986363e4a3260ad3ef11ae9c14aa0e67ef", size = 9972748 }, + { url = "https://files.pythonhosted.org/packages/0c/0b/17a0730f425f7f630446978b880ac0ad62a7c7e20fb4e21d2ab0a5154887/ruff-0.5.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dc42ebf56ede83cb080a50eba35a06e636775649a1ffd03dc986533f878702a3", size = 9289379 }, + { url = "https://files.pythonhosted.org/packages/67/c4/1dcdc4a381aa07509d15dd78ec65e8fedd14c0a70a674ca3bbafa48502ed/ruff-0.5.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c15c6e9f88c67ffa442681365d11df38afb11059fc44238e71a9d9f1fd51de70", size = 10087604 }, + { url = "https://files.pythonhosted.org/packages/a8/fc/2707aa15de9e2485f024535b0fe239013d1be13bb475050f3e21b33109c9/ruff-0.5.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d3de9a5960f72c335ef00763d861fc5005ef0644cb260ba1b5a115a102157251", size = 10875118 }, + { url = "https://files.pythonhosted.org/packages/ef/db/4890a8c350b3fad767c663991052ba5ce42feae05f433fbf73acc3d1e8c3/ruff-0.5.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe5a968ae933e8f7627a7b2fc8893336ac2be0eb0aace762d3421f6e8f7b7f83", size = 10464801 }, + { url = "https://files.pythonhosted.org/packages/d5/30/0018669eb5a0bfd42d4be1d961fa4533bba1926ba83b8cf3e50223ee7d21/ruff-0.5.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a04f54a9018f75615ae52f36ea1c5515e356e5d5e214b22609ddb546baef7132", size = 11356413 }, + { url = "https://files.pythonhosted.org/packages/ec/60/e2a9ae058b34128caa5f863f268e1c9bd083793264f4bf7e8e469be651f9/ruff-0.5.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed02fb52e3741f0738db5f93e10ae0fb5c71eb33a4f2ba87c9a2fa97462a649", size = 10123340 }, + { url = "https://files.pythonhosted.org/packages/1c/fd/83b9f0107f5d0eea1c4b3a98655d789586d8e2662819df011a7964efa675/ruff-0.5.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3cf8fe659f6362530435d97d738eb413e9f090e7e993f88711b0377fbdc99f60", size = 9940668 }, + { url = "https://files.pythonhosted.org/packages/11/75/2a98e9348bed95e0a121c3e1693c335530ef70280a364cf17f1d2da947cd/ruff-0.5.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:237a37e673e9f3cbfff0d2243e797c4862a44c93d2f52a52021c1a1b0899f846", size = 9380450 }, + { url = "https://files.pythonhosted.org/packages/0e/77/474f883393954f2323febd5cf7c96bfe8c684561f8d22ca843e90d122d73/ruff-0.5.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2a2949ce7c1cbd8317432ada80fe32156df825b2fd611688814c8557824ef060", size = 9718297 }, + { url = "https://files.pythonhosted.org/packages/b2/5a/72b3a1ddefbc7ccb382bcf9668648a6f1fdc4bfcc3d6687f14e6feb40636/ruff-0.5.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:481af57c8e99da92ad168924fd82220266043c8255942a1cb87958b108ac9335", size = 10221735 }, + { url = "https://files.pythonhosted.org/packages/bc/22/7aa3fb2b95dda4d485e5e5f15041679d3170a31b9317b24c6182f4c8faf1/ruff-0.5.2-py3-none-win32.whl", hash = "sha256:f1aea290c56d913e363066d83d3fc26848814a1fed3d72144ff9c930e8c7c718", size = 7786506 }, + { url = "https://files.pythonhosted.org/packages/a8/a0/f28c8380f4eff7451896618ca0cce097e65aef150c60c298a0b5c9f40311/ruff-0.5.2-py3-none-win_amd64.whl", hash = "sha256:8532660b72b5d94d2a0a7a27ae7b9b40053662d00357bb2a6864dd7e38819084", size = 8583643 }, + { url = "https://files.pythonhosted.org/packages/b5/c3/dd06a34c98fc887a8c027e1b17e7ceca479db98b24d3a2d98f8239f0ee71/ruff-0.5.2-py3-none-win_arm64.whl", hash = "sha256:73439805c5cb68f364d826a5c5c4b6c798ded6b7ebaa4011f01ce6c94e4d5583", size = 8012737 }, ] [[distribution]] @@ -5095,49 +5096,67 @@ wheels = [ [[distribution]] name = "sentry-sdk" -version = "2.8.0" +version = "2.10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/9d/d61d64819ecb0481647229c3ee8ddc00887552acc23745fd65d0d4d066f3/sentry_sdk-2.8.0.tar.gz", hash = "sha256:aa4314f877d9cd9add5a0c9ba18e3f27f99f7de835ce36bd150e48a41c7c646f", size = 273663 } +sdist = { url = "https://files.pythonhosted.org/packages/34/d8/ec3e43d4ce31e4f4cb6adb7210950362d71ce87a96c89934c4ac94f7110f/sentry_sdk-2.10.0.tar.gz", hash = "sha256:545fcc6e36c335faa6d6cda84669b6e17025f31efbf3b2211ec14efe008b75d1", size = 273996 } wheels = [ - { url = "https://files.pythonhosted.org/packages/80/f4/8e1be145ce63c4ef4e126ee362992ae1ada5e716723883912b74829583e7/sentry_sdk-2.8.0-py2.py3-none-any.whl", hash = "sha256:6051562d2cfa8087bb8b4b8b79dc44690f8a054762a29c07e22588b1f619bfb5", size = 300617 }, + { url = "https://files.pythonhosted.org/packages/4f/9e/9298785949269c8930e1fd3707b960da6e1a95a2442b747b8f8cca4578cb/sentry_sdk-2.10.0-py2.py3-none-any.whl", hash = "sha256:87b3d413c87d8e7f816cc9334bff255a83d8b577db2b22042651c30c19c09190", size = 302064 }, ] [[distribution]] name = "setuptools" -version = "70.2.0" +version = "70.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8d/e6/2fc95aec377988ff3ca882aa58d4f6ab35ff59a12b1611a9fe3075eb3019/setuptools-70.2.0.tar.gz", hash = "sha256:bd63e505105011b25c3c11f753f7e3b8465ea739efddaccef8f0efac2137bac1", size = 2332711 } +sdist = { url = "https://files.pythonhosted.org/packages/65/d8/10a70e86f6c28ae59f101a9de6d77bf70f147180fbf40c3af0f64080adc3/setuptools-70.3.0.tar.gz", hash = "sha256:f171bab1dfbc86b132997f26a119f6056a57950d058587841a0082e8830f9dc5", size = 2333112 } wheels = [ - { url = "https://files.pythonhosted.org/packages/42/54/2a8ecfcc9a714a6fbf86559a4b0f50b126a4ac4269ea8134f2c75c3e73de/setuptools-70.2.0-py3-none-any.whl", hash = "sha256:b8b8060bb426838fbe942479c90296ce976249451118ef566a5a0b7d8b78fb05", size = 930834 }, + { url = "https://files.pythonhosted.org/packages/ef/15/88e46eb9387e905704b69849618e699dc2f54407d8953cc4ec4b8b46528d/setuptools-70.3.0-py3-none-any.whl", hash = "sha256:fe384da74336c398e0d956d1cae0669bc02eed936cdb1d49b57de1990dc11ffc", size = 931070 }, ] [[distribution]] name = "shapely" -version = "2.0.4" +version = "2.0.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/7e/816fd1c135b062c80b72e17b7330d9a719cd413158afa580f4aaccf59aa9/shapely-2.0.4.tar.gz", hash = "sha256:5dc736127fac70009b8d309a0eeb74f3e08979e530cf7017f2f507ef62e6cfb8", size = 280935 } +sdist = { url = "https://files.pythonhosted.org/packages/ad/99/c47247f4d688bbb5346df5ff1de5d9792b6d95cbbb2fd7b71f45901c1878/shapely-2.0.5.tar.gz", hash = "sha256:bff2366bc786bfa6cb353d6b47d0443c570c32776612e527ee47b6df63fcfe32", size = 282188 } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/f6/b1b54fd7749e9cde332d8f55dd417cba189839b9a8a295ea4dbbab8a5fa3/shapely-2.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:de0205cb21ad5ddaef607cda9a3191eadd1e7a62a756ea3a356369675230ac35", size = 2503648 }, - { url = "https://files.pythonhosted.org/packages/93/fd/b205661ed60294a344406fb04227042fcede9501e81ee1e7018e9159455a/shapely-2.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7d56ce3e2a6a556b59a288771cf9d091470116867e578bebced8bfc4147fbfd7", size = 1434573 }, - { url = "https://files.pythonhosted.org/packages/2a/fb/e3f72b10a90e26bb1a92a38b3f30f3074ebac6d532f87848ac09c3e8a73b/shapely-2.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:58b0ecc505bbe49a99551eea3f2e8a9b3b24b3edd2a4de1ac0dc17bc75c9ec07", size = 1274613 }, - { url = "https://files.pythonhosted.org/packages/2f/3a/7a776b1733e0edfe386f109e3af3a40eaa2b5bda5b33827a8dbe630a5116/shapely-2.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:790a168a808bd00ee42786b8ba883307c0e3684ebb292e0e20009588c426da47", size = 2442866 }, - { url = "https://files.pythonhosted.org/packages/d5/fb/bcf6a8164ed307c99f1a8fabe5acd86ac99a33f52530a3ca84b0936f95bd/shapely-2.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4310b5494271e18580d61022c0857eb85d30510d88606fa3b8314790df7f367d", size = 2527009 }, - { url = "https://files.pythonhosted.org/packages/b1/c1/0136e1f8899f88d681f6872abfc210232d5b92fa879757827a23abd12f72/shapely-2.0.4-cp311-cp311-win32.whl", hash = "sha256:63f3a80daf4f867bd80f5c97fbe03314348ac1b3b70fb1c0ad255a69e3749879", size = 1293825 }, - { url = "https://files.pythonhosted.org/packages/6a/5c/3330f499ca860f0b92db4ceaebd7090096a83c1ea3ae7d8d4c6111761b82/shapely-2.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:c52ed79f683f721b69a10fb9e3d940a468203f5054927215586c5d49a072de8d", size = 1441078 }, - { url = "https://files.pythonhosted.org/packages/3a/d5/59efdf4d86cc6fb0c0e5ed2fd376eeda897ca32f7852ff4acba980bc87cb/shapely-2.0.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:5bbd974193e2cc274312da16b189b38f5f128410f3377721cadb76b1e8ca5328", size = 2503410 }, - { url = "https://files.pythonhosted.org/packages/b2/7f/2479812b618c61d72676749ae644671317af86683eb561183c4f7188cc1a/shapely-2.0.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:41388321a73ba1a84edd90d86ecc8bfed55e6a1e51882eafb019f45895ec0f65", size = 1434089 }, - { url = "https://files.pythonhosted.org/packages/6a/6b/b6f4371346ad8ad513e8a8a01118cdae9e25510a01cc108f61321e59f8e3/shapely-2.0.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0776c92d584f72f1e584d2e43cfc5542c2f3dd19d53f70df0900fda643f4bae6", size = 1274766 }, - { url = "https://files.pythonhosted.org/packages/50/a5/312ebc480f3069bd660e64e5cbde0c28a90aac2975d242f5ff470325a348/shapely-2.0.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c75c98380b1ede1cae9a252c6dc247e6279403fae38c77060a5e6186c95073ac", size = 2439568 }, - { url = "https://files.pythonhosted.org/packages/1f/11/9f70f606f492ee6fd8071df4f963843c92b16344bf9cf30016a3b0a4f63f/shapely-2.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3e700abf4a37b7b8b90532fa6ed5c38a9bfc777098bc9fbae5ec8e618ac8f30", size = 2524488 }, - { url = "https://files.pythonhosted.org/packages/8f/32/bc72211f652ebf0fc487b015cc5fab9703d1c8c6cf6b5c57c5d1261ecb68/shapely-2.0.4-cp312-cp312-win32.whl", hash = "sha256:4f2ab0faf8188b9f99e6a273b24b97662194160cc8ca17cf9d1fb6f18d7fb93f", size = 1294603 }, - { url = "https://files.pythonhosted.org/packages/81/35/6d8b5cf9a747b94e8940619d914280fc4ce8e86e411ad19d39e7e8be036c/shapely-2.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:03152442d311a5e85ac73b39680dd64a9892fa42bb08fd83b3bab4fe6999bfa0", size = 1441463 }, + { url = "https://files.pythonhosted.org/packages/29/3d/0d3ab80860cda6afbce9736fa1f091f452092d344fdd4e3c65e5fe7b1111/shapely-2.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5bbfb048a74cf273db9091ff3155d373020852805a37dfc846ab71dde4be93ec", size = 1448893 }, + { url = "https://files.pythonhosted.org/packages/80/68/6b51b7587547f6bbd0965cf957505a0ebec93510e840572a983003b3a0a9/shapely-2.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93be600cbe2fbaa86c8eb70656369f2f7104cd231f0d6585c7d0aa555d6878b8", size = 1282344 }, + { url = "https://files.pythonhosted.org/packages/7e/4e/4e83b9f3d7f0ce523c92bdf3dfe0292738d8ad2b589971390d6205bc843e/shapely-2.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f8e71bb9a46814019f6644c4e2560a09d44b80100e46e371578f35eaaa9da1c", size = 2444118 }, + { url = "https://files.pythonhosted.org/packages/ed/a8/c8b0f1a165e161247caf0fc265d61de3c4ea27d7c313c7ebfb1c4f6ddea4/shapely-2.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5251c28a29012e92de01d2e84f11637eb1d48184ee8f22e2df6c8c578d26760", size = 2528510 }, + { url = "https://files.pythonhosted.org/packages/76/04/111f8d42ad50fb60b2fa725c64a6988d2a49ea513c4feb4e02f93dc353bd/shapely-2.0.5-cp311-cp311-win32.whl", hash = "sha256:35110e80070d664781ec7955c7de557456b25727a0257b354830abb759bf8311", size = 1294608 }, + { url = "https://files.pythonhosted.org/packages/ec/1b/092fff53cbeced411eed2717592e31cadd3e52f0ebaba5f2df3f34913f96/shapely-2.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c6b78c0007a34ce7144f98b7418800e0a6a5d9a762f2244b00ea560525290c9", size = 1441974 }, + { url = "https://files.pythonhosted.org/packages/04/df/8062f14cb7aa502b8bda358103facedc80b87eec41e3391182655ff40615/shapely-2.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:03bd7b5fa5deb44795cc0a503999d10ae9d8a22df54ae8d4a4cd2e8a93466195", size = 1449608 }, + { url = "https://files.pythonhosted.org/packages/5d/e7/719f384857c39aa51aa19d09d7cac84aeab1b25a7d0dab62433bf7b419e9/shapely-2.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ff9521991ed9e201c2e923da014e766c1aa04771bc93e6fe97c27dcf0d40ace", size = 1284057 }, + { url = "https://files.pythonhosted.org/packages/a4/77/c05e794a65263deb020d7e25623234975dd96881f9e8cde341810ca683e7/shapely-2.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b65365cfbf657604e50d15161ffcc68de5cdb22a601bbf7823540ab4918a98d", size = 2440805 }, + { url = "https://files.pythonhosted.org/packages/f0/32/b7687654b6e747ceae8f9fa4cc7489a8ebf275c64caf811f949d87e89f5d/shapely-2.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21f64e647a025b61b19585d2247137b3a38a35314ea68c66aaf507a1c03ef6fe", size = 2524570 }, + { url = "https://files.pythonhosted.org/packages/f9/9c/5b68b3cd484065c7d33d83168d2ecfebfeeaa6d88bc9cfd830de2df490ac/shapely-2.0.5-cp312-cp312-win32.whl", hash = "sha256:3ac7dc1350700c139c956b03d9c3df49a5b34aaf91d024d1510a09717ea39199", size = 1295383 }, + { url = "https://files.pythonhosted.org/packages/d4/c3/e98e3eb9f06def32b8e2454ab718cafb99149f023dff023e257125132d6e/shapely-2.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:30e8737983c9d954cd17feb49eb169f02f1da49e24e5171122cf2c2b62d65c95", size = 1442365 }, +] + +[[distribution]] +name = "siphash24" +version = "1.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/d8/beb5183d1acc5a013d273452eac750b51e40855917a1841dead80fcf3086/siphash24-1.6.tar.gz", hash = "sha256:242d6901a81260f618938635a25ae7f208e744f7ee6c571f1b255c1c4c62917d", size = 19659 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/a5/0ffc51fe2e5f96258f0edfae15944006b09517ad7e98fdcbda05c67c70f6/siphash24-1.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3e1b3963c392a2d63cbe16af9171d789d2f15e69eb8314b21fe1e11bdc08205f", size = 80669 }, + { url = "https://files.pythonhosted.org/packages/80/ea/41d648cbbf3248a30f545f9e41ad5dedee19fcbad1d2baa7e39ae6f2779e/siphash24-1.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:de23d12c8a015904081e347900433a0c4b5e07690dbd0a104ad88929f3b91948", size = 75379 }, + { url = "https://files.pythonhosted.org/packages/48/a7/d6dcc551c8d53e436c58b7ecc96d1de0c0379c21b1e71b2543d38c039c95/siphash24-1.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8be513de01677e57989e028185a16e531942f7a9578d441481abe8b1085c45d6", size = 100466 }, + { url = "https://files.pythonhosted.org/packages/eb/46/b906d7e05e3d84239d6a04e3d5f106d96ab26483951c7cf2c5769ea8c894/siphash24-1.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef89477ce8f2e67fca025ad9b1c85b7498c6959baa7d9a502cbb5d8c7085f5b7", size = 105913 }, + { url = "https://files.pythonhosted.org/packages/4c/98/20159e2be9a957da2dffb3e18648c51ea7a0f09c49b8dce1cb268ca55ca7/siphash24-1.6-cp311-cp311-win32.whl", hash = "sha256:f702e646dc60b7d7915fa37f9357a03a2ec41ffb360b6946baf4801eb9f7e98f", size = 67528 }, + { url = "https://files.pythonhosted.org/packages/0d/0a/d8da621e624f3dbcf9a7a8066c54ddd2f6af437fc23169431caf6f9b403b/siphash24-1.6-cp311-cp311-win_amd64.whl", hash = "sha256:38715f61f0873e4a8b05125e14f349f465c64a1aaf79b6af0ff6f5f420d55dc5", size = 79961 }, + { url = "https://files.pythonhosted.org/packages/12/e4/ed944e92883b45996cf2c94447dd47b899c87674340b081b9e8cb317a88f/siphash24-1.6-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:51eefacbe82f8f48bc603eb97f54bf3819324349b69a9cd131ba02c40b1e6c61", size = 82399 }, + { url = "https://files.pythonhosted.org/packages/f9/d1/6ddbd7ba8972789f60282b9b9b1f88f08d26ef0913906e8ad5a9806c8432/siphash24-1.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c63321003aa1856b1bfd48e6ffbd4bff98afeaacb0fc902cb2ae44b861476335", size = 76253 }, + { url = "https://files.pythonhosted.org/packages/0d/87/0f125c1e069d09c4a39ab09d76fa9d4fe698bde68197627faeb38603f643/siphash24-1.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0ff4d068e9b0b3f138ef8e8b6f5de1990539d9d590e75a9a8beb6887535184a", size = 98184 }, + { url = "https://files.pythonhosted.org/packages/86/57/a274de0a91016cd4f870334a2af1193ffcdb88e34345ca098afea6dd10cb/siphash24-1.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1a671d91095e1872ca9988695200064ccca8db60133638d6061755fe669552", size = 103311 }, + { url = "https://files.pythonhosted.org/packages/5d/d4/b6a0c9f119b22938e36d74e0859167ae76c0ea0f7d7786eb48120b0e129d/siphash24-1.6-cp312-cp312-win32.whl", hash = "sha256:2dab672fcda08149b8c15f82ee74d732386428f53239cdb002ac2ad0a1f2f2bc", size = 68366 }, + { url = "https://files.pythonhosted.org/packages/ef/de/6ebd0f96184f8479e8348dcba93a9f14ff54ac3c6a68866cc77c334d7bdf/siphash24-1.6-cp312-cp312-win_amd64.whl", hash = "sha256:226af78af3b992c953cc4808f2c6a4bba320e91e6c89b34aa2492064fa417ae8", size = 81096 }, ] [[distribution]] @@ -5193,7 +5212,7 @@ wheels = [ [[distribution]] name = "sphinx" -version = "7.3.7" +version = "7.4.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "alabaster" }, @@ -5213,9 +5232,9 @@ dependencies = [ { name = "sphinxcontrib-qthelp" }, { name = "sphinxcontrib-serializinghtml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b7/0a/b88033900b1582f5ed8f880263363daef968d1cd064175e32abfd9714410/sphinx-7.3.7.tar.gz", hash = "sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc", size = 7094808 } +sdist = { url = "https://files.pythonhosted.org/packages/c3/7a/bc303eb950025a2cfa8f6968471fda8b28e8114621e2ab43f518094a4225/sphinx-7.4.3.tar.gz", hash = "sha256:bd846bcb09fd2b6e94ce3e1ad50f4618bccf03cc7c17d0f3fa87393c0bd9178b", size = 8113870 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/fa/130c32ed94cf270e3d0b9ded16fb7b2c8fea86fa7263c29a696a30c1dde7/sphinx-7.3.7-py3-none-any.whl", hash = "sha256:413f75440be4cacf328f580b4274ada4565fb2187d696a84970c23f77b64d8c3", size = 3335650 }, + { url = "https://files.pythonhosted.org/packages/c9/b8/8594be28e66d19c287c13dbc609a7695e5330ea59abce654a3f41b8a589e/sphinx-7.4.3-py3-none-any.whl", hash = "sha256:a3c295d0e8be6277e0a5ba5c6909a308bd208876b0f4f68c7cc591f566129412", size = 3454542 }, ] [[distribution]] @@ -5280,14 +5299,14 @@ sdist = { url = "https://files.pythonhosted.org/packages/c7/d9/401c0a7be089e0282 [[distribution]] name = "sympy" -version = "1.12.1" +version = "1.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mpmath" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/41/8a/0d1bbd33cd3091c913d298746e56f40586fa954788f51b816c6336424675/sympy-1.12.1.tar.gz", hash = "sha256:2877b03f998cd8c08f07cd0de5b767119cd3ef40d09f41c30d722f6686b0fb88", size = 6722359 } +sdist = { url = "https://files.pythonhosted.org/packages/cb/f5/8c7d91ce35816b72c2dd061dc4a33f00f59053aeffe881d42aed17279381/sympy-1.13.0.tar.gz", hash = "sha256:3b6af8f4d008b9a1a6a4268b335b984b23835f26d1d60b0526ebc71d48a25f57", size = 7532455 } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/53/e18c8c97d0b2724d85c9830477e3ebea3acf1dcdc6deb344d5d9c93a9946/sympy-1.12.1-py3-none-any.whl", hash = "sha256:9b2cbc7f1a640289430e13d2a56f02f867a1da0190f2f99d8968c2f74da0e515", size = 5743129 }, + { url = "https://files.pythonhosted.org/packages/62/74/7e6c65ee89ff43942bffffdbb238634f16967bf327aee3c76efcf6e49587/sympy-1.13.0-py3-none-any.whl", hash = "sha256:6b0b32a4673fb91bd3cac3b55406c8e01d53ae22780be467301cc452f6680c92", size = 6188245 }, ] [[distribution]] @@ -5322,14 +5341,14 @@ wheels = [ [[distribution]] name = "types-requests" -version = "2.32.0.20240622" +version = "2.32.0.20240712" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cf/99/ab96b7a68b26bbcff2865d0aa71bf6a895f04397a303dc027f96c58c4a58/types-requests-2.32.0.20240622.tar.gz", hash = "sha256:ed5e8a412fcc39159d6319385c009d642845f250c63902718f605cd90faade31", size = 17675 } +sdist = { url = "https://files.pythonhosted.org/packages/5e/9e/7663eb27c33568b8fc20ccdaf2a1ce53a9530c42a7cceb9f552a6ff4a1d8/types-requests-2.32.0.20240712.tar.gz", hash = "sha256:90c079ff05e549f6bf50e02e910210b98b8ff1ebdd18e19c873cd237737c1358", size = 17896 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/d0/409f7b40f9c34896b153c911d442c6e8d0f78035ddbfa387183aec5aa8c5/types_requests-2.32.0.20240622-py3-none-any.whl", hash = "sha256:97bac6b54b5bd4cf91d407e62f0932a74821bc2211f22116d9ee1dd643826caf", size = 15784 }, + { url = "https://files.pythonhosted.org/packages/30/4d/cbed87a6912fbd9259ce23a5d4aa1de9816edf75eec6ed9a757c00906c8e/types_requests-2.32.0.20240712-py3-none-any.whl", hash = "sha256:f754283e152c752e46e70942fa2a146b5bc70393522257bb85bd1ef7e019dcc3", size = 15816 }, ] [[distribution]] From 83d4623590f87dcb7df2b458a8814d5ad6ea711b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 16 Jul 2024 02:12:24 +0800 Subject: [PATCH 049/229] selfdrive/car: ban imports from external modules (#32973) * lint import * Update selfdrive/car/__init__.py --------- Co-authored-by: Shane Smiskol --- .importlinter | 36 +++++++++++++++++++ .pre-commit-config.yaml | 7 ++++ pyproject.toml | 1 + selfdrive/car/__init__.py | 1 + selfdrive/car/body/carcontroller.py | 2 +- selfdrive/car/body/interface.py | 3 +- selfdrive/car/card.py | 3 +- selfdrive/car/chrysler/carcontroller.py | 3 +- selfdrive/car/gm/carcontroller.py | 3 +- selfdrive/car/honda/carcontroller.py | 2 +- selfdrive/car/hyundai/carcontroller.py | 3 +- selfdrive/car/interfaces.py | 3 +- selfdrive/car/tests/test_car_interfaces.py | 3 +- selfdrive/car/tests/test_lateral_limits.py | 2 +- selfdrive/car/tests/test_models.py | 5 ++- selfdrive/car/toyota/carstate.py | 2 +- selfdrive/car/volkswagen/carcontroller.py | 3 +- selfdrive/controls/controlsd.py | 3 +- selfdrive/controls/lib/drive_helpers.py | 2 +- selfdrive/controls/lib/events.py | 2 +- selfdrive/controls/lib/latcontrol.py | 2 +- selfdrive/controls/lib/longcontrol.py | 2 +- selfdrive/controls/radard.py | 3 +- .../controls/tests/test_state_machine.py | 2 +- selfdrive/debug/cycle_alerts.py | 2 +- .../test/process_replay/process_replay.py | 2 +- tools/replay/can_replay.py | 3 +- 27 files changed, 73 insertions(+), 32 deletions(-) create mode 100644 .importlinter diff --git a/.importlinter b/.importlinter new file mode 100644 index 0000000000..3cb9e6b471 --- /dev/null +++ b/.importlinter @@ -0,0 +1,36 @@ +[importlinter] +root_packages = + openpilot + +[importlinter:contract:1] +name = Forbid imports from openpilot.selfdrive.car to openpilot.system +type = forbidden +source_modules = + openpilot.selfdrive.car +forbidden_modules = + openpilot.system + openpilot.body + openpilot.docs + openpilot.msgq + openpilot.panda + openpilot.rednose + openpilot.release + openpilot.teleoprtc + openpilot.tinygrad +ignore_imports = + openpilot.selfdrive.car.card -> openpilot.common.realtime + openpilot.selfdrive.car.card -> openpilot.selfdrive.controls.lib.events + openpilot.selfdrive.car.interfaces -> openpilot.selfdrive.controls.lib.events + openpilot.selfdrive.car.tests.test_models -> openpilot.tools.lib.logreader + openpilot.selfdrive.car.tests.test_models -> openpilot.selfdrive.car.card + openpilot.selfdrive.car.tests.test_models -> openpilot.tools.lib.route + openpilot.selfdrive.car.tests.test_models -> openpilot.system.hardware.hw + openpilot.selfdrive.car.tests.test_models -> openpilot.selfdrive.test.helpers + openpilot.selfdrive.car.isotp_parallel_query -> openpilot.common.swaglog + openpilot.selfdrive.car.fw_versions -> openpilot.common.swaglog + openpilot.selfdrive.car.disable_ecu -> openpilot.common.swaglog + openpilot.selfdrive.car.vin -> openpilot.common.swaglog + openpilot.selfdrive.car.ecu_addrs -> openpilot.common.swaglog + openpilot.selfdrive.car.car_helpers -> openpilot.common.swaglog + openpilot.selfdrive.car.car_helpers -> openpilot.system.version +unmatched_ignore_imports_alerting = warn diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6aa2a065ac..ab9ce08c7a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -96,3 +96,10 @@ repos: rev: 0.29.0 hooks: - id: check-github-workflows +- repo: local + hooks: + - id: import-linter + name: import linter + entry: lint-imports + language: system + pass_filenames: false diff --git a/pyproject.toml b/pyproject.toml index 13800fc1c5..e9c999400d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,6 +73,7 @@ docs = [ testing = [ "coverage", "hypothesis ==6.47.*", + "import-linter", "mypy", "pre-commit", "pytest", diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index 4a1df550d0..6f3bde7f0c 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -11,6 +11,7 @@ from openpilot.common.numpy_fast import clip, interp from openpilot.common.utils import Freezable from openpilot.selfdrive.car.docs_definitions import CarDocs +DT_CTRL = 0.01 # car state and control loop timestep (s) # kg of standard extra cargo to count for drive, gas, etc... STD_CARGO_KG = 136. diff --git a/selfdrive/car/body/carcontroller.py b/selfdrive/car/body/carcontroller.py index 259126c416..c45dc7f0d2 100644 --- a/selfdrive/car/body/carcontroller.py +++ b/selfdrive/car/body/carcontroller.py @@ -1,7 +1,7 @@ import numpy as np -from openpilot.common.realtime import DT_CTRL from opendbc.can.packer import CANPacker +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.body import bodycan from openpilot.selfdrive.car.body.values import SPEED_FROM_RPM from openpilot.selfdrive.car.interfaces import CarControllerBase diff --git a/selfdrive/car/body/interface.py b/selfdrive/car/body/interface.py index f797a7ecf8..50564d3ed8 100644 --- a/selfdrive/car/body/interface.py +++ b/selfdrive/car/body/interface.py @@ -1,7 +1,6 @@ import math from cereal import car -from openpilot.common.realtime import DT_CTRL -from openpilot.selfdrive.car import get_safety_config +from openpilot.selfdrive.car import DT_CTRL, get_safety_config from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.body.values import SPEED_FROM_RPM diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index d9ee020ba4..37f51b9aba 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -9,9 +9,10 @@ from cereal import car from panda import ALTERNATIVE_EXPERIENCE from openpilot.common.params import Params -from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL +from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper from openpilot.selfdrive.pandad import can_list_to_can_capnp +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.car_helpers import get_car, get_one_can from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.controls.lib.events import Events diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index 85f53f68eb..c9e7e2c9ed 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -1,6 +1,5 @@ from opendbc.can.packer import CANPacker -from openpilot.common.realtime import DT_CTRL -from openpilot.selfdrive.car import apply_meas_steer_torque_limits +from openpilot.selfdrive.car import DT_CTRL, apply_meas_steer_torque_limits from openpilot.selfdrive.car.chrysler import chryslercan from openpilot.selfdrive.car.chrysler.values import RAM_CARS, CarControllerParams, ChryslerFlags from openpilot.selfdrive.car.interfaces import CarControllerBase diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index b204d3b80f..013e72ad0b 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -1,9 +1,8 @@ from cereal import car from openpilot.common.conversions import Conversions as CV from openpilot.common.numpy_fast import interp -from openpilot.common.realtime import DT_CTRL from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import apply_driver_steer_torque_limits +from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits from openpilot.selfdrive.car.gm import gmcan from openpilot.selfdrive.car.gm.values import DBC, CanBus, CarControllerParams, CruiseButtons from openpilot.selfdrive.car.interfaces import CarControllerBase diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index fe023ea17d..66bd500485 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -2,8 +2,8 @@ from collections import namedtuple from cereal import car from openpilot.common.numpy_fast import clip, interp -from openpilot.common.realtime import DT_CTRL from opendbc.can.packer import CANPacker +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.honda import hondacan from openpilot.selfdrive.car.honda.values import CruiseButtons, VISUAL_HUD, HONDA_BOSCH, HONDA_BOSCH_RADARLESS, HONDA_NIDEC_ALT_PCM_ACCEL, CarControllerParams from openpilot.selfdrive.car.interfaces import CarControllerBase diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 4038ddcca9..3d7768a83b 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -1,9 +1,8 @@ from cereal import car from openpilot.common.conversions import Conversions as CV from openpilot.common.numpy_fast import clip -from openpilot.common.realtime import DT_CTRL from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance +from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits, common_fault_avoidance from openpilot.selfdrive.car.hyundai import hyundaicanfd, hyundaican from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 54070284e4..9f1b650158 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -13,8 +13,7 @@ from openpilot.common.basedir import BASEDIR from openpilot.common.conversions import Conversions as CV from openpilot.common.simple_kalman import KF1D, get_kalman_gain from openpilot.common.numpy_fast import clip -from openpilot.common.realtime import DT_CTRL -from openpilot.selfdrive.car import apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, STD_CARGO_KG +from openpilot.selfdrive.car import DT_CTRL, apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, STD_CARGO_KG from openpilot.selfdrive.car.values import PLATFORMS from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, get_friction from openpilot.selfdrive.controls.lib.events import Events diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index bb97ac8a9a..4ca19f019e 100644 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -6,8 +6,7 @@ import importlib from parameterized import parameterized from cereal import car, messaging -from openpilot.common.realtime import DT_CTRL -from openpilot.selfdrive.car import gen_empty_fingerprint +from openpilot.selfdrive.car import DT_CTRL, gen_empty_fingerprint from openpilot.selfdrive.car.car_helpers import interfaces from openpilot.selfdrive.car.fingerprints import all_known_cars from openpilot.selfdrive.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS diff --git a/selfdrive/car/tests/test_lateral_limits.py b/selfdrive/car/tests/test_lateral_limits.py index e61d197f4b..24eac01fcd 100755 --- a/selfdrive/car/tests/test_lateral_limits.py +++ b/selfdrive/car/tests/test_lateral_limits.py @@ -5,7 +5,7 @@ from parameterized import parameterized_class import pytest import sys -from openpilot.common.realtime import DT_CTRL +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.car_helpers import interfaces from openpilot.selfdrive.car.fingerprints import all_known_cars from openpilot.selfdrive.car.interfaces import get_torque_params diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index b5d75e665b..02e99f0b82 100644 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -12,14 +12,13 @@ from parameterized import parameterized_class from cereal import messaging, log, car from openpilot.common.basedir import BASEDIR from openpilot.common.params import Params -from openpilot.common.realtime import DT_CTRL -from openpilot.selfdrive.car import gen_empty_fingerprint -from openpilot.selfdrive.car.card import Car +from openpilot.selfdrive.car import DT_CTRL, gen_empty_fingerprint from openpilot.selfdrive.car.fingerprints import all_known_cars, MIGRATION from openpilot.selfdrive.car.car_helpers import FRAME_FINGERPRINT, interfaces from openpilot.selfdrive.car.honda.values import CAR as HONDA, HondaFlags from openpilot.selfdrive.car.tests.routes import non_tested_cars, routes, CarTestRoute from openpilot.selfdrive.car.values import Platform +from openpilot.selfdrive.car.card import Car from openpilot.selfdrive.test.helpers import read_segment_list from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT from openpilot.tools.lib.logreader import LogReader, internal_source, openpilotci_source diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index a596881c33..e02293da4e 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -4,9 +4,9 @@ from cereal import car from openpilot.common.conversions import Conversions as CV from openpilot.common.numpy_fast import mean from openpilot.common.filter_simple import FirstOrderFilter -from openpilot.common.realtime import DT_CTRL from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, \ TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index a4e0c8946a..8e8652d3be 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -2,8 +2,7 @@ from cereal import car from opendbc.can.packer import CANPacker from openpilot.common.numpy_fast import clip from openpilot.common.conversions import Conversions as CV -from openpilot.common.realtime import DT_CTRL -from openpilot.selfdrive.car import apply_driver_steer_torque_limits +from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits from openpilot.selfdrive.car.interfaces import CarControllerBase from openpilot.selfdrive.car.volkswagen import mqbcan, pqcan from openpilot.selfdrive.car.volkswagen.values import CANBUS, CarControllerParams, VolkswagenFlags diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 583cbaea1f..df84fc718e 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -15,9 +15,10 @@ from openpilot.common.conversions import Conversions as CV from openpilot.common.git import get_short_branch from openpilot.common.numpy_fast import clip from openpilot.common.params import Params -from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL +from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper from openpilot.common.swaglog import cloudlog +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.car_helpers import get_car_interface, get_startup_event from openpilot.selfdrive.controls.lib.alertmanager import AlertManager, set_offroad_alert from openpilot.selfdrive.controls.lib.drive_helpers import VCruiseHelper, clip_curvature diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index cfc6374a1d..a87e385b68 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -3,7 +3,7 @@ import math from cereal import car, log from openpilot.common.conversions import Conversions as CV from openpilot.common.numpy_fast import clip, interp -from openpilot.common.realtime import DT_CTRL +from openpilot.selfdrive.car import DT_CTRL # WARNING: this value was determined based on the model's training distribution, # model predictions above this speed can be unpredictable diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 25833da741..6c1c1d8c84 100755 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -9,7 +9,7 @@ from cereal import log, car import cereal.messaging as messaging from openpilot.common.conversions import Conversions as CV from openpilot.common.git import get_short_branch -from openpilot.common.realtime import DT_CTRL +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.locationd.calibrationd import MIN_SPEED_FILTER AlertSize = log.ControlsState.AlertSize diff --git a/selfdrive/controls/lib/latcontrol.py b/selfdrive/controls/lib/latcontrol.py index fddb331ccb..69d64d66af 100644 --- a/selfdrive/controls/lib/latcontrol.py +++ b/selfdrive/controls/lib/latcontrol.py @@ -1,7 +1,7 @@ from abc import abstractmethod, ABC from openpilot.common.numpy_fast import clip -from openpilot.common.realtime import DT_CTRL +from openpilot.selfdrive.car import DT_CTRL MIN_LATERAL_CONTROL_SPEED = 0.3 # m/s diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py index e4841c705f..0aa2a25171 100644 --- a/selfdrive/controls/lib/longcontrol.py +++ b/selfdrive/controls/lib/longcontrol.py @@ -1,6 +1,6 @@ from cereal import car from openpilot.common.numpy_fast import clip -from openpilot.common.realtime import DT_CTRL +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N from openpilot.selfdrive.controls.lib.pid import PIDController from openpilot.selfdrive.modeld.constants import ModelConstants diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index c3fb60c61a..6a4db0b4e9 100755 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -8,10 +8,11 @@ import capnp from cereal import messaging, log, car from openpilot.common.numpy_fast import interp from openpilot.common.params import Params -from openpilot.common.realtime import DT_CTRL, Ratekeeper, Priority, config_realtime_process +from openpilot.common.realtime import Ratekeeper, Priority, config_realtime_process from openpilot.common.swaglog import cloudlog from openpilot.common.simple_kalman import KF1D +from openpilot.selfdrive.car import DT_CTRL # Default lead acceleration decay set to 50% at 1s diff --git a/selfdrive/controls/tests/test_state_machine.py b/selfdrive/controls/tests/test_state_machine.py index b6ec512dc4..ebb742f4b1 100644 --- a/selfdrive/controls/tests/test_state_machine.py +++ b/selfdrive/controls/tests/test_state_machine.py @@ -1,5 +1,5 @@ from cereal import car, log -from openpilot.common.realtime import DT_CTRL +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.car_helpers import interfaces from openpilot.selfdrive.controls.controlsd import Controls, SOFT_DISABLE_TIME from openpilot.selfdrive.controls.lib.events import Events, ET, Alert, Priority, AlertSize, AlertStatus, VisualAlert, \ diff --git a/selfdrive/debug/cycle_alerts.py b/selfdrive/debug/cycle_alerts.py index 93b0430c1e..980c491c9c 100755 --- a/selfdrive/debug/cycle_alerts.py +++ b/selfdrive/debug/cycle_alerts.py @@ -4,7 +4,7 @@ import random from cereal import car, log import cereal.messaging as messaging -from openpilot.common.realtime import DT_CTRL +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.honda.interface import CarInterface from openpilot.selfdrive.controls.lib.events import ET, Events from openpilot.selfdrive.controls.lib.alertmanager import AlertManager diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index c7f57fd9bc..3ba129d031 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -20,8 +20,8 @@ from msgq.visionipc import VisionIpcServer, get_endpoint_name as vipc_get_endpoi from openpilot.common.params import Params from openpilot.common.prefix import OpenpilotPrefix from openpilot.common.timeout import Timeout -from openpilot.common.realtime import DT_CTRL from panda.python import ALTERNATIVE_EXPERIENCE +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.car_helpers import get_car, interfaces from openpilot.system.manager.process_config import managed_processes from openpilot.selfdrive.test.process_replay.vision_meta import meta_from_camera_state, available_streams diff --git a/tools/replay/can_replay.py b/tools/replay/can_replay.py index 3ab33a1dfd..9eea6b9050 100755 --- a/tools/replay/can_replay.py +++ b/tools/replay/can_replay.py @@ -7,7 +7,8 @@ import threading os.environ['FILEREADER_CACHE'] = '1' -from openpilot.common.realtime import config_realtime_process, Ratekeeper, DT_CTRL +from openpilot.common.realtime import config_realtime_process, Ratekeeper +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.pandad import can_capnp_to_can_list from openpilot.tools.lib.logreader import LogReader from panda import PandaJungle From 35a4a773f1ff6c7b171b7acdb2fd4a65279edebd Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 15 Jul 2024 11:14:04 -0700 Subject: [PATCH 050/229] Revert "selfdrive/car: ban imports from external modules" (#32993) Revert "selfdrive/car: ban imports from external modules (#32973)" This reverts commit 83d4623590f87dcb7df2b458a8814d5ad6ea711b. --- .importlinter | 36 ------------------- .pre-commit-config.yaml | 7 ---- pyproject.toml | 1 - selfdrive/car/__init__.py | 1 - selfdrive/car/body/carcontroller.py | 2 +- selfdrive/car/body/interface.py | 3 +- selfdrive/car/card.py | 3 +- selfdrive/car/chrysler/carcontroller.py | 3 +- selfdrive/car/gm/carcontroller.py | 3 +- selfdrive/car/honda/carcontroller.py | 2 +- selfdrive/car/hyundai/carcontroller.py | 3 +- selfdrive/car/interfaces.py | 3 +- selfdrive/car/tests/test_car_interfaces.py | 3 +- selfdrive/car/tests/test_lateral_limits.py | 2 +- selfdrive/car/tests/test_models.py | 5 +-- selfdrive/car/toyota/carstate.py | 2 +- selfdrive/car/volkswagen/carcontroller.py | 3 +- selfdrive/controls/controlsd.py | 3 +- selfdrive/controls/lib/drive_helpers.py | 2 +- selfdrive/controls/lib/events.py | 2 +- selfdrive/controls/lib/latcontrol.py | 2 +- selfdrive/controls/lib/longcontrol.py | 2 +- selfdrive/controls/radard.py | 3 +- .../controls/tests/test_state_machine.py | 2 +- selfdrive/debug/cycle_alerts.py | 2 +- .../test/process_replay/process_replay.py | 2 +- tools/replay/can_replay.py | 3 +- 27 files changed, 32 insertions(+), 73 deletions(-) delete mode 100644 .importlinter diff --git a/.importlinter b/.importlinter deleted file mode 100644 index 3cb9e6b471..0000000000 --- a/.importlinter +++ /dev/null @@ -1,36 +0,0 @@ -[importlinter] -root_packages = - openpilot - -[importlinter:contract:1] -name = Forbid imports from openpilot.selfdrive.car to openpilot.system -type = forbidden -source_modules = - openpilot.selfdrive.car -forbidden_modules = - openpilot.system - openpilot.body - openpilot.docs - openpilot.msgq - openpilot.panda - openpilot.rednose - openpilot.release - openpilot.teleoprtc - openpilot.tinygrad -ignore_imports = - openpilot.selfdrive.car.card -> openpilot.common.realtime - openpilot.selfdrive.car.card -> openpilot.selfdrive.controls.lib.events - openpilot.selfdrive.car.interfaces -> openpilot.selfdrive.controls.lib.events - openpilot.selfdrive.car.tests.test_models -> openpilot.tools.lib.logreader - openpilot.selfdrive.car.tests.test_models -> openpilot.selfdrive.car.card - openpilot.selfdrive.car.tests.test_models -> openpilot.tools.lib.route - openpilot.selfdrive.car.tests.test_models -> openpilot.system.hardware.hw - openpilot.selfdrive.car.tests.test_models -> openpilot.selfdrive.test.helpers - openpilot.selfdrive.car.isotp_parallel_query -> openpilot.common.swaglog - openpilot.selfdrive.car.fw_versions -> openpilot.common.swaglog - openpilot.selfdrive.car.disable_ecu -> openpilot.common.swaglog - openpilot.selfdrive.car.vin -> openpilot.common.swaglog - openpilot.selfdrive.car.ecu_addrs -> openpilot.common.swaglog - openpilot.selfdrive.car.car_helpers -> openpilot.common.swaglog - openpilot.selfdrive.car.car_helpers -> openpilot.system.version -unmatched_ignore_imports_alerting = warn diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ab9ce08c7a..6aa2a065ac 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -96,10 +96,3 @@ repos: rev: 0.29.0 hooks: - id: check-github-workflows -- repo: local - hooks: - - id: import-linter - name: import linter - entry: lint-imports - language: system - pass_filenames: false diff --git a/pyproject.toml b/pyproject.toml index e9c999400d..13800fc1c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,7 +73,6 @@ docs = [ testing = [ "coverage", "hypothesis ==6.47.*", - "import-linter", "mypy", "pre-commit", "pytest", diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index 6f3bde7f0c..4a1df550d0 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -11,7 +11,6 @@ from openpilot.common.numpy_fast import clip, interp from openpilot.common.utils import Freezable from openpilot.selfdrive.car.docs_definitions import CarDocs -DT_CTRL = 0.01 # car state and control loop timestep (s) # kg of standard extra cargo to count for drive, gas, etc... STD_CARGO_KG = 136. diff --git a/selfdrive/car/body/carcontroller.py b/selfdrive/car/body/carcontroller.py index c45dc7f0d2..259126c416 100644 --- a/selfdrive/car/body/carcontroller.py +++ b/selfdrive/car/body/carcontroller.py @@ -1,7 +1,7 @@ import numpy as np +from openpilot.common.realtime import DT_CTRL from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.body import bodycan from openpilot.selfdrive.car.body.values import SPEED_FROM_RPM from openpilot.selfdrive.car.interfaces import CarControllerBase diff --git a/selfdrive/car/body/interface.py b/selfdrive/car/body/interface.py index 50564d3ed8..f797a7ecf8 100644 --- a/selfdrive/car/body/interface.py +++ b/selfdrive/car/body/interface.py @@ -1,6 +1,7 @@ import math from cereal import car -from openpilot.selfdrive.car import DT_CTRL, get_safety_config +from openpilot.common.realtime import DT_CTRL +from openpilot.selfdrive.car import get_safety_config from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.body.values import SPEED_FROM_RPM diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index 37f51b9aba..d9ee020ba4 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -9,10 +9,9 @@ from cereal import car from panda import ALTERNATIVE_EXPERIENCE from openpilot.common.params import Params -from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper +from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL from openpilot.selfdrive.pandad import can_list_to_can_capnp -from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.car_helpers import get_car, get_one_can from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.controls.lib.events import Events diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index c9e7e2c9ed..85f53f68eb 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -1,5 +1,6 @@ from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import DT_CTRL, apply_meas_steer_torque_limits +from openpilot.common.realtime import DT_CTRL +from openpilot.selfdrive.car import apply_meas_steer_torque_limits from openpilot.selfdrive.car.chrysler import chryslercan from openpilot.selfdrive.car.chrysler.values import RAM_CARS, CarControllerParams, ChryslerFlags from openpilot.selfdrive.car.interfaces import CarControllerBase diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index 013e72ad0b..b204d3b80f 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -1,8 +1,9 @@ from cereal import car from openpilot.common.conversions import Conversions as CV from openpilot.common.numpy_fast import interp +from openpilot.common.realtime import DT_CTRL from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits +from openpilot.selfdrive.car import apply_driver_steer_torque_limits from openpilot.selfdrive.car.gm import gmcan from openpilot.selfdrive.car.gm.values import DBC, CanBus, CarControllerParams, CruiseButtons from openpilot.selfdrive.car.interfaces import CarControllerBase diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index 66bd500485..fe023ea17d 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -2,8 +2,8 @@ from collections import namedtuple from cereal import car from openpilot.common.numpy_fast import clip, interp +from openpilot.common.realtime import DT_CTRL from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.honda import hondacan from openpilot.selfdrive.car.honda.values import CruiseButtons, VISUAL_HUD, HONDA_BOSCH, HONDA_BOSCH_RADARLESS, HONDA_NIDEC_ALT_PCM_ACCEL, CarControllerParams from openpilot.selfdrive.car.interfaces import CarControllerBase diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 3d7768a83b..4038ddcca9 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -1,8 +1,9 @@ from cereal import car from openpilot.common.conversions import Conversions as CV from openpilot.common.numpy_fast import clip +from openpilot.common.realtime import DT_CTRL from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits, common_fault_avoidance +from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance from openpilot.selfdrive.car.hyundai import hyundaicanfd, hyundaican from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 9f1b650158..54070284e4 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -13,7 +13,8 @@ from openpilot.common.basedir import BASEDIR from openpilot.common.conversions import Conversions as CV from openpilot.common.simple_kalman import KF1D, get_kalman_gain from openpilot.common.numpy_fast import clip -from openpilot.selfdrive.car import DT_CTRL, apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, STD_CARGO_KG +from openpilot.common.realtime import DT_CTRL +from openpilot.selfdrive.car import apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, STD_CARGO_KG from openpilot.selfdrive.car.values import PLATFORMS from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, get_friction from openpilot.selfdrive.controls.lib.events import Events diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index 4ca19f019e..bb97ac8a9a 100644 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -6,7 +6,8 @@ import importlib from parameterized import parameterized from cereal import car, messaging -from openpilot.selfdrive.car import DT_CTRL, gen_empty_fingerprint +from openpilot.common.realtime import DT_CTRL +from openpilot.selfdrive.car import gen_empty_fingerprint from openpilot.selfdrive.car.car_helpers import interfaces from openpilot.selfdrive.car.fingerprints import all_known_cars from openpilot.selfdrive.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS diff --git a/selfdrive/car/tests/test_lateral_limits.py b/selfdrive/car/tests/test_lateral_limits.py index 24eac01fcd..e61d197f4b 100755 --- a/selfdrive/car/tests/test_lateral_limits.py +++ b/selfdrive/car/tests/test_lateral_limits.py @@ -5,7 +5,7 @@ from parameterized import parameterized_class import pytest import sys -from openpilot.selfdrive.car import DT_CTRL +from openpilot.common.realtime import DT_CTRL from openpilot.selfdrive.car.car_helpers import interfaces from openpilot.selfdrive.car.fingerprints import all_known_cars from openpilot.selfdrive.car.interfaces import get_torque_params diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index 02e99f0b82..b5d75e665b 100644 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -12,13 +12,14 @@ from parameterized import parameterized_class from cereal import messaging, log, car from openpilot.common.basedir import BASEDIR from openpilot.common.params import Params -from openpilot.selfdrive.car import DT_CTRL, gen_empty_fingerprint +from openpilot.common.realtime import DT_CTRL +from openpilot.selfdrive.car import gen_empty_fingerprint +from openpilot.selfdrive.car.card import Car from openpilot.selfdrive.car.fingerprints import all_known_cars, MIGRATION from openpilot.selfdrive.car.car_helpers import FRAME_FINGERPRINT, interfaces from openpilot.selfdrive.car.honda.values import CAR as HONDA, HondaFlags from openpilot.selfdrive.car.tests.routes import non_tested_cars, routes, CarTestRoute from openpilot.selfdrive.car.values import Platform -from openpilot.selfdrive.car.card import Car from openpilot.selfdrive.test.helpers import read_segment_list from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT from openpilot.tools.lib.logreader import LogReader, internal_source, openpilotci_source diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index e02293da4e..a596881c33 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -4,9 +4,9 @@ from cereal import car from openpilot.common.conversions import Conversions as CV from openpilot.common.numpy_fast import mean from openpilot.common.filter_simple import FirstOrderFilter +from openpilot.common.realtime import DT_CTRL from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser -from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, \ TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index 8e8652d3be..a4e0c8946a 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -2,7 +2,8 @@ from cereal import car from opendbc.can.packer import CANPacker from openpilot.common.numpy_fast import clip from openpilot.common.conversions import Conversions as CV -from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits +from openpilot.common.realtime import DT_CTRL +from openpilot.selfdrive.car import apply_driver_steer_torque_limits from openpilot.selfdrive.car.interfaces import CarControllerBase from openpilot.selfdrive.car.volkswagen import mqbcan, pqcan from openpilot.selfdrive.car.volkswagen.values import CANBUS, CarControllerParams, VolkswagenFlags diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index df84fc718e..583cbaea1f 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -15,10 +15,9 @@ from openpilot.common.conversions import Conversions as CV from openpilot.common.git import get_short_branch from openpilot.common.numpy_fast import clip from openpilot.common.params import Params -from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper +from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL from openpilot.common.swaglog import cloudlog -from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.car_helpers import get_car_interface, get_startup_event from openpilot.selfdrive.controls.lib.alertmanager import AlertManager, set_offroad_alert from openpilot.selfdrive.controls.lib.drive_helpers import VCruiseHelper, clip_curvature diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index a87e385b68..cfc6374a1d 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -3,7 +3,7 @@ import math from cereal import car, log from openpilot.common.conversions import Conversions as CV from openpilot.common.numpy_fast import clip, interp -from openpilot.selfdrive.car import DT_CTRL +from openpilot.common.realtime import DT_CTRL # WARNING: this value was determined based on the model's training distribution, # model predictions above this speed can be unpredictable diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 6c1c1d8c84..25833da741 100755 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -9,7 +9,7 @@ from cereal import log, car import cereal.messaging as messaging from openpilot.common.conversions import Conversions as CV from openpilot.common.git import get_short_branch -from openpilot.selfdrive.car import DT_CTRL +from openpilot.common.realtime import DT_CTRL from openpilot.selfdrive.locationd.calibrationd import MIN_SPEED_FILTER AlertSize = log.ControlsState.AlertSize diff --git a/selfdrive/controls/lib/latcontrol.py b/selfdrive/controls/lib/latcontrol.py index 69d64d66af..fddb331ccb 100644 --- a/selfdrive/controls/lib/latcontrol.py +++ b/selfdrive/controls/lib/latcontrol.py @@ -1,7 +1,7 @@ from abc import abstractmethod, ABC from openpilot.common.numpy_fast import clip -from openpilot.selfdrive.car import DT_CTRL +from openpilot.common.realtime import DT_CTRL MIN_LATERAL_CONTROL_SPEED = 0.3 # m/s diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py index 0aa2a25171..e4841c705f 100644 --- a/selfdrive/controls/lib/longcontrol.py +++ b/selfdrive/controls/lib/longcontrol.py @@ -1,6 +1,6 @@ from cereal import car from openpilot.common.numpy_fast import clip -from openpilot.selfdrive.car import DT_CTRL +from openpilot.common.realtime import DT_CTRL from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N from openpilot.selfdrive.controls.lib.pid import PIDController from openpilot.selfdrive.modeld.constants import ModelConstants diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index 6a4db0b4e9..c3fb60c61a 100755 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -8,11 +8,10 @@ import capnp from cereal import messaging, log, car from openpilot.common.numpy_fast import interp from openpilot.common.params import Params -from openpilot.common.realtime import Ratekeeper, Priority, config_realtime_process +from openpilot.common.realtime import DT_CTRL, Ratekeeper, Priority, config_realtime_process from openpilot.common.swaglog import cloudlog from openpilot.common.simple_kalman import KF1D -from openpilot.selfdrive.car import DT_CTRL # Default lead acceleration decay set to 50% at 1s diff --git a/selfdrive/controls/tests/test_state_machine.py b/selfdrive/controls/tests/test_state_machine.py index ebb742f4b1..b6ec512dc4 100644 --- a/selfdrive/controls/tests/test_state_machine.py +++ b/selfdrive/controls/tests/test_state_machine.py @@ -1,5 +1,5 @@ from cereal import car, log -from openpilot.selfdrive.car import DT_CTRL +from openpilot.common.realtime import DT_CTRL from openpilot.selfdrive.car.car_helpers import interfaces from openpilot.selfdrive.controls.controlsd import Controls, SOFT_DISABLE_TIME from openpilot.selfdrive.controls.lib.events import Events, ET, Alert, Priority, AlertSize, AlertStatus, VisualAlert, \ diff --git a/selfdrive/debug/cycle_alerts.py b/selfdrive/debug/cycle_alerts.py index 980c491c9c..93b0430c1e 100755 --- a/selfdrive/debug/cycle_alerts.py +++ b/selfdrive/debug/cycle_alerts.py @@ -4,7 +4,7 @@ import random from cereal import car, log import cereal.messaging as messaging -from openpilot.selfdrive.car import DT_CTRL +from openpilot.common.realtime import DT_CTRL from openpilot.selfdrive.car.honda.interface import CarInterface from openpilot.selfdrive.controls.lib.events import ET, Events from openpilot.selfdrive.controls.lib.alertmanager import AlertManager diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 3ba129d031..c7f57fd9bc 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -20,8 +20,8 @@ from msgq.visionipc import VisionIpcServer, get_endpoint_name as vipc_get_endpoi from openpilot.common.params import Params from openpilot.common.prefix import OpenpilotPrefix from openpilot.common.timeout import Timeout +from openpilot.common.realtime import DT_CTRL from panda.python import ALTERNATIVE_EXPERIENCE -from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.car_helpers import get_car, interfaces from openpilot.system.manager.process_config import managed_processes from openpilot.selfdrive.test.process_replay.vision_meta import meta_from_camera_state, available_streams diff --git a/tools/replay/can_replay.py b/tools/replay/can_replay.py index 9eea6b9050..3ab33a1dfd 100755 --- a/tools/replay/can_replay.py +++ b/tools/replay/can_replay.py @@ -7,8 +7,7 @@ import threading os.environ['FILEREADER_CACHE'] = '1' -from openpilot.common.realtime import config_realtime_process, Ratekeeper -from openpilot.selfdrive.car import DT_CTRL +from openpilot.common.realtime import config_realtime_process, Ratekeeper, DT_CTRL from openpilot.selfdrive.pandad import can_capnp_to_can_list from openpilot.tools.lib.logreader import LogReader from panda import PandaJungle From d684d8f0f6900d80a2a1618099b0b8e19e6492a2 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 15 Jul 2024 11:59:25 -0700 Subject: [PATCH 051/229] Reapply "selfdrive/car: ban imports from external modules" (#32993) (#32994) * Reapply "selfdrive/car: ban imports from external modules" (#32993) This reverts commit 35a4a773f1ff6c7b171b7acdb2fd4a65279edebd. * controls will just use controls * also these * ignore --- .importlinter | 44 ++++++++++++++++++++++ .pre-commit-config.yaml | 7 ++++ pyproject.toml | 1 + selfdrive/car/__init__.py | 1 + selfdrive/car/body/carcontroller.py | 2 +- selfdrive/car/body/interface.py | 3 +- selfdrive/car/card.py | 3 +- selfdrive/car/chrysler/carcontroller.py | 3 +- selfdrive/car/gm/carcontroller.py | 3 +- selfdrive/car/honda/carcontroller.py | 2 +- selfdrive/car/hyundai/carcontroller.py | 3 +- selfdrive/car/interfaces.py | 3 +- selfdrive/car/tests/test_car_interfaces.py | 3 +- selfdrive/car/tests/test_lateral_limits.py | 2 +- selfdrive/car/tests/test_models.py | 5 +-- selfdrive/car/toyota/carstate.py | 2 +- selfdrive/car/volkswagen/carcontroller.py | 3 +- 17 files changed, 68 insertions(+), 22 deletions(-) create mode 100644 .importlinter diff --git a/.importlinter b/.importlinter new file mode 100644 index 0000000000..594d75ee4a --- /dev/null +++ b/.importlinter @@ -0,0 +1,44 @@ +[importlinter] +root_packages = + openpilot + +[importlinter:contract:1] +name = Forbid imports from openpilot.selfdrive.car to openpilot.system +type = forbidden +source_modules = + openpilot.selfdrive.car +forbidden_modules = + openpilot.system + openpilot.body + openpilot.docs + openpilot.msgq + openpilot.panda + openpilot.rednose + openpilot.release + openpilot.teleoprtc + openpilot.tinygrad +ignore_imports = + openpilot.selfdrive.car.card -> openpilot.common.realtime + openpilot.selfdrive.car.card -> openpilot.selfdrive.controls.lib.events + openpilot.selfdrive.car.interfaces -> openpilot.selfdrive.controls.lib.events + openpilot.selfdrive.car.tests.test_models -> openpilot.tools.lib.logreader + openpilot.selfdrive.car.tests.test_models -> openpilot.selfdrive.car.card + openpilot.selfdrive.car.tests.test_models -> openpilot.tools.lib.route + openpilot.selfdrive.car.tests.test_models -> openpilot.system.hardware.hw + openpilot.selfdrive.car.tests.test_models -> openpilot.selfdrive.test.helpers + openpilot.selfdrive.car.isotp_parallel_query -> openpilot.common.swaglog + openpilot.selfdrive.car.fw_versions -> openpilot.common.swaglog + openpilot.selfdrive.car.disable_ecu -> openpilot.common.swaglog + openpilot.selfdrive.car.vin -> openpilot.common.swaglog + openpilot.selfdrive.car.ecu_addrs -> openpilot.common.swaglog + openpilot.selfdrive.car.car_helpers -> openpilot.common.swaglog + openpilot.selfdrive.car.car_helpers -> openpilot.system.version + openpilot.selfdrive.car.ford.carcontroller -> openpilot.selfdrive.controls.lib.drive_helpers + openpilot.selfdrive.car.gm.interface -> openpilot.selfdrive.controls.lib.drive_helpers + openpilot.selfdrive.car.honda.carcontroller -> openpilot.selfdrive.controls.lib.drive_helpers + openpilot.selfdrive.car.interfaces -> openpilot.selfdrive.controls.lib.drive_helpers + openpilot.selfdrive.car.tests.test_car_interfaces -> openpilot.selfdrive.controls.lib.latcontrol_angle + openpilot.selfdrive.car.tests.test_car_interfaces -> openpilot.selfdrive.controls.lib.longcontrol + openpilot.selfdrive.car.tests.test_car_interfaces -> openpilot.selfdrive.controls.lib.latcontrol_torque + openpilot.selfdrive.car.tests.test_car_interfaces -> openpilot.selfdrive.controls.lib.latcontrol_pid +unmatched_ignore_imports_alerting = warn diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6aa2a065ac..ab9ce08c7a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -96,3 +96,10 @@ repos: rev: 0.29.0 hooks: - id: check-github-workflows +- repo: local + hooks: + - id: import-linter + name: import linter + entry: lint-imports + language: system + pass_filenames: false diff --git a/pyproject.toml b/pyproject.toml index 13800fc1c5..e9c999400d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,6 +73,7 @@ docs = [ testing = [ "coverage", "hypothesis ==6.47.*", + "import-linter", "mypy", "pre-commit", "pytest", diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index 4a1df550d0..6f3bde7f0c 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -11,6 +11,7 @@ from openpilot.common.numpy_fast import clip, interp from openpilot.common.utils import Freezable from openpilot.selfdrive.car.docs_definitions import CarDocs +DT_CTRL = 0.01 # car state and control loop timestep (s) # kg of standard extra cargo to count for drive, gas, etc... STD_CARGO_KG = 136. diff --git a/selfdrive/car/body/carcontroller.py b/selfdrive/car/body/carcontroller.py index 259126c416..c45dc7f0d2 100644 --- a/selfdrive/car/body/carcontroller.py +++ b/selfdrive/car/body/carcontroller.py @@ -1,7 +1,7 @@ import numpy as np -from openpilot.common.realtime import DT_CTRL from opendbc.can.packer import CANPacker +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.body import bodycan from openpilot.selfdrive.car.body.values import SPEED_FROM_RPM from openpilot.selfdrive.car.interfaces import CarControllerBase diff --git a/selfdrive/car/body/interface.py b/selfdrive/car/body/interface.py index f797a7ecf8..50564d3ed8 100644 --- a/selfdrive/car/body/interface.py +++ b/selfdrive/car/body/interface.py @@ -1,7 +1,6 @@ import math from cereal import car -from openpilot.common.realtime import DT_CTRL -from openpilot.selfdrive.car import get_safety_config +from openpilot.selfdrive.car import DT_CTRL, get_safety_config from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.body.values import SPEED_FROM_RPM diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index d9ee020ba4..37f51b9aba 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -9,9 +9,10 @@ from cereal import car from panda import ALTERNATIVE_EXPERIENCE from openpilot.common.params import Params -from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL +from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper from openpilot.selfdrive.pandad import can_list_to_can_capnp +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.car_helpers import get_car, get_one_can from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.controls.lib.events import Events diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index 85f53f68eb..c9e7e2c9ed 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -1,6 +1,5 @@ from opendbc.can.packer import CANPacker -from openpilot.common.realtime import DT_CTRL -from openpilot.selfdrive.car import apply_meas_steer_torque_limits +from openpilot.selfdrive.car import DT_CTRL, apply_meas_steer_torque_limits from openpilot.selfdrive.car.chrysler import chryslercan from openpilot.selfdrive.car.chrysler.values import RAM_CARS, CarControllerParams, ChryslerFlags from openpilot.selfdrive.car.interfaces import CarControllerBase diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index b204d3b80f..013e72ad0b 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -1,9 +1,8 @@ from cereal import car from openpilot.common.conversions import Conversions as CV from openpilot.common.numpy_fast import interp -from openpilot.common.realtime import DT_CTRL from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import apply_driver_steer_torque_limits +from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits from openpilot.selfdrive.car.gm import gmcan from openpilot.selfdrive.car.gm.values import DBC, CanBus, CarControllerParams, CruiseButtons from openpilot.selfdrive.car.interfaces import CarControllerBase diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index fe023ea17d..66bd500485 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -2,8 +2,8 @@ from collections import namedtuple from cereal import car from openpilot.common.numpy_fast import clip, interp -from openpilot.common.realtime import DT_CTRL from opendbc.can.packer import CANPacker +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.honda import hondacan from openpilot.selfdrive.car.honda.values import CruiseButtons, VISUAL_HUD, HONDA_BOSCH, HONDA_BOSCH_RADARLESS, HONDA_NIDEC_ALT_PCM_ACCEL, CarControllerParams from openpilot.selfdrive.car.interfaces import CarControllerBase diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 4038ddcca9..3d7768a83b 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -1,9 +1,8 @@ from cereal import car from openpilot.common.conversions import Conversions as CV from openpilot.common.numpy_fast import clip -from openpilot.common.realtime import DT_CTRL from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance +from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits, common_fault_avoidance from openpilot.selfdrive.car.hyundai import hyundaicanfd, hyundaican from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 54070284e4..9f1b650158 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -13,8 +13,7 @@ from openpilot.common.basedir import BASEDIR from openpilot.common.conversions import Conversions as CV from openpilot.common.simple_kalman import KF1D, get_kalman_gain from openpilot.common.numpy_fast import clip -from openpilot.common.realtime import DT_CTRL -from openpilot.selfdrive.car import apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, STD_CARGO_KG +from openpilot.selfdrive.car import DT_CTRL, apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, STD_CARGO_KG from openpilot.selfdrive.car.values import PLATFORMS from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, get_friction from openpilot.selfdrive.controls.lib.events import Events diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index bb97ac8a9a..4ca19f019e 100644 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -6,8 +6,7 @@ import importlib from parameterized import parameterized from cereal import car, messaging -from openpilot.common.realtime import DT_CTRL -from openpilot.selfdrive.car import gen_empty_fingerprint +from openpilot.selfdrive.car import DT_CTRL, gen_empty_fingerprint from openpilot.selfdrive.car.car_helpers import interfaces from openpilot.selfdrive.car.fingerprints import all_known_cars from openpilot.selfdrive.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS diff --git a/selfdrive/car/tests/test_lateral_limits.py b/selfdrive/car/tests/test_lateral_limits.py index e61d197f4b..24eac01fcd 100755 --- a/selfdrive/car/tests/test_lateral_limits.py +++ b/selfdrive/car/tests/test_lateral_limits.py @@ -5,7 +5,7 @@ from parameterized import parameterized_class import pytest import sys -from openpilot.common.realtime import DT_CTRL +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.car_helpers import interfaces from openpilot.selfdrive.car.fingerprints import all_known_cars from openpilot.selfdrive.car.interfaces import get_torque_params diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index b5d75e665b..02e99f0b82 100644 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -12,14 +12,13 @@ from parameterized import parameterized_class from cereal import messaging, log, car from openpilot.common.basedir import BASEDIR from openpilot.common.params import Params -from openpilot.common.realtime import DT_CTRL -from openpilot.selfdrive.car import gen_empty_fingerprint -from openpilot.selfdrive.car.card import Car +from openpilot.selfdrive.car import DT_CTRL, gen_empty_fingerprint from openpilot.selfdrive.car.fingerprints import all_known_cars, MIGRATION from openpilot.selfdrive.car.car_helpers import FRAME_FINGERPRINT, interfaces from openpilot.selfdrive.car.honda.values import CAR as HONDA, HondaFlags from openpilot.selfdrive.car.tests.routes import non_tested_cars, routes, CarTestRoute from openpilot.selfdrive.car.values import Platform +from openpilot.selfdrive.car.card import Car from openpilot.selfdrive.test.helpers import read_segment_list from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT from openpilot.tools.lib.logreader import LogReader, internal_source, openpilotci_source diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index a596881c33..e02293da4e 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -4,9 +4,9 @@ from cereal import car from openpilot.common.conversions import Conversions as CV from openpilot.common.numpy_fast import mean from openpilot.common.filter_simple import FirstOrderFilter -from openpilot.common.realtime import DT_CTRL from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser +from openpilot.selfdrive.car import DT_CTRL from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, \ TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index a4e0c8946a..8e8652d3be 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -2,8 +2,7 @@ from cereal import car from opendbc.can.packer import CANPacker from openpilot.common.numpy_fast import clip from openpilot.common.conversions import Conversions as CV -from openpilot.common.realtime import DT_CTRL -from openpilot.selfdrive.car import apply_driver_steer_torque_limits +from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits from openpilot.selfdrive.car.interfaces import CarControllerBase from openpilot.selfdrive.car.volkswagen import mqbcan, pqcan from openpilot.selfdrive.car.volkswagen.values import CANBUS, CarControllerParams, VolkswagenFlags From c0739cd9ee41ccd372bd8cd816c44dfce4e3a8a2 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 16 Jul 2024 03:05:20 +0800 Subject: [PATCH 052/229] selfdrive/car/ecu_addrs: prefix internal functions with underscore (#32980) underscore prefix --- selfdrive/car/ecu_addrs.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/selfdrive/car/ecu_addrs.py b/selfdrive/car/ecu_addrs.py index 756cd7f963..0fd4bbd0be 100755 --- a/selfdrive/car/ecu_addrs.py +++ b/selfdrive/car/ecu_addrs.py @@ -10,7 +10,7 @@ from openpilot.selfdrive.pandad import can_list_to_can_capnp from openpilot.common.swaglog import cloudlog -def make_tester_present_msg(addr, bus, subaddr=None): +def _make_tester_present_msg(addr, bus, subaddr=None): dat = [0x02, SERVICE_TYPE.TESTER_PRESENT, 0x0] if subaddr is not None: dat.insert(0, subaddr) @@ -19,7 +19,7 @@ def make_tester_present_msg(addr, bus, subaddr=None): return make_can_msg(addr, bytes(dat), bus) -def is_tester_present_response(msg: capnp.lib.capnp._DynamicStructReader, subaddr: int = None) -> bool: +def _is_tester_present_response(msg: capnp.lib.capnp._DynamicStructReader, subaddr: int = None) -> bool: # ISO-TP messages are always padded to 8 bytes # tester present response is always a single frame dat_offset = 1 if subaddr is not None else 0 @@ -33,7 +33,7 @@ def is_tester_present_response(msg: capnp.lib.capnp._DynamicStructReader, subadd return False -def get_all_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, bus: int, timeout: float = 1, debug: bool = True) -> set[EcuAddrBusType]: +def _get_all_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, bus: int, timeout: float = 1, debug: bool = True) -> set[EcuAddrBusType]: addr_list = [0x700 + i for i in range(256)] + [0x18da00f1 + (i << 8) for i in range(256)] queries: set[EcuAddrBusType] = {(addr, None, bus) for addr in addr_list} responses = queries @@ -44,7 +44,7 @@ def get_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, que responses: set[EcuAddrBusType], timeout: float = 1, debug: bool = False) -> set[EcuAddrBusType]: ecu_responses: set[EcuAddrBusType] = set() # set((addr, subaddr, bus),) try: - msgs = [make_tester_present_msg(addr, bus, subaddr) for addr, subaddr, bus in queries] + msgs = [_make_tester_present_msg(addr, bus, subaddr) for addr, subaddr, bus in queries] messaging.drain_sock_raw(logcan) sendcan.send(can_list_to_can_capnp(msgs, msgtype='sendcan')) @@ -58,7 +58,7 @@ def get_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, que continue subaddr = None if (msg.address, None, msg.src) in responses else msg.dat[0] - if (msg.address, subaddr, msg.src) in responses and is_tester_present_response(msg, subaddr): + if (msg.address, subaddr, msg.src) in responses and _is_tester_present_response(msg, subaddr): if debug: print(f"CAN-RX: {hex(msg.address)} - 0x{bytes.hex(msg.dat)}") if (msg.address, subaddr, msg.src) in ecu_responses: @@ -94,7 +94,7 @@ if __name__ == "__main__": set_obd_multiplexing(params, not args.no_obd) print("Getting ECU addresses ...") - ecu_addrs = get_all_ecu_addrs(logcan, sendcan, args.bus, args.timeout, debug=args.debug) + ecu_addrs = _get_all_ecu_addrs(logcan, sendcan, args.bus, args.timeout, debug=args.debug) print() print("Found ECUs on rx addresses:") From 00af33c6ed3ada846ccfec9de489452c900afffd Mon Sep 17 00:00:00 2001 From: commaci-public <60409688+commaci-public@users.noreply.github.com> Date: Mon, 15 Jul 2024 12:05:33 -0700 Subject: [PATCH 053/229] [bot] Bump submodules (#32989) bump submodules Co-authored-by: Vehicle Researcher --- msgq_repo | 2 +- opendbc | 2 +- teleoprtc_repo | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/msgq_repo b/msgq_repo index 74074d650f..d7b99c4296 160000 --- a/msgq_repo +++ b/msgq_repo @@ -1 +1 @@ -Subproject commit 74074d650f5d516a33962c1681a2a15b1d603537 +Subproject commit d7b99c4296f7a5c098e756bad73af8ef38370261 diff --git a/opendbc b/opendbc index de39b143a3..5ba787024f 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit de39b143a31cd29b4df4c0cbba71316c1bc8e71b +Subproject commit 5ba787024f53a00d76c7b253d1f3fee87763c679 diff --git a/teleoprtc_repo b/teleoprtc_repo index fdcff87aaf..389815b8ca 160000 --- a/teleoprtc_repo +++ b/teleoprtc_repo @@ -1 +1 @@ -Subproject commit fdcff87aaf2b1ca099be4fc820044334cec02cc5 +Subproject commit 389815b8ca5302ce7c1504b7841d4eb61a8cd51b From aa8484093e886cd8ae90e4eb42118306794fc439 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 15 Jul 2024 14:40:24 -0700 Subject: [PATCH 054/229] [bot] Fingerprints: add missing FW versions from new users (#32996) Export fingerprints --- selfdrive/car/hyundai/fingerprints.py | 1 + selfdrive/car/toyota/fingerprints.py | 1 + 2 files changed, 2 insertions(+) diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index 4ad7e0e0aa..4c659f053f 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -171,6 +171,7 @@ FW_VERSIONS = { (Ecu.eps, 0x7d4, None): [ b'\xf1\x00DN8 MDPS C 1,00 1,01 56310L0010\x00 4DNAC101', b'\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0010 4DNAC101', + b'\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0200 4DNAC102', b'\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0210 4DNAC101', b'\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0210 4DNAC102', b'\xf1\x00DN8 MDPS C 1.00 1.01 56310L0010\x00 4DNAC101', diff --git a/selfdrive/car/toyota/fingerprints.py b/selfdrive/car/toyota/fingerprints.py index 67203da7d0..a4d0ad1707 100644 --- a/selfdrive/car/toyota/fingerprints.py +++ b/selfdrive/car/toyota/fingerprints.py @@ -167,6 +167,7 @@ FW_VERSIONS = { (Ecu.abs, 0x7b0, None): [ b'F152606210\x00\x00\x00\x00\x00\x00', b'F152606230\x00\x00\x00\x00\x00\x00', + b'F152606260\x00\x00\x00\x00\x00\x00', b'F152606270\x00\x00\x00\x00\x00\x00', b'F152606290\x00\x00\x00\x00\x00\x00', b'F152606410\x00\x00\x00\x00\x00\x00', From 4b794773b0486a15732ce5551771584af7c41e43 Mon Sep 17 00:00:00 2001 From: Greg Hogan Date: Tue, 16 Jul 2024 18:24:01 -0700 Subject: [PATCH 055/229] use rounded constant instead of hard-coded value for incrementing set speed (#32992) * use rounded constant instead of hard-coded value for incrementing set speed * better comment --- selfdrive/controls/lib/drive_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index cfc6374a1d..bd74051374 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -13,7 +13,7 @@ V_CRUISE_MAX = 145 V_CRUISE_UNSET = 255 V_CRUISE_INITIAL = 40 V_CRUISE_INITIAL_EXPERIMENTAL_MODE = 105 -IMPERIAL_INCREMENT = 1.6 # should be CV.MPH_TO_KPH, but this causes rounding errors +IMPERIAL_INCREMENT = round(CV.MPH_TO_KPH, 1) # round here to avoid rounding errors incrementing set speed MIN_SPEED = 1.0 CONTROL_N = 17 From 996bced674e6943976f1d6dba37075e113bf9288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 17 Jul 2024 16:17:23 -0700 Subject: [PATCH 056/229] livePose log (#32868) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add livepose * Formatting * Add to sevices * Update locationd to publish livePose * Remove fields and increase decimation * Fix field indices * Remove the line * Add livePose to pubmaster * Fix llk decimation * Update ref commit * XYZ measurements instead of lists * Update locationd * Update ref commit * Lower the qlog size in test_onroad * Update lower and upper boundary --------- Co-authored-by: Kacper Rączy --- cereal/log.capnp | 33 +++++++ cereal/services.py | 3 +- selfdrive/locationd/locationd.cc | 90 +++++++++++++++---- selfdrive/locationd/locationd.h | 7 +- .../test/process_replay/process_replay.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- selfdrive/test/test_onroad.py | 2 +- 7 files changed, 117 insertions(+), 22 deletions(-) diff --git a/cereal/log.capnp b/cereal/log.capnp index 3a53db9cc4..d94d9632fe 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -1252,6 +1252,38 @@ struct LiveLocationKalman { } } + +struct LivePose { + # More info on reference frames: + # https://github.com/commaai/openpilot/tree/master/common/transformations + orientationNED @0 :XYZMeasurement; + velocityDevice @1 :XYZMeasurement; + accelerationDevice @2 :XYZMeasurement; + angularVelocityDevice @3 :XYZMeasurement; + + inputsOK @4 :Bool = false; + posenetOK @5 :Bool = false; + sensorsOK @6 :Bool = false; + + filterState @7 :FilterState; + + struct XYZMeasurement { + x @0 :Float32; + y @1 :Float32; + z @2 :Float32; + xStd @3 :Float32; + yStd @4 :Float32; + zStd @5 :Float32; + valid @6 :Bool; + } + + struct FilterState { + value @0 : List(Float64); + std @1 : List(Float64); + valid @2 : Bool; + } +} + struct ProcLog { cpuTimes @0 :List(CPUTimes); mem @1 :Mem; @@ -2293,6 +2325,7 @@ struct Event { carParams @69: Car.CarParams; driverMonitoringState @71: DriverMonitoringState; liveLocationKalman @72 :LiveLocationKalman; + livePose @129 :LivePose; modelV2 @75 :ModelDataV2; drivingModelData @128 :DrivingModelData; driverStateV2 @92 :DriverStateV2; diff --git a/cereal/services.py b/cereal/services.py index f1e1935c54..f2d01b9220 100755 --- a/cereal/services.py +++ b/cereal/services.py @@ -47,7 +47,8 @@ _services: dict[str, tuple] = { "gnssMeasurements": (True, 10., 10), "clocks": (True, 0.1, 1), "ubloxRaw": (True, 20.), - "liveLocationKalman": (True, 20., 5), + "livePose": (True, 20., 4), + "liveLocationKalman": (True, 20.), "liveParameters": (True, 20., 5), "cameraOdometry": (True, 20., 5), "thumbnail": (True, 0.2, 1), diff --git a/selfdrive/locationd/locationd.cc b/selfdrive/locationd/locationd.cc index 2ac392a778..5607871f5f 100644 --- a/selfdrive/locationd/locationd.cc +++ b/selfdrive/locationd/locationd.cc @@ -41,14 +41,25 @@ const int GPS_ORIENTATION_ERROR_RESET_CNT = 3; const bool DEBUG = getenv("DEBUG") != nullptr && std::string(getenv("DEBUG")) != "0"; -static VectorXd floatlist2vector(const capnp::List::Reader& floatlist) { - VectorXd res(floatlist.size()); +template +static Vector floatlist2vector(const ListType& floatlist) { + Vector res(floatlist.size()); for (int i = 0; i < floatlist.size(); i++) { res[i] = floatlist[i]; } return res; } +template +static VectorXd float64list2vector(const ListType& floatlist) { + return floatlist2vector(floatlist); +} + +template +static VectorXf float32list2vector(const ListType& floatlist) { + return floatlist2vector(floatlist); +} + static Vector4d quat2vector(const Quaterniond& quat) { return Vector4d(quat.w(), quat.x(), quat.y(), quat.z()); } @@ -63,6 +74,11 @@ static void init_measurement(cereal::LiveLocationKalman::Measurement::Builder me meas.setValid(valid); } +static void init_xyz_measurement(cereal::LivePose::XYZMeasurement::Builder meas, const VectorXf& val, const VectorXf& std, bool valid) { + meas.setX(val[0]); meas.setY(val[1]); meas.setZ(val[2]); + meas.setXStd(std[0]); meas.setYStd(std[1]); meas.setZStd(std[2]); + meas.setValid(valid); +} static MatrixXdr rotate_cov(const MatrixXdr& rot_matrix, const MatrixXdr& cov_in) { // To rotate a covariance matrix, the cov matrix needs to multiplied left and right by the transform matrix @@ -91,6 +107,30 @@ Localizer::Localizer(LocalizerGnssSource gnss_source) { this->configure_gnss_source(gnss_source); } +void Localizer::build_live_pose(cereal::LivePose::Builder& livePose, cereal::LiveLocationKalman::Reader& liveLocation) { + // Just copy the values from liveLocation to livePose for now + VectorXf orientation_ned = float32list2vector(liveLocation.getOrientationNED().getValue()), orientation_ned_std = float32list2vector(liveLocation.getOrientationNED().getStd()); + init_xyz_measurement(livePose.initOrientationNED(), orientation_ned, orientation_ned_std, this->gps_mode); + VectorXf velocity_device = float32list2vector(liveLocation.getVelocityDevice().getValue()), velocity_device_std = float32list2vector(liveLocation.getVelocityDevice().getStd()); + init_xyz_measurement(livePose.initVelocityDevice(), velocity_device, velocity_device_std, true); + VectorXf acceleration_device = float32list2vector(liveLocation.getAccelerationDevice().getValue()), acceleration_device_std = float32list2vector(liveLocation.getAccelerationDevice().getStd()); + init_xyz_measurement(livePose.initAccelerationDevice(), acceleration_device, acceleration_device_std, true); + VectorXf ang_velocity_device = float32list2vector(liveLocation.getAngularVelocityDevice().getValue()), ang_velocity_device_std = float32list2vector(liveLocation.getAngularVelocityDevice().getStd()); + init_xyz_measurement(livePose.initAngularVelocityDevice(), ang_velocity_device, ang_velocity_device_std, true); + + if (DEBUG) { + VectorXd filter_state = float64list2vector(liveLocation.getFilterState().getValue()), filter_state_std = float64list2vector(liveLocation.getFilterState().getStd()); + cereal::LivePose::FilterState::Builder filter_state_builder = livePose.initFilterState(); + filter_state_builder.setValue(kj::arrayPtr(filter_state.data(), filter_state.size())); + filter_state_builder.setStd(kj::arrayPtr(filter_state_std.data(), filter_state_std.size())); + filter_state_builder.setValid(true); + } + + livePose.setInputsOK(liveLocation.getInputsOK()); + livePose.setPosenetOK(liveLocation.getPosenetOK()); + livePose.setSensorsOK(liveLocation.getSensorsOK()); +} + void Localizer::build_live_location(cereal::LiveLocationKalman::Builder& fix) { VectorXd predicted_state = this->kf->get_x(); MatrixXdr predicted_cov = this->kf->get_P(); @@ -279,7 +319,7 @@ void Localizer::handle_sensor(double current_time, const cereal::SensorEventData // TODO: reduce false positives and re-enable this check // check if device fell, estimate 10 for g // 40m/s**2 is a good filter for falling detection, no false positives in 20k minutes of driving - // this->device_fell |= (floatlist2vector(v) - Vector3d(10.0, 0.0, 0.0)).norm() > 40.0; + // this->device_fell |= (float64list2vector(v) - Vector3d(10.0, 0.0, 0.0)).norm() > 40.0; auto meas = Vector3d(-v[2], -v[1], -v[0]); if (meas.norm() < ACCEL_SANITY_CHECK) { @@ -311,7 +351,7 @@ void Localizer::handle_gps(double current_time, const cereal::GpsLocationData::R bool gps_unreasonable = (Vector2d(log.getHorizontalAccuracy(), log.getVerticalAccuracy()).norm() >= SANE_GPS_UNCERTAINTY); bool gps_accuracy_insane = ((log.getVerticalAccuracy() <= 0) || (log.getSpeedAccuracy() <= 0) || (log.getBearingAccuracyDeg() <= 0)); bool gps_lat_lng_alt_insane = ((std::abs(log.getLatitude()) > 90) || (std::abs(log.getLongitude()) > 180) || (std::abs(log.getAltitude()) > ALTITUDE_SANITY_CHECK)); - bool gps_vel_insane = (floatlist2vector(log.getVNED()).norm() > TRANS_SANITY_CHECK); + bool gps_vel_insane = (float64list2vector(log.getVNED()).norm() > TRANS_SANITY_CHECK); if (!log.getHasFix() || gps_unreasonable || gps_accuracy_insane || gps_lat_lng_alt_insane || gps_vel_insane) { //this->gps_valid = false; @@ -450,8 +490,8 @@ void Localizer::handle_car_state(double current_time, const cereal::CarState::Re } void Localizer::handle_cam_odo(double current_time, const cereal::CameraOdometry::Reader& log) { - VectorXd rot_device = this->device_from_calib * floatlist2vector(log.getRot()); - VectorXd trans_device = this->device_from_calib * floatlist2vector(log.getTrans()); + VectorXd rot_device = this->device_from_calib * float64list2vector(log.getRot()); + VectorXd trans_device = this->device_from_calib * float64list2vector(log.getTrans()); if (!this->is_timestamp_valid(current_time)) { this->observation_timings_invalid = true; @@ -463,8 +503,8 @@ void Localizer::handle_cam_odo(double current_time, const cereal::CameraOdometry return; } - VectorXd rot_calib_std = floatlist2vector(log.getRotStd()); - VectorXd trans_calib_std = floatlist2vector(log.getTransStd()); + VectorXd rot_calib_std = float64list2vector(log.getRotStd()); + VectorXd trans_calib_std = float64list2vector(log.getTransStd()); if ((rot_calib_std.minCoeff() <= MIN_STD_SANITY_CHECK) || (trans_calib_std.minCoeff() <= MIN_STD_SANITY_CHECK)) { this->observation_values_invalid["cameraOdometry"] += 1.0; @@ -499,7 +539,7 @@ void Localizer::handle_live_calib(double current_time, const cereal::LiveCalibra } if (log.getRpyCalib().size() > 0) { - auto live_calib = floatlist2vector(log.getRpyCalib()); + auto live_calib = float64list2vector(log.getRpyCalib()); if ((live_calib.minCoeff() < -CALIB_RPY_SANITY_CHECK) || (live_calib.maxCoeff() > CALIB_RPY_SANITY_CHECK)) { this->observation_values_invalid["liveCalibration"] += 1.0; return; @@ -611,8 +651,8 @@ void Localizer::handle_msg(const cereal::Event::Reader& log) { this->update_reset_tracker(); } -kj::ArrayPtr Localizer::get_message_bytes(MessageBuilder& msg_builder, bool inputsOK, - bool sensorsOK, bool gpsOK, bool msgValid) { +void Localizer::build_location_message( + MessageBuilder& msg_builder, bool inputsOK, bool sensorsOK, bool gpsOK, bool msgValid) { cereal::Event::Builder evt = msg_builder.initEvent(); evt.setValid(msgValid); cereal::LiveLocationKalman::Builder liveLoc = evt.initLiveLocationKalman(); @@ -620,7 +660,19 @@ kj::ArrayPtr Localizer::get_message_bytes(MessageBuilder& msg_build liveLoc.setSensorsOK(sensorsOK); liveLoc.setGpsOK(gpsOK); liveLoc.setInputsOK(inputsOK); - return msg_builder.toBytes(); +} + +void Localizer::build_pose_message( + MessageBuilder& msg_builder, MessageBuilder& location_msg_builder, bool inputsOK, bool sensorsOK, bool msgValid) { + cereal::Event::Builder evt = msg_builder.initEvent(); + evt.setValid(msgValid); + cereal::LivePose::Builder livePose = evt.initLivePose(); + + cereal::LiveLocationKalman::Reader location_msg = location_msg_builder.getRoot().getLiveLocationKalman().asReader(); + this->build_live_pose(livePose, location_msg); + + livePose.setSensorsOK(sensorsOK); + livePose.setInputsOK(inputsOK); } bool Localizer::is_gps_ok() { @@ -692,7 +744,7 @@ int Localizer::locationd_thread() { "carState", "accelerometer", "gyroscope"}; SubMaster sm(service_list, {}, nullptr, {gps_location_socket}); - PubMaster pm({"liveLocationKalman"}); + PubMaster pm({"liveLocationKalman", "livePose"}); uint64_t cnt = 0; bool filterInitialized = false; @@ -726,9 +778,15 @@ int Localizer::locationd_thread() { this->ttff = std::max(1e-3, (sm[trigger_msg].getLogMonoTime() * 1e-9) - this->first_valid_log_time); } - MessageBuilder msg_builder; - kj::ArrayPtr bytes = this->get_message_bytes(msg_builder, inputsOK, sensorsOK, gpsOK, filterInitialized); - pm.send("liveLocationKalman", bytes.begin(), bytes.size()); + MessageBuilder location_msg_builder, pose_msg_builder; + this->build_location_message(location_msg_builder, inputsOK, sensorsOK, gpsOK, filterInitialized); + this->build_pose_message(pose_msg_builder, location_msg_builder, inputsOK, sensorsOK, filterInitialized); + + kj::ArrayPtr location_bytes = location_msg_builder.toBytes(); + pm.send("liveLocationKalman", location_bytes.begin(), location_bytes.size()); + + kj::ArrayPtr pose_bytes = pose_msg_builder.toBytes(); + pm.send("livePose", pose_bytes.begin(), pose_bytes.size()); if (cnt % 1200 == 0 && gpsOK) { // once a minute VectorXd posGeo = this->get_position_geodetic(); diff --git a/selfdrive/locationd/locationd.h b/selfdrive/locationd/locationd.h index 47c8bf5627..615f31c9d0 100644 --- a/selfdrive/locationd/locationd.h +++ b/selfdrive/locationd/locationd.h @@ -45,9 +45,12 @@ public: bool are_inputs_ok(); void observation_timings_invalid_reset(); - kj::ArrayPtr get_message_bytes(MessageBuilder& msg_builder, - bool inputsOK, bool sensorsOK, bool gpsOK, bool msgValid); + void build_location_message( + MessageBuilder& msg_builder, bool inputsOK, bool sensorsOK, bool gpsOK, bool msgValid); + void build_pose_message( + MessageBuilder& msg_builder, MessageBuilder& location_msg_builder, bool inputsOK, bool sensorsOK, bool msgValid); void build_live_location(cereal::LiveLocationKalman::Builder& fix); + void build_live_pose(cereal::LivePose::Builder& livePose, cereal::LiveLocationKalman::Reader& liveLocation); Eigen::VectorXd get_position_geodetic(); Eigen::VectorXd get_state(); diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index c7f57fd9bc..eae6abfaad 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -532,7 +532,7 @@ CONFIGS = [ "cameraOdometry", "accelerometer", "gyroscope", "gpsLocationExternal", "liveCalibration", "carState", "gpsLocation" ], - subs=["liveLocationKalman"], + subs=["liveLocationKalman", "livePose"], ignore=["logMonoTime"], config_callback=locationd_config_pubsub_callback, tolerance=NUMPY_TOLERANCE, diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 13b427b894..02e4b997aa 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -0adff03d45c99dcfb330c48b2aa9d2093ce674a2 +3942de8e75caa7a99828e65c3396abd94d6b3da7 diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 78486a176d..bbb99d13b9 100644 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -206,7 +206,7 @@ class TestOnroad: if f.name == "qcamera.ts": assert 2.15 < sz < 2.35 elif f.name == "qlog": - assert 0.6 < sz < 1.0 + assert 0.4 < sz < 0.6 elif f.name == "rlog": assert 5 < sz < 50 elif f.name.endswith('.hevc'): From 7f9cdf8e43e50c9ec4c90cf96bfa4317094cc8f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Wed, 17 Jul 2024 19:31:29 -0700 Subject: [PATCH 057/229] increase cameraOdometry decimation (#33010) reduce cameraOdometry decimation --- cereal/services.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cereal/services.py b/cereal/services.py index f2d01b9220..6ff821e7f1 100755 --- a/cereal/services.py +++ b/cereal/services.py @@ -50,7 +50,7 @@ _services: dict[str, tuple] = { "livePose": (True, 20., 4), "liveLocationKalman": (True, 20.), "liveParameters": (True, 20., 5), - "cameraOdometry": (True, 20., 5), + "cameraOdometry": (True, 20., 10), "thumbnail": (True, 0.2, 1), "onroadEvents": (True, 1., 1), "carParams": (True, 0.02, 1), From 3c48a6154b95f0ae2ab84fd916e02b704c74b258 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 17 Jul 2024 20:42:12 -0700 Subject: [PATCH 058/229] increase longitudinalPlan decimation (#33009) change longitudinalPlan decimation --- cereal/services.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cereal/services.py b/cereal/services.py index 6ff821e7f1..7d73374df1 100755 --- a/cereal/services.py +++ b/cereal/services.py @@ -38,7 +38,7 @@ _services: dict[str, tuple] = { "carState": (True, 100., 10), "carControl": (True, 100., 10), "carOutput": (True, 100., 10), - "longitudinalPlan": (True, 20., 5), + "longitudinalPlan": (True, 20., 10), "procLog": (True, 0.5, 15), "gpsLocationExternal": (True, 10., 10), "gpsLocation": (True, 1., 1), From f31ad97e924af579ec60961bc7cc3c170525fcef Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 17 Jul 2024 21:57:36 -0700 Subject: [PATCH 059/229] qlog_size: decimate rlog option (#33011) * decimate option * clean up * check exists --- selfdrive/debug/internal/qlog_size.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/selfdrive/debug/internal/qlog_size.py b/selfdrive/debug/internal/qlog_size.py index 2d17a1ee28..7dc61ed9df 100755 --- a/selfdrive/debug/internal/qlog_size.py +++ b/selfdrive/debug/internal/qlog_size.py @@ -5,6 +5,7 @@ from collections import defaultdict import matplotlib.pyplot as plt +from cereal.services import SERVICE_LIST from openpilot.tools.lib.logreader import LogReader from tqdm import tqdm @@ -48,9 +49,29 @@ def make_pie(msgs, typ): if __name__ == "__main__": parser = argparse.ArgumentParser(description='View log size breakdown by message type') parser.add_argument('route', help='route to use') + parser.add_argument('--as-qlog', action='store_true', help='decimate rlog using latest decimation factors') args = parser.parse_args() msgs = list(LogReader(args.route)) + if args.as_qlog: + new_msgs = [] + msg_cnts: dict[str, int] = defaultdict(int) + for msg in msgs: + msg_which = msg.which() + if msg.which() in ("initData", "sentinel"): + new_msgs.append(msg) + continue + + if msg_which not in SERVICE_LIST: + continue + + decimation = SERVICE_LIST[msg_which].decimation + if decimation is not None and msg_cnts[msg_which] % decimation == 0: + new_msgs.append(msg) + msg_cnts[msg_which] += 1 + + msgs = new_msgs + make_pie(msgs, 'qlog') plt.show() From 560e37cd83c51149328aedc83b7d34c40941bf46 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 18 Jul 2024 18:48:54 -0700 Subject: [PATCH 060/229] tici: set STM_BOOT0 in reset (#33015) * tici: reset panda boot0 * ooops --- system/hardware/tici/hardware.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index a5dee88b56..eb524dbafa 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -563,8 +563,10 @@ class Tici(HardwareBase): def reset_internal_panda(self): gpio_init(GPIO.STM_RST_N, True) + gpio_init(GPIO.STM_BOOT0, True) gpio_set(GPIO.STM_RST_N, 1) + gpio_set(GPIO.STM_BOOT0, 0) time.sleep(1) gpio_set(GPIO.STM_RST_N, 0) From fd5549bba1dc33e16a8e3e09b02393d8f0dd4aa6 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 18 Jul 2024 19:26:22 -0700 Subject: [PATCH 061/229] nightly build takes longer than this --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 654aed49c5..d2dffeecc7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -82,7 +82,7 @@ def deviceStage(String stageName, String deviceType, List extra_env, def steps) lock(resource: "", label: deviceType, inversePrecedence: true, variable: 'device_ip', quantity: 1, resourceSelectStrategy: 'random') { docker.image('ghcr.io/commaai/alpine-ssh').inside('--user=root') { - timeout(time: 20, unit: 'MINUTES') { + timeout(time: 35, unit: 'MINUTES') { retry (3) { device(device_ip, "git checkout", extra + "\n" + readFile("selfdrive/test/setup_device_ci.sh")) } From c96dbd5a0b681c76b94191d1b928e29eb2b72119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Thu, 18 Jul 2024 20:19:39 -0700 Subject: [PATCH 062/229] Fix msgq context overrides (#33014) * Fix msgq context overrides * Remove unneccesary changes * add reset_context helper * Remove redundant import --- cereal/messaging/__init__.py | 7 ++++++- selfdrive/debug/internal/measure_torque_time_to_max.py | 2 +- system/manager/process.py | 2 +- tools/camerastream/compressed_vipc.py | 7 ++++--- tools/lib/live_logreader.py | 2 +- tools/replay/rp_visualization.py | 2 +- tools/tuning/measure_steering_accuracy.py | 2 +- 7 files changed, 15 insertions(+), 9 deletions(-) diff --git a/cereal/messaging/__init__.py b/cereal/messaging/__init__.py index 8dfa42056d..9646047de3 100644 --- a/cereal/messaging/__init__.py +++ b/cereal/messaging/__init__.py @@ -2,7 +2,8 @@ from msgq.ipc_pyx import Context, Poller, SubSocket, PubSocket, SocketEventHandle, toggle_fake_events, \ set_fake_prefix, get_fake_prefix, delete_fake_prefix, wait_for_one_event from msgq.ipc_pyx import MultiplePublishersError, IpcError -from msgq import fake_event_handle, pub_sock, sub_sock, drain_sock_raw, context +from msgq import fake_event_handle, pub_sock, sub_sock, drain_sock_raw +import msgq import os import capnp @@ -17,6 +18,10 @@ from cereal.services import SERVICE_LIST NO_TRAVERSAL_LIMIT = 2**64-1 +def reset_context(): + msgq.context = Context() + + def log_from_bytes(dat: bytes, struct: capnp.lib.capnp._StructModule = log.Event) -> capnp.lib.capnp._DynamicStructReader: with struct.from_bytes(dat, traversal_limit_in_words=NO_TRAVERSAL_LIMIT) as msg: return msg diff --git a/selfdrive/debug/internal/measure_torque_time_to_max.py b/selfdrive/debug/internal/measure_torque_time_to_max.py index ef3152b50c..7052dccf7d 100755 --- a/selfdrive/debug/internal/measure_torque_time_to_max.py +++ b/selfdrive/debug/internal/measure_torque_time_to_max.py @@ -18,7 +18,7 @@ if __name__ == "__main__": if args.addr != "127.0.0.1": os.environ["ZMQ"] = "1" - messaging.context = messaging.Context() + messaging.reset_context() poller = messaging.Poller() messaging.sub_sock('can', poller, addr=args.addr) diff --git a/system/manager/process.py b/system/manager/process.py index 9214e417c1..c78d263dcc 100644 --- a/system/manager/process.py +++ b/system/manager/process.py @@ -30,7 +30,7 @@ def launcher(proc: str, name: str) -> None: setthreadname(proc) # create new context since we forked - messaging.context = messaging.Context() + messaging.reset_context() # add daemon name tag to logs cloudlog.bind(daemon=name) diff --git a/tools/camerastream/compressed_vipc.py b/tools/camerastream/compressed_vipc.py index 6c27e861ff..f531a289f9 100755 --- a/tools/camerastream/compressed_vipc.py +++ b/tools/camerastream/compressed_vipc.py @@ -8,6 +8,7 @@ import multiprocessing import time import signal + import cereal.messaging as messaging from msgq.visionipc import VisionIpcServer, VisionStreamType @@ -42,7 +43,7 @@ def decoder(addr, vipc_server, vst, nvidia, W, H, debug=False): codec = av.CodecContext.create("hevc", "r") os.environ["ZMQ"] = "1" - messaging.context = messaging.Context() + messaging.reset_context() sock = messaging.sub_sock(sock_name, None, addr=addr, conflate=False) cnt = 0 last_idx = -1 @@ -109,12 +110,12 @@ class CompressedVipc: def __init__(self, addr, vision_streams, nvidia=False, debug=False): print("getting frame sizes") os.environ["ZMQ"] = "1" - messaging.context = messaging.Context() + messaging.reset_context() sm = messaging.SubMaster([ENCODE_SOCKETS[s] for s in vision_streams], addr=addr) while min(sm.recv_frame.values()) == 0: sm.update(100) os.environ.pop("ZMQ") - messaging.context = messaging.Context() + messaging.reset_context() self.vipc_server = VisionIpcServer("camerad") for vst in vision_streams: diff --git a/tools/lib/live_logreader.py b/tools/lib/live_logreader.py index 6a7ecee6fd..edc4ac1611 100644 --- a/tools/lib/live_logreader.py +++ b/tools/lib/live_logreader.py @@ -10,7 +10,7 @@ ALL_SERVICES = list(SERVICE_LIST.keys()) def raw_live_logreader(services: list[str] = ALL_SERVICES, addr: str = '127.0.0.1') -> RawLogIterable: if addr != "127.0.0.1": os.environ["ZMQ"] = "1" - messaging.context = messaging.Context() + messaging.reset_context() poller = messaging.Poller() diff --git a/tools/replay/rp_visualization.py b/tools/replay/rp_visualization.py index 853a83c150..01058967b2 100755 --- a/tools/replay/rp_visualization.py +++ b/tools/replay/rp_visualization.py @@ -53,7 +53,7 @@ if __name__ == "__main__": args = get_arg_parser().parse_args(sys.argv[1:]) if args.ip_address != "127.0.0.1": os.environ["ZMQ"] = "1" - messaging.context = messaging.Context() + messaging.reset_context() rr.init("RadarPoints", spawn= True) rr.log("tracks", rr.AnnotationContext(rerunColorPalette), static=True) visualize(args.ip_address) diff --git a/tools/tuning/measure_steering_accuracy.py b/tools/tuning/measure_steering_accuracy.py index 6abf1338dc..0b8916343e 100755 --- a/tools/tuning/measure_steering_accuracy.py +++ b/tools/tuning/measure_steering_accuracy.py @@ -147,7 +147,7 @@ if __name__ == "__main__": else: if args.addr != "127.0.0.1": os.environ["ZMQ"] = "1" - messaging.context = messaging.Context() + messaging.reset_context() carControl = messaging.sub_sock('carControl', addr=args.addr, conflate=True) sm = messaging.SubMaster(['carState', 'carControl', 'carOutput', 'controlsState', 'modelV2'], addr=args.addr) From 917ea5699f3af241e60311455af5f20c0c55a8c4 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 20 Jul 2024 01:14:04 +0800 Subject: [PATCH 063/229] cereal: deprecate FrameData.frameType (#33019) deprecate FrameData.frameType --- cereal/log.capnp | 5 ++--- system/camerad/cameras/camera_qcom2.cc | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cereal/log.capnp b/cereal/log.capnp index d94d9632fe..d849f4840b 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -137,8 +137,6 @@ struct FrameData { requestId @28 :UInt32; encodeId @1 :UInt32; - frameType @7 :FrameType; - # Timestamps timestampEof @2 :UInt64; timestampSof @8 :UInt64; @@ -158,7 +156,7 @@ struct FrameData { temperaturesC @24 :List(Float32); - enum FrameType { + enum FrameTypeDEPRECATED { unknown @0; neo @1; chffrAndroid @2; @@ -175,6 +173,7 @@ struct FrameData { frameLengthDEPRECATED @3 :Int32; globalGainDEPRECATED @5 :Int32; + frameTypeDEPRECATED @7 :FrameTypeDEPRECATED; androidCaptureResultDEPRECATED @9 :AndroidCaptureResult; lensPosDEPRECATED @11 :Int32; lensSagDEPRECATED @12 :Float32; diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index 096e288cc2..47ea5ded4d 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -932,7 +932,6 @@ static void process_driver_camera(MultiCameraState *s, CameraState *c, int cnt) MessageBuilder msg; auto framed = msg.initEvent().initDriverCameraState(); - framed.setFrameType(cereal::FrameData::FrameType::FRONT); fill_frame_data(framed, c->buf.cur_frame_data, c); c->ci->processRegisters(c, framed); From 07fcc4825f7e669068024c12987120a7662b220f Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Fri, 19 Jul 2024 10:19:38 -0700 Subject: [PATCH 064/229] make pyproject.toml pep508 compliant (#33021) pep508 --- pyproject.toml | 8 ++--- uv.lock | 93 +++++++++++++++++++++++++++++++------------------- 2 files changed, 61 insertions(+), 40 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e9c999400d..126e122ab3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -100,7 +100,7 @@ dev = [ "inputs", "lru-dict", "matplotlib", - "metadrive-simulator; platform_machine != 'aarch64'", + "metadrive-simulator@git+https://github.com/commaai/metadrive@opencv_headless ; platform_machine != 'aarch64'", "mpld3", "myst-parser", "natsort", @@ -122,9 +122,6 @@ dev = [ ] -[tool.uv.sources] -metadrive-simulator = { git = "https://github.com/commaai/metadrive.git", branch = "opencv_headless" } - [project.urls] Homepage = "https://comma.ai" @@ -135,6 +132,9 @@ build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = [ "." ] +[tool.hatch.metadata] +allow-direct-references = true + [tool.pytest.ini_options] minversion = "6.0" addopts = "--ignore=openpilot/ --ignore=opendbc/ --ignore=panda/ --ignore=rednose_repo/ --ignore=tinygrad_repo/ --ignore=teleoprtc_repo/ --ignore=msgq/ -Werror --strict-config --strict-markers --durations=10 -n auto --dist=loadgroup" diff --git a/uv.lock b/uv.lock index b0ba09ca3c..48d53bbda9 100644 --- a/uv.lock +++ b/uv.lock @@ -214,12 +214,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9f/a6/edb201c436c820779b1f4e2bf5a74b6fd5e4d7d7b703336e5c0518e1b08f/casadi-3.6.5-cp27-none-manylinux1_i686.whl", hash = "sha256:b5192dfabf6f5266b168b984d124dd3086c1c5a408c0743ff3a82290a8ccf3b5", size = 47956673 }, { url = "https://files.pythonhosted.org/packages/f7/4d/6c8f37e08a3a91a69be8fffa67ce4a27823d3d4ca2099312f938690938f9/casadi-3.6.5-cp27-none-manylinux2010_x86_64.whl", hash = "sha256:35b2ff6098e386a4d5e8bc681744e52bcd2f2f15cfa44c09814a8979b51a6794", size = 53936205 }, { url = "https://files.pythonhosted.org/packages/b5/95/1a087e511ded93ab74f3a0adf36a4beaee22ce30d2951ab7115dad3d26b5/casadi-3.6.5-cp27-none-win_amd64.whl", hash = "sha256:caf395d1e36bfb215b154e8df61583d534a07ddabb18cbe50f259b7692a41ac8", size = 43027309 }, - { url = "https://files.pythonhosted.org/packages/a6/29/11a974e24bdaa50c0ee4c03b8631c7cfed65b5caba5123d91331d4cb969b/casadi-3.6.5-cp310-none-macosx_10_13_x86_64.macosx_10_13_intel.whl", hash = "sha256:314886ef44bd01f1a98579e7784a3bed6e0584e88f9465cf9596af2523efb0dd", size = 42876397 }, - { url = "https://files.pythonhosted.org/packages/31/57/28043eca210517b9071ef41e4b965ed3f9366e4441b6af5d172466b76d5e/casadi-3.6.5-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:c6789c8060a99b329bb584d97c1eab6a5e4f3e2d2db391e6c2001c6323774990", size = 40753981 }, - { url = "https://files.pythonhosted.org/packages/56/21/ef9baac75ada94da8d2470578533cbd3a48755277e9dbcd2d65b954678c2/casadi-3.6.5-cp310-none-manylinux2014_aarch64.whl", hash = "sha256:e40afb3c062817dd6ce2497cd001f00f107ee1ea41ec4d6ee9f9a5056d219e83", size = 42905440 }, - { url = "https://files.pythonhosted.org/packages/3d/89/0bfc9a71d632750685763751698b233f5a9622cea8fbdb03f94bcfe04950/casadi-3.6.5-cp310-none-manylinux2014_i686.whl", hash = "sha256:ee5a4ed50d2becd0bd6d203c7a60ffad27c14a3e0ae357480de11c846a8dd928", size = 69778574 }, - { url = "https://files.pythonhosted.org/packages/b4/b0/1289804327602e892c36f14fa2b4492afbeee8f465a365c8759b03186f1c/casadi-3.6.5-cp310-none-manylinux2014_x86_64.whl", hash = "sha256:1ddb6e4afdd1da95d7d9d652ed973c1b7f50ef1454965a9170b657e223a2c73e", size = 72306982 }, - { url = "https://files.pythonhosted.org/packages/b3/bc/95a28e081c303b876b1fd85edc3acc26f73430c056b5aea273ece5765c66/casadi-3.6.5-cp310-none-win_amd64.whl", hash = "sha256:e96ca81b00b9621007d45db1254fcf232d518ebcc802f42853f57b4df977c567", size = 43057148 }, { url = "https://files.pythonhosted.org/packages/7b/fa/7198dff19f2d6d511c220f1815709581ff9e533403cfeebe187f204f68b2/casadi-3.6.5-cp311-none-macosx_10_13_x86_64.macosx_10_13_intel.whl", hash = "sha256:bebd3909db24ba711e094aacc0a2329b9903d422d73f61be851873731244b7d1", size = 42876397 }, { url = "https://files.pythonhosted.org/packages/3d/fc/2ba7f33fa843f56cc4df55b4027a037f7f34e8396bd585003f113ee6bcfa/casadi-3.6.5-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:ccb962ea02b7d6d245d5cd40fb52c29e812040a45273c6eed32cb8fcff673dda", size = 40752910 }, { url = "https://files.pythonhosted.org/packages/1f/c1/2a3290487330fa334c3a86308f9378dce226a7f0f3f7bd11a8f70ac47d3b/casadi-3.6.5-cp311-none-manylinux2014_aarch64.whl", hash = "sha256:1ce199a4ea1d376edbe5399cd622a4564040c83f50c50114fe50a69a8ea81d92", size = 42905415 }, @@ -231,32 +225,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/46/49/551760cdcedcd8d0fd7109d620c7c9e332cb8a706b2bd1beec6e4fda1cd1/casadi-3.6.5-cp312-none-manylinux2014_i686.whl", hash = "sha256:be40e9897d80fb72a97e750b2143c32f63f8800cfb78f9b396d8ce7a913fca39", size = 69777406 }, { url = "https://files.pythonhosted.org/packages/ff/17/2f97a9638072216448b50fd14855939abeff1632edac92739683ffac9b08/casadi-3.6.5-cp312-none-manylinux2014_x86_64.whl", hash = "sha256:0118637823e292a9270133e02c9c6d3f3c7f75e8c91a6f6dc5275ade82dd1d9d", size = 72311551 }, { url = "https://files.pythonhosted.org/packages/88/08/c55e2172f033a44b831ee771bb32fa89c369311c0598a52c03755f29a75e/casadi-3.6.5-cp312-none-win_amd64.whl", hash = "sha256:fe2b64d777e36cc3f101220dd1e219a0e11c3e4ee2b5e708b30fea9a27107e41", size = 43057681 }, - { url = "https://files.pythonhosted.org/packages/66/e7/2b24199211f92b8ba3533fe09bef42b352caccf381429e7fda449f07458b/casadi-3.6.5-cp35-none-macosx_10_13_x86_64.macosx_10_13_intel.whl", hash = "sha256:a1ae36449adec534125d4af5be912b6fb9dafe74d1fee39f6c82263695e21ca5", size = 42869977 }, - { url = "https://files.pythonhosted.org/packages/4d/0d/fea3604668c7bda76fa874d057a001d0006074cb6d2dca7af60d0635e1c6/casadi-3.6.5-cp35-none-manylinux1_i686.whl", hash = "sha256:32644c47fbfb643d5cf9769c7bbc94c6bdb9a40ea9c12c54af5e2754599c3186", size = 47970545 }, - { url = "https://files.pythonhosted.org/packages/a1/5d/16cf69bb8a00059fb0e4c6e21ed5d550a99b17a1dee5e4cae304b4a1456e/casadi-3.6.5-cp35-none-manylinux2010_x86_64.whl", hash = "sha256:601b76b7afcb27b11563999f6ad1d9d2a2510ab3d00a6f4ce86a0bee97c9d17a", size = 53958472 }, - { url = "https://files.pythonhosted.org/packages/ab/7d/9204a8c2e6a8a3f6447d2d9e5e0b177443dcd9f8b5165743f26a1335a3da/casadi-3.6.5-cp35-none-win_amd64.whl", hash = "sha256:febc645bcc0aed6d7a2bdb6e58b9a89cb8f74b19bc028c41cc807d75a5d54058", size = 43041688 }, - { url = "https://files.pythonhosted.org/packages/a8/e4/a5ae1ef8909b26dd7c4ab7f5303a3ac298c143661b437d9070c0608d35ae/casadi-3.6.5-cp36-none-macosx_10_13_x86_64.macosx_10_13_intel.whl", hash = "sha256:c98e68023c9e5905d9d6b99ae1fbbfe4b85ba9846b3685408bb498b20509f99a", size = 42869977 }, - { url = "https://files.pythonhosted.org/packages/22/57/e7d2fad22a74f0ef7a5e4fc2ec77fbf11258743b94a0bbffa73f9cbdc468/casadi-3.6.5-cp36-none-manylinux2014_aarch64.whl", hash = "sha256:eb311088dca5359acc05aa4d8895bf99afaa16c7c04b27bf640ce4c2361b8cde", size = 42899148 }, - { url = "https://files.pythonhosted.org/packages/d8/b5/c2dd2ff700d03db674cfacfa97678d7b6621cf02b47e9553616de48b3970/casadi-3.6.5-cp36-none-manylinux2014_i686.whl", hash = "sha256:bceb69bf9f04fded8a564eb64e298d19e945eaf4734f7145a5ee61cf9ac693e7", size = 69772344 }, - { url = "https://files.pythonhosted.org/packages/92/fb/4c6b4682084eb8b567a909bea7d03b4f0bad00bdcf66aea4f29fd1dda66f/casadi-3.6.5-cp36-none-manylinux2014_x86_64.whl", hash = "sha256:c951031e26d987986dbc334492b2e6ef108077f11c00e178ff4007e4a9bf91d8", size = 72306252 }, - { url = "https://files.pythonhosted.org/packages/8d/33/7c90f3fcb4dae99f9052a494d98c9d0c8c8b22cdca169af847a5ea4e9bb7/casadi-3.6.5-cp36-none-win_amd64.whl", hash = "sha256:e44af450ce944649932f9ef63ff00d2d21f642b506444418b4b20e69dba3adaf", size = 43041687 }, - { url = "https://files.pythonhosted.org/packages/fd/28/b22c8206615ca24f71c2ea52ff552e74d6eb0afc850750ad8bd97d778a6d/casadi-3.6.5-cp37-none-macosx_10_13_x86_64.macosx_10_13_intel.whl", hash = "sha256:c661fe88a93b7cc7ea42802aac76a674135cd65e3e564a6f08570dd3bea05201", size = 42869949 }, - { url = "https://files.pythonhosted.org/packages/14/40/d5c1d9b3e964ef295eee7cc518c8e1abd7cb92bbfc6dcd74f9aa30839731/casadi-3.6.5-cp37-none-manylinux2014_aarch64.whl", hash = "sha256:5266fc82e39352e26cb1a4e0a5c3deb32d09e6333be637bd78c273fa50f9012b", size = 42899157 }, - { url = "https://files.pythonhosted.org/packages/26/b3/85ff05610e862a90f70daa4e58772dc9719dde2a5481ff293ca27e056729/casadi-3.6.5-cp37-none-manylinux2014_i686.whl", hash = "sha256:02d6fb63c460abd99a450e861034d97568a8aec621fc0a4fed22f7494989c682", size = 69773643 }, - { url = "https://files.pythonhosted.org/packages/6b/e4/12562e3b7411afc15f923fbd9a39d065590e48e5949a395114b4e3825e56/casadi-3.6.5-cp37-none-manylinux2014_x86_64.whl", hash = "sha256:5e8adffe2015cde370fc545b2d0fe731e96e583e4ea4c5f3044e818fea975cfc", size = 72306085 }, - { url = "https://files.pythonhosted.org/packages/bb/0d/6af19e039d99342200b9418063501c0555a57e27b461a3112812422c854f/casadi-3.6.5-cp37-none-win_amd64.whl", hash = "sha256:7ea8545579872b6f5412985dafec26b906b67bd4639a6c718b7e07f802af4e42", size = 43041620 }, - { url = "https://files.pythonhosted.org/packages/b6/67/68eebae41a005e3897dd69b83680f18a1548b2132b87e13b595cea83b0f1/casadi-3.6.5-cp38-none-macosx_10_13_x86_64.macosx_10_13_intel.whl", hash = "sha256:0a38bf808bf51368607c64307dd77a7363fbe8e5c910cd5c605546be60edfaff", size = 42876576 }, - { url = "https://files.pythonhosted.org/packages/d3/1d/faed4b8b127d336e27753d7f9ef6895edcf4697e0f027e9eb4f934fef49d/casadi-3.6.5-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:f62f779481b30e5ea88392bdb8225e9545a21c4460dc3e96c2b782405b938d04", size = 40757892 }, - { url = "https://files.pythonhosted.org/packages/bf/6b/b47ff3b2dfc61cf0abbb0516f1621488afa199c0d79266d627e1e4c840c3/casadi-3.6.5-cp38-none-manylinux2014_aarch64.whl", hash = "sha256:deb2cb2bee8aba0c2cad03c832965b51ca305d0f8eb15de8b857ba86a76f0db0", size = 42906110 }, - { url = "https://files.pythonhosted.org/packages/f6/0a/55839ba892dd3371b1ef96722fc11241834012c9fe5bef8396239470e244/casadi-3.6.5-cp38-none-manylinux2014_i686.whl", hash = "sha256:f6e10b66d6ae8216dab01532f7ad75cc9d66a95125d421b33d078a51ea0fc2a0", size = 69780479 }, - { url = "https://files.pythonhosted.org/packages/70/25/b4aadc6efbab3603b9f344e09e415fd79cded82e3934d7ade6fd25c4df6e/casadi-3.6.5-cp38-none-manylinux2014_x86_64.whl", hash = "sha256:f9e82658c910e3317535d769334260e0a24d97bbce68cadb72f592e9fcbafd61", size = 72307901 }, - { url = "https://files.pythonhosted.org/packages/07/e2/d859726b623a6239fcb3a95b78bc2aa932d9e162cf5755bd7ec942b02623/casadi-3.6.5-cp38-none-win_amd64.whl", hash = "sha256:092e448e05feaed8958d684e896d909e756d199b84d3b9d0182da38cd3deebf6", size = 43054557 }, - { url = "https://files.pythonhosted.org/packages/42/32/0924ac73b83258322d2d4ab4aeabcc615b428e6b6e60eb72fc068428d4e0/casadi-3.6.5-cp39-none-macosx_10_13_x86_64.macosx_10_13_intel.whl", hash = "sha256:f9c1de9a798767c00f89c27677b74059df4c9601d69270967b06d7fcff204b4d", size = 42876397 }, - { url = "https://files.pythonhosted.org/packages/f4/09/8f56da3a01294ccbaeecc47ef6500b43a0abd5920e99fe7cf2ea28649b12/casadi-3.6.5-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:83e3404de4449cb7382e49d811eec79cd370e64b97b5c94b155c604d7c523a40", size = 40753984 }, - { url = "https://files.pythonhosted.org/packages/ef/7a/8eb40df7b234ffff254714b48a51ad7181496122dbc342e4b7ce714c8103/casadi-3.6.5-cp39-none-manylinux2014_aarch64.whl", hash = "sha256:af95de5aa5942d627d43312834791623384c2ad6ba87928bf0e3cacc8a6698e8", size = 42905431 }, - { url = "https://files.pythonhosted.org/packages/a1/78/3655586496b7560e9a3a789dc8185ed3e30a48b147069b2e26e8c98c9e23/casadi-3.6.5-cp39-none-manylinux2014_i686.whl", hash = "sha256:dbeb50726603454a1f85323cba7caf72524cd43ca0aeb1f286d07005a967ece9", size = 69778788 }, - { url = "https://files.pythonhosted.org/packages/a1/f8/06b68c5f7fa724c8ce5b5a7c269c7836efc10914d97dc0d37c497f5937b0/casadi-3.6.5-cp39-none-manylinux2014_x86_64.whl", hash = "sha256:8bbfb2eb8cb6b9e2384814d6427e48bcf6df049bf7ed05b0a58bb311a1fbf18c", size = 72306869 }, - { url = "https://files.pythonhosted.org/packages/81/16/c413a49a582935009f6fd9e7b031c43a3b2e919c02e38de0dba1b91d776f/casadi-3.6.5-cp39-none-win_amd64.whl", hash = "sha256:0e4a4ec2e26ebeb22b0c129f2db3cf90f730cf9fbe98adb9a12720ff6ca1834a", size = 43056766 }, ] [[distribution]] @@ -461,7 +429,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/64/ea/848f064727fe172e80f8a7abc77664c593b6bece14d5acab7d7087f1244e/coverage-7.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:76d5f82213aa78098b9b964ea89de4617e70e0d43e97900c2778a50856dac605", size = 238003 }, { url = "https://files.pythonhosted.org/packages/c2/b1/8f54a56789aecc930e227fc5900d18628d6efae4a8ad24981d58fc14b1e3/coverage-7.6.0-cp312-cp312-win32.whl", hash = "sha256:3c59105f8d58ce500f348c5b56163a4113a440dad6daa2294b5052a10db866da", size = 208686 }, { url = "https://files.pythonhosted.org/packages/cb/db/242c44433c5d342c8bf83864131e56af8c1c1ea5645a825b1800c19ad9bf/coverage-7.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca5d79cfdae420a1d52bf177de4bc2289c321d6c961ae321503b2ca59c17ae67", size = 209455 }, - { url = "https://files.pythonhosted.org/packages/ea/69/2b79b6b37c57cd05c85b76ec5ceabf7e091ab0f4986dfefaddbb468881c0/coverage-7.6.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:6fe885135c8a479d3e37a7aae61cbd3a0fb2deccb4dda3c25f92a49189f766d6", size = 198032 }, ] [[distribution]] @@ -751,6 +718,47 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ce/8b/02bf4765c487901c8660290ade9929d65a6151c367ba32e75d136ef2d0eb/google_crc32c-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba1eb1843304b1e5537e1fca632fa894d6f6deca8d6389636ee5b4797affb968", size = 27318 }, ] +[[distribution]] +name = "grimp" +version = "3.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/94/6c/6b071cc23c6c643b333af6f54147b59687e79b3a49bba80b4a0627bc5d90/grimp-3.4.1.tar.gz", hash = "sha256:c743c989ea49582171a93ac5aa0d22ecf04fd57143f956b3e35b6a1c7cddafec", size = 833762 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/73/9e0db6d8b2c38021cabe8a757b7cab00cd2175d08c4f026b552d39c6ec7a/grimp-3.4.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:cc6740e0b467cd4e67a43a4b4c7137a561b8118a59af1faef258ed2901dfdb52", size = 351435 }, + { url = "https://files.pythonhosted.org/packages/44/75/87e4965da3d03cb27c606876f8e0be98fbb7f7222760472e28454b88aa05/grimp-3.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f4be0ded7b5882c5e94024c5424dd1f252da9905dca0051ca41b520d771dcb92", size = 345021 }, + { url = "https://files.pythonhosted.org/packages/a5/cd/e61e225bf53b12f5eb1cde4f6c78649236548b44019c5f4a04537a9e7fda/grimp-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b04f3ec0a88fa3d0da5a83560da80a53392bea35541834847bdc8bc29d38af", size = 403355 }, + { url = "https://files.pythonhosted.org/packages/0d/89/8cb3b7e385e566f1fecd455db06324e0e6ba33d376118f9a9b98e35e7cfc/grimp-3.4.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c820bc059a2fa80a53303c1fe6923787e999c653c39f351d4d812dd1edd37217", size = 405186 }, + { url = "https://files.pythonhosted.org/packages/ac/4e/d8effd090a36ddd6da18b5e75ac0a88e99cee704a9a42ea5d36113f94ca6/grimp-3.4.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28b383fca3271e77f690a789b756abcc01fcd6f820886ecf0ea1189c82469c85", size = 415890 }, + { url = "https://files.pythonhosted.org/packages/d4/f2/a739d0d98142f47ede1aa1eb45f669352d14e86cd9d0f9e4926c554d1dfd/grimp-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d9a585ed5f65dba3b5aeb4176061068768362dea3a3205b305ad87e06e11a66", size = 438923 }, + { url = "https://files.pythonhosted.org/packages/5e/ea/00dc7cc41003de2f8d2c98dd326fb1cc1ff118244992cdfffcddaa3d9efe/grimp-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:09196954a1f7f4e2388d3537fd0d6d4e89193d808a842b961431214c1eb2f689", size = 443130 }, + { url = "https://files.pythonhosted.org/packages/fb/a4/eb40d954d4eb0db4128c18b319133997676dc50bba08104c07a2631f25b5/grimp-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44a65e100ac856050ac845d90925498c50bbbcb7fde2a4dfdb2ae19aea2b3574", size = 396429 }, + { url = "https://files.pythonhosted.org/packages/52/78/0814d4005b62814f7d09c01af7130d5df7724842280a380676362ebfcd95/grimp-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a532febfef86fa99bb17c4e1a0bd1955ee865529595c9743572327008faaed16", size = 580018 }, + { url = "https://files.pythonhosted.org/packages/e7/ce/86ae2ffb59f2966c89d62e455c154a4a25e7a566e367c94a36710519477f/grimp-3.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ed9f6c594de624f9cf5e00c793f903b445233c3e1267dc46294e0e55692a33f4", size = 666042 }, + { url = "https://files.pythonhosted.org/packages/bb/82/c4bc5ad12c0f385d6d412730c7e231e43bf8d4e761c0e6a0a42653a360ed/grimp-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:000656b94398d62112ef0f5d8a46ea06a0c56084caf7f1d89b6360638bcb2f14", size = 589481 }, + { url = "https://files.pythonhosted.org/packages/cd/1b/270cd24d2dc9586170c044be78b04414eb05898a70f38ebece50868a387a/grimp-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a4b0b2ee2364bcfd20c9f0a4dd42d3875b6d928d9105ff56249eb03554fb840a", size = 566755 }, + { url = "https://files.pythonhosted.org/packages/7f/ef/890b80433b156f2184783321a9eb168e91dc2e8a17e097a0bd64cacec9a1/grimp-3.4.1-cp311-none-win32.whl", hash = "sha256:65d0dbc64b51878460c80257540e81aa502bcb1021cbefcbe5862649860822db", size = 229097 }, + { url = "https://files.pythonhosted.org/packages/99/c6/685b7fbf50844522b3d2db0c89997835f8df3ffaed3a811d7603e5ea1933/grimp-3.4.1-cp311-none-win_amd64.whl", hash = "sha256:8a54c6bddfdb74f6c3c5c0f9c0668d0cf6299f8d3ef7767eaa319dc888c2e7e8", size = 240189 }, + { url = "https://files.pythonhosted.org/packages/09/53/98f52df9b801d71f615e4588f34139e0cf8ae0a600c0502f61365f4f0b15/grimp-3.4.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:2e4e283e7c8ab5597c4f98dd706f7cdf7c6085d966b34c00e00815d79c05a29d", size = 350902 }, + { url = "https://files.pythonhosted.org/packages/87/cc/bab79b2460c1fdc8d147ffd427794480cbdd9a6439ddd3a07e4da9312add/grimp-3.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c085f77cc0ecd875ab11f7c5ebbaea2a7e09b8c1e3eb7bee0c29127f9f744bfc", size = 344973 }, + { url = "https://files.pythonhosted.org/packages/94/65/f50fb78d5e8db1a51fd23c34c7ad7a3279fb28832b96477096d67bc95c8e/grimp-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5904d270dc4663c653287891b34ddfbe20c24a26053d673f41a51f949d719699", size = 403442 }, + { url = "https://files.pythonhosted.org/packages/a0/d4/38393d4c12d94c6941b8978aaee3d3046fd7cdbc27415df5b78f9457e3a5/grimp-3.4.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:011a04ed6927d1931851858331dbbe1e52f240923135bfa15dece8c78ba5b1bf", size = 405686 }, + { url = "https://files.pythonhosted.org/packages/e6/75/a917fe65ff386f62beb2b51f7ac3f710a3f8ff4b8379cb9b1a3199335f4b/grimp-3.4.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:caed62820ee04ed115ef6a925a349f244b0c1cc2577deba6802f253eed65fbb2", size = 415748 }, + { url = "https://files.pythonhosted.org/packages/1b/1b/8769b0e851b40dd78f4a8a4311c3f8c3e4513d6b0498720b38fee89d568e/grimp-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:762cdbb0184cadfcaaac5e16aa5fa96b805f9720edce81a5e2a85114bc335f78", size = 439676 }, + { url = "https://files.pythonhosted.org/packages/22/69/ebf9e7c6265b24464570b01ad41d2ff087f0938cce3de953849a4ec7bea4/grimp-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:761ff441888a0e344fdea7f385275b4c4e2acdadc1dd4e71d0753a6bf34ac58e", size = 445123 }, + { url = "https://files.pythonhosted.org/packages/38/68/c556897049b8057218990e6b044e8a4528a38b83f5d76f1887e495285b86/grimp-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0a00d521c3d41a5b257c92960ebb7f3bebdc7ea996801364c213f1ff74a5a4a", size = 396054 }, + { url = "https://files.pythonhosted.org/packages/4c/ad/7cc7983dcd828fe72473cfb2a53502875e98d5136d570df2429120b75ee4/grimp-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2c4adaac06c6f18ee4ba2dd5a2e94183e0419f5c156c427ccc27728fa4bbddd0", size = 579813 }, + { url = "https://files.pythonhosted.org/packages/8d/a4/fefc216034465d942c33af20cc9be6b19dc76316a5f4938baef23fd09eae/grimp-3.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:84acd1ceb07a543768bc022df543f870efb90f95147e6172b75437811c364faa", size = 666867 }, + { url = "https://files.pythonhosted.org/packages/4e/e3/17718e5b5379df057ade916d3b9bf426f5f4ccda1069e13aa269afd982ee/grimp-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0b8e9cfd0d62bf632304229afc4c4bf40c2371c9a23cefce762df1f22a7b55d1", size = 589948 }, + { url = "https://files.pythonhosted.org/packages/6d/01/bcf152d063b2c69920e2a1c3e8b4e104b68a1d717e530f4f60804bb5c824/grimp-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c44522ffd385d99ab2f12be049c38bc60dcd09ae80b4c28c83df89ad9b9456f", size = 566425 }, + { url = "https://files.pythonhosted.org/packages/1f/f9/a02824142dd43a86287a6dd31586b7e50beea97f80aed1c793d4a7ed60e6/grimp-3.4.1-cp312-none-win32.whl", hash = "sha256:ca8e67309b353b3e4f63bcc1f2be66ce67712a9bc9c777472dd946ab90e0614d", size = 229109 }, + { url = "https://files.pythonhosted.org/packages/7d/f8/910deab3002c6c70909430d99854889886090f4c9bf1063b63e18747414e/grimp-3.4.1-cp312-none-win_amd64.whl", hash = "sha256:2d515079b33497d83d3bd34c47ebb6bc6cbadcb0ec5405100c15027176e618ca", size = 239266 }, + { url = "https://files.pythonhosted.org/packages/ad/8e/7188f23347b39a0144f9f94337d6fc32fa22c5a2d79b35c545183ddca3d0/grimp-3.4.1-cp313-none-win32.whl", hash = "sha256:e3a5e969246562cb405a3acfc35a1d1a014f1764d5d0398b4d3e9b6a9f956efb", size = 228767 }, + { url = "https://files.pythonhosted.org/packages/00/ab/fd0b42471e3bc167761e1406732b57ba9448fa7ecb9bc9af97dd55fe1c3c/grimp-3.4.1-cp313-none-win_amd64.whl", hash = "sha256:17edd54ad125a9650c8dc9ca7a57ba913043ace3f7053e51ffa900236f8fddc9", size = 239009 }, +] + [[distribution]] name = "gymnasium" version = "0.29.1" @@ -833,6 +841,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769 }, ] +[[distribution]] +name = "import-linter" +version = "2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "grimp" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d4/3a/6b433eace42d2f92cb96667f326b11582004b74acd045bf10a277761eed4/import-linter-2.0.tar.gz", hash = "sha256:b067cf0cdbf11c4f87524e32c2e3eaa62d46572e9e06511e6b453198b15b1c9a", size = 28678 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/82/5a23aefe774927b45d9964282496c5228d537bb5de1e54eedce832fa4901/import_linter-2.0-py3-none-any.whl", hash = "sha256:200f9b46d20a055c1f6f514e4cd8074852261bc9c8733d028201a55be6058bb0", size = 41018 }, +] + [[distribution]] name = "importlib-metadata" version = "8.0.0" @@ -1142,7 +1164,7 @@ wheels = [ [[distribution]] name = "metadrive-simulator" version = "0.4.2.3" -source = { git = "https://github.com/commaai/metadrive.git?branch=opencv_headless#9b6ddb791919249effa0573883076681514787e4" } +source = { git = "https://github.com/commaai/metadrive?rev=opencv_headless#9b6ddb791919249effa0573883076681514787e4" } dependencies = [ { name = "filelock" }, { name = "geopandas" }, @@ -1571,6 +1593,7 @@ docs = [ testing = [ { name = "coverage" }, { name = "hypothesis" }, + { name = "import-linter" }, { name = "mypy" }, { name = "pre-commit" }, { name = "pytest" }, @@ -4623,8 +4646,6 @@ sdist = { url = "https://files.pythonhosted.org/packages/28/6c/640e3f5c734c296a7 wheels = [ { url = "https://files.pythonhosted.org/packages/0f/28/fcaf2aeede42456538d1543aefa253d70282bf326f5f795c99233366b66f/PyQt5-5.15.2-5.15.2-cp35.cp36.cp37.cp38.cp39-abi3-macosx_10_13_intel.whl", hash = "sha256:894ca4ae767a8d6cf5903784b71f755073c78cb8c167eecf6e4ed6b3b055ac6a", size = 47599356 }, { url = "https://files.pythonhosted.org/packages/91/cf/cc705497cdae04c3c0bc34f94b91e31b6585bb65eb561f18473c998caae1/PyQt5-5.15.2-5.15.2-cp35.cp36.cp37.cp38.cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:29889845688a54d62820585ad5b2e0200a36b304ff3d7a555e95599f110ba4ce", size = 68328841 }, - { url = "https://files.pythonhosted.org/packages/b7/3e/a10c682f8ee33583cdc86a0d0eafe82b39156be3771abaa219b6e50251cd/PyQt5-5.15.2-5.15.2-cp35.cp36.cp37.cp38.cp39-none-win32.whl", hash = "sha256:ea24f24b7679bf393dd2e4f53fe0ce65021be18304c1ff7a226c2fc5c356d0da", size = 48859916 }, - { url = "https://files.pythonhosted.org/packages/aa/72/754c693db0e745b9fe47debc3ec52844461f090d5beff28489a0cde5ef82/PyQt5-5.15.2-5.15.2-cp35.cp36.cp37.cp38.cp39-none-win_amd64.whl", hash = "sha256:faaecb76ec65e12673a968e7f5bc02495957e6996f0a3fa0d98895f9e4113746", size = 56911575 }, ] [[distribution]] From 0907b30d7b87957ae14cad7954358c1d78d9a528 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 19 Jul 2024 15:39:44 -0700 Subject: [PATCH 065/229] ui: fix flipped experimental path acceleration (#33026) * fix * clean up * better comment * Update selfdrive/ui/qt/onroad/annotated_camera.cc --- selfdrive/ui/qt/onroad/annotated_camera.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc index 60f2380dc5..484075b3e2 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.cc +++ b/selfdrive/ui/qt/onroad/annotated_camera.cc @@ -177,10 +177,11 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { for (int i = 0; i < max_len; ++i) { // Some points are out of frame - if (scene.track_vertices[i].y() < 0 || scene.track_vertices[i].y() > height()) continue; + int track_idx = (scene.track_vertices.length() / 2) - i; // flip idx to start from top + if (scene.track_vertices[track_idx].y() < 0 || scene.track_vertices[track_idx].y() > height()) continue; // Flip so 0 is bottom of frame - float lin_grad_point = (height() - scene.track_vertices[i].y()) / height(); + float lin_grad_point = (height() - scene.track_vertices[track_idx].y()) / height(); // speed up: 120, slow down: 0 float path_hue = fmax(fmin(60 + acceleration[i] * 35, 120), 0); From 1aa467cb003e7915a6dbc1ee7786f8c199cf6223 Mon Sep 17 00:00:00 2001 From: jamperezmondragon <70548653+jamperezmondragon@users.noreply.github.com> Date: Sat, 20 Jul 2024 16:54:51 -0600 Subject: [PATCH 066/229] Spanish Translation Update (#32995) * Update main_es.ts * Update main_es.ts * Update Spanish Translation [(#32995)](https://github.com/commaai/openpilot/pull/32995) --- selfdrive/ui/translations/main_es.ts | 152 +++++++++++++-------------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/selfdrive/ui/translations/main_es.ts b/selfdrive/ui/translations/main_es.ts index 941b30e2d0..c8093e3029 100644 --- a/selfdrive/ui/translations/main_es.ts +++ b/selfdrive/ui/translations/main_es.ts @@ -64,7 +64,7 @@ Prevent large data uploads when on a metered connection - Evitar grandes descargas de datos cuando tiene una conexión limitada + Evitar grandes descargas de datos cuando tenga una conexión limitada Hidden Network @@ -72,7 +72,7 @@ CONNECT - CONNECTAR + CONECTAR Enter SSID @@ -117,7 +117,7 @@ DeclinePage You must accept the Terms and Conditions in order to use openpilot. - Debe aceptar los terminos y condiciones para poder utilizar openpilot. + Debe aceptar los términos y condiciones para poder utilizar openpilot. Back @@ -164,11 +164,11 @@ Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - Previsualizar la cámara del conductor para garantizar que la monitorización del sistema tenga buena visibilidad (El vehículo tiene que estar apagado) + Previsualizar la cámara del conductor para garantizar que la monitorización del sistema tenga buena visibilidad (el vehículo tiene que estar apagado) Reset Calibration - Reiniciar Calibración + Formatear Calibración RESET @@ -176,11 +176,11 @@ Are you sure you want to reset calibration? - ¿Seguro qué quiere reiniciar la calibración? + ¿Seguro que quiere formatear la calibración? Reset - Reiniciar + Formatear Review Training Guide @@ -196,7 +196,7 @@ Are you sure you want to review the training guide? - ¿Seguro qué quiere revisar la guía de entrenamiento? + ¿Seguro que quiere revisar la guía de entrenamiento? Review @@ -232,11 +232,11 @@ openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required. - openpilot requiere que el dispositivo sea montado entre 4° izquierda o derecha y entre 5° arriba o 9° abajo. openpilot está constantemente en calibración, reiniciar es rara vez necesario. + openpilot requiere que el dispositivo sea montado entre 4° grados a la izquierda o derecha y entre 5° grados hacia arriba o 9° grados hacia abajo. openpilot está constantemente en calibración, formatear rara vez es necesario. Your device is pointed %1° %2 and %3° %4. - Su dispositivo está apuntando %1° %2 e %3° %4. + Su dispositivo está apuntando %1° %2 y %3° %4. down @@ -286,7 +286,7 @@ CHILL MODE ON - MODO TRANQUILO + MODO CHILL @@ -298,7 +298,7 @@ Need at least %n character(s)! - ¡Necesita mínimo %n caractere! + ¡Necesita mínimo %n caracter! ¡Necesita mínimo %n caracteres! @@ -314,7 +314,7 @@ MultiOptionDialog Select - Seleccione + Seleccionar Cancel @@ -337,22 +337,22 @@ Wrong password - Contraseña equivocada + Contraseña incorrecta OffroadAlert Device temperature too high. System cooling down before starting. Current internal component temperature: %1 - Temperatura de dispositivo muy alta. Systema enfriando antes de iniciar. Temperatura actual del componente interno: %1 + La temperatura del dispositivo es muy alta. El sistema se está enfriando antes de iniciar. Temperatura actual del componente interno: %1 Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 - Inmediatamente conectar al internet para buscar actualizaciones. Si no se conecta al internet, openpilot no iniciara en %1 + Conéctese inmediatamente al internet para buscar actualizaciones. Si no se conecta al internet, openpilot no iniciará en %1 Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. - Conectar al internet para buscar actualizaciones. openpilot no iniciara automáticamente hasta conectarse al internet para buscar actualizaciones. + Conectese al internet para buscar actualizaciones. openpilot no iniciará automáticamente hasta conectarse al internet para buscar actualizaciones. Unable to download updates @@ -362,7 +362,7 @@ Taking camera snapshots. System won't start until finished. - Tomando instantáneas de la cámara. El sistema no se iniciará hasta que finalice. + Tomando capturas de las cámaras. El sistema no se iniciará hasta que finalice. An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. @@ -370,7 +370,7 @@ Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support. - El dispositivo no pudo registrarse. No se conectará ni cargará en los servidores de comma.ai y no recibe soporte de comma.ai. Si este es un dispositivo oficial, visite https://comma.ai/support. + El dispositivo no pudo registrarse. No se conectará ni subirá datos a los servidores de comma.ai y no recibe soporte de comma.ai. Si este es un dispositivo oficial, visite https://comma.ai/support. NVMe drive not mounted. @@ -378,15 +378,15 @@ Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe. - Se detectó una unidad NVMe no compatible. El dispositivo puede consumir mucha más energía y sobrecalentarse debido a que NVMe no es compatible. + Se detectó una unidad NVMe incompatible. El dispositivo puede consumir mucha más energía y sobrecalentarse debido a esto. openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - openpilot no pudo identificar su automóvil. Su automóvil no es compatible o no se reconocen sus ECU. Envíe una solicitud de extracción para agregar las versiones de firmware al vehículo adecuado. ¿Necesitas ayuda? Únase a discord.comma.ai. + openpilot no pudo identificar su automóvil. Su automóvil no es compatible o no se reconocen sus ECU. Por favor haga un pull request para agregar las versiones de firmware del vehículo adecuado. ¿Necesita ayuda? Únase a discord.comma.ai. openpilot was unable to identify your car. Check integrity of cables and ensure all connections are secure, particularly that the comma power is fully inserted in the OBD-II port of the vehicle. Need help? Join discord.comma.ai. - openpilot no pudo identificar su automóvil. Verifique la integridad de los cables y asegúrese de que todas las conexiones estén seguras, en particular que comma power esté completamente insertada en el puerto OBD-II del vehículo. ¿Necesitas ayuda? Únase a discord.comma.ai. + openpilot no pudo identificar su automóvil. Verifique la integridad de los cables y asegúrese de que todas las conexiones estén seguras, en particular que el comma power esté completamente insertado en el puerto OBD-II del vehículo. ¿Necesita ayuda? Únase discord.comma.ai. openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. @@ -439,15 +439,15 @@ Go to https://connect.comma.ai on your phone - Ve a https://connect.comma.ai en su telefono + Vaya a https://connect.comma.ai en su teléfono Click "add new device" and scan the QR code on the right - Clic en "agregar nuevo dispositivo" y escanee el código QR a la derecha + Seleccione "agregar nuevo dispositivo" y escanee el código QR a la derecha Bookmark connect.comma.ai to your home screen to use it like an app - Marcar connect.comma.ai como su pantalla de inicio para usarlo como una aplicación + Añada connect.comma.ai a su pantalla de inicio para usarlo como una aplicación @@ -469,7 +469,7 @@ Become a comma prime member at connect.comma.ai - Hazte miembro prime de comma en connect.comma.ai + Hazte miembro de comma prime en connect.comma.ai PRIME FEATURES: @@ -485,11 +485,11 @@ 1 year of drive storage - 1 año de almacenamiento en disco + 1 año de almacenamiento Remote snapshots - Istantánea remota + Capturas remotas @@ -547,25 +547,25 @@ Reset Reset failed. Reboot to try again. - Reset fallido. Reinicie de nuevo. + Formateo fallido. Reinicie para reintentar. Resetting device... This may take up to a minute. - Reiniciando dispositivo... -Esto puede tardar hasta un minuto. + formateando dispositivo... +Esto puede tardar un minuto. Are you sure you want to reset your device? - ¿Seguro que quiere reiniciar su dispositivo? + ¿Seguro que quiere formatear su dispositivo? System Reset - Reiniciar Sistema + Formatear Sistema System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - Reinicio del sistema activado. Presione confirmar para borrar todo el contenido y la configuración. Presione cancelar para reanudar el inicio. + Formateo del sistema activado. Presione confirmar para borrar todo el contenido y la configuración. Presione cancelar para reanudar el inicio. Cancel @@ -581,7 +581,7 @@ Esto puede tardar hasta un minuto. Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - No es posible montar una partición de datos. Partición corrompida. Confirme para borrar y reiniciar su dispositivo. + No es posible montar una partición de datos. La partición podría estar corrompida. Confirme para borrar y formatear su dispositivo. @@ -615,19 +615,19 @@ Esto puede tardar hasta un minuto. Ensure the entered URL is valid, and the device’s internet connection is good. - Asegurese de que la URL insertada es válida, y que el dispositivo tiene buena conexión. + Asegúrese de que la URL insertada es válida y que el dispositivo tiene buena conexión. No custom software found at this URL. - No hay software personalizado en esta URL. + No encontramos software personalizado en esta URL. WARNING: Low Voltage - ALERTA: Volage bajo + ALERTA: Voltaje bajo Power your device in a car with a harness or proceed at your own risk. - Encender su dispositivo en el auto con el arnés o proceda bajo su propio riesgo. + Encienda su dispositivo en un auto con el arnés o proceda bajo su propio riesgo. Power off @@ -643,11 +643,11 @@ Esto puede tardar hasta un minuto. Before we get on the road, let’s finish installation and cover some details. - Antes de comenzar, terminemos la instalación y cubramos algunos detalles. + Antes de ponernos en marcha, terminemos la instalación y cubramos algunos detalles. Connect to Wi-Fi - Conectar a la Wi-Fi + Conectarse al Wi-Fi Back @@ -663,7 +663,7 @@ Esto puede tardar hasta un minuto. Choose Software to Install - Elija el software para instalar + Elija el software a instalar openpilot @@ -699,7 +699,7 @@ Esto puede tardar hasta un minuto. Select a language - Seleccione el idioma + Seleccione un idioma @@ -710,7 +710,7 @@ Esto puede tardar hasta un minuto. Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - Empareja tu dispositivo con comma connect (connect.comma.ai) y reclama tu oferta de comma prime. + Empareje su dispositivo con comma connect (connect.comma.ai) y reclame su oferta de comma prime. Pair device @@ -725,11 +725,11 @@ Esto puede tardar hasta un minuto. OFFLINE - SIN LINEA + OFFLINE ONLINE - EN LINEA + EN LÍNEA ERROR @@ -745,7 +745,7 @@ Esto puede tardar hasta un minuto. GOOD - BUENO + BUENA OK @@ -769,7 +769,7 @@ Esto puede tardar hasta un minuto. SEARCH - BUSQUEDA + BÚSQUEDA -- @@ -804,7 +804,7 @@ Esto puede tardar hasta un minuto. SoftwarePanel Updates are only downloaded while the car is off. - Apague el auto para descargar actualizaciones. + Actualizaciones solo se descargan con el auto apagado. Current Version @@ -856,7 +856,7 @@ Esto puede tardar hasta un minuto. failed to check for update - no se pudo buscar actualización + no se pudo buscar actualizaciones DOWNLOAD @@ -883,7 +883,7 @@ Esto puede tardar hasta un minuto. Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - Aviso: Esto otorga acceso SSH a todas las claves públicas en su Github. Nunca inserte un nombre de usuario de Github que no sea suyo. Un empleado de comma nunca le pedirá que añada su nombre de Github. + Aviso: Esto otorga acceso SSH a todas las claves públicas en su Github. Nunca ingrese un nombre de usuario de Github que no sea suyo. Un empleado de comma NUNCA le pedirá que añada un usuario de Github que no sea el suyo. ADD @@ -891,7 +891,7 @@ Esto puede tardar hasta un minuto. Enter your GitHub username - Ingresa tu usuario de GitHub + Ingrese su usuario de GitHub LOADING @@ -903,7 +903,7 @@ Esto puede tardar hasta un minuto. Username '%1' has no keys on GitHub - Nombre de usuario "%1” no tiene claves en GitHub + El usuario "%1” no tiene claves en GitHub Request timed out @@ -911,7 +911,7 @@ Esto puede tardar hasta un minuto. Username '%1' doesn't exist on GitHub - Nombre de usuario '%1' no existe en Github + El usuario '%1' no existe en Github @@ -925,7 +925,7 @@ Esto puede tardar hasta un minuto. TermsPage Terms & Conditions - Terminos & Condiciones + Términos & Condiciones Decline @@ -948,19 +948,19 @@ Esto puede tardar hasta un minuto. Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. - Utilice el sistema openpilot para control de crucero adaptativo y asistencia al conductor para mantenerse en el carril. Se requiere su atención en todo momento para utilizar esta función. Cambiar esta configuración solo tendrá efecto con el auto apagado. + Utilice el sistema openpilot para acceder a un autocrucero adaptativo y asistencia al conductor para mantenerse en el carril. Se requiere su atención en todo momento para utilizar esta función. Cambiar esta configuración solo tendrá efecto con el auto apagado. openpilot Longitudinal Control (Alpha) - Control longitudinal de openpilot (Alfa) + Control longitudinal de openpilot (fase experimental) WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - Aviso: el control longitudinal de openpilot está en fase alfa para este automóvil y desactivará el Frenado Automático de Emergencia (AEB). + AVISO: el control longitudinal de openpilot está en fase experimental para este automóvil y desactivará el Frenado Automático de Emergencia (AEB). On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - En este vehículo, openpilot se configura de manera predeterminada con el Control de Crucero Adaptativo (ACC) incorporado en el automóvil en lugar del control longitudinal de openpilot. Habilita esta opción para cambiar al control longitudinal de openpilot. Se recomienda activar el modo experimental al habilitar el control longitudinal alfa de openpilot. + En este automóvil, openpilot se configura de manera predeterminada con el Autocrucero Adaptativo (ACC) incorporado en el automóvil en lugar del control longitudinal de openpilot. Habilita esta opción para cambiar al control longitudinal de openpilot. Se recomienda activar el modo experimental al habilitar el control longitudinal de openpilot (aún en fase experimental). Experimental Mode @@ -972,23 +972,23 @@ Esto puede tardar hasta un minuto. When enabled, pressing the accelerator pedal will disengage openpilot. - Cuando esté activado, presionar el acelerador deshabilitará el openpilot. + Cuando esté activado, presionar el acelerador deshabilitará openpilot. Enable Lane Departure Warnings - Activar Aviso de Salida de Carril + Activar Avisos de Salida de Carril Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). - Recibir alertas para volver dentro del carril cuando su vehículo se sale fuera del carril sin que esté activado la señal de giro mientras esté conduciendo por encima de 50 km/h (31 mph). + Recibir alertas para volver al carril cuando su vehículo se salga fuera del carril sin que esté activada la señal de giro y esté conduciendo por encima de 50 km/h (31 mph). Always-On Driver Monitoring - Monitoreo del Conductor Siempre Activo + Monitoreo Permanente del Conductor Enable driver monitoring even when openpilot is not engaged. - Habilite el monitoreo del conductor incluso cuando Openpilot no esté activado. + Habilitar el monitoreo del conductor incluso cuando Openpilot no esté activado. Record and Upload Driver Camera @@ -996,7 +996,7 @@ Esto puede tardar hasta un minuto. Upload data from the driver facing camera and help improve the driver monitoring algorithm. - Subir datos de la cámara del conductor para ayudar a mejorar el algoritmo de monitorización del conductor. + Subir datos de la cámara del conductor para ayudar a mejorar el algoritmo de monitoreo del conductor. Use Metric System @@ -1024,19 +1024,19 @@ Esto puede tardar hasta un minuto. Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - Se recomienda estándar. En el modo agresivo, openpilot seguirá a los autos líderes más cerca y será más agresivo con el acelerador y el freno. En modo relajado, openpilot se mantendrá más alejado de los coches líderes. En automóviles compatibles, puede recorrer estas personalidades con el botón de distancia del volante. + Se recomienda el modo estándar. En el modo agresivo, openpilot seguirá más cerca a los autos delante suyo y será más agresivo con el acelerador y el freno. En modo relajado, openpilot se mantendrá más alejado de los autos delante suyo. En automóviles compatibles, puede recorrer estas personalidades con el botón de distancia del volante. openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - openpilot por defecto conduce en <b>modo chill</b>. El modo Experimental activa <b>recursos de nível-alfa</b> que no están listos para el modo chill. Los recursos del modo expeimental están listados abajo: + openpilot por defecto conduce en <b>modo chill</b>. El modo Experimental activa <b>funcionalidades en fase experimental</b>, que no están listas para el modo chill. Las funcionalidades del modo expeimental están listados abajo: End-to-End Longitudinal Control - 🌮 Control Longitudinal de Punta a Punta 🌮 + Control Longitudinal de Punta a Punta Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - Dajar que el modelo de conducción controle la aceleración y el frenado. openpilot va a conducir como lo haría una persona, incluiyendo parar en los semaforos en rojo y las señales de stop. Dado que el modelo decide la velocidad de conducción, la velocidad de crucero establecida actuará como limitador. Este recurso es de una calidad alfa; errores pueden ocurrir. + Dajar que el modelo de conducción controle la aceleración y el frenado. openpilot conducirá como piensa que lo haría una persona, incluiyendo parar en los semáforos en rojo y las señales de alto. Dado que el modelo decide la velocidad de conducción, la velocidad de crucero establecida solo actuará como el límite superior. Este recurso aún está en fase experimental; deberían esperarse errores. New Driving Visualization @@ -1044,11 +1044,11 @@ Esto puede tardar hasta un minuto. The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. - La visualización de la conducción cambiará a la cámara que enfoca la carretera a velocidades bajas para mostrar mejor los giros. El logo del modo experimental se mostrará en la esquina superior derecha. + La visualización de la conducción cambiará a la cámara que enfoca la carretera a velocidades bajas para mostrar mejor los giros. El logo del modo experimental también se mostrará en la esquina superior derecha. Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - El modo Experimental no está disponible actualmente para este auto, ya que el ACC del auto está siendo usado para el control longitudinal. + El modo Experimental no está disponible actualmente para este auto, ya que el ACC default del auto está siendo usado para el control longitudinal. openpilot longitudinal control may come in a future update. @@ -1056,11 +1056,11 @@ Esto puede tardar hasta un minuto. An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - Se puede probar una versión experimental del control longitudinal openpilot, junto con el modo Experimental, en ramas sin liberación. + Se puede probar una versión experimental del control longitudinal openpilot, junto con el modo Experimental, en ramas no liberadas. Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. - Activar el control longitudinal experimental para permitir el modo Experimental. + Activar el control longitudinal (fase experimental) para permitir el modo Experimental. @@ -1071,7 +1071,7 @@ Esto puede tardar hasta un minuto. An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - Es necesario la actualización del sistema operativo. Conecte su dispositivo a Wi-Fi para una actualización rápida. El tamaño de descarga es de aproximadamente 1GB. + Es necesario la actualización del sistema operativo. Conecte su dispositivo al Wi-Fi para una actualización rápida. El tamaño de descarga es de aproximadamente 1GB. Connect to Wi-Fi @@ -1106,7 +1106,7 @@ Esto puede tardar hasta un minuto. Connect to Wi-Fi to upload driving data and help improve openpilot - Conectar a Wi-Fi para subir los datos de conducir para mejorar openpilot + Conectarse al Wi-Fi para subir los datos de conducción y mejorar openpilot Open Settings @@ -1137,7 +1137,7 @@ Esto puede tardar hasta un minuto. Forget Wi-Fi Network "%1"? - Olvidar Red Wi-Fi "%1"? + ¿Olvidar la Red de Wi-Fi "%1"? Forget From dc886e195f9815c77b721a8a438bbdffe9067e38 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 22 Jul 2024 10:19:34 +0800 Subject: [PATCH 067/229] camerad: add CameraConfig struct for initializing CameraState in constructor (#33034) * Add CameraConfig struct for initializing CameraState in constructor * Update system/camerad/cameras/camera_qcom2.h --------- Co-authored-by: Adeeb Shihadeh --- system/camerad/cameras/camera_common.h | 3 -- system/camerad/cameras/camera_qcom2.cc | 43 +++++++++++++++--------- system/camerad/cameras/camera_qcom2.h | 46 +++++++++++++++++++++----- 3 files changed, 65 insertions(+), 27 deletions(-) diff --git a/system/camerad/cameras/camera_common.h b/system/camerad/cameras/camera_common.h index 555362ab8b..f97940b669 100644 --- a/system/camerad/cameras/camera_common.h +++ b/system/camerad/cameras/camera_common.h @@ -18,9 +18,6 @@ enum CameraType { }; // for debugging -const bool env_disable_road = getenv("DISABLE_ROAD") != NULL; -const bool env_disable_wide_road = getenv("DISABLE_WIDE_ROAD") != NULL; -const bool env_disable_driver = getenv("DISABLE_DRIVER") != NULL; const bool env_debug_frames = getenv("DEBUG_FRAMES") != NULL; const bool env_log_raw_frames = getenv("LOG_RAW_FRAMES") != NULL; const bool env_ctrl_exp_from_params = getenv("CTRL_EXP_FROM_PARAMS") != NULL; diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index 47ea5ded4d..2eba1e3615 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -26,6 +26,14 @@ const int MIPI_SETTLE_CNT = 33; // Calculated by camera_freqs.py extern ExitHandler do_exit; +CameraState::CameraState(MultiCameraState *multi_camera_state, const CameraConfig &config) + : multi_cam_state(multi_camera_state), + camera_num(config.camera_num), + stream_type(config.stream_type), + focal_len(config.focal_len), + enabled(config.enabled) { +} + int CameraState::clear_req_queue() { struct cam_req_mgr_flush_info req_mgr_flush_request = {0}; req_mgr_flush_request.session_hdl = session_handle; @@ -434,39 +442,36 @@ void CameraState::sensor_set_parameters() { cur_ev[0] = cur_ev[1] = cur_ev[2] = (1 + dc_gain_weight * (ci->dc_gain_factor-1) / ci->dc_gain_max_weight) * ci->sensor_analog_gains[gain_idx] * exposure_time; } -void CameraState::camera_map_bufs(MultiCameraState *s) { +void CameraState::camera_map_bufs() { for (int i = 0; i < FRAME_BUF_COUNT; i++) { // configure ISP to put the image in place struct cam_mem_mgr_map_cmd mem_mgr_map_cmd = {0}; - mem_mgr_map_cmd.mmu_hdls[0] = s->device_iommu; + mem_mgr_map_cmd.mmu_hdls[0] = multi_cam_state->device_iommu; mem_mgr_map_cmd.num_hdl = 1; mem_mgr_map_cmd.flags = CAM_MEM_FLAG_HW_READ_WRITE; mem_mgr_map_cmd.fd = buf.camera_bufs[i].fd; - int ret = do_cam_control(s->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd)); + int ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd)); LOGD("map buf req: (fd: %d) 0x%x %d", buf.camera_bufs[i].fd, mem_mgr_map_cmd.out.buf_handle, ret); buf_handle[i] = mem_mgr_map_cmd.out.buf_handle; } enqueue_req_multi(1, FRAME_BUF_COUNT, 0); } -void CameraState::camera_init(MultiCameraState *s, VisionIpcServer * v, cl_device_id device_id, cl_context ctx, VisionStreamType yuv_type, float focal_len) { +void CameraState::camera_init(VisionIpcServer * v, cl_device_id device_id, cl_context ctx) { if (!enabled) return; LOGD("camera init %d", camera_num); request_id_last = 0; skipped = true; - buf.init(device_id, ctx, this, v, FRAME_BUF_COUNT, yuv_type); - camera_map_bufs(s); + buf.init(device_id, ctx, this, v, FRAME_BUF_COUNT, stream_type); + camera_map_bufs(); fl_pix = focal_len / ci->pixel_size_mm; set_exposure_rect(); } -void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num_, bool enabled_) { - multi_cam_state = multi_cam_state_; - camera_num = camera_num_; - enabled = enabled_; +void CameraState::camera_open() { if (!enabled) return; sensor_fd = open_v4l_by_name_and_index("cam-sensor-driver", camera_num); @@ -644,9 +649,9 @@ void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num } void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_id, cl_context ctx) { - s->driver_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_DRIVER, DRIVER_FL_MM); - s->road_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_ROAD, ROAD_FL_MM); - s->wide_road_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_WIDE_ROAD, WIDE_FL_MM); + s->driver_cam.camera_init(v, device_id, ctx); + s->road_cam.camera_init(v, device_id, ctx); + s->wide_road_cam.camera_init(v, device_id, ctx); s->pm = new PubMaster({"roadCameraState", "driverCameraState", "wideRoadCameraState", "thumbnail"}); } @@ -690,11 +695,11 @@ void cameras_open(MultiCameraState *s) { ret = HANDLE_EINTR(ioctl(s->video0_fd, VIDIOC_SUBSCRIBE_EVENT, &sub)); LOGD("req mgr subscribe: %d", ret); - s->driver_cam.camera_open(s, 2, !env_disable_driver); + s->driver_cam.camera_open(); LOGD("driver camera opened"); - s->road_cam.camera_open(s, 1, !env_disable_road); + s->road_cam.camera_open(); LOGD("road camera opened"); - s->wide_road_cam.camera_open(s, 0, !env_disable_wide_road); + s->wide_road_cam.camera_open(); LOGD("wide road camera opened"); } @@ -956,6 +961,12 @@ void process_road_camera(MultiCameraState *s, CameraState *c, int cnt) { c->set_camera_exposure(set_exposure_target(b, c->ae_xywh, skip, skip)); } +MultiCameraState::MultiCameraState() + : driver_cam(this, DRIVER_CAMERA_CONFIG), + road_cam(this, ROAD_CAMERA_CONFIG), + wide_road_cam(this, WIDE_ROAD_CAMERA_CONFIG) { +} + void cameras_run(MultiCameraState *s) { LOG("-- Starting threads"); std::vector threads; diff --git a/system/camerad/cameras/camera_qcom2.h b/system/camerad/cameras/camera_qcom2.h index 0b15c9c3f0..bdebeef9f8 100644 --- a/system/camerad/cameras/camera_qcom2.h +++ b/system/camerad/cameras/camera_qcom2.h @@ -11,15 +11,41 @@ #define FRAME_BUF_COUNT 4 -#define ROAD_FL_MM 8.0f -#define WIDE_FL_MM 1.71f -#define DRIVER_FL_MM 1.71f +struct CameraConfig { + int camera_num; + VisionStreamType stream_type; + float focal_len; // millimeters + bool enabled; +}; + +const CameraConfig WIDE_ROAD_CAMERA_CONFIG = { + .camera_num = 0, + .stream_type = VISION_STREAM_WIDE_ROAD, + .focal_len = 1.71, + .enabled = !getenv("DISABLE_WIDE_ROAD"), +}; + +const CameraConfig ROAD_CAMERA_CONFIG = { + .camera_num = 1, + .stream_type = VISION_STREAM_ROAD, + .focal_len = 8.0, + .enabled = !getenv("DISABLE_ROAD"), +}; + +const CameraConfig DRIVER_CAMERA_CONFIG = { + .camera_num = 2, + .stream_type = VISION_STREAM_DRIVER, + .focal_len = 1.71, + .enabled = !getenv("DISABLE_DRIVER"), +}; class CameraState { public: MultiCameraState *multi_cam_state; std::unique_ptr ci; bool enabled; + VisionStreamType stream_type; + float focal_len; std::mutex exp_lock; @@ -44,17 +70,18 @@ public: int camera_num; float fl_pix; + CameraState(MultiCameraState *multi_camera_state, const CameraConfig &config); void handle_camera_event(void *evdat); void update_exposure_score(float desired_ev, int exp_t, int exp_g_idx, float exp_gain); void set_camera_exposure(float grey_frac); void sensors_start(); - void camera_open(MultiCameraState *multi_cam_state, int camera_num, bool enabled); + void camera_open(); void set_exposure_rect(); void sensor_set_parameters(); - void camera_map_bufs(MultiCameraState *s); - void camera_init(MultiCameraState *s, VisionIpcServer *v, cl_device_id device_id, cl_context ctx, VisionStreamType yuv_type, float focal_len); + void camera_map_bufs(); + void camera_init(VisionIpcServer *v, cl_device_id device_id, cl_context ctx); void camera_close(); int32_t session_handle; @@ -90,7 +117,10 @@ private: Params params; }; -typedef struct MultiCameraState { +class MultiCameraState { +public: + MultiCameraState(); + unique_fd video0_fd; unique_fd cam_sync_fd; unique_fd isp_fd; @@ -102,4 +132,4 @@ typedef struct MultiCameraState { CameraState driver_cam; PubMaster *pm; -} MultiCameraState; +}; From cefe00c964d41f5ac15f13bc83b3e389d8965a5e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 21 Jul 2024 20:36:45 -0700 Subject: [PATCH 068/229] Revert "camerad: add CameraConfig struct for initializing CameraState in constructor (#33034)" This reverts commit dc886e195f9815c77b721a8a438bbdffe9067e38. --- system/camerad/cameras/camera_common.h | 3 ++ system/camerad/cameras/camera_qcom2.cc | 43 +++++++++--------------- system/camerad/cameras/camera_qcom2.h | 46 +++++--------------------- 3 files changed, 27 insertions(+), 65 deletions(-) diff --git a/system/camerad/cameras/camera_common.h b/system/camerad/cameras/camera_common.h index f97940b669..555362ab8b 100644 --- a/system/camerad/cameras/camera_common.h +++ b/system/camerad/cameras/camera_common.h @@ -18,6 +18,9 @@ enum CameraType { }; // for debugging +const bool env_disable_road = getenv("DISABLE_ROAD") != NULL; +const bool env_disable_wide_road = getenv("DISABLE_WIDE_ROAD") != NULL; +const bool env_disable_driver = getenv("DISABLE_DRIVER") != NULL; const bool env_debug_frames = getenv("DEBUG_FRAMES") != NULL; const bool env_log_raw_frames = getenv("LOG_RAW_FRAMES") != NULL; const bool env_ctrl_exp_from_params = getenv("CTRL_EXP_FROM_PARAMS") != NULL; diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index 2eba1e3615..47ea5ded4d 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -26,14 +26,6 @@ const int MIPI_SETTLE_CNT = 33; // Calculated by camera_freqs.py extern ExitHandler do_exit; -CameraState::CameraState(MultiCameraState *multi_camera_state, const CameraConfig &config) - : multi_cam_state(multi_camera_state), - camera_num(config.camera_num), - stream_type(config.stream_type), - focal_len(config.focal_len), - enabled(config.enabled) { -} - int CameraState::clear_req_queue() { struct cam_req_mgr_flush_info req_mgr_flush_request = {0}; req_mgr_flush_request.session_hdl = session_handle; @@ -442,36 +434,39 @@ void CameraState::sensor_set_parameters() { cur_ev[0] = cur_ev[1] = cur_ev[2] = (1 + dc_gain_weight * (ci->dc_gain_factor-1) / ci->dc_gain_max_weight) * ci->sensor_analog_gains[gain_idx] * exposure_time; } -void CameraState::camera_map_bufs() { +void CameraState::camera_map_bufs(MultiCameraState *s) { for (int i = 0; i < FRAME_BUF_COUNT; i++) { // configure ISP to put the image in place struct cam_mem_mgr_map_cmd mem_mgr_map_cmd = {0}; - mem_mgr_map_cmd.mmu_hdls[0] = multi_cam_state->device_iommu; + mem_mgr_map_cmd.mmu_hdls[0] = s->device_iommu; mem_mgr_map_cmd.num_hdl = 1; mem_mgr_map_cmd.flags = CAM_MEM_FLAG_HW_READ_WRITE; mem_mgr_map_cmd.fd = buf.camera_bufs[i].fd; - int ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd)); + int ret = do_cam_control(s->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd)); LOGD("map buf req: (fd: %d) 0x%x %d", buf.camera_bufs[i].fd, mem_mgr_map_cmd.out.buf_handle, ret); buf_handle[i] = mem_mgr_map_cmd.out.buf_handle; } enqueue_req_multi(1, FRAME_BUF_COUNT, 0); } -void CameraState::camera_init(VisionIpcServer * v, cl_device_id device_id, cl_context ctx) { +void CameraState::camera_init(MultiCameraState *s, VisionIpcServer * v, cl_device_id device_id, cl_context ctx, VisionStreamType yuv_type, float focal_len) { if (!enabled) return; LOGD("camera init %d", camera_num); request_id_last = 0; skipped = true; - buf.init(device_id, ctx, this, v, FRAME_BUF_COUNT, stream_type); - camera_map_bufs(); + buf.init(device_id, ctx, this, v, FRAME_BUF_COUNT, yuv_type); + camera_map_bufs(s); fl_pix = focal_len / ci->pixel_size_mm; set_exposure_rect(); } -void CameraState::camera_open() { +void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num_, bool enabled_) { + multi_cam_state = multi_cam_state_; + camera_num = camera_num_; + enabled = enabled_; if (!enabled) return; sensor_fd = open_v4l_by_name_and_index("cam-sensor-driver", camera_num); @@ -649,9 +644,9 @@ void CameraState::camera_open() { } void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_id, cl_context ctx) { - s->driver_cam.camera_init(v, device_id, ctx); - s->road_cam.camera_init(v, device_id, ctx); - s->wide_road_cam.camera_init(v, device_id, ctx); + s->driver_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_DRIVER, DRIVER_FL_MM); + s->road_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_ROAD, ROAD_FL_MM); + s->wide_road_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_WIDE_ROAD, WIDE_FL_MM); s->pm = new PubMaster({"roadCameraState", "driverCameraState", "wideRoadCameraState", "thumbnail"}); } @@ -695,11 +690,11 @@ void cameras_open(MultiCameraState *s) { ret = HANDLE_EINTR(ioctl(s->video0_fd, VIDIOC_SUBSCRIBE_EVENT, &sub)); LOGD("req mgr subscribe: %d", ret); - s->driver_cam.camera_open(); + s->driver_cam.camera_open(s, 2, !env_disable_driver); LOGD("driver camera opened"); - s->road_cam.camera_open(); + s->road_cam.camera_open(s, 1, !env_disable_road); LOGD("road camera opened"); - s->wide_road_cam.camera_open(); + s->wide_road_cam.camera_open(s, 0, !env_disable_wide_road); LOGD("wide road camera opened"); } @@ -961,12 +956,6 @@ void process_road_camera(MultiCameraState *s, CameraState *c, int cnt) { c->set_camera_exposure(set_exposure_target(b, c->ae_xywh, skip, skip)); } -MultiCameraState::MultiCameraState() - : driver_cam(this, DRIVER_CAMERA_CONFIG), - road_cam(this, ROAD_CAMERA_CONFIG), - wide_road_cam(this, WIDE_ROAD_CAMERA_CONFIG) { -} - void cameras_run(MultiCameraState *s) { LOG("-- Starting threads"); std::vector threads; diff --git a/system/camerad/cameras/camera_qcom2.h b/system/camerad/cameras/camera_qcom2.h index bdebeef9f8..0b15c9c3f0 100644 --- a/system/camerad/cameras/camera_qcom2.h +++ b/system/camerad/cameras/camera_qcom2.h @@ -11,41 +11,15 @@ #define FRAME_BUF_COUNT 4 -struct CameraConfig { - int camera_num; - VisionStreamType stream_type; - float focal_len; // millimeters - bool enabled; -}; - -const CameraConfig WIDE_ROAD_CAMERA_CONFIG = { - .camera_num = 0, - .stream_type = VISION_STREAM_WIDE_ROAD, - .focal_len = 1.71, - .enabled = !getenv("DISABLE_WIDE_ROAD"), -}; - -const CameraConfig ROAD_CAMERA_CONFIG = { - .camera_num = 1, - .stream_type = VISION_STREAM_ROAD, - .focal_len = 8.0, - .enabled = !getenv("DISABLE_ROAD"), -}; - -const CameraConfig DRIVER_CAMERA_CONFIG = { - .camera_num = 2, - .stream_type = VISION_STREAM_DRIVER, - .focal_len = 1.71, - .enabled = !getenv("DISABLE_DRIVER"), -}; +#define ROAD_FL_MM 8.0f +#define WIDE_FL_MM 1.71f +#define DRIVER_FL_MM 1.71f class CameraState { public: MultiCameraState *multi_cam_state; std::unique_ptr ci; bool enabled; - VisionStreamType stream_type; - float focal_len; std::mutex exp_lock; @@ -70,18 +44,17 @@ public: int camera_num; float fl_pix; - CameraState(MultiCameraState *multi_camera_state, const CameraConfig &config); void handle_camera_event(void *evdat); void update_exposure_score(float desired_ev, int exp_t, int exp_g_idx, float exp_gain); void set_camera_exposure(float grey_frac); void sensors_start(); - void camera_open(); + void camera_open(MultiCameraState *multi_cam_state, int camera_num, bool enabled); void set_exposure_rect(); void sensor_set_parameters(); - void camera_map_bufs(); - void camera_init(VisionIpcServer *v, cl_device_id device_id, cl_context ctx); + void camera_map_bufs(MultiCameraState *s); + void camera_init(MultiCameraState *s, VisionIpcServer *v, cl_device_id device_id, cl_context ctx, VisionStreamType yuv_type, float focal_len); void camera_close(); int32_t session_handle; @@ -117,10 +90,7 @@ private: Params params; }; -class MultiCameraState { -public: - MultiCameraState(); - +typedef struct MultiCameraState { unique_fd video0_fd; unique_fd cam_sync_fd; unique_fd isp_fd; @@ -132,4 +102,4 @@ public: CameraState driver_cam; PubMaster *pm; -}; +} MultiCameraState; From 27faa8f82b67989dc099b39483d2c8dbd3b05676 Mon Sep 17 00:00:00 2001 From: commaci-public <60409688+commaci-public@users.noreply.github.com> Date: Mon, 22 Jul 2024 10:10:39 -0700 Subject: [PATCH 069/229] [bot] Update Python packages and pre-commit hooks (#33037) Update Python packages and pre-commit hooks Co-authored-by: Vehicle Researcher --- .pre-commit-config.yaml | 2 +- uv.lock | 245 ++++++++++++++++++++-------------------- 2 files changed, 121 insertions(+), 126 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ab9ce08c7a..10939f4289 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,7 +33,7 @@ repos: - -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn - --builtins clear,rare,informal,usage,code,names,en-GB_to_en-US - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.2 + rev: v0.5.4 hooks: - id: ruff exclude: '^(third_party/)|(msgq/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)' diff --git a/uv.lock b/uv.lock index 48d53bbda9..7808954e72 100644 --- a/uv.lock +++ b/uv.lock @@ -116,22 +116,22 @@ wheels = [ [[distribution]] name = "av" -version = "12.2.0" +version = "12.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9e/e2/1c5708feb7ceb46c8ab9d2e3fbd451a725f0741d7c5336020d13be527490/av-12.2.0.tar.gz", hash = "sha256:460670325bbd64b7a6774b6bda05985cbe4582d111f81993bfbb08058f8c0484", size = 3828627 } +sdist = { url = "https://files.pythonhosted.org/packages/00/f8/5adeeae0c42a7130933d168b8d84a21c98a32cb9fcf9222e2541ed0d9c7b/av-12.3.0.tar.gz", hash = "sha256:04b1892562aff3277efc79f32bd8f1d0cbb64ed011241cb3e96f9ad471816c22", size = 3833953 } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/08/41200974e40a803da6d008cab7a801d187f950d92efa71182680b419a99a/av-12.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f74c9987798d45302b86e94b3bdb6009e9a509c57971b5599aae4353f5b8c5c0", size = 26057398 }, - { url = "https://files.pythonhosted.org/packages/10/94/d4383c50b1a819e0edb43637d6cb03086b1fcc563e9c07fc0eb2840c4e2d/av-12.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7d17e4110efe449842d12bc11166141b5ca08ce821b7529f02ed9dc3b73c9291", size = 20871004 }, - { url = "https://files.pythonhosted.org/packages/b8/eb/82b86e8f763dd104a75478a02228465715984e0fe91ae6c7567093bf75a2/av-12.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a7cc709c0c231f282f1b26a76b42d63100a8bc088522cfd06c500ed4b6c660c", size = 33310123 }, - { url = "https://files.pythonhosted.org/packages/72/b9/bc306aaae0743004ea0f45a779c35ce0896d284e36e715f383eaf04d3a9c/av-12.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:433589001c309d4ab655f0085b47bcab89e5ddeb6472993d9ef92e05eabbbe8e", size = 32783301 }, - { url = "https://files.pythonhosted.org/packages/f2/50/0014d42a7165dc386bef02cae9de3fd5512daafcf0bae56d3cfc1e880df5/av-12.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:505955d5c2c9b7e0034fad7d0b57df6944adda9e42a606c9964ca5693c9b090d", size = 35224812 }, - { url = "https://files.pythonhosted.org/packages/77/fd/a1e1f10666e3aa37caed52804e656f525b978591ab69d20fccc6bb35d115/av-12.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:a9ca519ae6525a88637b73a1adae87235ac9a141a8d0b0c26a75cd4182c12a9f", size = 26827978 }, - { url = "https://files.pythonhosted.org/packages/26/7e/92107c359b802555f33feef5f60650a433ac084ec5e257134bf26f1ae559/av-12.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f0026b52b9981b15d71f7f09ecd32587d9b99dd350588f8e17ce726662b466c5", size = 26070643 }, - { url = "https://files.pythonhosted.org/packages/9a/9f/7a94c61856e243ecb3aa58ceebbeae5f165862ffb4e8548b497d1d906418/av-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6e60a6da4eb5200900b37716dd971676a1dfb8731b53e8f49a3e630b772f5c97", size = 20877075 }, - { url = "https://files.pythonhosted.org/packages/5b/2a/9b02466d6b53581b64c3fb9f6e063e2d83b549bffa7141ba10b0523ad23c/av-12.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d143d10ce726ced812eb0d4834841349027efd082c13d45a42f6914aae402ca6", size = 33536552 }, - { url = "https://files.pythonhosted.org/packages/28/fe/8b7ec1008f42942f0cb0db1f700bc4d1e862018677c32f4d47331202302e/av-12.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbe1ace6ebaae1de41f3b0412367eec42188a381fae83669d4b18e1340648839", size = 33060022 }, - { url = "https://files.pythonhosted.org/packages/ea/aa/2e74958ebb9dde8b33940fedd7ead406bd52760589cd7bcd9c19dbac3163/av-12.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8280def29f209ce294b0aa5045a66c1027b8ba2ba5b82e1f66e8a910ff1c1120", size = 35549894 }, - { url = "https://files.pythonhosted.org/packages/38/cc/437ca48e268120abab9634775d0befecee7ed54327c4df2573f2cf9f9d51/av-12.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:6740ae90ffd7fe6e7439beab6494c966cd46739943d3046ea01021d4bc2b36e6", size = 26829453 }, + { url = "https://files.pythonhosted.org/packages/5d/20/256fa4fc4ef9bb46fdc4be4662e13a30b0334487c955961f3816d94db04b/av-12.3.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:cc06a806419fddc7102150ffe353c7d96b99b95fd12864280c91c851603fd4cb", size = 24658122 }, + { url = "https://files.pythonhosted.org/packages/5d/45/a9d0475539b4f49deb34f3da558de31cefc6be867d5c0603d575a8485069/av-12.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e2130ff622a574d3d5d6e88ac335efcdd98c375bb341f87d9fe540830a746f5", size = 19923068 }, + { url = "https://files.pythonhosted.org/packages/af/27/1f2b3e46059c6618fd76ba12a96b49dc8515a426cd477032cd33f80505e8/av-12.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e8b9bd99f916ff4d1278654e94658e6ace7ca60f6321f254d09c8cd81d9095b", size = 32555100 }, + { url = "https://files.pythonhosted.org/packages/28/34/759741d397a8bdbb8a359b8b5d49832a444b26c9a7f79c0f88be76a6b979/av-12.3.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e375d1d89a5c6edfd9f66701fdb6cc9161cc1ff99d15ff0bda21ee1ad38e9e0", size = 31936355 }, + { url = "https://files.pythonhosted.org/packages/b4/6e/77426cb92117c941b0f759908bc83f34f259b11b353acb5de95972b452f7/av-12.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef9066fd8d86548e12d587cbfe7b852159e48ff3c732271c3032668d4bd7c599", size = 34416598 }, + { url = "https://files.pythonhosted.org/packages/ff/d3/4b0fddcd54d0a88ee7e035f239ebb56ce139fac8e02ee0942c43746a66ff/av-12.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:bfaa9864560e43d45d254ed95f70ab1aab24a2fa0cc35ac99eef362f1453bec0", size = 25975217 }, + { url = "https://files.pythonhosted.org/packages/e4/c1/0636bccf5a1a2c935952614b9d34d8d8aae078c9773a60efb5376702f499/av-12.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5174e995772ebe33561980dca625f830aea8d39a4338728dedb41ae7dc2605af", size = 24669628 }, + { url = "https://files.pythonhosted.org/packages/ef/7d/9126abdafe20fa73d2c19fd108450363253cfea283c350618cc1434f473c/av-12.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:028d8b40308536f740dace3efd0178eb96825b414897c9594fb74136532901cb", size = 19928928 }, + { url = "https://files.pythonhosted.org/packages/27/75/c1b9e0aa4bd0d8b8311f366b6b38f6c6600d66baddfe2888accc7f76b1f5/av-12.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b030791ecc6185776d832d19ce196f61daf3e17e591a9bb6fd181280e1754138", size = 32793461 }, + { url = "https://files.pythonhosted.org/packages/5a/06/1364c445f8a8ab4870f0f5c4530b496257ae09de7fa01b6108525abea8b9/av-12.3.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3703a35481fda5798a27bf6208c1ec3b61c18931625771fb3c9fd870539c7d7", size = 32217647 }, + { url = "https://files.pythonhosted.org/packages/27/08/220d5a1ae7e7830d66d041c71e607c1f5df2e3598b12fb406b0d7c2defa7/av-12.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32f3eef56b2df289db6105f9fe2ebc9a8134a8adbd62190daeb8e22c4ff47794", size = 34746451 }, + { url = "https://files.pythonhosted.org/packages/96/67/9f1c444864d4f3e3773100b9ed20e670f80d5575b7a8fd53cca20de9d681/av-12.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:62d036ee8321d67190887012c3dbcd1ad83248603cc29ea75fbb75835b8d6e6e", size = 25977611 }, ] [[distribution]] @@ -166,7 +166,7 @@ wheels = [ [[distribution]] name = "azure-storage-blob" -version = "12.20.0" +version = "12.21.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "azure-core" }, @@ -174,9 +174,9 @@ dependencies = [ { name = "isodate" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1b/0f/86cdaec4be486d12fd5bd2c56e835492a58d3bcd4915d24473e889b70f2c/azure-storage-blob-12.20.0.tar.gz", hash = "sha256:eeb91256e41d4b5b9bad6a87fd0a8ade07dd58aa52344e2c8d2746e27a017d3b", size = 551196 } +sdist = { url = "https://files.pythonhosted.org/packages/97/c9/0e1e864eef8071102de2d6b11dfcf8d35410735145b2fbc2e0a5f58d1490/azure-storage-blob-12.21.0.tar.gz", hash = "sha256:b9722725072f5b7373c0f4dd6d78fbae2bb37bffc5c3e01731ab8c750ee8dd7e", size = 557430 } wheels = [ - { url = "https://files.pythonhosted.org/packages/15/19/2be26569e708cb618feecd7316ee0c5475273f7cdb4f9030a862870c74c8/azure_storage_blob-12.20.0-py3-none-any.whl", hash = "sha256:de6b3bf3a90e9341a6bcb96a2ebe981dffff993e9045818f6549afea827a52a9", size = 392162 }, + { url = "https://files.pythonhosted.org/packages/f4/da/4033cee3855395e84ff73da4b50d3528f9338205299cde89676639387fcc/azure_storage_blob-12.21.0-py3-none-any.whl", hash = "sha256:f9ede187dd5a0ef296b583a7c1861c6938ddd6708d6e70f4203a163c2ab42d43", size = 396449 }, ] [[distribution]] @@ -439,36 +439,31 @@ sdist = { url = "https://files.pythonhosted.org/packages/6b/b0/e595ce2a2527e169c [[distribution]] name = "cryptography" -version = "42.0.8" +version = "43.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/93/a7/1498799a2ea06148463a9a2c10ab2f6a921a74fb19e231b27dc412a748e2/cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2", size = 671250 } +sdist = { url = "https://files.pythonhosted.org/packages/69/ec/9fb9dcf4f91f0e5e76de597256c43eedefd8423aa59be95c70c4c3db426a/cryptography-43.0.0.tar.gz", hash = "sha256:b88075ada2d51aa9f18283532c9f60e72170041bba88d7f37e49cbb10275299e", size = 686873 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/8b/1b929ba8139430e09e140e6939c2b29c18df1f2fc2149e41bdbdcdaf5d1f/cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e", size = 5899961 }, - { url = "https://files.pythonhosted.org/packages/fa/5d/31d833daa800e4fab33209843095df7adb4a78ea536929145534cbc15026/cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d", size = 3114353 }, - { url = "https://files.pythonhosted.org/packages/5d/32/f6326c70a9f0f258a201d3b2632bca586ea24d214cec3cf36e374040e273/cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902", size = 3647773 }, - { url = "https://files.pythonhosted.org/packages/35/66/2d87e9ca95c82c7ee5f2c09716fc4c4242c1ae6647b9bd27e55e920e9f10/cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801", size = 3839763 }, - { url = "https://files.pythonhosted.org/packages/c2/de/8083fa2e68d403553a01a9323f4f8b9d7ffed09928ba25635c29fb28c1e7/cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949", size = 3632661 }, - { url = "https://files.pythonhosted.org/packages/07/40/d6f6819c62e808ea74639c3c640f7edd636b86cce62cb14943996a15df92/cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9", size = 3851536 }, - { url = "https://files.pythonhosted.org/packages/5c/46/de71d48abf2b6d3c808f4fbb0f4dc44a4e72786be23df0541aa2a3f6fd7e/cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583", size = 3754209 }, - { url = "https://files.pythonhosted.org/packages/25/c9/86f04e150c5d5d5e4a731a2c1e0e43da84d901f388e3fea3d5de98d689a7/cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7", size = 3923551 }, - { url = "https://files.pythonhosted.org/packages/53/c2/903014dafb7271fb148887d4355b2e90319cad6e810663be622b0c933fc9/cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b", size = 3739265 }, - { url = "https://files.pythonhosted.org/packages/95/26/82d704d988a193cbdc69ac3b41c687c36eaed1642cce52530ad810c35645/cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7", size = 3937371 }, - { url = "https://files.pythonhosted.org/packages/cf/71/4e0d05c9acd638a225f57fb6162aa3d03613c11b76893c23ea4675bb28c5/cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2", size = 2438849 }, - { url = "https://files.pythonhosted.org/packages/06/0f/78da3cad74f2ba6c45321dc90394d70420ea846730dc042ef527f5a224b5/cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba", size = 2889090 }, - { url = "https://files.pythonhosted.org/packages/60/12/f064af29190cdb1d38fe07f3db6126091639e1dece7ec77c4ff037d49193/cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28", size = 5901232 }, - { url = "https://files.pythonhosted.org/packages/43/c2/4a3eef67e009a522711ebd8ac89424c3a7fe591ece7035d964419ad52a1d/cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e", size = 3648711 }, - { url = "https://files.pythonhosted.org/packages/49/1c/9f6d13cc8041c05eebff1154e4e71bedd1db8e174fff999054435994187a/cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70", size = 3841968 }, - { url = "https://files.pythonhosted.org/packages/5f/f9/c3d4f19b82bdb25a3d857fe96e7e571c981810e47e3f299cc13ac429066a/cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c", size = 3633032 }, - { url = "https://files.pythonhosted.org/packages/fa/e2/b7e6e8c261536c489d9cf908769880d94bd5d9a187e166b0dc838d2e6a56/cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7", size = 3852478 }, - { url = "https://files.pythonhosted.org/packages/a2/68/e16751f6b859bc120f53fddbf3ebada5c34f0e9689d8af32884d8b2e4b4c/cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e", size = 3754102 }, - { url = "https://files.pythonhosted.org/packages/0f/38/85c74d0ac4c540780e072b1e6f148ecb718418c1062edcb20d22f3ec5bbb/cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961", size = 3925042 }, - { url = "https://files.pythonhosted.org/packages/89/f4/a8b982e88eb5350407ebdbf4717b55043271d878705329e107f4783555f2/cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1", size = 3738833 }, - { url = "https://files.pythonhosted.org/packages/fd/2b/be327b580645927bb1a1f32d5a175b897a9b956bc085b095e15c40bac9ed/cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14", size = 3938751 }, - { url = "https://files.pythonhosted.org/packages/3c/d5/c6a78ffccdbe4516711ebaa9ed2c7eb6ac5dfa3dc920f2c7e920af2418b0/cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c", size = 2439281 }, - { url = "https://files.pythonhosted.org/packages/a2/7b/b0d330852dd5953daee6b15f742f15d9f18e9c0154eb4cfcc8718f0436da/cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a", size = 2886038 }, + { url = "https://files.pythonhosted.org/packages/d3/46/dcd2eb6840b9452e7fbc52720f3dc54a85eb41e68414733379e8f98e3275/cryptography-43.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:64c3f16e2a4fc51c0d06af28441881f98c5d91009b8caaff40cf3548089e9c74", size = 6239718 }, + { url = "https://files.pythonhosted.org/packages/e8/23/b0713319edff1d8633775b354f8b34a476e4dd5f4cd4b91e488baec3361a/cryptography-43.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3dcdedae5c7710b9f97ac6bba7e1052b95c7083c9d0e9df96e02a1932e777895", size = 3808466 }, + { url = "https://files.pythonhosted.org/packages/77/9d/0b98c73cebfd41e4fb0439fe9ce08022e8d059f51caa7afc8934fc1edcd9/cryptography-43.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d9a1eca329405219b605fac09ecfc09ac09e595d6def650a437523fcd08dd22", size = 3998060 }, + { url = "https://files.pythonhosted.org/packages/ae/71/e073795d0d1624847f323481f7d84855f699172a632aa37646464b0e1712/cryptography-43.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ea9e57f8ea880eeea38ab5abf9fbe39f923544d7884228ec67d666abd60f5a47", size = 3792596 }, + { url = "https://files.pythonhosted.org/packages/83/25/439a8ddd8058e7f898b7d27c36f94b66c8c8a2d60e1855d725845f4be0bc/cryptography-43.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9a8d6802e0825767476f62aafed40532bd435e8a5f7d23bd8b4f5fd04cc80ecf", size = 4008355 }, + { url = "https://files.pythonhosted.org/packages/c7/a2/1607f1295eb2c30fcf2c07d7fd0c3772d21dcdb827de2b2730b02df0af51/cryptography-43.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cc70b4b581f28d0a254d006f26949245e3657d40d8857066c2ae22a61222ef55", size = 3899133 }, + { url = "https://files.pythonhosted.org/packages/5e/64/f41f42ddc9c583737c9df0093affb92c61de7d5b0d299bf644524afe31c1/cryptography-43.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4a997df8c1c2aae1e1e5ac49c2e4f610ad037fc5a3aadc7b64e39dea42249431", size = 4096946 }, + { url = "https://files.pythonhosted.org/packages/cd/cd/d165adcf3e707d6a049d44ade6ca89973549bed0ab3686fa49efdeefea53/cryptography-43.0.0-cp37-abi3-win32.whl", hash = "sha256:6e2b11c55d260d03a8cf29ac9b5e0608d35f08077d8c087be96287f43af3ccdc", size = 2616826 }, + { url = "https://files.pythonhosted.org/packages/f9/b7/38924229e84c41b0e88d7a5eed8a29d05a44364f85fbb9ddb3984b746fd2/cryptography-43.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:31e44a986ceccec3d0498e16f3d27b2ee5fdf69ce2ab89b52eaad1d2f33d8778", size = 3078700 }, + { url = "https://files.pythonhosted.org/packages/66/d7/397515233e6a861f921bd0365b162b38e0cc513fcf4f1bdd9cc7bc5a3384/cryptography-43.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:7b3f5fe74a5ca32d4d0f302ffe6680fcc5c28f8ef0dc0ae8f40c0f3a1b4fca66", size = 6242814 }, + { url = "https://files.pythonhosted.org/packages/58/aa/99b2c00a4f54c60d210d6d1759c720ecf28305aa32d6fb1bb1853f415be6/cryptography-43.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac1955ce000cb29ab40def14fd1bbfa7af2017cca696ee696925615cafd0dce5", size = 3809467 }, + { url = "https://files.pythonhosted.org/packages/76/eb/ab783b47b3b9b55371b4361c7ec695144bde1a3343ff2b7a8c1d8fe617bb/cryptography-43.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299d3da8e00b7e2b54bb02ef58d73cd5f55fb31f33ebbf33bd00d9aa6807df7e", size = 3998617 }, + { url = "https://files.pythonhosted.org/packages/a3/62/62770f34290ebb1b6542bd3f13b3b102875b90aed4804e296f8d2a5ac6d7/cryptography-43.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ee0c405832ade84d4de74b9029bedb7b31200600fa524d218fc29bfa371e97f5", size = 3794003 }, + { url = "https://files.pythonhosted.org/packages/0f/6c/b42660b3075ff543065b2c1c5a3d9bedaadcff8ebce2ee981be2babc2934/cryptography-43.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb013933d4c127349b3948aa8aaf2f12c0353ad0eccd715ca789c8a0f671646f", size = 4008774 }, + { url = "https://files.pythonhosted.org/packages/f7/74/028cea86db9315ba3f991e307adabf9f0aa15067011137c38b2fb2aa16eb/cryptography-43.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fdcb265de28585de5b859ae13e3846a8e805268a823a12a4da2597f1f5afc9f0", size = 3900098 }, + { url = "https://files.pythonhosted.org/packages/bd/f6/e4387edb55563e2546028ba4c634522fe727693d3cdd9ec0ecacedc75411/cryptography-43.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2905ccf93a8a2a416f3ec01b1a7911c3fe4073ef35640e7ee5296754e30b762b", size = 4096867 }, + { url = "https://files.pythonhosted.org/packages/ce/61/55560405e75432bdd9f6cf72fa516cab623b83a3f6d230791bc8fc4afeee/cryptography-43.0.0-cp39-abi3-win32.whl", hash = "sha256:47ca71115e545954e6c1d207dd13461ab81f4eccfcb1345eac874828b5e3eaaf", size = 2616481 }, + { url = "https://files.pythonhosted.org/packages/e6/3d/696e7a0f04555c58a2813d47aaa78cb5ba863c1f453c74a4f45ae772b054/cryptography-43.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:0663585d02f76929792470451a5ba64424acc3cd5227b03921dab0e2f27b1709", size = 3081462 }, ] [[distribution]] @@ -1279,17 +1274,16 @@ wheels = [ [[distribution]] name = "msal" -version = "1.29.0" +version = "1.30.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, - { name = "pyjwt" }, - { name = "pyjwt", extra = "crypto" }, + { name = "pyjwt", extra = ["crypto"] }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/39/d8/438af3c52f48bab135edbd47f24447c4985ec81c122ebf36e027621f6742/msal-1.29.0.tar.gz", hash = "sha256:8f6725f099752553f9b2fe84125e2a5ebe47b49f92eacca33ebedd3a9ebaae25", size = 140817 } +sdist = { url = "https://files.pythonhosted.org/packages/03/ce/45b9af8f43fbbf34d15162e1e39ce34b675c234c56638277cc05562b6dbf/msal-1.30.0.tar.gz", hash = "sha256:b4bf00850092e465157d814efa24a18f788284c9a479491024d62903085ea2fb", size = 142510 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/a7/5b51016902118052a1342e073138a319b758020cd66f3ee79a7e98e56d62/msal-1.29.0-py3-none-any.whl", hash = "sha256:6b301e63f967481f0cc1a3a3bac0cf322b276855bc1b0955468d9deb3f33d511", size = 110860 }, + { url = "https://files.pythonhosted.org/packages/ab/82/8f19334da43b7ef72d995587991a446f140346d76edb96a2c1a2689588e9/msal-1.30.0-py3-none-any.whl", hash = "sha256:423872177410cb61683566dc3932db7a76f661a5d2f6f52f02a047f101e1c1de", size = 111760 }, ] [[distribution]] @@ -1346,25 +1340,25 @@ wheels = [ [[distribution]] name = "mypy" -version = "1.10.1" +version = "1.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mypy-extensions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c7/b9/81e4c6dbb1ec1e72503de3ff2c5fe4b7f224e04613b670f8b9004cd8a4dd/mypy-1.10.1.tar.gz", hash = "sha256:1f8f492d7db9e3593ef42d4f115f04e556130f2819ad33ab84551403e97dd4c0", size = 3022304 } +sdist = { url = "https://files.pythonhosted.org/packages/b1/95/a6dbb4fef19402c488b001ff4bd9f1a770e44049ce049b904dcffc65356c/mypy-1.11.0.tar.gz", hash = "sha256:93743608c7348772fdc717af4aeee1997293a1ad04bc0ea6efa15bf65385c538", size = 3078260 } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/cf/0645128c6edf70eb9b9687ad42fcb61ea344a7927ed2b78ce2275282fe87/mypy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd6f629b67bb43dc0d9211ee98b96d8dabc97b1ad38b9b25f5e4c4d7569a0c6a", size = 10740526 }, - { url = "https://files.pythonhosted.org/packages/19/c9/10842953066265e6063c41a85bbee3b877501947c970ea84a1db5f11d32e/mypy-1.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1bbb3a6f5ff319d2b9d40b4080d46cd639abe3516d5a62c070cf0114a457d84", size = 9898375 }, - { url = "https://files.pythonhosted.org/packages/e4/9e/551e897f67c5d67aa1976bc3b4951f297d1daf07250c421bb045b2613350/mypy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8edd4e9bbbc9d7b79502eb9592cab808585516ae1bcc1446eb9122656c6066f", size = 12602338 }, - { url = "https://files.pythonhosted.org/packages/2b/a4/55e3635253e5fa7051674dd5a67582f08b0ba8823e1fdbf7241ed5b32d4e/mypy-1.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6166a88b15f1759f94a46fa474c7b1b05d134b1b61fca627dd7335454cc9aa6b", size = 12680741 }, - { url = "https://files.pythonhosted.org/packages/7a/cc/aa881ad051f99915887db0b5de8facc0e224295be22f92178c8f77fd8359/mypy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bb9cd11c01c8606a9d0b83ffa91d0b236a0e91bc4126d9ba9ce62906ada868e", size = 9393661 }, - { url = "https://files.pythonhosted.org/packages/5d/86/3c3bdaccc3cbd1372acb15667a2c2cb773523a710a22e2748cbda9a7c1e2/mypy-1.10.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d8681909f7b44d0b7b86e653ca152d6dff0eb5eb41694e163c6092124f8246d7", size = 10864022 }, - { url = "https://files.pythonhosted.org/packages/ec/05/7c87b26b6a769b70f6c0b8a6daef01fc6f3ae566df89a2fa9d04f690b0d3/mypy-1.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:378c03f53f10bbdd55ca94e46ec3ba255279706a6aacaecac52ad248f98205d3", size = 9857795 }, - { url = "https://files.pythonhosted.org/packages/ff/b5/cbccba4dca9703c4c467171e7f61ea6a1a75eae991208aa5bc7d49807f91/mypy-1.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bacf8f3a3d7d849f40ca6caea5c055122efe70e81480c8328ad29c55c69e93e", size = 12647633 }, - { url = "https://files.pythonhosted.org/packages/02/3c/1f5e57c8cfab4299f7189821ae8bb4896e8e623a04d293fd32e32eb0e617/mypy-1.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:701b5f71413f1e9855566a34d6e9d12624e9e0a8818a5704d74d6b0402e66c04", size = 12730251 }, - { url = "https://files.pythonhosted.org/packages/f9/20/d33608e8dc3bc0f5966fc1f6c2d16671f0725dcca279beec47c3e19afd9d/mypy-1.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c4c2992f6ea46ff7fce0072642cfb62af7a2484efe69017ed8b095f7b39ef31", size = 9491734 }, - { url = "https://files.pythonhosted.org/packages/2b/ee/d53a3d4792a09b6cd757978951d6dcf8b10825a8b8522b68e9b5eb53b9a1/mypy-1.10.1-py3-none-any.whl", hash = "sha256:71d8ac0b906354ebda8ef1673e5fde785936ac1f29ff6987c7483cfbd5a4235a", size = 2580108 }, + { url = "https://files.pythonhosted.org/packages/46/69/728aca603433e52b7d2d659678f47562fead09106686a28967d978ef50b8/mypy-1.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:98790025861cb2c3db8c2f5ad10fc8c336ed2a55f4daf1b8b3f877826b6ff2eb", size = 10872601 }, + { url = "https://files.pythonhosted.org/packages/9a/fd/ba4064c7c0e3c650ef496bf6f41785eaa9091532f0ddffe47186ae24db08/mypy-1.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:25bcfa75b9b5a5f8d67147a54ea97ed63a653995a82798221cca2a315c0238c1", size = 10034398 }, + { url = "https://files.pythonhosted.org/packages/ab/43/ef3b86ac6899dc211bb1dbef79df589991e0155cc9ac05925b44fc676d86/mypy-1.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bea2a0e71c2a375c9fa0ede3d98324214d67b3cbbfcbd55ac8f750f85a414e3", size = 12418537 }, + { url = "https://files.pythonhosted.org/packages/be/3e/db067303af93fdc532b784b719e887d69d26a13ff52477c65304555c3198/mypy-1.11.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d2b3d36baac48e40e3064d2901f2fbd2a2d6880ec6ce6358825c85031d7c0d4d", size = 12895138 }, + { url = "https://files.pythonhosted.org/packages/4b/56/a1ac65714ee33a35d9f1b6173b8c989c05120cb386dbbe6709ba4cc7a9e4/mypy-1.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:d8e2e43977f0e09f149ea69fd0556623919f816764e26d74da0c8a7b48f3e18a", size = 9562630 }, + { url = "https://files.pythonhosted.org/packages/ad/f2/656171fddcfc81527f6c1a8c9550896999e7f7da9606aae1ffde2518f0c7/mypy-1.11.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1d44c1e44a8be986b54b09f15f2c1a66368eb43861b4e82573026e04c48a9e20", size = 11002476 }, + { url = "https://files.pythonhosted.org/packages/70/c9/a906c097dddacbcc52068196db1f3c6ecf636b039dd002baf9ffe6904e99/mypy-1.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cea3d0fb69637944dd321f41bc896e11d0fb0b0aa531d887a6da70f6e7473aba", size = 10001386 }, + { url = "https://files.pythonhosted.org/packages/5d/3a/9cb76b2fca4fb4a3aafa9f6f487c873360f3c6a1b2d05fedaa19ba681f28/mypy-1.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a83ec98ae12d51c252be61521aa5731f5512231d0b738b4cb2498344f0b840cd", size = 12505911 }, + { url = "https://files.pythonhosted.org/packages/08/87/47fe67de644f2eefce265425742e439206653c7d7abf589a9db7adda2c16/mypy-1.11.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c7b73a856522417beb78e0fb6d33ef89474e7a622db2653bc1285af36e2e3e3d", size = 12952479 }, + { url = "https://files.pythonhosted.org/packages/05/80/aa7b8d066bce6fe07f9b7fab2e557f428e22eff417481ffe065378275402/mypy-1.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:f2268d9fcd9686b61ab64f077be7ffbc6fbcdfb4103e5dd0cc5eaab53a8886c2", size = 9662673 }, + { url = "https://files.pythonhosted.org/packages/ce/0e/fc28db5d225623cbbca54d9f4207a3ebf4937d816ba4b61aa3a5ad2af2e7/mypy-1.11.0-py3-none-any.whl", hash = "sha256:56913ec8c7638b0091ef4da6fcc9136896914a9d60d54670a75880c3e5b99ace", size = 2619149 }, ] [[distribution]] @@ -1834,27 +1828,27 @@ wheels = [ [[distribution]] name = "pyarrow" -version = "16.1.0" +version = "17.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1a/f2/67533f116deb6dae7a0ac04681695fe06135912253a115c5ecdc714a32d4/pyarrow-16.1.0.tar.gz", hash = "sha256:15fbb22ea96d11f0b5768504a3f961edab25eaf4197c341720c4a387f6c60315", size = 1080280 } +sdist = { url = "https://files.pythonhosted.org/packages/27/4e/ea6d43f324169f8aec0e57569443a38bab4b398d09769ca64f7b4d467de3/pyarrow-17.0.0.tar.gz", hash = "sha256:4beca9521ed2c0921c1023e68d097d0299b62c362639ea315572a58f3f50fd28", size = 1112479 } wheels = [ - { url = "https://files.pythonhosted.org/packages/28/17/a12aaddb818b7b73d17f3304afc22bce32ccb26723b507cc9c267aa809f3/pyarrow-16.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:d0ebea336b535b37eee9eee31761813086d33ed06de9ab6fc6aaa0bace7b250c", size = 28380406 }, - { url = "https://files.pythonhosted.org/packages/f3/94/4e2a579bbac1adb19e63b054b300f6f7fa04f32f212ce86c18727bdda698/pyarrow-16.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e73cfc4a99e796727919c5541c65bb88b973377501e39b9842ea71401ca6c1c", size = 26040531 }, - { url = "https://files.pythonhosted.org/packages/7e/34/d5b6eb5066553533dd6eb9782d50f353f8c6451ee2e49e0ea54d0e67bc34/pyarrow-16.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf9251264247ecfe93e5f5a0cd43b8ae834f1e61d1abca22da55b20c788417f6", size = 38666685 }, - { url = "https://files.pythonhosted.org/packages/d2/34/4e3c04e7398764e56ef00f8f267f8ebf565808478f5fee850cef4be670c3/pyarrow-16.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddf5aace92d520d3d2a20031d8b0ec27b4395cab9f74e07cc95edf42a5cc0147", size = 40949577 }, - { url = "https://files.pythonhosted.org/packages/47/62/b446ee0971b00e7437b9c54a8409ae20413235a64c0a301d7cf97070cffa/pyarrow-16.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:25233642583bf658f629eb230b9bb79d9af4d9f9229890b3c878699c82f7d11e", size = 38077480 }, - { url = "https://files.pythonhosted.org/packages/fa/15/48a68b30542a0231a75c26d8661bc5c9bbc07b42c5b219e929adba814ba7/pyarrow-16.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a33a64576fddfbec0a44112eaf844c20853647ca833e9a647bfae0582b2ff94b", size = 40821141 }, - { url = "https://files.pythonhosted.org/packages/49/4d/62a09116ec357ade462fac4086e0711457a87177bea25ae46b25897d6d7c/pyarrow-16.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:185d121b50836379fe012753cf15c4ba9638bda9645183ab36246923875f8d1b", size = 25889334 }, - { url = "https://files.pythonhosted.org/packages/84/bd/d5903125e38c33b74f7b3d57ffffd4ef48145208cfd8742367f12effb59c/pyarrow-16.1.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:2e51ca1d6ed7f2e9d5c3c83decf27b0d17bb207a7dea986e8dc3e24f80ff7d6f", size = 28372822 }, - { url = "https://files.pythonhosted.org/packages/9b/73/560ef6bf05f16305502b8e368c771e8f82d774898b37a3fb231f89c13342/pyarrow-16.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06ebccb6f8cb7357de85f60d5da50e83507954af617d7b05f48af1621d331c9a", size = 26004052 }, - { url = "https://files.pythonhosted.org/packages/56/5e/3cd956aceb1c960e8ac6fdc6eea69d642aa2e6ee10e2f10ce7815dbf62a9/pyarrow-16.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b04707f1979815f5e49824ce52d1dceb46e2f12909a48a6a753fe7cafbc44a0c", size = 38660648 }, - { url = "https://files.pythonhosted.org/packages/08/4a/668e7fb6bc564e5361097f1f160b2891ca40bcacfe018638e2841073ec3d/pyarrow-16.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d32000693deff8dc5df444b032b5985a48592c0697cb6e3071a5d59888714e2", size = 40961053 }, - { url = "https://files.pythonhosted.org/packages/f7/8f/a51a290a855172514b8496c8a74f0e0b98e5e0582d44ae7547cf68dd033b/pyarrow-16.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8785bb10d5d6fd5e15d718ee1d1f914fe768bf8b4d1e5e9bf253de8a26cb1628", size = 38060675 }, - { url = "https://files.pythonhosted.org/packages/25/7b/8da91f8de0b40b760dd748031973b6ac2aa3d4f85c67f45b7e58577ca22e/pyarrow-16.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e1369af39587b794873b8a307cc6623a3b1194e69399af0efd05bb202195a5a7", size = 40826735 }, - { url = "https://files.pythonhosted.org/packages/fa/2b/a0053f1304586f2976cb2c37ddb0e52cf4114220e805ebba272a1e231ccc/pyarrow-16.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:febde33305f1498f6df85e8020bca496d0e9ebf2093bab9e0f65e2b4ae2b3444", size = 25838156 }, + { url = "https://files.pythonhosted.org/packages/f9/46/ce89f87c2936f5bb9d879473b9663ce7a4b1f4359acc2f0eb39865eaa1af/pyarrow-17.0.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:1c8856e2ef09eb87ecf937104aacfa0708f22dfeb039c363ec99735190ffb977", size = 29028748 }, + { url = "https://files.pythonhosted.org/packages/8d/8e/ce2e9b2146de422f6638333c01903140e9ada244a2a477918a368306c64c/pyarrow-17.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e19f569567efcbbd42084e87f948778eb371d308e137a0f97afe19bb860ccb3", size = 27190965 }, + { url = "https://files.pythonhosted.org/packages/3b/c8/5675719570eb1acd809481c6d64e2136ffb340bc387f4ca62dce79516cea/pyarrow-17.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b244dc8e08a23b3e352899a006a26ae7b4d0da7bb636872fa8f5884e70acf15", size = 39269081 }, + { url = "https://files.pythonhosted.org/packages/5e/78/3931194f16ab681ebb87ad252e7b8d2c8b23dad49706cadc865dff4a1dd3/pyarrow-17.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b72e87fe3e1db343995562f7fff8aee354b55ee83d13afba65400c178ab2597", size = 39864921 }, + { url = "https://files.pythonhosted.org/packages/d8/81/69b6606093363f55a2a574c018901c40952d4e902e670656d18213c71ad7/pyarrow-17.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:dc5c31c37409dfbc5d014047817cb4ccd8c1ea25d19576acf1a001fe07f5b420", size = 38740798 }, + { url = "https://files.pythonhosted.org/packages/4c/21/9ca93b84b92ef927814cb7ba37f0774a484c849d58f0b692b16af8eebcfb/pyarrow-17.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e3343cb1e88bc2ea605986d4b94948716edc7a8d14afd4e2c097232f729758b4", size = 39871877 }, + { url = "https://files.pythonhosted.org/packages/30/d1/63a7c248432c71c7d3ee803e706590a0b81ce1a8d2b2ae49677774b813bb/pyarrow-17.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:a27532c38f3de9eb3e90ecab63dfda948a8ca859a66e3a47f5f42d1e403c4d03", size = 25151089 }, + { url = "https://files.pythonhosted.org/packages/d4/62/ce6ac1275a432b4a27c55fe96c58147f111d8ba1ad800a112d31859fae2f/pyarrow-17.0.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:9b8a823cea605221e61f34859dcc03207e52e409ccf6354634143e23af7c8d22", size = 29019418 }, + { url = "https://files.pythonhosted.org/packages/8e/0a/dbd0c134e7a0c30bea439675cc120012337202e5fac7163ba839aa3691d2/pyarrow-17.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f1e70de6cb5790a50b01d2b686d54aaf73da01266850b05e3af2a1bc89e16053", size = 27152197 }, + { url = "https://files.pythonhosted.org/packages/cb/05/3f4a16498349db79090767620d6dc23c1ec0c658a668d61d76b87706c65d/pyarrow-17.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0071ce35788c6f9077ff9ecba4858108eebe2ea5a3f7cf2cf55ebc1dbc6ee24a", size = 39263026 }, + { url = "https://files.pythonhosted.org/packages/c2/0c/ea2107236740be8fa0e0d4a293a095c9f43546a2465bb7df34eee9126b09/pyarrow-17.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:757074882f844411fcca735e39aae74248a1531367a7c80799b4266390ae51cc", size = 39880798 }, + { url = "https://files.pythonhosted.org/packages/f6/b0/b9164a8bc495083c10c281cc65064553ec87b7537d6f742a89d5953a2a3e/pyarrow-17.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:9ba11c4f16976e89146781a83833df7f82077cdab7dc6232c897789343f7891a", size = 38715172 }, + { url = "https://files.pythonhosted.org/packages/f1/c4/9625418a1413005e486c006e56675334929fad864347c5ae7c1b2e7fe639/pyarrow-17.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b0c6ac301093b42d34410b187bba560b17c0330f64907bfa4f7f7f2444b0cf9b", size = 39874508 }, + { url = "https://files.pythonhosted.org/packages/ae/49/baafe2a964f663413be3bd1cf5c45ed98c5e42e804e2328e18f4570027c1/pyarrow-17.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:392bc9feabc647338e6c89267635e111d71edad5fcffba204425a7c8d13610d7", size = 25099235 }, ] [[distribution]] @@ -4581,14 +4575,14 @@ wheels = [ [[distribution]] name = "pyopenssl" -version = "24.1.0" +version = "24.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/91/a8/cbeec652549e30103b9e6147ad433405fdd18807ac2d54e6dbb73184d8a1/pyOpenSSL-24.1.0.tar.gz", hash = "sha256:cabed4bfaa5df9f1a16c0ef64a0cb65318b5cd077a7eda7d6970131ca2f41a6f", size = 179671 } +sdist = { url = "https://files.pythonhosted.org/packages/5d/70/ff56a63248562e77c0c8ee4aefc3224258f1856977e0c1472672b62dadb8/pyopenssl-24.2.1.tar.gz", hash = "sha256:4247f0dbe3748d560dcbb2ff3ea01af0f9a1a001ef5f7c4c647956ed8cbf0e95", size = 184323 } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/a7/2104f674a5a6845b04c8ff01659becc6b8978ca410b82b94287e0b1e018b/pyOpenSSL-24.1.0-py3-none-any.whl", hash = "sha256:17ed5be5936449c5418d1cd269a1a9e9081bc54c17aed272b45856a3d3dc86ad", size = 56945 }, + { url = "https://files.pythonhosted.org/packages/d9/dd/e0aa7ebef5168c75b772eda64978c597a9129b46be17779054652a7999e4/pyOpenSSL-24.2.1-py3-none-any.whl", hash = "sha256:967d5719b12b243588573f39b0c677637145c7a1ffedcd495a487e58177fbb8d", size = 58390 }, ] [[distribution]] @@ -4699,7 +4693,7 @@ wheels = [ [[distribution]] name = "pytest" -version = "8.2.2" +version = "8.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -4707,21 +4701,21 @@ dependencies = [ { name = "packaging" }, { name = "pluggy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/58/e993ca5357553c966b9e73cb3475d9c935fe9488746e13ebdf9b80fae508/pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977", size = 1427980 } +sdist = { url = "https://files.pythonhosted.org/packages/bc/7f/a6f79e033aa8318b6dfe2173fa6409ee75dafccf409d90884bf921433d88/pytest-8.3.1.tar.gz", hash = "sha256:7e8e5c5abd6e93cb1cc151f23e57adc31fcf8cfd2a3ff2da63e23f732de35db6", size = 1438997 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/e7/81ebdd666d3bff6670d27349b5053605d83d55548e6bd5711f3b0ae7dd23/pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", size = 339873 }, + { url = "https://files.pythonhosted.org/packages/b9/77/ccea391104f576a6e54a54334fc26d29c28aa0ec85714c781fbd2c34ac86/pytest-8.3.1-py3-none-any.whl", hash = "sha256:e9600ccf4f563976e2c99fa02c7624ab938296551f280835ee6516df8bc4ae8c", size = 341628 }, ] [[distribution]] name = "pytest-asyncio" -version = "0.23.7" +version = "0.23.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/13/d9/1dcac9b3fc6eccf8f1e3a657439c11ffc5cf762edd20f65577f832ba248b/pytest_asyncio-0.23.7.tar.gz", hash = "sha256:5f5c72948f4c49e7db4f29f2521d4031f1c27f86e57b046126654083d4770268", size = 46296 } +sdist = { url = "https://files.pythonhosted.org/packages/de/b4/0b378b7bf26a8ae161c3890c0b48a91a04106c5713ce81b4b080ea2f4f18/pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3", size = 46920 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/98/947690b1a79af83e584143cb904497caff05bb6016614b38326a81076357/pytest_asyncio-0.23.7-py3-none-any.whl", hash = "sha256:009b48127fbe44518a547bddd25611551b0e43ccdbf1e67d12479f569832c20b", size = 17585 }, + { url = "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl", hash = "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2", size = 17663 }, ] [[distribution]] @@ -4788,15 +4782,15 @@ wheels = [ [[distribution]] name = "pytest-subtests" -version = "0.13.0" +version = "0.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/95/be/cebc1b9f6358d174443f46737979e244048a385fe2b0be6fab2b96771dc5/pytest_subtests-0.13.0.tar.gz", hash = "sha256:9e02b9d243c0379b02abf3e0887da122bcb2714b021c3608a37f17ce210adce5", size = 15842 } +sdist = { url = "https://files.pythonhosted.org/packages/67/fe/e691d2f4ce061a475f488cad1ef58431556affea323dde5c764fd7515a70/pytest_subtests-0.13.1.tar.gz", hash = "sha256:989e38f0f1c01bc7c6b2e04db7d9fd859db35d77c2c1a430c831a70cbf3fde2d", size = 15936 } wheels = [ - { url = "https://files.pythonhosted.org/packages/74/19/9fd9ff6e8827983bcfc74a39c4a98ab6b4c32b3f3403b917f352f7b83777/pytest_subtests-0.13.0-py3-none-any.whl", hash = "sha256:5a142064218df37a52299ddb393b1a6b2c1161ca19e71ca60c3a8040eb17e811", size = 8038 }, + { url = "https://files.pythonhosted.org/packages/f5/ac/fc132cb88e8f2042cebcb6ef0ffac40017c514fbadf3931e0b4bcb4bdfb6/pytest_subtests-0.13.1-py3-none-any.whl", hash = "sha256:ab616a22f64cd17c1aee65f18af94dbc30c444f8683de2b30895c3778265e3bd", size = 8038 }, ] [[distribution]] @@ -4856,15 +4850,16 @@ sdist = { url = "https://files.pythonhosted.org/packages/ef/c6/2c5999de3bb153352 [[distribution]] name = "pytools" -version = "2024.1.8" +version = "2024.1.10" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "platformdirs" }, { name = "siphash24" }, + { name = "typing-extensions", marker = "python_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c0/0a/33961bdb345c0621f2883e6c192f05116fe7e4871700eb2100d3e37d152a/pytools-2024.1.8.tar.gz", hash = "sha256:cccc184a10af56dabab3077af82ab0cf7a5b06625313cae0b2f06a3c4b126001", size = 82220 } +sdist = { url = "https://files.pythonhosted.org/packages/ee/0f/56e109c0307f831b5d598ad73976aaaa84b4d0e98da29a642e797eaa940c/pytools-2024.1.10.tar.gz", hash = "sha256:9af6f4b045212c49be32bb31fe19606c478ee4b09631886d05a32459f4ce0a12", size = 81741 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/ea/fa3124d613e07ee93aaf1ec38b846c712a25eda3035af20ae2e7cd5927e5/pytools-2024.1.8-py3-none-any.whl", hash = "sha256:3fe89cf182e97d16842de78f2b08c009030c895c4e1496e96e3679664cf2bd3b", size = 88527 }, + { url = "https://files.pythonhosted.org/packages/66/cf/0a6aaa44b1f9e02b8c0648b5665a82246a93bcc75224c167b4fafa25c093/pytools-2024.1.10-py3-none-any.whl", hash = "sha256:9cabb71038048291400e244e2da441a051d86053339bc484e64e58d8ea263f44", size = 88108 }, ] [[distribution]] @@ -5042,27 +5037,27 @@ wheels = [ [[distribution]] name = "ruff" -version = "0.5.2" +version = "0.5.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/6c/147f04f6a799f659cc810352742994e51441b14c7a5621e285d021261388/ruff-0.5.2.tar.gz", hash = "sha256:2c0df2d2de685433794a14d8d2e240df619b748fbe3367346baa519d8e6f1ca2", size = 2596910 } +sdist = { url = "https://files.pythonhosted.org/packages/8e/1a/5955fa22ab088c1f4d8458b4cbc158c6db72143361e8d46e179c48576aab/ruff-0.5.4.tar.gz", hash = "sha256:2795726d5f71c4f4e70653273d1c23a8182f07dd8e48c12de5d867bfb7557eed", size = 2424702 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/05/9ec81c397be41596e4329b340780d56bfa9ad1cb95247148bf9859edf575/ruff-0.5.2-py3-none-linux_armv6l.whl", hash = "sha256:7bab8345df60f9368d5f4594bfb8b71157496b44c30ff035d1d01972e764d3be", size = 9482764 }, - { url = "https://files.pythonhosted.org/packages/f3/ea/ebf3ea51ad48abfc6e0bbb762e71b0ffc6220a6fb8735cb09bd5aca7c52e/ruff-0.5.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1aa7acad382ada0189dbe76095cf0a36cd0036779607c397ffdea16517f535b1", size = 8612665 }, - { url = "https://files.pythonhosted.org/packages/0f/52/9e7868770615c16be60549746ad6f48f483320f7ecf5a294f4f051f4e7d4/ruff-0.5.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:aec618d5a0cdba5592c60c2dee7d9c865180627f1a4a691257dea14ac1aa264d", size = 8191223 }, - { url = "https://files.pythonhosted.org/packages/7a/9d/c880e41895b9bc48bf7051c81bcf270d2f6eebdce3c8f02c72fdef582d20/ruff-0.5.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b62adc5ce81780ff04077e88bac0986363e4a3260ad3ef11ae9c14aa0e67ef", size = 9972748 }, - { url = "https://files.pythonhosted.org/packages/0c/0b/17a0730f425f7f630446978b880ac0ad62a7c7e20fb4e21d2ab0a5154887/ruff-0.5.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dc42ebf56ede83cb080a50eba35a06e636775649a1ffd03dc986533f878702a3", size = 9289379 }, - { url = "https://files.pythonhosted.org/packages/67/c4/1dcdc4a381aa07509d15dd78ec65e8fedd14c0a70a674ca3bbafa48502ed/ruff-0.5.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c15c6e9f88c67ffa442681365d11df38afb11059fc44238e71a9d9f1fd51de70", size = 10087604 }, - { url = "https://files.pythonhosted.org/packages/a8/fc/2707aa15de9e2485f024535b0fe239013d1be13bb475050f3e21b33109c9/ruff-0.5.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d3de9a5960f72c335ef00763d861fc5005ef0644cb260ba1b5a115a102157251", size = 10875118 }, - { url = "https://files.pythonhosted.org/packages/ef/db/4890a8c350b3fad767c663991052ba5ce42feae05f433fbf73acc3d1e8c3/ruff-0.5.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe5a968ae933e8f7627a7b2fc8893336ac2be0eb0aace762d3421f6e8f7b7f83", size = 10464801 }, - { url = "https://files.pythonhosted.org/packages/d5/30/0018669eb5a0bfd42d4be1d961fa4533bba1926ba83b8cf3e50223ee7d21/ruff-0.5.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a04f54a9018f75615ae52f36ea1c5515e356e5d5e214b22609ddb546baef7132", size = 11356413 }, - { url = "https://files.pythonhosted.org/packages/ec/60/e2a9ae058b34128caa5f863f268e1c9bd083793264f4bf7e8e469be651f9/ruff-0.5.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed02fb52e3741f0738db5f93e10ae0fb5c71eb33a4f2ba87c9a2fa97462a649", size = 10123340 }, - { url = "https://files.pythonhosted.org/packages/1c/fd/83b9f0107f5d0eea1c4b3a98655d789586d8e2662819df011a7964efa675/ruff-0.5.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3cf8fe659f6362530435d97d738eb413e9f090e7e993f88711b0377fbdc99f60", size = 9940668 }, - { url = "https://files.pythonhosted.org/packages/11/75/2a98e9348bed95e0a121c3e1693c335530ef70280a364cf17f1d2da947cd/ruff-0.5.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:237a37e673e9f3cbfff0d2243e797c4862a44c93d2f52a52021c1a1b0899f846", size = 9380450 }, - { url = "https://files.pythonhosted.org/packages/0e/77/474f883393954f2323febd5cf7c96bfe8c684561f8d22ca843e90d122d73/ruff-0.5.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2a2949ce7c1cbd8317432ada80fe32156df825b2fd611688814c8557824ef060", size = 9718297 }, - { url = "https://files.pythonhosted.org/packages/b2/5a/72b3a1ddefbc7ccb382bcf9668648a6f1fdc4bfcc3d6687f14e6feb40636/ruff-0.5.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:481af57c8e99da92ad168924fd82220266043c8255942a1cb87958b108ac9335", size = 10221735 }, - { url = "https://files.pythonhosted.org/packages/bc/22/7aa3fb2b95dda4d485e5e5f15041679d3170a31b9317b24c6182f4c8faf1/ruff-0.5.2-py3-none-win32.whl", hash = "sha256:f1aea290c56d913e363066d83d3fc26848814a1fed3d72144ff9c930e8c7c718", size = 7786506 }, - { url = "https://files.pythonhosted.org/packages/a8/a0/f28c8380f4eff7451896618ca0cce097e65aef150c60c298a0b5c9f40311/ruff-0.5.2-py3-none-win_amd64.whl", hash = "sha256:8532660b72b5d94d2a0a7a27ae7b9b40053662d00357bb2a6864dd7e38819084", size = 8583643 }, - { url = "https://files.pythonhosted.org/packages/b5/c3/dd06a34c98fc887a8c027e1b17e7ceca479db98b24d3a2d98f8239f0ee71/ruff-0.5.2-py3-none-win_arm64.whl", hash = "sha256:73439805c5cb68f364d826a5c5c4b6c798ded6b7ebaa4011f01ce6c94e4d5583", size = 8012737 }, + { url = "https://files.pythonhosted.org/packages/5b/34/2235ecce6794345f42ad334d1b14384c70b202f77509e5678b68a640fe78/ruff-0.5.4-py3-none-linux_armv6l.whl", hash = "sha256:82acef724fc639699b4d3177ed5cc14c2a5aacd92edd578a9e846d5b5ec18ddf", size = 9499774 }, + { url = "https://files.pythonhosted.org/packages/11/23/ffe51028ba274223191d3f96b059108cf7690eb93985a7fdb077c3d1191b/ruff-0.5.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:da62e87637c8838b325e65beee485f71eb36202ce8e3cdbc24b9fcb8b99a37be", size = 8550240 }, + { url = "https://files.pythonhosted.org/packages/28/75/843aa3d10a39ab60fbd63f65c825f647907a9732ac27e24d3f94dd2db618/ruff-0.5.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e98ad088edfe2f3b85a925ee96da652028f093d6b9b56b76fc242d8abb8e2059", size = 8160520 }, + { url = "https://files.pythonhosted.org/packages/19/88/3d0f5244905088cc2fd136fae8ce81f46d145e2449051313c462032d144d/ruff-0.5.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c55efbecc3152d614cfe6c2247a3054cfe358cefbf794f8c79c8575456efe19", size = 9911606 }, + { url = "https://files.pythonhosted.org/packages/1f/ff/6546020836408351e7558dedacc6e5ca7f652f76a9d05ac4882c787d45b1/ruff-0.5.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9b85eaa1f653abd0a70603b8b7008d9e00c9fa1bbd0bf40dad3f0c0bdd06793", size = 9286353 }, + { url = "https://files.pythonhosted.org/packages/b6/bf/51e0c5f12a9bf3c7596cf7f45e1b102f8b49f1da39943e03739890bbf6a4/ruff-0.5.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cf497a47751be8c883059c4613ba2f50dd06ec672692de2811f039432875278", size = 10082929 }, + { url = "https://files.pythonhosted.org/packages/b5/0e/a44cb6edb629788de892fc7bb8ac8b47059df94d7ec9c4e52e04bab5be95/ruff-0.5.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:09c14ed6a72af9ccc8d2e313d7acf7037f0faff43cde4b507e66f14e812e37f7", size = 10832586 }, + { url = "https://files.pythonhosted.org/packages/97/ca/e3810f701ae472e5fe3180d56fe6fcc92ea94c7490097a0f731f5602f26f/ruff-0.5.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:628f6b8f97b8bad2490240aa84f3e68f390e13fabc9af5c0d3b96b485921cd60", size = 10421967 }, + { url = "https://files.pythonhosted.org/packages/01/47/a62df6ccd6e5d019271df203ea6564f2022c49f85c0bf6ada708cd7b4a5e/ruff-0.5.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3520a00c0563d7a7a7c324ad7e2cde2355733dafa9592c671fb2e9e3cd8194c1", size = 11371031 }, + { url = "https://files.pythonhosted.org/packages/a1/02/64f24893eea23c447460e6509e9dd0ae18d7a797f67fee1bafed964ebbae/ruff-0.5.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93789f14ca2244fb91ed481456f6d0bb8af1f75a330e133b67d08f06ad85b516", size = 10103164 }, + { url = "https://files.pythonhosted.org/packages/ca/78/683b6c6976fcc33e4a03a0e234e0b9f9b8682f807a661225c829b248de82/ruff-0.5.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:029454e2824eafa25b9df46882f7f7844d36fd8ce51c1b7f6d97e2615a57bbcc", size = 9920056 }, + { url = "https://files.pythonhosted.org/packages/78/3a/6c67c5d670aae2a51a11713aff819d729ed92cb0b1d962b8df27e4657650/ruff-0.5.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9492320eed573a13a0bc09a2957f17aa733fff9ce5bf00e66e6d4a88ec33813f", size = 9361286 }, + { url = "https://files.pythonhosted.org/packages/0d/f5/da3a0e2fd0bcbdb3d2ff579ef9cb3ca2af71b9bee97fa917c9a9e0500b67/ruff-0.5.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a6e1f62a92c645e2919b65c02e79d1f61e78a58eddaebca6c23659e7c7cb4ac7", size = 9720829 }, + { url = "https://files.pythonhosted.org/packages/4a/56/5062119a5c9e06d98cd6406bfc1eab7616a7c67494a4d05b6052d99dd147/ruff-0.5.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:768fa9208df2bec4b2ce61dbc7c2ddd6b1be9fb48f1f8d3b78b3332c7d71c1ff", size = 10143530 }, + { url = "https://files.pythonhosted.org/packages/e6/76/16f8f1c8d0cba6c96ab6f292146fc0acb6dd633a989f524d3b3ef1ee8364/ruff-0.5.4-py3-none-win32.whl", hash = "sha256:e1e7393e9c56128e870b233c82ceb42164966f25b30f68acbb24ed69ce9c3a4e", size = 7794271 }, + { url = "https://files.pythonhosted.org/packages/82/35/d6c3c83fb8817328db73c15b1836ccb0c3ce56b72d0d01d98b3a452bec58/ruff-0.5.4-py3-none-win_amd64.whl", hash = "sha256:58b54459221fd3f661a7329f177f091eb35cf7a603f01d9eb3eb11cc348d38c4", size = 8579021 }, + { url = "https://files.pythonhosted.org/packages/3c/ef/3e732c0152280775f728ab99691c718ee9a4ae79bf5af1dd9258f7fe7fef/ruff-0.5.4-py3-none-win_arm64.whl", hash = "sha256:bd53da65f1085fb5b307c38fd3c0829e76acf7b2a912d8d79cadcdb4875c1eb7", size = 8034239 }, ] [[distribution]] @@ -5130,11 +5125,11 @@ wheels = [ [[distribution]] name = "setuptools" -version = "70.3.0" +version = "71.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/d8/10a70e86f6c28ae59f101a9de6d77bf70f147180fbf40c3af0f64080adc3/setuptools-70.3.0.tar.gz", hash = "sha256:f171bab1dfbc86b132997f26a119f6056a57950d058587841a0082e8830f9dc5", size = 2333112 } +sdist = { url = "https://files.pythonhosted.org/packages/32/c0/5b8013b5a812701c72e3b1e2b378edaa6514d06bee6704a5ab0d7fa52931/setuptools-71.1.0.tar.gz", hash = "sha256:032d42ee9fb536e33087fb66cac5f840eb9391ed05637b3f2a76a7c8fb477936", size = 2422233 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/15/88e46eb9387e905704b69849618e699dc2f54407d8953cc4ec4b8b46528d/setuptools-70.3.0-py3-none-any.whl", hash = "sha256:fe384da74336c398e0d956d1cae0669bc02eed936cdb1d49b57de1990dc11ffc", size = 931070 }, + { url = "https://files.pythonhosted.org/packages/51/a0/ee460cc54e68afcf33190d198299c9579a5eafeadef0016ae8563237ccb6/setuptools-71.1.0-py3-none-any.whl", hash = "sha256:33874fdc59b3188304b2e7c80d9029097ea31627180896fb549c578ceb8a0855", size = 2341722 }, ] [[distribution]] @@ -5233,7 +5228,7 @@ wheels = [ [[distribution]] name = "sphinx" -version = "7.4.3" +version = "7.4.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "alabaster" }, @@ -5253,9 +5248,9 @@ dependencies = [ { name = "sphinxcontrib-qthelp" }, { name = "sphinxcontrib-serializinghtml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/7a/bc303eb950025a2cfa8f6968471fda8b28e8114621e2ab43f518094a4225/sphinx-7.4.3.tar.gz", hash = "sha256:bd846bcb09fd2b6e94ce3e1ad50f4618bccf03cc7c17d0f3fa87393c0bd9178b", size = 8113870 } +sdist = { url = "https://files.pythonhosted.org/packages/5b/be/50e50cb4f2eff47df05673d361095cafd95521d2a22521b920c67a372dcb/sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe", size = 8067911 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c9/b8/8594be28e66d19c287c13dbc609a7695e5330ea59abce654a3f41b8a589e/sphinx-7.4.3-py3-none-any.whl", hash = "sha256:a3c295d0e8be6277e0a5ba5c6909a308bd208876b0f4f68c7cc591f566129412", size = 3454542 }, + { url = "https://files.pythonhosted.org/packages/0d/ef/153f6803c5d5f8917dbb7f7fcf6d34a871ede3296fa89c2c703f5f8a6c8e/sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239", size = 3401624 }, ] [[distribution]] @@ -5278,11 +5273,11 @@ wheels = [ [[distribution]] name = "sphinxcontrib-htmlhelp" -version = "2.0.5" +version = "2.0.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/03/2f9d699fbfdf03ecb3b6d0e2a268a8998d009f2a9f699c2dcc936899257d/sphinxcontrib_htmlhelp-2.0.5.tar.gz", hash = "sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015", size = 21925 } +sdist = { url = "https://files.pythonhosted.org/packages/92/d9/a1c50c8a7b5e12f34bf4d63300a1e2629c29b71603115d900c0fa7c79219/sphinxcontrib_htmlhelp-2.0.6.tar.gz", hash = "sha256:c6597da06185f0e3b4dc952777a04200611ef563882e0c244d27a15ee22afa73", size = 21957 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/e9/74c4cda5b409af3222fda38f0774e616011bc935f639dbc0da5ca2d1be7d/sphinxcontrib_htmlhelp-2.0.5-py3-none-any.whl", hash = "sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04", size = 99217 }, + { url = "https://files.pythonhosted.org/packages/a4/b4/6ebbdc57b5b216b400b355f34ef669e9b6b5c31a6ede8cf5ac36f9e8fc0c/sphinxcontrib_htmlhelp-2.0.6-py3-none-any.whl", hash = "sha256:1b9af5a2671a61410a868fce050cab7ca393c218e6205cbc7f590136f207395c", size = 99225 }, ] [[distribution]] @@ -5296,11 +5291,11 @@ wheels = [ [[distribution]] name = "sphinxcontrib-qthelp" -version = "1.0.7" +version = "1.0.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ac/29/705cd4e93e98a8473d62b5c32288e6de3f0c9660d3c97d4e80d3dbbad82b/sphinxcontrib_qthelp-1.0.7.tar.gz", hash = "sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6", size = 16685 } +sdist = { url = "https://files.pythonhosted.org/packages/a6/67/f5c7df6457315877202f370450acb28626d033822eec1e8163600612b4ef/sphinxcontrib_qthelp-1.0.8.tar.gz", hash = "sha256:db3f8fa10789c7a8e76d173c23364bdf0ebcd9449969a9e6a3dd31b8b7469f03", size = 16778 } wheels = [ - { url = "https://files.pythonhosted.org/packages/80/b3/1beac14a88654d2e5120d0143b49be5ad450b86eb1963523d8dbdcc51eb2/sphinxcontrib_qthelp-1.0.7-py3-none-any.whl", hash = "sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182", size = 89441 }, + { url = "https://files.pythonhosted.org/packages/cf/91/cec9416d27ebe9b8aa83f014a1ac8402c729aed791da67704e10bb2c8f33/sphinxcontrib_qthelp-1.0.8-py3-none-any.whl", hash = "sha256:323d6acc4189af76dfe94edd2a27d458902319b60fcca2aeef3b2180c106a75f", size = 89456 }, ] [[distribution]] @@ -5320,14 +5315,14 @@ sdist = { url = "https://files.pythonhosted.org/packages/c7/d9/401c0a7be089e0282 [[distribution]] name = "sympy" -version = "1.13.0" +version = "1.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mpmath" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cb/f5/8c7d91ce35816b72c2dd061dc4a33f00f59053aeffe881d42aed17279381/sympy-1.13.0.tar.gz", hash = "sha256:3b6af8f4d008b9a1a6a4268b335b984b23835f26d1d60b0526ebc71d48a25f57", size = 7532455 } +sdist = { url = "https://files.pythonhosted.org/packages/ca/99/5a5b6f19ff9f083671ddf7b9632028436167cd3d33e11015754e41b249a4/sympy-1.13.1.tar.gz", hash = "sha256:9cebf7e04ff162015ce31c9c6c9144daa34a93bd082f54fd8f12deca4f47515f", size = 7533040 } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/74/7e6c65ee89ff43942bffffdbb238634f16967bf327aee3c76efcf6e49587/sympy-1.13.0-py3-none-any.whl", hash = "sha256:6b0b32a4673fb91bd3cac3b55406c8e01d53ae22780be467301cc452f6680c92", size = 6188245 }, + { url = "https://files.pythonhosted.org/packages/b2/fe/81695a1aa331a842b582453b605175f419fe8540355886031328089d840a/sympy-1.13.1-py3-none-any.whl", hash = "sha256:db36cdc64bf61b9b24578b6f7bab1ecdd2452cf008f34faa33776680c26d66f8", size = 6189177 }, ] [[distribution]] From dcdac84f0c7944433f262af903a39e6b5d3a026a Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Mon, 22 Jul 2024 11:45:39 -0700 Subject: [PATCH 070/229] ci: bring back aarch64 (#33017) * casadi wheel * ci * test 312 * test with new aarch64 build * use release wheels * assert * bool * try this * maybe * work * use final wheel --- .github/workflows/selfdrive_tests.yaml | 26 ++++++++++++++++++++++--- pyproject.toml | 3 ++- selfdrive/ui/SConscript | 2 +- third_party/libyuv/larch64/lib/libyuv.a | 4 ++-- uv.lock | 14 ++++++++++++- 5 files changed, 41 insertions(+), 8 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 8968b493cf..42c1dbb5eb 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -74,8 +74,11 @@ jobs: build: strategy: matrix: - arch: ${{ fromJson('["x86_64"]') }} # TODO: Re-add build test for aarch64 once we switched to ubuntu-2404 - runs-on: ubuntu-latest + arch: ${{ fromJson( + ((github.repository == 'commaai/openpilot') && + ((github.event_name != 'pull_request') || + (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && '["x86_64", "aarch64"]' || '["x86_64"]' ) }} + runs-on: ${{ (matrix.arch == 'aarch64') && 'namespace-profile-arm64-2x8' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 with: @@ -84,7 +87,7 @@ jobs: if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' run: | echo "PUSH_IMAGE=true" >> "$GITHUB_ENV" - : # (TODO: Re-add this once we test other archs) echo "TARGET_ARCHITECTURE=${{ matrix.arch }}" >> "$GITHUB_ENV" + echo "TARGET_ARCHITECTURE=${{ matrix.arch }}" >> "$GITHUB_ENV" $DOCKER_LOGIN - uses: ./.github/workflows/setup-with-retry with: @@ -118,6 +121,23 @@ jobs: - name: Building openpilot run: . .venv/bin/activate && scons -j$(nproc) + docker_push_multiarch: + name: docker push multiarch tag + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' + needs: [build] + steps: + - uses: actions/checkout@v4 + with: + submodules: false + - name: Setup docker + run: | + $DOCKER_LOGIN + - name: Merge x64 and arm64 tags + run: | + export PUSH_IMAGE=true + scripts/retry.sh selfdrive/test/docker_tag_multiarch.sh base x86_64 aarch64 + static_analysis: name: static analysis runs-on: ${{ ((github.repository == 'commaai/openpilot') && diff --git a/pyproject.toml b/pyproject.toml index 126e122ab3..1226c8345a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,7 +52,8 @@ dependencies = [ "websocket_client", # acados deps - "casadi", + "casadi @ https://github.com/commaai/casadi/releases/download/nightly-release-3.6.6/casadi-3.6.6-cp312-none-manylinux2014_aarch64.whl ; (python_version == '3.12' and platform_machine == 'aarch64')", # TODO: Go back to pypi casadi when they fix aarch64 for python312 + "casadi; platform_machine != 'aarch64' or python_version != '3.12'", "future-fstrings", # these should be removed diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 9046ecc228..c6b4860bf7 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -109,7 +109,7 @@ if GetOption('extras') and arch != "Darwin": obj = senv.Object(f"installer/installers/installer_{name}.o", ["installer/installer.cc"], CPPDEFINES=d) f = senv.Program(f"installer/installers/installer_{name}", [obj, cont], LIBS=qt_libs) # keep installers small - assert f[0].get_size() < 350*1e3 + assert f[0].get_size() < 370*1e3 # build watch3 if arch in ['x86_64', 'aarch64', 'Darwin'] or GetOption('extras'): diff --git a/third_party/libyuv/larch64/lib/libyuv.a b/third_party/libyuv/larch64/lib/libyuv.a index fd18814ef1..1c91250231 100644 --- a/third_party/libyuv/larch64/lib/libyuv.a +++ b/third_party/libyuv/larch64/lib/libyuv.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:85e765be665eab8ce8b64d6a884148e0ff3905fadcef6c0daa75e4efd84bb5cb -size 499734 +oid sha256:320bef5a75a62dd2731a496040921d5000f1ed237ae70fd7aeb6c010a1534363 +size 462482 diff --git a/uv.lock b/uv.lock index 7808954e72..8a0dc29b2a 100644 --- a/uv.lock +++ b/uv.lock @@ -227,6 +227,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/08/c55e2172f033a44b831ee771bb32fa89c369311c0598a52c03755f29a75e/casadi-3.6.5-cp312-none-win_amd64.whl", hash = "sha256:fe2b64d777e36cc3f101220dd1e219a0e11c3e4ee2b5e708b30fea9a27107e41", size = 43057681 }, ] +[[distribution]] +name = "casadi" +version = "3.6.6" +source = { url = "https://github.com/commaai/casadi/releases/download/nightly-release-3.6.6/casadi-3.6.6-cp312-none-manylinux2014_aarch64.whl" } +dependencies = [ + { name = "numpy" }, +] +wheels = [ + { url = "https://github.com/commaai/casadi/releases/download/nightly-release-3.6.6/casadi-3.6.6-cp312-none-manylinux2014_aarch64.whl", hash = "sha256:06a15e0099657b960620a2491e565c7f126030018da80c39f6bd33439160c669" }, +] + [[distribution]] name = "certifi" version = "2024.7.4" @@ -1519,7 +1530,8 @@ source = { editable = "." } dependencies = [ { name = "aiohttp" }, { name = "aiortc" }, - { name = "casadi" }, + { name = "casadi", version = "3.6.5", source = { registry = "https://pypi.org/simple" }, marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "casadi", version = "3.6.6", source = { url = "https://github.com/commaai/casadi/releases/download/nightly-release-3.6.6/casadi-3.6.6-cp312-none-manylinux2014_aarch64.whl" }, marker = "python_version == '3.12' and platform_machine == 'aarch64'" }, { name = "cffi" }, { name = "crcmod" }, { name = "cython" }, From 1da71f5c3c3234e9c6c7486437adfb3bf41181f5 Mon Sep 17 00:00:00 2001 From: commaci-public <60409688+commaci-public@users.noreply.github.com> Date: Mon, 22 Jul 2024 11:51:39 -0700 Subject: [PATCH 071/229] [bot] Bump submodules (#33036) bump submodules Co-authored-by: Vehicle Researcher --- opendbc | 2 +- panda | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/opendbc b/opendbc index 5ba787024f..cff2af8ff8 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 5ba787024f53a00d76c7b253d1f3fee87763c679 +Subproject commit cff2af8ff8690466109f56be62129ebfb85cd5dc diff --git a/panda b/panda index b4e3d5cdd2..f6375848ca 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit b4e3d5cdd2dec2a58807b0d710a5d3561a59529d +Subproject commit f6375848ca393a9483921665b6a2d131d7ec9b20 From 5e0aff92ae24952bfb13271c7875e89487da5b31 Mon Sep 17 00:00:00 2001 From: Hoang Bui <47828508+bongbui321@users.noreply.github.com> Date: Mon, 22 Jul 2024 15:05:03 -0400 Subject: [PATCH 072/229] tools/Rerun: Add video logging features (#32810) * working * multiprocessing * fix that * print services * all services + fix * less verbose * start readme * segment range * cleanup * update readme + fix bug in 'all' * cleanup + update readme * update readme * cleanup * cleanup * rm frame_iter * cleanup * staticmethod * proc kill * split files * fix range with hevc vids * update reamde + add prompt * readme * readme * readme --- tools/rerun/README.md | 57 ++++++++++ tools/rerun/camera_reader.py | 92 ++++++++++++++++ tools/rerun/run.py | 206 +++++++++++++++++++++++++---------- 3 files changed, 295 insertions(+), 60 deletions(-) create mode 100644 tools/rerun/README.md create mode 100644 tools/rerun/camera_reader.py diff --git a/tools/rerun/README.md b/tools/rerun/README.md new file mode 100644 index 0000000000..0fd50e1562 --- /dev/null +++ b/tools/rerun/README.md @@ -0,0 +1,57 @@ +# Rerun +Rerun is a tool to quickly visualize time series data. It supports all openpilot logs , both the `logMessages` and video logs. + +[Instructions](https://rerun.io/docs/reference/viewer/overview) for navigation within the Rerun Viewer. + +## Usage +``` +usage: run.py [-h] [--demo] [--qcam] [--fcam] [--ecam] [--dcam] [--print_services] [--services [SERVICES ...]] [route_or_segment_name] + +A helper to run rerun on openpilot routes + +options: + -h, --help show this help message and exit + --demo Use the demo route instead of providing one (default: False) + --qcam Log decimated driving camera (default: False) + --fcam Log driving camera (default: False) + --ecam Log wide camera (default: False) + --dcam Log driver monitoring camera (default: False) + --print_services List out openpilot services (default: False) + --services [SERVICES ...] Specify openpilot services that will be logged. No service will be logged if not specified. + To log all services include 'all' as one of your services (default: []) + --route [ROUTE] The route or segment name to plot (default: None) +``` + +Examples using route name to observe accelerometer and qcamera: + +`./run.py --services accelerometer --qcam --route "a2a0ccea32023010/2023-07-27--13-01-19"` + +Examples using segment range (more on [SegmentRange](https://github.com/commaai/openpilot/tree/master/tools/lib)): + +`./run.py --qcam --route "a2a0ccea32023010/2023-07-27--13-01-19/2:4"` + +## Cautions: +- You can specify `--services all` to visualize all `logMessage`, but it will draw a lot of memory usage and take a long time to log all messages. Rerun isn't ready for logging big number of data. + +- Logging hevc videos (`--fcam`, `--ecam`, and `--dcam`) are expensive, and it's recommended to use `--qcam` for optimized performance. If possible, limiting your route to a few segments using `SegmentRange` will speed up logging and reduce memory usage + +This example draws 13GB of memory: + +`./run.py --services accelerometer --qcam --route "a2a0ccea32023010/2023-07-27--13-01-19"` + + +## Openpilot services +To list all openpilot services: + +`./run.py --print_services` + +Examples including openpilot services: + +`./run.py --services accelerometer cameraodometry --route "a2a0ccea32023010/2023-07-27--13-01-19/0/q"` + +Examples including all services: + +`./run.py --services all --route "a2a0ccea32023010/2023-07-27--13-01-19/0/q"` + +## Demo +`./run.py --services accelerometer carcontrol caroutput --qcam --demo` diff --git a/tools/rerun/camera_reader.py b/tools/rerun/camera_reader.py new file mode 100644 index 0000000000..325fad18b8 --- /dev/null +++ b/tools/rerun/camera_reader.py @@ -0,0 +1,92 @@ +import tqdm +import subprocess +import multiprocessing +from enum import StrEnum +from functools import partial +from collections import namedtuple + +from openpilot.tools.lib.framereader import ffprobe + +CameraConfig = namedtuple("CameraConfig", ["qcam", "fcam", "ecam", "dcam"]) + +class CameraType(StrEnum): + qcam = "qcamera" + fcam = "fcamera" + ecam = "ecamera" + dcam = "dcamera" + + +def probe_packet_info(camera_path): + args = ["ffprobe", "-v", "quiet", "-show_packets", "-probesize", "10M", camera_path] + dat = subprocess.check_output(args) + dat = dat.decode().split() + return dat + + +class _FrameReader: + def __init__(self, camera_path, segment, h, w, start_time): + self.camera_path = camera_path + self.segment = segment + self.h = h + self.w = w + self.start_time = start_time + + self.ts = self._get_ts() + + def _read_stream_nv12(self): + frame_sz = self.w * self.h * 3 // 2 + proc = subprocess.Popen( + ["ffmpeg", "-v", "quiet", "-i", self.camera_path, "-f", "rawvideo", "-pix_fmt", "nv12", "-"], + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL + ) + try: + while True: + dat = proc.stdout.read(frame_sz) + if len(dat) == 0: + break + yield dat + finally: + proc.kill() + + def _get_ts(self): + dat = probe_packet_info(self.camera_path) + try: + ret = [float(d.split('=')[1]) for d in dat if d.startswith("pts_time=")] + except ValueError: + # pts_times aren't available. Infer timestamps from duration_times + ret = [d for d in dat if d.startswith("duration_time")] + ret = [float(d.split('=')[1])*(i+1)+(self.segment*60)+self.start_time for i, d in enumerate(ret)] + return ret + + def __iter__(self): + for i, frame in enumerate(self._read_stream_nv12()): + yield self.ts[i], frame + + +class CameraReader: + def __init__(self, camera_paths, start_time, seg_idxs): + self.seg_idxs = seg_idxs + self.camera_paths = camera_paths + self.start_time = start_time + + probe = ffprobe(camera_paths[0])["streams"][0] + self.h = probe["height"] + self.w = probe["width"] + + self.__frs = {} + + def _get_fr(self, i): + if i not in self.__frs: + self.__frs[i] = _FrameReader(self.camera_paths[i], segment=i, h=self.h, w=self.w, start_time=self.start_time) + return self.__frs[i] + + def _run_on_segment(self, func, i): + return func(self._get_fr(i)) + + def run_across_segments(self, num_processes, func): + with multiprocessing.Pool(num_processes) as pool: + num_segs = len(self.seg_idxs) + for _ in tqdm.tqdm(pool.imap_unordered(partial(self._run_on_segment, func), self.seg_idxs), total=num_segs): + continue + diff --git a/tools/rerun/run.py b/tools/rerun/run.py index 9975478a73..421785a2d5 100755 --- a/tools/rerun/run.py +++ b/tools/rerun/run.py @@ -6,84 +6,170 @@ import rerun as rr import rerun.blueprint as rrb from functools import partial -from openpilot.tools.lib.logreader import LogReader from cereal.services import SERVICE_LIST +from openpilot.tools.rerun.camera_reader import probe_packet_info, CameraReader, CameraConfig, CameraType +from openpilot.tools.lib.logreader import LogReader +from openpilot.tools.lib.route import Route, SegmentRange NUM_CPUS = multiprocessing.cpu_count() DEMO_ROUTE = "a2a0ccea32023010|2023-07-27--13-01-19" +RR_TIMELINE_NAME = "Timeline" +RR_WIN = "rerun_test" -def log_msg(msg, parent_key=''): - stack = [(msg, parent_key)] - while stack: - current_msg, current_parent_key = stack.pop() - if isinstance(current_msg, list): - for index, item in enumerate(current_msg): - new_key = f"{current_parent_key}/{index}" - if isinstance(item, (int, float)): - rr.log(str(new_key), rr.Scalar(item)) - elif isinstance(item, dict): - stack.append((item, new_key)) - elif isinstance(current_msg, dict): - for key, value in current_msg.items(): - new_key = f"{current_parent_key}/{key}" - if isinstance(value, (int, float)): - rr.log(str(new_key), rr.Scalar(value)) - elif isinstance(value, dict): - stack.append((value, new_key)) - elif isinstance(value, list): - for index, item in enumerate(value): - if isinstance(item, (int, float)): - rr.log(f"{new_key}/{index}", rr.Scalar(item)) - else: - pass # Not a plottable value -def createBlueprint(): - blueprint = None - timeSeriesViews = [] - for topic in sorted(SERVICE_LIST.keys()): - timeSeriesViews.append(rrb.TimeSeriesView(name=topic, origin=f"/{topic}/", visible=False)) - rr.log(topic, rr.SeriesLine(name=topic), timeless=True) - blueprint = rrb.Blueprint(rrb.Grid(rrb.Vertical(*timeSeriesViews,rrb.SelectionPanel(expanded=False),rrb.TimePanel(expanded=False)), - rrb.Spatial2DView(name="thumbnail", origin="/thumbnail"))) - return blueprint +class Rerunner: + def __init__(self, route, segment_range, camera_config, enabled_services): + self.enabled_services = [s.lower() for s in enabled_services] + self.log_all = "all" in self.enabled_services + self.lr = LogReader(route_or_segment_name) -def log_thumbnail(thumbnailMsg): - bytesImgData = thumbnailMsg.get('thumbnail') - rr.log("/thumbnail", rr.ImageEncoded(contents=bytesImgData)) + # hevc files don't have start_time. We get it from qcamera.ts + start_time = 0 + dat = probe_packet_info(r.qcamera_paths()[0]) + for d in dat: + if d.startswith("pts_time="): + start_time = float(d.split('=')[1]) + break -@rr.shutdown_at_exit -def process(blueprint, lr): - rr.init("rerun_test") - rr.connect(default_blueprint=blueprint) + qcam, fcam, ecam, dcam = camera_config + self.camera_readers = {} + if qcam: + self.camera_readers[CameraType.qcam] = CameraReader(route.qcamera_paths(), start_time, segment_range.seg_idxs) + if fcam: + self.camera_readers[CameraType.fcam] = CameraReader(route.camera_paths(), start_time, segment_range.seg_idxs) + if ecam: + self.camera_readers[CameraType.ecam] = CameraReader(route.ecamera_paths(), start_time, segment_range.seg_idxs) + if dcam: + self.camera_readers[CameraType.dcam] = CameraReader(route.dcamera_paths(), start_time, segment_range.seg_idxs) + + def _start_rerun(self): + self.blueprint = self._create_blueprint() + rr.init(RR_WIN, spawn=True) + + def _create_blueprint(self): + blueprint = None + service_views = [] + + log_msg_visible = len(self.enabled_services) <= 3 and not self.log_all + for topic in sorted(SERVICE_LIST.keys()): + if not self.log_all and topic.lower() not in self.enabled_services: + continue + View = rrb.TimeSeriesView if topic != "thumbnail" else rrb.Spatial2DView + service_views.append(View(name=topic, origin=f"/{topic}/", visible=log_msg_visible)) + rr.log(topic, rr.SeriesLine(name=topic), timeless=True) + + blueprint = rrb.Blueprint( + rrb.Horizontal( + rrb.Vertical(*service_views), + rrb.Vertical(*[rrb.Spatial2DView(name=cam_type, origin=cam_type) for cam_type in self.camera_readers.keys()]), + ), + rrb.SelectionPanel(expanded=False), + rrb.TimePanel(expanded=False) + ) + return blueprint + + @staticmethod + def _log_msg(msg, parent_key=''): + stack = [(msg, parent_key)] + while stack: + current_msg, current_parent_key = stack.pop() + if isinstance(current_msg, list): + for index, item in enumerate(current_msg): + new_key = f"{current_parent_key}/{index}" + if isinstance(item, (int, float)): + rr.log(new_key, rr.Scalar(item)) + elif isinstance(item, dict): + stack.append((item, new_key)) + elif isinstance(current_msg, dict): + for key, value in current_msg.items(): + new_key = f"{current_parent_key}/{key}" + if isinstance(value, (int, float)): + rr.log(new_key, rr.Scalar(value)) + elif isinstance(value, dict): + stack.append((value, new_key)) + elif isinstance(value, list): + for index, item in enumerate(value): + if isinstance(item, (int, float)): + rr.log(f"{new_key}/{index}", rr.Scalar(item)) + else: + pass # Not a plottable value + + @staticmethod + @rr.shutdown_at_exit + def _process_log_msgs(blueprint, enabled_services, log_all, lr): + rr.init(RR_WIN) + rr.connect(default_blueprint=blueprint) + + for msg in lr: + rr.set_time_nanos(RR_TIMELINE_NAME, msg.logMonoTime) + msg_type = msg.which() + + if not log_all and msg_type.lower() not in enabled_services: + continue + + if msg_type != "thumbnail": + Rerunner._log_msg(msg.to_dict()[msg.which()], msg.which()) + else: + rr.log("/thumbnail", rr.ImageEncoded(contents=msg.to_dict()[msg.which()].get("thumbnail"))) + + return [] + + @staticmethod + @rr.shutdown_at_exit + def _process_cam_readers(blueprint, cam_type, h, w, fr): + rr.init(RR_WIN) + rr.connect(default_blueprint=blueprint) + + size_hint = (h, w) + for ts, frame in fr: + rr.set_time_nanos(RR_TIMELINE_NAME, int(ts * 1e9)) + rr.log(cam_type, rr.ImageEncoded(contents=frame,format=rr.ImageFormat.NV12(size_hint))) + + def load_data(self): + self._start_rerun() + if len(self.enabled_services) > 0: + self.lr.run_across_segments(NUM_CPUS, partial(self._process_log_msgs, self.blueprint, self.enabled_services, self.log_all)) + for cam_type, cr in self.camera_readers.items(): + cr.run_across_segments(NUM_CPUS, partial(self._process_cam_readers, self.blueprint, cam_type, cr.h, cr.w)) - ret = [] - for msg in lr: - ret.append(msg) - rr.set_time_nanos("TIMELINE", msg.logMonoTime) - if msg.which() != "thumbnail": - log_msg(msg.to_dict()[msg.which()], msg.which()) - else: - log_thumbnail(msg.to_dict()[msg.which()]) - return ret if __name__ == '__main__': parser = argparse.ArgumentParser(description="A helper to run rerun on openpilot routes", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("--demo", action="store_true", help="Use the demo route instead of providing one") - parser.add_argument("route_or_segment_name", nargs='?', help="The route or segment name to plot") + parser.add_argument("--qcam", action="store_true", help="Log decimated driving camera") + parser.add_argument("--fcam", action="store_true", help="Log driving camera") + parser.add_argument("--ecam", action="store_true", help="Log wide camera") + parser.add_argument("--dcam", action="store_true", help="Log driver monitoring camera") + parser.add_argument("--print_services", action="store_true", help="List out openpilot services") + parser.add_argument("--services", default=[], nargs='*', help="Specify openpilot services that will be logged.\ + No service will be logged if not specified.\ + To log all services include 'all' as one of your services") + parser.add_argument("--route", nargs='?', help="The route or segment name to plot") + args = parser.parse_args() - if len(sys.argv) == 1: + if not args.demo and not args.route: parser.print_help() sys.exit() - args = parser.parse_args() + if args.print_services: + print("\n".join(SERVICE_LIST.keys())) + sys.exit() - blueprint = createBlueprint() - rr.init("rerun_test") - rr.spawn(connect=False) # child processes stream data to Viewer + camera_config = CameraConfig(args.qcam, args.fcam, args.ecam, args.dcam) + + route_or_segment_name = DEMO_ROUTE if args.demo else args.route.strip() + sr = SegmentRange(route_or_segment_name) + r = Route(sr.route_name) + + if len(sr.seg_idxs) > 10: + print("You're requesting more than 10 segments of the route, " + \ + "please be aware that might take a lot of memory") + response = input("Do you wish to continue? (Y/n): ") + if response.strip() != "Y": + sys.exit() + + rerunner = Rerunner(r, sr, camera_config, args.services) + rerunner.load_data() - route_or_segment_name = DEMO_ROUTE if args.demo else args.route_or_segment_name.strip() - print("Getting route log paths") - lr = LogReader(route_or_segment_name) - lr.run_across_segments(NUM_CPUS, partial(process, blueprint)) From 8d77cea3a509ac80c18ecdd705a9f01754d1cb2c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 22 Jul 2024 13:05:57 -0700 Subject: [PATCH 073/229] [bot] Fingerprints: add missing FW versions from new users (#33038) Export fingerprints --- selfdrive/car/chrysler/fingerprints.py | 3 +++ selfdrive/car/hyundai/fingerprints.py | 1 + 2 files changed, 4 insertions(+) diff --git a/selfdrive/car/chrysler/fingerprints.py b/selfdrive/car/chrysler/fingerprints.py index 5528bfd5d5..74a5368145 100644 --- a/selfdrive/car/chrysler/fingerprints.py +++ b/selfdrive/car/chrysler/fingerprints.py @@ -26,6 +26,7 @@ FW_VERSIONS = { ], (Ecu.fwdRadar, 0x753, None): [ b'04672758AA', + b'04672758AB', b'68226356AF', b'68226356AH', b'68226356AI', @@ -47,6 +48,7 @@ FW_VERSIONS = { b'68352654AE ', b'68366851AH ', b'68366853AE ', + b'68366853AG ', b'68372861AF ', ], (Ecu.transmission, 0x7e1, None): [ @@ -60,6 +62,7 @@ FW_VERSIONS = { b'68277374AD', b'68277374AN', b'68367471AC', + b'68367471AD', b'68380571AB', ], }, diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index 4c659f053f..a9ab8bb79e 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -408,6 +408,7 @@ FW_VERSIONS = { b'\xf1\x00ON ESC \x0b 100\x18\x12\x18 58910-S9360', b'\xf1\x00ON ESC \x0b 101\x19\t\x05 58910-S9320', b'\xf1\x00ON ESC \x0b 101\x19\t\x08 58910-S9360', + b'\xf1\x00ON ESC \x0b 103$\x04\x08 58910-S9360', ], (Ecu.eps, 0x7d4, None): [ b'\xf1\x00LX2 MDPS C 1,00 1,03 56310-S8020 4LXDC103', From a654e5bd05811a896005ebb41bc2f15dcf443b5d Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Mon, 22 Jul 2024 12:09:00 -0800 Subject: [PATCH 074/229] espActive: `IMMEDIATE_DISABLE` -> `SOFT_DISABLE` (#33003) * espActive: `IMMEDIATE_DISABLE` -> `SOFT_DISABLE` * only stock long * just soft disable for now --------- Co-authored-by: Shane Smiskol --- selfdrive/controls/lib/events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 25833da741..588e638c95 100755 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -832,7 +832,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { }, EventName.espActive: { - ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Electronic Stability Control Active"), + ET.SOFT_DISABLE: soft_disable_alert("Electronic Stability Control Active"), ET.NO_ENTRY: NoEntryAlert("Electronic Stability Control Active"), }, From bd00a9d800c1cf308feb2bf85f7fde11d6f0ff7b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 22 Jul 2024 13:36:53 -0700 Subject: [PATCH 075/229] [bot] Fingerprints: add missing FW versions from new users (#33039) Export fingerprints --- selfdrive/car/chrysler/fingerprints.py | 9 +++++++++ selfdrive/car/hyundai/fingerprints.py | 3 +++ selfdrive/car/toyota/fingerprints.py | 2 ++ 3 files changed, 14 insertions(+) diff --git a/selfdrive/car/chrysler/fingerprints.py b/selfdrive/car/chrysler/fingerprints.py index 74a5368145..5198c661d7 100644 --- a/selfdrive/car/chrysler/fingerprints.py +++ b/selfdrive/car/chrysler/fingerprints.py @@ -390,6 +390,7 @@ FW_VERSIONS = { b'68294051AI', b'68294052AG', b'68294052AH', + b'68294059AI', b'68294063AG', b'68294063AH', b'68294063AI', @@ -400,6 +401,7 @@ FW_VERSIONS = { b'68434858AC', b'68434859AC', b'68434860AC', + b'68453471AD', b'68453483AC', b'68453483AD', b'68453487AD', @@ -424,11 +426,13 @@ FW_VERSIONS = { b'68527346AE', b'68527361AD', b'68527375AD', + b'68527381AD', b'68527381AE', b'68527382AE', b'68527383AD', b'68527383AE', b'68527387AE', + b'68527397AD', b'68527403AC', b'68527403AD', b'68546047AF', @@ -519,6 +523,7 @@ FW_VERSIONS = { b'05036066AE ', b'05036193AA ', b'05149368AA ', + b'05149374AA ', b'05149591AD ', b'05149591AE ', b'05149592AE ', @@ -549,6 +554,7 @@ FW_VERSIONS = { b'68455145AC ', b'68455145AE ', b'68455146AC ', + b'68460927AA ', b'68467915AC ', b'68467916AC ', b'68467936AC ', @@ -567,6 +573,7 @@ FW_VERSIONS = { b'68539650AF', b'68539651AD', b'68586101AA ', + b'68586102AA ', b'68586105AB ', b'68629919AC ', b'68629922AC ', @@ -605,6 +612,8 @@ FW_VERSIONS = { b'68520867AE', b'68520867AF', b'68520870AC', + b'68520871AC', + b'68528325AE', b'68540431AB', b'68540433AB', b'68551676AA', diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index a9ab8bb79e..30e4b9ed74 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -292,6 +292,7 @@ FW_VERSIONS = { b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLAC0 4TSHC102', b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLEC0 4TSHC102', b'\xf1\x00TM MDPS C 1.00 1.02 56310-GA000 4TSHA100', + b'\xf1\x00TM MDPS C 1.00 1.02 56310GA000\x00 4TSHA100', b'\xf1\x00TM MDPS R 1.00 1.05 57700-CL000 4TSHP105', b'\xf1\x00TM MDPS R 1.00 1.06 57700-CL000 4TSHP106', ], @@ -482,11 +483,13 @@ FW_VERSIONS = { }, CAR.GENESIS_G80: { (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00DH__ SCC F-CU- 1.00 1.01 96400-B1110 ', b'\xf1\x00DH__ SCC F-CUP 1.00 1.01 96400-B1120 ', b'\xf1\x00DH__ SCC F-CUP 1.00 1.02 96400-B1120 ', b'\xf1\x00DH__ SCC FHCUP 1.00 1.01 96400-B1110 ', ], (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00DH LKAS AT EUR LHD 1.01 1.01 95895-B1500 161014', b'\xf1\x00DH LKAS AT KOR LHD 1.01 1.01 95895-B1500 161014', b'\xf1\x00DH LKAS AT KOR LHD 1.01 1.02 95895-B1500 170810', b'\xf1\x00DH LKAS AT USA LHD 1.01 1.01 95895-B1500 161014', diff --git a/selfdrive/car/toyota/fingerprints.py b/selfdrive/car/toyota/fingerprints.py index a4d0ad1707..37c69b54fb 100644 --- a/selfdrive/car/toyota/fingerprints.py +++ b/selfdrive/car/toyota/fingerprints.py @@ -1152,6 +1152,7 @@ FW_VERSIONS = { }, CAR.TOYOTA_RAV4_TSS2_2023: { (Ecu.abs, 0x7b0, None): [ + b'\x01F15260R440\x00\x00\x00\x00\x00\x00', b'\x01F15260R450\x00\x00\x00\x00\x00\x00', b'\x01F15260R50000\x00\x00\x00\x00', b'\x01F15260R51000\x00\x00\x00\x00', @@ -1173,6 +1174,7 @@ FW_VERSIONS = { b'\x01896634AE1001\x00\x00\x00\x00', b'\x01896634AF0000\x00\x00\x00\x00', b'\x01896634AJ2000\x00\x00\x00\x00', + b'\x01896634AJ3000\x00\x00\x00\x00', b'\x01896634AL5000\x00\x00\x00\x00', b'\x01896634AL6000\x00\x00\x00\x00', b'\x01896634AL8000\x00\x00\x00\x00', From fb3336614484553456bee6c2116b729177ecbc46 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 24 Jul 2024 00:27:10 +0800 Subject: [PATCH 076/229] Fix FutureWarning "Cython directive 'language_level' not set" (#33046) fix FutureWarning --- selfdrive/modeld/models/commonmodel_pyx.pyx | 2 +- selfdrive/modeld/runners/runmodel_pyx.pyx | 2 +- selfdrive/modeld/runners/snpemodel_pyx.pyx | 2 +- selfdrive/modeld/runners/thneedmodel_pyx.pyx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/modeld/models/commonmodel_pyx.pyx b/selfdrive/modeld/models/commonmodel_pyx.pyx index e292bb0d2d..ecbe644e09 100644 --- a/selfdrive/modeld/models/commonmodel_pyx.pyx +++ b/selfdrive/modeld/models/commonmodel_pyx.pyx @@ -1,5 +1,5 @@ # distutils: language = c++ -# cython: c_string_encoding=ascii +# cython: c_string_encoding=ascii, language_level=3 import numpy as np cimport numpy as cnp diff --git a/selfdrive/modeld/runners/runmodel_pyx.pyx b/selfdrive/modeld/runners/runmodel_pyx.pyx index e1b201a6a9..12b8ec10ff 100644 --- a/selfdrive/modeld/runners/runmodel_pyx.pyx +++ b/selfdrive/modeld/runners/runmodel_pyx.pyx @@ -1,5 +1,5 @@ # distutils: language = c++ -# cython: c_string_encoding=ascii +# cython: c_string_encoding=ascii, language_level=3 from libcpp.string cimport string diff --git a/selfdrive/modeld/runners/snpemodel_pyx.pyx b/selfdrive/modeld/runners/snpemodel_pyx.pyx index c3b2b7e9bd..f83b7c8cff 100644 --- a/selfdrive/modeld/runners/snpemodel_pyx.pyx +++ b/selfdrive/modeld/runners/snpemodel_pyx.pyx @@ -1,5 +1,5 @@ # distutils: language = c++ -# cython: c_string_encoding=ascii +# cython: c_string_encoding=ascii, language_level=3 import os from libcpp cimport bool diff --git a/selfdrive/modeld/runners/thneedmodel_pyx.pyx b/selfdrive/modeld/runners/thneedmodel_pyx.pyx index 53487afa1b..6f8fdd255f 100644 --- a/selfdrive/modeld/runners/thneedmodel_pyx.pyx +++ b/selfdrive/modeld/runners/thneedmodel_pyx.pyx @@ -1,5 +1,5 @@ # distutils: language = c++ -# cython: c_string_encoding=ascii +# cython: c_string_encoding=ascii, language_level=3 from libcpp cimport bool from libcpp.string cimport string From 93eb7ee0cc5af0d7c86248cbcafad86dd374976f Mon Sep 17 00:00:00 2001 From: Joseph Wagner <68037585+wjoseph0@users.noreply.github.com> Date: Tue, 23 Jul 2024 12:35:19 -0500 Subject: [PATCH 077/229] README.md: 275+ cars (#33048) 275+ cars --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index db74ee6a1a..5afaf6e7d6 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ To start using openpilot in a car To use openpilot in a car, you need four things: 1. **Supported Device:** a comma 3/3X, available at [comma.ai/shop](https://comma.ai/shop/comma-3x). 2. **Software:** The setup procedure for the comma 3/3X allows users to enter a URL for custom software. Use the URL `openpilot.comma.ai` to install the release version. -3. **Supported Car:** Ensure that you have one of [the 250+ supported cars](docs/CARS.md). +3. **Supported Car:** Ensure that you have one of [the 275+ supported cars](docs/CARS.md). 4. **Car Harness:** You will also need a [car harness](https://comma.ai/shop/car-harness) to connect your comma 3/3X to your car. We have detailed instructions for [how to install the harness and device in a car](https://comma.ai/setup). Note that it's possible to run openpilot on [other hardware](https://blog.comma.ai/self-driving-car-for-free/), although it's not plug-and-play. From d828ac43444dad2d25dafcd4ba7543230b1f156f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 23 Jul 2024 11:11:31 -0700 Subject: [PATCH 078/229] CI: setup triggering jenkins for forks (#33049) --- .github/workflows/jenkins-pr-trigger.yaml | 50 +++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/jenkins-pr-trigger.yaml diff --git a/.github/workflows/jenkins-pr-trigger.yaml b/.github/workflows/jenkins-pr-trigger.yaml new file mode 100644 index 0000000000..42ef4a7391 --- /dev/null +++ b/.github/workflows/jenkins-pr-trigger.yaml @@ -0,0 +1,50 @@ +name: jenkins scan + +on: + issue_comment: + types: [created] + +jobs: + # TODO: gc old branches in a separate job in this workflow + scan-comments: + runs-on: ubuntu-latest + if: github.event.issue.pull_request != null + steps: + - name: Check if comment contains trigger phrase and is from someone with write access + id: check_comment + uses: actions/github-script@v6 + with: + script: | + const triggerPhrase = "trigger-jenkins"; + const comment = context.payload.comment.body; + const commenter = context.payload.comment.user.login; + + const { data: permissions } = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: context.repo.owner, + repo: context.repo.repo, + username: commenter + }); + + const hasWriteAccess = permissions.permission === 'write' || permissions.permission === 'admin'; + + return (hasWriteAccess && comment.includes(triggerPhrase)); + result-encoding: boolean + + - name: Set PR number + id: set_pr_number + if: steps.check_comment.outputs.result == 'true' + run: echo "PR_NUMBER=$(echo ${{ github.event.issue.number }})" >> $GITHUB_ENV + + - name: Checkout repository + if: steps.check_comment.outputs.result == 'true' + uses: actions/checkout@v4 + with: + ref: ${{ github.event.issue.pull_request.head.ref }} + + - name: Push to tmp-jenkins branch + if: steps.check_comment.outputs.result == 'true' + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git checkout -b tmp-jenkins-${{ env.PR_NUMBER }} + git push -f origin tmp-jenkins-${{ env.PR_NUMBER }} From e7ec1b8ff16feeb3d02200c95692aa4bcb402337 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 23 Jul 2024 11:14:00 -0700 Subject: [PATCH 079/229] json encoding --- .github/workflows/jenkins-pr-trigger.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/jenkins-pr-trigger.yaml b/.github/workflows/jenkins-pr-trigger.yaml index 42ef4a7391..10c601777d 100644 --- a/.github/workflows/jenkins-pr-trigger.yaml +++ b/.github/workflows/jenkins-pr-trigger.yaml @@ -28,7 +28,7 @@ jobs: const hasWriteAccess = permissions.permission === 'write' || permissions.permission === 'admin'; return (hasWriteAccess && comment.includes(triggerPhrase)); - result-encoding: boolean + result-encoding: json - name: Set PR number id: set_pr_number From ef5d6a0466dd2ebf0b5595150b68b3c59722f397 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 23 Jul 2024 11:27:56 -0700 Subject: [PATCH 080/229] jenkins trigger fixups --- .github/workflows/jenkins-pr-trigger.yaml | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/.github/workflows/jenkins-pr-trigger.yaml b/.github/workflows/jenkins-pr-trigger.yaml index 10c601777d..acdf5feb86 100644 --- a/.github/workflows/jenkins-pr-trigger.yaml +++ b/.github/workflows/jenkins-pr-trigger.yaml @@ -2,17 +2,17 @@ name: jenkins scan on: issue_comment: - types: [created] + types: [created, edited] jobs: # TODO: gc old branches in a separate job in this workflow scan-comments: runs-on: ubuntu-latest - if: github.event.issue.pull_request != null + if: ${{ github.event.issue.pull_request }} steps: - - name: Check if comment contains trigger phrase and is from someone with write access + - name: Check for trigger phrase id: check_comment - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const triggerPhrase = "trigger-jenkins"; @@ -30,21 +30,16 @@ jobs: return (hasWriteAccess && comment.includes(triggerPhrase)); result-encoding: json - - name: Set PR number - id: set_pr_number - if: steps.check_comment.outputs.result == 'true' - run: echo "PR_NUMBER=$(echo ${{ github.event.issue.number }})" >> $GITHUB_ENV - - name: Checkout repository if: steps.check_comment.outputs.result == 'true' uses: actions/checkout@v4 with: - ref: ${{ github.event.issue.pull_request.head.ref }} + ref: refs/pull/${{ github.event.issue.number }}/head - name: Push to tmp-jenkins branch if: steps.check_comment.outputs.result == 'true' run: | git config --global user.name "github-actions[bot]" git config --global user.email "github-actions[bot]@users.noreply.github.com" - git checkout -b tmp-jenkins-${{ env.PR_NUMBER }} - git push -f origin tmp-jenkins-${{ env.PR_NUMBER }} + git checkout -b tmp-jenkins-${{ github.event.issue.number }} + git push -f origin tmp-jenkins-${{ github.event.issue.number }} From 29d0bfe1ab832832f027c899e337551fd8716a49 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 23 Jul 2024 11:32:51 -0700 Subject: [PATCH 081/229] skip lfs --- .github/workflows/jenkins-pr-trigger.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/jenkins-pr-trigger.yaml b/.github/workflows/jenkins-pr-trigger.yaml index acdf5feb86..eb2a7271be 100644 --- a/.github/workflows/jenkins-pr-trigger.yaml +++ b/.github/workflows/jenkins-pr-trigger.yaml @@ -42,4 +42,4 @@ jobs: git config --global user.name "github-actions[bot]" git config --global user.email "github-actions[bot]@users.noreply.github.com" git checkout -b tmp-jenkins-${{ github.event.issue.number }} - git push -f origin tmp-jenkins-${{ github.event.issue.number }} + GIT_LFS_SKIP_SMUDGE=1 git push -f origin tmp-jenkins-${{ github.event.issue.number }} From 9b8c1693c9c74bae87c44615e90fc372c551900c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 23 Jul 2024 11:41:27 -0700 Subject: [PATCH 082/229] skip push --- .github/workflows/jenkins-pr-trigger.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/jenkins-pr-trigger.yaml b/.github/workflows/jenkins-pr-trigger.yaml index eb2a7271be..db1d524018 100644 --- a/.github/workflows/jenkins-pr-trigger.yaml +++ b/.github/workflows/jenkins-pr-trigger.yaml @@ -42,4 +42,4 @@ jobs: git config --global user.name "github-actions[bot]" git config --global user.email "github-actions[bot]@users.noreply.github.com" git checkout -b tmp-jenkins-${{ github.event.issue.number }} - GIT_LFS_SKIP_SMUDGE=1 git push -f origin tmp-jenkins-${{ github.event.issue.number }} + GIT_LFS_SKIP_PUSH=1 git push -f origin tmp-jenkins-${{ github.event.issue.number }} From fbbd4ee692d2f84b90bfaf93499c6360e5bdad2b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 24 Jul 2024 02:53:40 +0800 Subject: [PATCH 083/229] Fix `/usr/bin/ld: skipping incompatible /usr/lib/libgcc_s.so.1` warnings (#33047) fix incompatible lib warning --- SConstruct | 1 - 1 file changed, 1 deletion(-) diff --git a/SConstruct b/SConstruct index 0c4dbee18e..1f83b1e43d 100644 --- a/SConstruct +++ b/SConstruct @@ -102,7 +102,6 @@ if arch == "larch64": libpath = [ "/usr/local/lib", - "/usr/lib", "/system/vendor/lib64", f"#third_party/acados/{arch}/lib", ] From 3bc1b173d2390a93b0c31090861bbc597eff4d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Tue, 23 Jul 2024 13:55:30 -0700 Subject: [PATCH 084/229] Longcontrol: engage into stopped state when needed (#33042) test stay stopped --- selfdrive/controls/lib/longcontrol.py | 14 +++-- selfdrive/controls/tests/test_longcontrol.py | 56 ++++++++++++++++++++ 2 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 selfdrive/controls/tests/test_longcontrol.py diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py index e4841c705f..efeb76c4a8 100644 --- a/selfdrive/controls/lib/longcontrol.py +++ b/selfdrive/controls/lib/longcontrol.py @@ -22,22 +22,26 @@ def long_control_state_trans(CP, active, long_control_state, v_ego, long_control_state = LongCtrlState.off else: - if long_control_state in (LongCtrlState.off, LongCtrlState.pid): - long_control_state = LongCtrlState.pid - if stopping_condition: + if long_control_state == LongCtrlState.off: + if not starting_condition: long_control_state = LongCtrlState.stopping + else: + if starting_condition and CP.startingState: + long_control_state = LongCtrlState.starting + else: + long_control_state = LongCtrlState.pid + elif long_control_state == LongCtrlState.stopping: if starting_condition and CP.startingState: long_control_state = LongCtrlState.starting elif starting_condition: long_control_state = LongCtrlState.pid - elif long_control_state == LongCtrlState.starting: + elif long_control_state in [LongCtrlState.starting, LongCtrlState.pid]: if stopping_condition: long_control_state = LongCtrlState.stopping elif started_condition: long_control_state = LongCtrlState.pid - return long_control_state class LongControl: diff --git a/selfdrive/controls/tests/test_longcontrol.py b/selfdrive/controls/tests/test_longcontrol.py new file mode 100644 index 0000000000..ab50810d89 --- /dev/null +++ b/selfdrive/controls/tests/test_longcontrol.py @@ -0,0 +1,56 @@ +from cereal import car +from openpilot.selfdrive.controls.lib.longcontrol import LongCtrlState, long_control_state_trans + + + + +class TestLongControlStateTransition: + + def test_stay_stopped(self): + CP = car.CarParams.new_message() + active = True + current_state = LongCtrlState.stopping + next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1, + should_stop=True, brake_pressed=False, cruise_standstill=False) + assert next_state == LongCtrlState.stopping + next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1, + should_stop=False, brake_pressed=True, cruise_standstill=False) + assert next_state == LongCtrlState.stopping + next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1, + should_stop=False, brake_pressed=False, cruise_standstill=True) + assert next_state == LongCtrlState.stopping + next_state = long_control_state_trans(CP, active, current_state, v_ego=1.0, + should_stop=False, brake_pressed=False, cruise_standstill=False) + assert next_state == LongCtrlState.pid + active = False + next_state = long_control_state_trans(CP, active, current_state, v_ego=1.0, + should_stop=False, brake_pressed=False, cruise_standstill=False) + assert next_state == LongCtrlState.off + +def test_engage(): + CP = car.CarParams.new_message() + active = True + current_state = LongCtrlState.off + next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1, + should_stop=True, brake_pressed=False, cruise_standstill=False) + assert next_state == LongCtrlState.stopping + next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1, + should_stop=False, brake_pressed=True, cruise_standstill=False) + assert next_state == LongCtrlState.stopping + next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1, + should_stop=False, brake_pressed=False, cruise_standstill=True) + assert next_state == LongCtrlState.stopping + next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1, + should_stop=False, brake_pressed=False, cruise_standstill=False) + assert next_state == LongCtrlState.pid + +def test_starting(): + CP = car.CarParams.new_message(startingState=True, vEgoStarting=0.5) + active = True + current_state = LongCtrlState.starting + next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1, + should_stop=False, brake_pressed=False, cruise_standstill=False) + assert next_state == LongCtrlState.starting + next_state = long_control_state_trans(CP, active, current_state, v_ego=1.0, + should_stop=False, brake_pressed=False, cruise_standstill=False) + assert next_state == LongCtrlState.pid From 1e9738131d7737cbc9af161cf829c83c67577970 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Tue, 23 Jul 2024 14:52:08 -0700 Subject: [PATCH 085/229] don't lock when installing python packages (#33051) frozen --- tools/install_python_dependencies.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/install_python_dependencies.sh b/tools/install_python_dependencies.sh index 276de58db7..a90462888f 100755 --- a/tools/install_python_dependencies.sh +++ b/tools/install_python_dependencies.sh @@ -34,7 +34,7 @@ update_uv # TODO: remove --no-cache once this is fixed: https://github.com/astral-sh/uv/issues/4378 echo "installing python packages..." -uv --no-cache sync --all-extras +uv --no-cache sync --frozen --all-extras source .venv/bin/activate echo "PYTHONPATH=${PWD}" > $ROOT/.env From f60dfd4dbb5d33bb1ec36c550742d185e2c4bf78 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Tue, 23 Jul 2024 21:47:07 -0700 Subject: [PATCH 086/229] op tool helper (#33053) * op * change this * juggler * options * fix * submodules * typo * venv * clean + install --- tools/op.sh | 262 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100755 tools/op.sh diff --git a/tools/op.sh b/tools/op.sh new file mode 100755 index 0000000000..d8a3f4b809 --- /dev/null +++ b/tools/op.sh @@ -0,0 +1,262 @@ +#!/bin/bash + +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' + +function op_first_install() { + (set -e + + echo "Installing op system-wide..." + RC_FILE="${HOME}/.$(basename ${SHELL})rc" + if [ "$(uname)" == "Darwin" ] && [ $SHELL == "/bin/bash" ]; then + RC_FILE="$HOME/.bash_profile" + fi + printf "\nalias op='source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/op.sh" \"\$@\"'\n" >> $RC_FILE + echo -e " ↳ [${GREEN}✔${NC}] op installed successfully. Open a new shell to use it.\n" + + ) +} + +# be default, assume openpilot dir is in current directory +OPENPILOT_ROOT=$(pwd) +function op_check_openpilot_dir() { + (set -e + + if [ ! -f "$OPENPILOT_ROOT/launch_openpilot.sh" ]; then + echo "openpilot directory not found!" + return 1 + fi + + ) +} + +function op_check_git() { + (set -e + + cd $OPENPILOT_ROOT + + echo "Checking for git..." + if ! command -v "git" > /dev/null 2>&1; then + echo -e " ↳ [${RED}✗${NC}] git not found on your system!" + return 1 + else + echo -e " ↳ [${GREEN}✔${NC}] git found on your system.\n" + fi + + echo "Checking for git lfs files..." + if [[ $(file -b $(git lfs ls-files -n | grep "\.so" | head -n 1)) == "ASCII text" ]]; then + echo -e " ↳ [${RED}✗${NC}] git lfs files not found! Run git lfs pull" + return 1 + else + echo -e " ↳ [${GREEN}✔${NC}] git lfs files found on your system.\n" + fi + + echo "Checking for git submodules..." + if $(git submodule foreach --quiet --recursive 'return 1' 2&> /dev/null); then + echo -e " ↳ [${RED}✗${NC}] git submodules not found! Run 'git submodule update --init --recursive'" + return 1 + else + echo -e " ↳ [${GREEN}✔${NC}] git submodules found on your system.\n" + fi + + ) +} + +function op_check_os() { + (set -e + + echo "Checking for compatible os version..." + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + + if [ -f "/etc/os-release" ]; then + source /etc/os-release + case "$VERSION_CODENAME" in + "jammy" | "kinetic" | "noble" | "focal") + OS_VERSION="Ubuntu" + echo -e " ↳ [${GREEN}✔${NC}] Ubuntu $VERSION_CODENAME detected.\n" + ;; + * ) + echo -e " ↳ [${RED}✗${NC}] Incompatible Ubuntu version $VERSION_CODENAME detected!" + return 1 + ;; + esac + else + echo -e " ↳ [${RED}✗${NC}] No /etc/os-release on your system. Make sure you're running on Ubuntu, or similar!" + return 1 + fi + + elif [[ "$OSTYPE" == "darwin"* ]]; then + echo -e " ↳ [${GREEN}✔${NC}] macos detected.\n" + OS_VERSION="Darwin" + else + echo -e " ↳ [${RED}✗${NC}] OS type $OSTYPE not supported!" + return 1 + fi + + ) +} + +function op_check_python() { + (set -e + + echo "Checking for compatible python version..." + export REQUIRED_PYTHON_VERSION=$(grep "requires-python" pyproject.toml | cut -d= -f3- | tr -d '"' | tr -d ' ') + if ! command -v "python3" > /dev/null 2>&1; then + echo -e " ↳ [${RED}✗${NC}] python3 not found on your system. You need python version at least $REQUIRED_PYTHON_VERSION to continue!" + return 1 + else + if $(python3 -c "import sys; quit(not sys.version_info >= tuple(map(int, \"$REQUIRED_PYTHON_VERSION\".split('.'))))"); then + echo -e " ↳ [${GREEN}✔${NC}] $(python3 --version) detected.\n" + else + echo -e " ↳ [${RED}✗${NC}] You need python version at least $REQUIRED_PYTHON_VERSION to continue!" + return 1 + fi + fi + + ) +} + +# this must be run in the same shell as the user calling "op" +function op_venv() { + op_check_openpilot_dir || return 1 + source $OPENPILOT_ROOT/.venv/bin/activate || (echo -e "\nCan't activate venv. Have you ran 'op install' ?" && return 1) +} + +function op_check() { + (set -e + + op_check_openpilot_dir + cd $OPENPILOT_ROOT + op_check_git + op_check_os + op_check_python + + ) +} + +function op_run() { + (set -e + + op_venv + cd $OPENPILOT_ROOT + $OPENPILOT_ROOT/launch_openpilot.sh + + ) +} + +function op_install() { + (set -e + + op_check_openpilot_dir + cd $OPENPILOT_ROOT + + op_check_os + op_check_python + + case "$OS_VERSION" in + "Ubuntu") + $OPENPILOT_ROOT/tools/ubuntu_setup.sh + ;; + "Darwin") + $OPENPILOT_ROOT/tools/mac_setup.sh + ;; + esac + + git submodules update --init --recursive + git lfs pull + + ) +} + +function op_build() { + (set -e + + op_venv + cd $OPENPILOT_ROOT + + scons $@ || echo -e "\nBuild failed. Have you ran 'op install' ?" + + ) +} + +function op_juggle() { + (set -e + + op_venv + cd $OPENPILOT_ROOT + + $OPENPILOT_ROOT/tools/plotjuggler/juggle.py $@ + + ) +} + +function op_default() { + echo "An openpilot helper" + echo "" + echo -e "\e[4mUsage:\e[0m op [OPTIONS] " + echo "" + echo -e "\e[4mCommands:\e[0m" + echo " venv Activate the virtual environment" + echo " check Check system requirements (git, os, python) to start using openpilot" + echo " install Install requirements to use openpilot" + echo " build Build openpilot" + echo " run Run openpilot" + echo " juggle Run Plotjuggler" + echo " help Show this message" + echo " --install Install this tool system wide" + echo "" + echo -e "\e[4mOptions:\e[0m" + echo " -d, --dir" + echo " Specify the openpilot directory you want to use" + echo " Default to the current working directory" + echo "" + echo -e "\e[4mExamples:\e[0m" + echo " op --dir /tmp/openpilot check" + echo " Run the check command on openpilot located in /tmp/openpilot" + echo "" + echo " op juggle --install" + echo " Install plotjuggler in the openpilot located in your current" + echo " working directory" + echo "" + echo " op --dir /tmp/openpilot build -j4" + echo " Run the build command on openpilot located in /tmp/openpilot" + echo " on 4 cores" +} + + +function _op() { + # parse Options + case $1 in + -d | --dir ) shift 1; OPENPILOT_ROOT="$1"; shift 1 ;; + esac + + # parse Commands + case $1 in + venv ) shift 1; op_venv "$@" ;; + check ) shift 1; op_check "$@" ;; + install ) shift 1; op_install "$@" ;; + build ) shift 1; op_build "$@" ;; + run ) shift 1; op_run "$@" ;; + juggle ) shift 1; op_juggle "$@" ;; + --install ) shift 1; op_first_install "$@" ;; + * ) op_default "$@" ;; + esac +} + +_op $@ + +# remove from env +unset -f _op +unset -f op_check +unset -f op_install +unset -f op_build +unset -f op_run +unset -f op_juggle +unset -f op_venv +unset -f op_check_openpilot_dir +unset -f op_check_git +unset -f op_check_python +unset -f op_check_os +unset -f op_first_install +unset -f op_default From 3382002cd03604710f39d01f19a37f4bb66b7cdf Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Tue, 23 Jul 2024 22:34:21 -0700 Subject: [PATCH 087/229] Update op.sh --- tools/op.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/op.sh b/tools/op.sh index d8a3f4b809..f7caa9d047 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -163,7 +163,7 @@ function op_install() { ;; esac - git submodules update --init --recursive + git submodule update --init --recursive git lfs pull ) From 18c310addf7e19688f6cfc4530026b281ac7e75f Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Tue, 23 Jul 2024 23:04:42 -0700 Subject: [PATCH 088/229] Update op.sh --- tools/op.sh | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/tools/op.sh b/tools/op.sh index f7caa9d047..bbc4ded445 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -73,7 +73,6 @@ function op_check_os() { source /etc/os-release case "$VERSION_CODENAME" in "jammy" | "kinetic" | "noble" | "focal") - OS_VERSION="Ubuntu" echo -e " ↳ [${GREEN}✔${NC}] Ubuntu $VERSION_CODENAME detected.\n" ;; * ) @@ -88,7 +87,6 @@ function op_check_os() { elif [[ "$OSTYPE" == "darwin"* ]]; then echo -e " ↳ [${GREEN}✔${NC}] macos detected.\n" - OS_VERSION="Darwin" else echo -e " ↳ [${RED}✗${NC}] OS type $OSTYPE not supported!" return 1 @@ -154,14 +152,11 @@ function op_install() { op_check_os op_check_python - case "$OS_VERSION" in - "Ubuntu") - $OPENPILOT_ROOT/tools/ubuntu_setup.sh - ;; - "Darwin") - $OPENPILOT_ROOT/tools/mac_setup.sh - ;; - esac + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + $OPENPILOT_ROOT/tools/ubuntu_setup.sh + elif [[ "$OSTYPE" == "darwin"* ]]; then + $OPENPILOT_ROOT/tools/mac_setup.sh + fi git submodule update --init --recursive git lfs pull From bd8dd65ce0e5477100e07f33d2b237111e922c62 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 25 Jul 2024 00:42:31 +0800 Subject: [PATCH 089/229] ui: fix wayland requestActivate warning on device (#33054) fix wayland requestActivate warning in fullscreen mode --- selfdrive/ui/qt/qt_window.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/selfdrive/ui/qt/qt_window.cc b/selfdrive/ui/qt/qt_window.cc index f71cea04e9..8d3d7cf72e 100644 --- a/selfdrive/ui/qt/qt_window.cc +++ b/selfdrive/ui/qt/qt_window.cc @@ -18,7 +18,9 @@ void setMainWindow(QWidget *w) { wl_surface *s = reinterpret_cast(native->nativeResourceForWindow("surface", w->windowHandle())); wl_surface_set_buffer_transform(s, WL_OUTPUT_TRANSFORM_270); wl_surface_commit(s); - w->showFullScreen(); + + w->setWindowState(Qt::WindowFullScreen); + w->setVisible(true); // ensure we have a valid eglDisplay, otherwise the ui will silently fail void *egl = native->nativeResourceForWindow("egldisplay", w->windowHandle()); From 0fa6745a67b60a572cfa4060d8155ac50f4e4e06 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 25 Jul 2024 01:07:10 +0800 Subject: [PATCH 090/229] camerad: refactor camera_open() into separate functions for clarity (#33056) split function --- system/camerad/cameras/camera_qcom2.cc | 32 +++++++++++++++++++------- system/camerad/cameras/camera_qcom2.h | 5 ++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index 47ea5ded4d..7c1f8e44e7 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -469,6 +469,16 @@ void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num enabled = enabled_; if (!enabled) return; + if (!openSensor()) { + return; + } + + configISP(); + configCSIPHY(); + linkDevices(); +} + +bool CameraState::openSensor() { sensor_fd = open_v4l_by_name_and_index("cam-sensor-driver", camera_num); assert(sensor_fd >= 0); LOGD("opened sensor for %d", camera_num); @@ -493,7 +503,7 @@ void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num !init_sensor_lambda(new OS04C10)) { LOGE("** sensor %d FAILED bringup, disabling", camera_num); enabled = false; - return; + return false; } LOGD("-- Probing sensor %d success", camera_num); @@ -512,7 +522,10 @@ void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num LOG("-- Configuring sensor"); sensors_i2c(ci->init_reg_array.data(), ci->init_reg_array.size(), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, ci->data_word); + return true; +} +void CameraState::configISP() { // NOTE: to be able to disable road and wide road, we still have to configure the sensor over i2c // If you don't do this, the strobe GPIO is an output (even in reset it seems!) if (!enabled) return; @@ -570,6 +583,13 @@ void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num isp_dev_handle = *isp_dev_handle_; LOGD("acquire isp dev"); + // config ISP + alloc_w_mmu_hdl(multi_cam_state->video0_fd, 984480, (uint32_t*)&buf0_handle, 0x20, CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | + CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, multi_cam_state->device_iommu, multi_cam_state->cdm_iommu); + config_isp(0, 0, 1, buf0_handle, 0); +} + +void CameraState::configCSIPHY() { csiphy_fd = open_v4l_by_name_and_index("cam-csiphy-driver", camera_num); assert(csiphy_fd >= 0); LOGD("opened csiphy for %d", camera_num); @@ -580,11 +600,6 @@ void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num csiphy_dev_handle = *csiphy_dev_handle_; LOGD("acquire csiphy dev"); - // config ISP - alloc_w_mmu_hdl(multi_cam_state->video0_fd, 984480, (uint32_t*)&buf0_handle, 0x20, CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | - CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, multi_cam_state->device_iommu, multi_cam_state->cdm_iommu); - config_isp(0, 0, 1, buf0_handle, 0); - // config csiphy LOG("-- Config CSI PHY"); { @@ -612,15 +627,16 @@ void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num int ret_ = device_config(csiphy_fd, session_handle, csiphy_dev_handle, cam_packet_handle); assert(ret_ == 0); } +} - // link devices +void CameraState::linkDevices() { LOG("-- Link devices"); struct cam_req_mgr_link_info req_mgr_link_info = {0}; req_mgr_link_info.session_hdl = session_handle; req_mgr_link_info.num_devices = 2; req_mgr_link_info.dev_hdls[0] = isp_dev_handle; req_mgr_link_info.dev_hdls[1] = sensor_dev_handle; - ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_LINK, &req_mgr_link_info, sizeof(req_mgr_link_info)); + int ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_LINK, &req_mgr_link_info, sizeof(req_mgr_link_info)); link_handle = req_mgr_link_info.link_hdl; LOGD("link: %d session: 0x%X isp: 0x%X sensors: 0x%X link: 0x%X", ret, session_handle, isp_dev_handle, sensor_dev_handle, link_handle); diff --git a/system/camerad/cameras/camera_qcom2.h b/system/camerad/cameras/camera_qcom2.h index 0b15c9c3f0..b702d1bb69 100644 --- a/system/camerad/cameras/camera_qcom2.h +++ b/system/camerad/cameras/camera_qcom2.h @@ -86,6 +86,11 @@ public: void sensors_i2c(const struct i2c_random_wr_payload* dat, int len, int op_code, bool data_word); private: + bool openSensor(); + void configISP(); + void configCSIPHY(); + void linkDevices(); + // for debugging Params params; }; From d49c5193c33a41447d1d5748a069972893b7c6ec Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Wed, 24 Jul 2024 10:31:27 -0700 Subject: [PATCH 091/229] ci: fix ui preview (#33002) * use pull_request_target * env for name --- .github/workflows/selfdrive_tests.yaml | 55 +--------------- .github/workflows/ui_preview.yaml | 91 ++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 52 deletions(-) create mode 100644 .github/workflows/ui_preview.yaml diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 42c1dbb5eb..1154948ace 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -338,6 +338,7 @@ jobs: }) create_ui_report: + # This job name needs to be the same as UI_JOB_NAME in ui_preview.yaml name: Create UI Report runs-on: ubuntu-latest steps: @@ -355,55 +356,5 @@ jobs: - name: Upload Test Report uses: actions/upload-artifact@v4 with: - name: report-${{ inputs.run_number || '1' }} - path: selfdrive/ui/tests/test_ui/report_${{ inputs.run_number || '1' }} - - name: Get changes to selfdrive/ui - if: ${{ github.event_name == 'pull_request' }} - id: changed-files - uses: tj-actions/changed-files@v44 - with: - files: | - selfdrive/ui/** - - name: Checkout ci-artifacts - if: ${{ github.event_name == 'pull_request' && steps.changed-files.outputs.any_changed == 'true' }} - uses: actions/checkout@v4 - with: - repository: commaai/ci-artifacts - ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }} - path: ${{ github.workspace }}/ci-artifacts - ref: master - - name: Push Screenshots - if: ${{ github.event_name == 'pull_request' && steps.changed-files.outputs.any_changed == 'true' }} - working-directory: ${{ github.workspace }}/ci-artifacts - run: | - git checkout -b openpilot/pr-${{ github.event.pull_request.number }} - git config user.name "GitHub Actions Bot" - git config user.email "<>" - sudo mv ${{ github.workspace }}/selfdrive/ui/tests/test_ui/report_1/screenshots/* . - git add . - git commit -m "screenshots for PR #${{ github.event.pull_request.number }}" - git push origin openpilot/pr-${{ github.event.pull_request.number }} --force - - name: Comment Screenshots on PR - if: ${{ github.event_name == 'pull_request' && steps.changed-files.outputs.any_changed == 'true' }} - uses: thollander/actions-comment-pull-request@v2 - with: - message: | - - ## UI Screenshots - - - - - - - - - - - - - -
- comment_tag: run_id_screenshots - pr_number: ${{ github.event.pull_request.number }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + name: report-${{ github.event.number }} + path: selfdrive/ui/tests/test_ui/report_1/screenshots diff --git a/.github/workflows/ui_preview.yaml b/.github/workflows/ui_preview.yaml new file mode 100644 index 0000000000..c05c01f3e3 --- /dev/null +++ b/.github/workflows/ui_preview.yaml @@ -0,0 +1,91 @@ +name: "ui preview" +on: + pull_request_target: + types: [assigned, opened, synchronize, reopened, edited] + branches: + - 'master' + paths: + - 'selfdrive/ui/**' + +env: + UI_JOB_NAME: "Create UI Report" + +jobs: + preview: + if: github.repository == 'commaai/openpilot' + name: preview + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: + contents: read + pull-requests: write + actions: read + steps: + - name: Waiting for ui test to start + run: sleep 30 + + - name: Wait for ui report + uses: lewagon/wait-on-check-action@v1.3.4 + with: + ref: ${{ github.event.pull_request.head.sha }} + check-name: $UI_JOB_NAME + repo-token: ${{ secrets.GITHUB_TOKEN }} + allowed-conclusions: success + wait-interval: 20 + + - name: Get workflow run ID + id: get_run_id + run: | + echo "run_id=$(curl https://api.github.com/repos/${{ github.repository }}/commits/${{ github.event.pull_request.head.sha }}/check-runs | jq -r '.check_runs[] | select(.name == "$UI_JOB_NAME") | .html_url | capture("(?[0-9]+)") | .number')" >> $GITHUB_OUTPUT + + - name: Checkout ci-artifacts + uses: actions/checkout@v4 + with: + repository: commaai/ci-artifacts + ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }} + path: ${{ github.workspace }}/ci-artifacts + ref: master + + - name: Download artifact + id: download-artifact + uses: dawidd6/action-download-artifact@v6 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + run_id: ${{ steps.get_run_id.outputs.run_id }} + search_artifacts: true + name: report-${{ github.event.number }} + path: ${{ github.workspace }}/ci-artifacts + + - name: Push Screenshots + working-directory: ${{ github.workspace }}/ci-artifacts + run: | + git checkout -b openpilot/pr-${{ github.event.number }} + git config user.name "GitHub Actions Bot" + git config user.email "<>" + git add ${{ github.workspace }}/ci-artifacts/* + git commit -m "screenshots for PR #${{ github.event.number }}" + git push origin openpilot/pr-${{ github.event.number }} --force + + - name: Comment Screenshots on PR + uses: thollander/actions-comment-pull-request@v2 + with: + message: | + + ## UI Screenshots + + + + + + + + + + + + + +
+ comment_tag: run_id_screenshots + pr_number: ${{ github.event.number }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 344694110751b8282eabe0b8b1e4de38646e4623 Mon Sep 17 00:00:00 2001 From: Hoang Bui <47828508+bongbui321@users.noreply.github.com> Date: Wed, 24 Jul 2024 10:36:28 -0700 Subject: [PATCH 092/229] CI: remove redundant save cache step (#33052) remove --- .github/workflows/tools_tests.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index b64963fb60..9085556392 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -73,12 +73,6 @@ jobs: scons-${{ runner.arch }}-ubuntu2004 - name: Building openpilot run: uv run scons -u -j$(nproc) - - name: Saving scons cache - uses: actions/cache/save@v4 - if: github.ref == 'refs/heads/master' - with: - path: /tmp/scons_cache - key: scons-${{ runner.arch }}-ubuntu2004-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }} devcontainer: name: devcontainer From 2221ffcf0ea0d0631d92e016d5c1bd98116b9aba Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Wed, 24 Jul 2024 11:03:24 -0700 Subject: [PATCH 093/229] ci: use github env for ui preview job name (#33060) fix this --- .github/workflows/ui_preview.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ui_preview.yaml b/.github/workflows/ui_preview.yaml index c05c01f3e3..bc19e23778 100644 --- a/.github/workflows/ui_preview.yaml +++ b/.github/workflows/ui_preview.yaml @@ -28,7 +28,7 @@ jobs: uses: lewagon/wait-on-check-action@v1.3.4 with: ref: ${{ github.event.pull_request.head.sha }} - check-name: $UI_JOB_NAME + check-name: ${{ env.UI_JOB_NAME }} repo-token: ${{ secrets.GITHUB_TOKEN }} allowed-conclusions: success wait-interval: 20 @@ -36,7 +36,7 @@ jobs: - name: Get workflow run ID id: get_run_id run: | - echo "run_id=$(curl https://api.github.com/repos/${{ github.repository }}/commits/${{ github.event.pull_request.head.sha }}/check-runs | jq -r '.check_runs[] | select(.name == "$UI_JOB_NAME") | .html_url | capture("(?[0-9]+)") | .number')" >> $GITHUB_OUTPUT + echo "run_id=$(curl https://api.github.com/repos/${{ github.repository }}/commits/${{ github.event.pull_request.head.sha }}/check-runs | jq -r '.check_runs[] | select(.name == "${{ env.UI_JOB_NAME }}") | .html_url | capture("(?[0-9]+)") | .number')" >> $GITHUB_OUTPUT - name: Checkout ci-artifacts uses: actions/checkout@v4 From 31036771ee8ba71e3fbe7c7f08aad3b5be0127e6 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 24 Jul 2024 12:11:20 -0700 Subject: [PATCH 094/229] rerun: link to upstream issues --- tools/rerun/run.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/rerun/run.py b/tools/rerun/run.py index 421785a2d5..6d9554038c 100755 --- a/tools/rerun/run.py +++ b/tools/rerun/run.py @@ -18,6 +18,12 @@ RR_TIMELINE_NAME = "Timeline" RR_WIN = "rerun_test" +""" +Relevant upstream Rerun issues: +- large time series: https://github.com/rerun-io/rerun/issues/5967 +- loading videos directly: https://github.com/rerun-io/rerun/issues/6532 +""" + class Rerunner: def __init__(self, route, segment_range, camera_config, enabled_services): self.enabled_services = [s.lower() for s in enabled_services] From e38a1428aa20aad134b4ad9fd1abab33a1de70b9 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 24 Jul 2024 14:47:33 -0700 Subject: [PATCH 095/229] LogReader: support multiple log extensions in route (#33066) * support rlog.zst * TODO --- tools/lib/logreader.py | 1 + tools/lib/route.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/lib/logreader.py b/tools/lib/logreader.py index 6ad77bf823..07a4b2003e 100755 --- a/tools/lib/logreader.py +++ b/tools/lib/logreader.py @@ -140,6 +140,7 @@ def internal_source(sr: SegmentRange, mode: ReadMode, file_ext: str = "bz2") -> def get_internal_url(sr: SegmentRange, seg, file): return f"cd:/{sr.dongle_id}/{sr.log_id}/{seg}/{file}.{file_ext}" + # TODO: list instead of using static URLs to support routes with multiple file extensions rlog_paths = [get_internal_url(sr, seg, "rlog") for seg in sr.seg_idxs] qlog_paths = [get_internal_url(sr, seg, "qlog") for seg in sr.seg_idxs] diff --git a/tools/lib/route.py b/tools/lib/route.py index 6ff5d19208..ddb8b0486e 100644 --- a/tools/lib/route.py +++ b/tools/lib/route.py @@ -11,7 +11,7 @@ from openpilot.tools.lib.helpers import RE QLOG_FILENAMES = ['qlog', 'qlog.bz2', 'qlog.zst'] QCAMERA_FILENAMES = ['qcamera.ts'] -LOG_FILENAMES = ['rlog', 'rlog.bz2', 'raw_log.bz2'] +LOG_FILENAMES = ['rlog', 'rlog.bz2', 'raw_log.bz2', 'rlog.zst'] CAMERA_FILENAMES = ['fcamera.hevc', 'video.hevc'] DCAMERA_FILENAMES = ['dcamera.hevc'] ECAMERA_FILENAMES = ['ecamera.hevc'] From add958bb08890c653be89999701cb3d794c5c717 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 24 Jul 2024 14:48:33 -0700 Subject: [PATCH 096/229] athenad: log failed upload items --- system/athena/athenad.py | 1 + 1 file changed, 1 insertion(+) diff --git a/system/athena/athenad.py b/system/athena/athenad.py index 9769f065f6..b4f9b8b6a7 100755 --- a/system/athena/athenad.py +++ b/system/athena/athenad.py @@ -401,6 +401,7 @@ def uploadFilesToUrls(files_data: list[UploadFileDict]) -> UploadFilesToUrlRespo resp: UploadFilesToUrlResponse = {"enqueued": len(items), "items": items} if failed: + cloudlog.event("athena.uploadFilesToUrls.failed", failed=failed, error=True) resp["failed"] = failed return resp From 71ad5a8deef595d3e0cb01d3e8a4d8ced1ae5085 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Wed, 24 Jul 2024 14:49:35 -0700 Subject: [PATCH 097/229] op.sh: general improvements (#33062) * color * format * dry * unset * venv * search for openpilot * linter * replay --- tools/op.sh | 106 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 81 insertions(+), 25 deletions(-) diff --git a/tools/op.sh b/tools/op.sh index bbc4ded445..111a06e81c 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -2,6 +2,8 @@ RED='\033[0;31m' GREEN='\033[0;32m' +UNDERLINE='\033[4m' +BOLD='\033[1m' NC='\033[0m' function op_first_install() { @@ -12,7 +14,7 @@ function op_first_install() { if [ "$(uname)" == "Darwin" ] && [ $SHELL == "/bin/bash" ]; then RC_FILE="$HOME/.bash_profile" fi - printf "\nalias op='source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/op.sh" \"\$@\"'\n" >> $RC_FILE + op_run_command printf "\nalias op='source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/op.sh" \"\$@\"'\n" >> $RC_FILE echo -e " ↳ [${GREEN}✔${NC}] op installed successfully. Open a new shell to use it.\n" ) @@ -21,14 +23,25 @@ function op_first_install() { # be default, assume openpilot dir is in current directory OPENPILOT_ROOT=$(pwd) function op_check_openpilot_dir() { - (set -e + while [[ "$OPENPILOT_ROOT" != '/' ]]; + do + if find "$OPENPILOT_ROOT/launch_openpilot.sh" -maxdepth 1 -mindepth 1 &> /dev/null; then + return 0 + fi + OPENPILOT_ROOT="$(readlink -f "$OPENPILOT_ROOT/"..)" + done - if [ ! -f "$OPENPILOT_ROOT/launch_openpilot.sh" ]; then - echo "openpilot directory not found!" - return 1 + echo "openpilot directory not found! Make sure that you are inside openpilot" + echo "directory or specify one with the --dir option!" + return 1 +} + +function op_run_command() { + CMD="$@" + echo -e "${BOLD}Running:${NC} $CMD" + if [[ -z "$DRY" ]]; then + $CMD fi - - ) } function op_check_git() { @@ -118,7 +131,7 @@ function op_check_python() { # this must be run in the same shell as the user calling "op" function op_venv() { op_check_openpilot_dir || return 1 - source $OPENPILOT_ROOT/.venv/bin/activate || (echo -e "\nCan't activate venv. Have you ran 'op install' ?" && return 1) + op_run_command source $OPENPILOT_ROOT/.venv/bin/activate || (echo -e "\nCan't activate venv. Have you ran 'op install' ?" && return 1) } function op_check() { @@ -138,7 +151,8 @@ function op_run() { op_venv cd $OPENPILOT_ROOT - $OPENPILOT_ROOT/launch_openpilot.sh + + op_run_command $OPENPILOT_ROOT/launch_openpilot.sh ) } @@ -170,7 +184,7 @@ function op_build() { op_venv cd $OPENPILOT_ROOT - scons $@ || echo -e "\nBuild failed. Have you ran 'op install' ?" + op_run_command scons $@ ) } @@ -181,7 +195,28 @@ function op_juggle() { op_venv cd $OPENPILOT_ROOT - $OPENPILOT_ROOT/tools/plotjuggler/juggle.py $@ + op_run_command $OPENPILOT_ROOT/tools/plotjuggler/juggle.py $@ + + ) +} + +function op_linter() { + (set -e + + op_venv + cd $OPENPILOT_ROOT + + op_run_command pre-commit run --all $@ + + ) +} + +function op_replay() { + (set -e + op_check_openpilot_dir + cd $OPENPILOT_ROOT + + op_run_command $OPENPILOT_ROOT/tools/replay/replay $@ ) } @@ -189,24 +224,37 @@ function op_juggle() { function op_default() { echo "An openpilot helper" echo "" - echo -e "\e[4mUsage:\e[0m op [OPTIONS] " + echo -e "${BOLD}${UNDERLINE}Description:${NC}" + echo " op is your entry point for all things related to openpilot development." + echo " op is only a wrapper for scripts, tools and commands already existing." + echo " op will always show you what it will run on your system." echo "" - echo -e "\e[4mCommands:\e[0m" - echo " venv Activate the virtual environment" - echo " check Check system requirements (git, os, python) to start using openpilot" - echo " install Install requirements to use openpilot" - echo " build Build openpilot" - echo " run Run openpilot" - echo " juggle Run Plotjuggler" - echo " help Show this message" - echo " --install Install this tool system wide" + echo " op will try to find your openpilot directory in the following order:" + echo " 1: use the directory specified with the --dir option" + echo " 2: use the current working directory" + echo " 3: go up the file tree non-recursively" echo "" - echo -e "\e[4mOptions:\e[0m" - echo " -d, --dir" + echo -e "${BOLD}${UNDERLINE}Usage:${NC} op [OPTIONS] " + echo "" + echo -e "${BOLD}${UNDERLINE}Commands:${NC}" + echo -e " ${BOLD}venv${NC} Activate the virtual environment" + echo -e " ${BOLD}check${NC} Check system requirements (git, os, python) to start using openpilot" + echo -e " ${BOLD}install${NC} Install requirements to use openpilot" + echo -e " ${BOLD}build${NC} Build openpilot" + echo -e " ${BOLD}run${NC} Run openpilot" + echo -e " ${BOLD}juggle${NC} Run Plotjuggler" + echo -e " ${BOLD}replay${NC} Run replay" + echo -e " ${BOLD}linter${NC} Run all the pre-commit checks" + echo -e " ${BOLD}help${NC} Show this message" + echo -e " ${BOLD}--install${NC} Install this tool system wide" + echo "" + echo -e "${BOLD}${UNDERLINE}Options:${NC}" + echo -e " ${BOLD}-d, --dir${NC}" echo " Specify the openpilot directory you want to use" - echo " Default to the current working directory" + echo -e " ${BOLD}--dry${NC}" + echo " Don't actually run anything, just print what would be" echo "" - echo -e "\e[4mExamples:\e[0m" + echo -e "${BOLD}${UNDERLINE}Examples:${NC}" echo " op --dir /tmp/openpilot check" echo " Run the check command on openpilot located in /tmp/openpilot" echo "" @@ -224,6 +272,7 @@ function _op() { # parse Options case $1 in -d | --dir ) shift 1; OPENPILOT_ROOT="$1"; shift 1 ;; + --dry ) shift 1; DRY="1" ;; esac # parse Commands @@ -234,6 +283,8 @@ function _op() { build ) shift 1; op_build "$@" ;; run ) shift 1; op_run "$@" ;; juggle ) shift 1; op_juggle "$@" ;; + linter ) shift 1; op_linter "$@" ;; + replay ) shift 1; op_replay "$@" ;; --install ) shift 1; op_first_install "$@" ;; * ) op_default "$@" ;; esac @@ -255,3 +306,8 @@ unset -f op_check_python unset -f op_check_os unset -f op_first_install unset -f op_default +unset -f op_run_command +unset -f op_linter +unset -f op_replay +unset DRY +unset OPENPILOT_ROOT From 4ac938a578e68c88e39b73fa35024a4320557f64 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Wed, 24 Jul 2024 22:20:16 -0700 Subject: [PATCH 098/229] op.sh: improvements (#33067) * cabana * pre-check * cd * change this * fix * fix install --- tools/op.sh | 197 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 117 insertions(+), 80 deletions(-) diff --git a/tools/op.sh b/tools/op.sh index 111a06e81c..27f1817211 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash RED='\033[0;31m' GREEN='\033[0;32m' @@ -14,28 +14,12 @@ function op_first_install() { if [ "$(uname)" == "Darwin" ] && [ $SHELL == "/bin/bash" ]; then RC_FILE="$HOME/.bash_profile" fi - op_run_command printf "\nalias op='source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/op.sh" \"\$@\"'\n" >> $RC_FILE + printf "\nalias op='source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/op.sh" \"\$@\"'\n" >> $RC_FILE echo -e " ↳ [${GREEN}✔${NC}] op installed successfully. Open a new shell to use it.\n" ) } -# be default, assume openpilot dir is in current directory -OPENPILOT_ROOT=$(pwd) -function op_check_openpilot_dir() { - while [[ "$OPENPILOT_ROOT" != '/' ]]; - do - if find "$OPENPILOT_ROOT/launch_openpilot.sh" -maxdepth 1 -mindepth 1 &> /dev/null; then - return 0 - fi - OPENPILOT_ROOT="$(readlink -f "$OPENPILOT_ROOT/"..)" - done - - echo "openpilot directory not found! Make sure that you are inside openpilot" - echo "directory or specify one with the --dir option!" - return 1 -} - function op_run_command() { CMD="$@" echo -e "${BOLD}Running:${NC} $CMD" @@ -44,34 +28,52 @@ function op_run_command() { fi } +# be default, assume openpilot dir is in current directory +OPENPILOT_ROOT=$(pwd) +function op_check_openpilot_dir() { + echo "Checking for openpilot directory..." + while [[ "$OPENPILOT_ROOT" != '/' ]]; + do + if find "$OPENPILOT_ROOT/launch_openpilot.sh" -maxdepth 1 -mindepth 1 &> /dev/null; then + echo -e " ↳ [${GREEN}✔${NC}] openpilot found.\n" + return 0 + fi + OPENPILOT_ROOT="$(readlink -f "$OPENPILOT_ROOT/"..)" + done + + echo -e " ↳ [${RED}✗${NC}] openpilot directory not found! Make sure that you are" + echo " inside the openpilot directory or specify one with the" + echo " --dir option!" + return 1 +} + function op_check_git() { (set -e - cd $OPENPILOT_ROOT - echo "Checking for git..." if ! command -v "git" > /dev/null 2>&1; then - echo -e " ↳ [${RED}✗${NC}] git not found on your system!" + echo -e " ↳ [${RED}✗${NC}] git not found on your system!\n" return 1 else - echo -e " ↳ [${GREEN}✔${NC}] git found on your system.\n" + echo -e " ↳ [${GREEN}✔${NC}] git found.\n" fi echo "Checking for git lfs files..." - if [[ $(file -b $(git lfs ls-files -n | grep "\.so" | head -n 1)) == "ASCII text" ]]; then - echo -e " ↳ [${RED}✗${NC}] git lfs files not found! Run git lfs pull" + if [[ $(file -b $OPENPILOT_ROOT/selfdrive/modeld/models/supercombo.onnx) == "ASCII text" ]]; then + echo -e " ↳ [${RED}✗${NC}] git lfs files not found! Run 'git lfs pull'\n" return 1 else - echo -e " ↳ [${GREEN}✔${NC}] git lfs files found on your system.\n" + echo -e " ↳ [${GREEN}✔${NC}] git lfs files found.\n" fi echo "Checking for git submodules..." - if $(git submodule foreach --quiet --recursive 'return 1' 2&> /dev/null); then - echo -e " ↳ [${RED}✗${NC}] git submodules not found! Run 'git submodule update --init --recursive'" - return 1 - else - echo -e " ↳ [${GREEN}✔${NC}] git submodules found on your system.\n" - fi + for name in body msgq_repo opendbc panda rednose_repo tinygrad_repo; do + if [[ -z $(ls $OPENPILOT_ROOT/$name) ]]; then + echo -e " ↳ [${RED}✗${NC}] git submodule $name not found! Run 'git submodule update --init --recursive'\n" + return 1 + fi + done + echo -e " ↳ [${GREEN}✔${NC}] git submodules found.\n" ) } @@ -89,19 +91,19 @@ function op_check_os() { echo -e " ↳ [${GREEN}✔${NC}] Ubuntu $VERSION_CODENAME detected.\n" ;; * ) - echo -e " ↳ [${RED}✗${NC}] Incompatible Ubuntu version $VERSION_CODENAME detected!" + echo -e " ↳ [${RED}✗${NC}] Incompatible Ubuntu version $VERSION_CODENAME detected!\n" return 1 ;; esac else - echo -e " ↳ [${RED}✗${NC}] No /etc/os-release on your system. Make sure you're running on Ubuntu, or similar!" + echo -e " ↳ [${RED}✗${NC}] No /etc/os-release on your system. Make sure you're running on Ubuntu, or similar!\n" return 1 fi elif [[ "$OSTYPE" == "darwin"* ]]; then echo -e " ↳ [${GREEN}✔${NC}] macos detected.\n" else - echo -e " ↳ [${RED}✗${NC}] OS type $OSTYPE not supported!" + echo -e " ↳ [${RED}✗${NC}] OS type $OSTYPE not supported!\n" return 1 fi @@ -112,49 +114,43 @@ function op_check_python() { (set -e echo "Checking for compatible python version..." - export REQUIRED_PYTHON_VERSION=$(grep "requires-python" pyproject.toml | cut -d= -f3- | tr -d '"' | tr -d ' ') - if ! command -v "python3" > /dev/null 2>&1; then - echo -e " ↳ [${RED}✗${NC}] python3 not found on your system. You need python version at least $REQUIRED_PYTHON_VERSION to continue!" + REQUIRED_PYTHON_VERSION=$(grep "requires-python" $OPENPILOT_ROOT/pyproject.toml) + INSTALLED_PYTHON_VERSION=$(python3 --version 2> /dev/null || true) + + if [[ -z $INSTALLED_PYTHON_VERSION ]]; then + echo -e " ↳ [${RED}✗${NC}] python3 not found on your system. You need python version at least $(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9.]') to continue!\n" return 1 + elif [[ $(echo $INSTALLED_PYTHON_VERSION | tr -d -c '[0-9]') -ge $(($(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9]') * 10)) ]]; then + echo -e " ↳ [${GREEN}✔${NC}] $INSTALLED_PYTHON_VERSION detected.\n" else - if $(python3 -c "import sys; quit(not sys.version_info >= tuple(map(int, \"$REQUIRED_PYTHON_VERSION\".split('.'))))"); then - echo -e " ↳ [${GREEN}✔${NC}] $(python3 --version) detected.\n" - else - echo -e " ↳ [${RED}✗${NC}] You need python version at least $REQUIRED_PYTHON_VERSION to continue!" - return 1 - fi + echo -e " ↳ [${RED}✗${NC}] You need python version at least $(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9.]') to continue!\n" + return 1 fi ) } -# this must be run in the same shell as the user calling "op" -function op_venv() { - op_check_openpilot_dir || return 1 - op_run_command source $OPENPILOT_ROOT/.venv/bin/activate || (echo -e "\nCan't activate venv. Have you ran 'op install' ?" && return 1) +function op_check_venv() { + echo "Checking for venv..." + if source $OPENPILOT_ROOT/.venv/bin/activate; then + echo -e " ↳ [${GREEN}✔${NC}] venv detected.\n" + else + echo -e " ↳ [${RED}✗${NC}] Can't activate venv in $OPENPILOT_ROOT. Assuming global env!\n" + fi } -function op_check() { - (set -e +function op_before_cmd() { + if [[ ! -z "$NO_VERIFY" ]]; then + return 0 + fi op_check_openpilot_dir cd $OPENPILOT_ROOT op_check_git op_check_os + op_check_venv op_check_python - - ) -} - -function op_run() { - (set -e - - op_venv - cd $OPENPILOT_ROOT - - op_run_command $OPENPILOT_ROOT/launch_openpilot.sh - - ) + echo -e "-----------------------------\n" } function op_install() { @@ -162,18 +158,48 @@ function op_install() { op_check_openpilot_dir cd $OPENPILOT_ROOT - op_check_os op_check_python if [[ "$OSTYPE" == "linux-gnu"* ]]; then - $OPENPILOT_ROOT/tools/ubuntu_setup.sh + op_run_command $OPENPILOT_ROOT/tools/ubuntu_setup.sh elif [[ "$OSTYPE" == "darwin"* ]]; then - $OPENPILOT_ROOT/tools/mac_setup.sh + op_run_command $OPENPILOT_ROOT/tools/mac_setup.sh fi - git submodule update --init --recursive - git lfs pull + op_run_command git submodule update --init --recursive + op_run_command git lfs pull + + ) +} + +function op_venv() { + ( set -e + + op_before_cmd + + ) + + if [[ "$?" -eq 0 ]]; then + # this must be run in the same shell as the user calling "op" + op_check_openpilot_dir > /dev/null + op_run_command source $OPENPILOT_ROOT/.venv/bin/activate + fi +} + +function op_check() { + (set -e + + op_before_cmd + + ) +} + +function op_run() { + (set -e + + op_before_cmd + op_run_command $OPENPILOT_ROOT/launch_openpilot.sh ) } @@ -181,9 +207,7 @@ function op_install() { function op_build() { (set -e - op_venv - cd $OPENPILOT_ROOT - + op_before_cmd op_run_command scons $@ ) @@ -192,9 +216,7 @@ function op_build() { function op_juggle() { (set -e - op_venv - cd $OPENPILOT_ROOT - + op_before_cmd op_run_command $OPENPILOT_ROOT/tools/plotjuggler/juggle.py $@ ) @@ -203,9 +225,7 @@ function op_juggle() { function op_linter() { (set -e - op_venv - cd $OPENPILOT_ROOT - + op_before_cmd op_run_command pre-commit run --all $@ ) @@ -213,14 +233,22 @@ function op_linter() { function op_replay() { (set -e - op_check_openpilot_dir - cd $OPENPILOT_ROOT + op_before_cmd op_run_command $OPENPILOT_ROOT/tools/replay/replay $@ ) } +function op_cabana() { + (set -e + + op_before_cmd + op_run_command $OPENPILOT_ROOT/tools/cabana/cabana $@ + + ) +} + function op_default() { echo "An openpilot helper" echo "" @@ -244,6 +272,7 @@ function op_default() { echo -e " ${BOLD}run${NC} Run openpilot" echo -e " ${BOLD}juggle${NC} Run Plotjuggler" echo -e " ${BOLD}replay${NC} Run replay" + echo -e " ${BOLD}cabana${NC} Run cabana" echo -e " ${BOLD}linter${NC} Run all the pre-commit checks" echo -e " ${BOLD}help${NC} Show this message" echo -e " ${BOLD}--install${NC} Install this tool system wide" @@ -253,6 +282,8 @@ function op_default() { echo " Specify the openpilot directory you want to use" echo -e " ${BOLD}--dry${NC}" echo " Don't actually run anything, just print what would be" + echo -e " ${BOLD}-n, --no-verify${NC}" + echo " Don't run checks before running a command" echo "" echo -e "${BOLD}${UNDERLINE}Examples:${NC}" echo " op --dir /tmp/openpilot check" @@ -271,8 +302,9 @@ function op_default() { function _op() { # parse Options case $1 in - -d | --dir ) shift 1; OPENPILOT_ROOT="$1"; shift 1 ;; - --dry ) shift 1; DRY="1" ;; + -d | --dir ) shift 1; OPENPILOT_ROOT="$1"; shift 1 ;; + --dry ) shift 1; DRY="1" ;; + -n | --no-verify ) shift 1; NO_VERIFY="1" ;; esac # parse Commands @@ -283,6 +315,7 @@ function _op() { build ) shift 1; op_build "$@" ;; run ) shift 1; op_run "$@" ;; juggle ) shift 1; op_juggle "$@" ;; + cabana ) shift 1; op_cabana "$@" ;; linter ) shift 1; op_linter "$@" ;; replay ) shift 1; op_replay "$@" ;; --install ) shift 1; op_first_install "$@" ;; @@ -309,5 +342,9 @@ unset -f op_default unset -f op_run_command unset -f op_linter unset -f op_replay +unset -f op_cabana +unset -f op_check_venv +unset -f op_before_cmd unset DRY unset OPENPILOT_ROOT +unset NO_VERIFY From 6cdf2a1499885acec46d77498e96cad0f972592b Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Wed, 24 Jul 2024 23:11:23 -0700 Subject: [PATCH 099/229] Update op.sh --- tools/op.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/op.sh b/tools/op.sh index 27f1817211..7ad9697185 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -24,7 +24,7 @@ function op_run_command() { CMD="$@" echo -e "${BOLD}Running:${NC} $CMD" if [[ -z "$DRY" ]]; then - $CMD + eval "$CMD" fi } From edd8759f3934b44c640d7d044bd0c383caf68a42 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 26 Jul 2024 01:16:59 +0800 Subject: [PATCH 100/229] scons: move `-Ithird_party/qrcode` to qt modules (#33071) move -Ithird_party/qrcode to qt modeules --- SConstruct | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SConstruct b/SConstruct index 1f83b1e43d..90fc5b5ee7 100644 --- a/SConstruct +++ b/SConstruct @@ -205,7 +205,6 @@ env = Environment( "#third_party/json11", "#third_party/linux/include", "#third_party/snpe/include", - "#third_party/qrcode", "#third_party", "#cereal", "#msgq", @@ -314,7 +313,7 @@ try: except SCons.Errors.UserError: qt_env.Tool('qt') -qt_env['CPPPATH'] += qt_dirs# + ["#selfdrive/ui/qt/"] +qt_env['CPPPATH'] += qt_dirs + ["#third_party/qrcode"] qt_flags = [ "-D_REENTRANT", "-DQT_NO_DEBUG", From 75f49f84f3b71c970e7f4a5768016a092175e870 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 26 Jul 2024 04:09:03 +0800 Subject: [PATCH 101/229] camerad: add CameraConfig struct for initializing CameraState in constructor (#33065) * Add CameraConfig struct for initializing CameraState in constructor * init member variables --- system/camerad/cameras/camera_common.cc | 2 +- system/camerad/cameras/camera_common.h | 3 - system/camerad/cameras/camera_qcom2.cc | 50 ++++++----- system/camerad/cameras/camera_qcom2.h | 108 +++++++++++++++--------- 4 files changed, 97 insertions(+), 66 deletions(-) diff --git a/system/camerad/cameras/camera_common.cc b/system/camerad/cameras/camera_common.cc index 9d82284d9f..aef00c1bba 100644 --- a/system/camerad/cameras/camera_common.cc +++ b/system/camerad/cameras/camera_common.cc @@ -324,7 +324,7 @@ void camerad_thread() { #endif { - MultiCameraState cameras = {}; + MultiCameraState cameras; VisionIpcServer vipc_server("camerad", device_id, context); cameras_open(&cameras); diff --git a/system/camerad/cameras/camera_common.h b/system/camerad/cameras/camera_common.h index 555362ab8b..f97940b669 100644 --- a/system/camerad/cameras/camera_common.h +++ b/system/camerad/cameras/camera_common.h @@ -18,9 +18,6 @@ enum CameraType { }; // for debugging -const bool env_disable_road = getenv("DISABLE_ROAD") != NULL; -const bool env_disable_wide_road = getenv("DISABLE_WIDE_ROAD") != NULL; -const bool env_disable_driver = getenv("DISABLE_DRIVER") != NULL; const bool env_debug_frames = getenv("DEBUG_FRAMES") != NULL; const bool env_log_raw_frames = getenv("LOG_RAW_FRAMES") != NULL; const bool env_ctrl_exp_from_params = getenv("CTRL_EXP_FROM_PARAMS") != NULL; diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index 7c1f8e44e7..5767bec870 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -26,6 +26,14 @@ const int MIPI_SETTLE_CNT = 33; // Calculated by camera_freqs.py extern ExitHandler do_exit; +CameraState::CameraState(MultiCameraState *multi_camera_state, const CameraConfig &config) + : multi_cam_state(multi_camera_state), + camera_num(config.camera_num), + stream_type(config.stream_type), + focal_len(config.focal_len), + enabled(config.enabled) { +} + int CameraState::clear_req_queue() { struct cam_req_mgr_flush_info req_mgr_flush_request = {0}; req_mgr_flush_request.session_hdl = session_handle; @@ -425,48 +433,38 @@ void CameraState::set_exposure_rect() { } void CameraState::sensor_set_parameters() { - target_grey_fraction = 0.3; - - dc_gain_enabled = false; dc_gain_weight = ci->dc_gain_min_weight; gain_idx = ci->analog_gain_rec_idx; - exposure_time = 5; cur_ev[0] = cur_ev[1] = cur_ev[2] = (1 + dc_gain_weight * (ci->dc_gain_factor-1) / ci->dc_gain_max_weight) * ci->sensor_analog_gains[gain_idx] * exposure_time; } -void CameraState::camera_map_bufs(MultiCameraState *s) { +void CameraState::camera_map_bufs() { for (int i = 0; i < FRAME_BUF_COUNT; i++) { // configure ISP to put the image in place struct cam_mem_mgr_map_cmd mem_mgr_map_cmd = {0}; - mem_mgr_map_cmd.mmu_hdls[0] = s->device_iommu; + mem_mgr_map_cmd.mmu_hdls[0] = multi_cam_state->device_iommu; mem_mgr_map_cmd.num_hdl = 1; mem_mgr_map_cmd.flags = CAM_MEM_FLAG_HW_READ_WRITE; mem_mgr_map_cmd.fd = buf.camera_bufs[i].fd; - int ret = do_cam_control(s->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd)); + int ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd)); LOGD("map buf req: (fd: %d) 0x%x %d", buf.camera_bufs[i].fd, mem_mgr_map_cmd.out.buf_handle, ret); buf_handle[i] = mem_mgr_map_cmd.out.buf_handle; } enqueue_req_multi(1, FRAME_BUF_COUNT, 0); } -void CameraState::camera_init(MultiCameraState *s, VisionIpcServer * v, cl_device_id device_id, cl_context ctx, VisionStreamType yuv_type, float focal_len) { +void CameraState::camera_init(VisionIpcServer * v, cl_device_id device_id, cl_context ctx) { if (!enabled) return; LOGD("camera init %d", camera_num); - request_id_last = 0; - skipped = true; - - buf.init(device_id, ctx, this, v, FRAME_BUF_COUNT, yuv_type); - camera_map_bufs(s); + buf.init(device_id, ctx, this, v, FRAME_BUF_COUNT, stream_type); + camera_map_bufs(); fl_pix = focal_len / ci->pixel_size_mm; set_exposure_rect(); } -void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num_, bool enabled_) { - multi_cam_state = multi_cam_state_; - camera_num = camera_num_; - enabled = enabled_; +void CameraState::camera_open() { if (!enabled) return; if (!openSensor()) { @@ -660,9 +658,9 @@ void CameraState::linkDevices() { } void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_id, cl_context ctx) { - s->driver_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_DRIVER, DRIVER_FL_MM); - s->road_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_ROAD, ROAD_FL_MM); - s->wide_road_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_WIDE_ROAD, WIDE_FL_MM); + s->driver_cam.camera_init(v, device_id, ctx); + s->road_cam.camera_init(v, device_id, ctx); + s->wide_road_cam.camera_init(v, device_id, ctx); s->pm = new PubMaster({"roadCameraState", "driverCameraState", "wideRoadCameraState", "thumbnail"}); } @@ -706,11 +704,11 @@ void cameras_open(MultiCameraState *s) { ret = HANDLE_EINTR(ioctl(s->video0_fd, VIDIOC_SUBSCRIBE_EVENT, &sub)); LOGD("req mgr subscribe: %d", ret); - s->driver_cam.camera_open(s, 2, !env_disable_driver); + s->driver_cam.camera_open(); LOGD("driver camera opened"); - s->road_cam.camera_open(s, 1, !env_disable_road); + s->road_cam.camera_open(); LOGD("road camera opened"); - s->wide_road_cam.camera_open(s, 0, !env_disable_wide_road); + s->wide_road_cam.camera_open(); LOGD("wide road camera opened"); } @@ -972,6 +970,12 @@ void process_road_camera(MultiCameraState *s, CameraState *c, int cnt) { c->set_camera_exposure(set_exposure_target(b, c->ae_xywh, skip, skip)); } +MultiCameraState::MultiCameraState() + : driver_cam(this, DRIVER_CAMERA_CONFIG), + road_cam(this, ROAD_CAMERA_CONFIG), + wide_road_cam(this, WIDE_ROAD_CAMERA_CONFIG) { +} + void cameras_run(MultiCameraState *s) { LOG("-- Starting threads"); std::vector threads; diff --git a/system/camerad/cameras/camera_qcom2.h b/system/camerad/cameras/camera_qcom2.h index b702d1bb69..47981e0753 100644 --- a/system/camerad/cameras/camera_qcom2.h +++ b/system/camerad/cameras/camera_qcom2.h @@ -11,67 +11,94 @@ #define FRAME_BUF_COUNT 4 -#define ROAD_FL_MM 8.0f -#define WIDE_FL_MM 1.71f -#define DRIVER_FL_MM 1.71f +struct CameraConfig { + int camera_num; + VisionStreamType stream_type; + float focal_len; // millimeters + bool enabled; +}; + +const CameraConfig WIDE_ROAD_CAMERA_CONFIG = { + .camera_num = 0, + .stream_type = VISION_STREAM_WIDE_ROAD, + .focal_len = 1.71, + .enabled = !getenv("DISABLE_WIDE_ROAD"), +}; + +const CameraConfig ROAD_CAMERA_CONFIG = { + .camera_num = 1, + .stream_type = VISION_STREAM_ROAD, + .focal_len = 8.0, + .enabled = !getenv("DISABLE_ROAD"), +}; + +const CameraConfig DRIVER_CAMERA_CONFIG = { + .camera_num = 2, + .stream_type = VISION_STREAM_DRIVER, + .focal_len = 1.71, + .enabled = !getenv("DISABLE_DRIVER"), +}; class CameraState { public: - MultiCameraState *multi_cam_state; + MultiCameraState *multi_cam_state = nullptr; std::unique_ptr ci; - bool enabled; + bool enabled = true; + VisionStreamType stream_type; + float focal_len = 0; std::mutex exp_lock; - int exposure_time; - bool dc_gain_enabled; - int dc_gain_weight; - int gain_idx; - float analog_gain_frac; + int exposure_time = 5; + bool dc_gain_enabled = false; + int dc_gain_weight = 0; + int gain_idx = 0; + float analog_gain_frac = 0; - float cur_ev[3]; - float best_ev_score; - int new_exp_g; - int new_exp_t; + float cur_ev[3] = {}; + float best_ev_score = 0; + int new_exp_g = 0; + int new_exp_t = 0; - Rect ae_xywh; - float measured_grey_fraction; - float target_grey_fraction; + Rect ae_xywh = {}; + float measured_grey_fraction = 0; + float target_grey_fraction = 0.3; unique_fd sensor_fd; unique_fd csiphy_fd; - int camera_num; - float fl_pix; + int camera_num = 0; + float fl_pix = 0; + CameraState(MultiCameraState *multi_camera_state, const CameraConfig &config); void handle_camera_event(void *evdat); void update_exposure_score(float desired_ev, int exp_t, int exp_g_idx, float exp_gain); void set_camera_exposure(float grey_frac); void sensors_start(); - void camera_open(MultiCameraState *multi_cam_state, int camera_num, bool enabled); + void camera_open(); void set_exposure_rect(); void sensor_set_parameters(); - void camera_map_bufs(MultiCameraState *s); - void camera_init(MultiCameraState *s, VisionIpcServer *v, cl_device_id device_id, cl_context ctx, VisionStreamType yuv_type, float focal_len); + void camera_map_bufs(); + void camera_init(VisionIpcServer *v, cl_device_id device_id, cl_context ctx); void camera_close(); - int32_t session_handle; - int32_t sensor_dev_handle; - int32_t isp_dev_handle; - int32_t csiphy_dev_handle; + int32_t session_handle = -1; + int32_t sensor_dev_handle = -1; + int32_t isp_dev_handle = -1; + int32_t csiphy_dev_handle = -1; - int32_t link_handle; + int32_t link_handle = -1; - int buf0_handle; - int buf_handle[FRAME_BUF_COUNT]; - int sync_objs[FRAME_BUF_COUNT]; - int request_ids[FRAME_BUF_COUNT]; - int request_id_last; - int frame_id_last; - int idx_offset; - bool skipped; + int buf0_handle = 0; + int buf_handle[FRAME_BUF_COUNT] = {}; + int sync_objs[FRAME_BUF_COUNT] = {}; + int request_ids[FRAME_BUF_COUNT] = {}; + int request_id_last = 0; + int frame_id_last = 0; + int idx_offset = 0; + bool skipped = true; CameraBuf buf; MemoryManager mm; @@ -95,16 +122,19 @@ private: Params params; }; -typedef struct MultiCameraState { +class MultiCameraState { +public: + MultiCameraState(); + unique_fd video0_fd; unique_fd cam_sync_fd; unique_fd isp_fd; - int device_iommu; - int cdm_iommu; + int device_iommu = -1; + int cdm_iommu = -1; CameraState road_cam; CameraState wide_road_cam; CameraState driver_cam; PubMaster *pm; -} MultiCameraState; +}; From 2da4aef2683dc9af4ff49435c8d021b6261d329b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 26 Jul 2024 04:10:36 +0800 Subject: [PATCH 102/229] scons: remove redundant -DSWAGLOG Flag (#33070) remove redundant_-DSWAGLOG Flag --- SConstruct | 1 - 1 file changed, 1 deletion(-) diff --git a/SConstruct b/SConstruct index 90fc5b5ee7..329ebe3308 100644 --- a/SConstruct +++ b/SConstruct @@ -169,7 +169,6 @@ if arch != "Darwin": ldflags += ["-Wl,--as-needed", "-Wl,--no-undefined"] # Enable swaglog include in submodules -cflags += ['-DSWAGLOG="\\"common/swaglog.h\\""'] cxxflags += ['-DSWAGLOG="\\"common/swaglog.h\\""'] ccflags_option = GetOption('ccflags') From 313a2826c268a7974ce7422084ab294767b7c9bd Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 26 Jul 2024 04:36:44 +0800 Subject: [PATCH 103/229] mcid.py: optimize FFT and A-weighting calculations (#33057) * Precomputing weighting * add comments back * use cache * spacing spacing * clean up * lower by diff --------- Co-authored-by: Shane Smiskol --- selfdrive/test/test_onroad.py | 2 +- system/micd.py | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index bbb99d13b9..1e4669fb0a 100644 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -56,7 +56,7 @@ PROCS = { "system.logmessaged": 0.2, "system.tombstoned": 0, "logcatd": 0, - "system.micd": 6.0, + "system.micd": 5.0, "system.timed": 0, "selfdrive.pandad.pandad": 0, "system.statsd": 0.4, diff --git a/system/micd.py b/system/micd.py index 8b738ebe93..af1aa31360 100755 --- a/system/micd.py +++ b/system/micd.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import numpy as np +from functools import cache from cereal import messaging from openpilot.common.realtime import Ratekeeper @@ -10,7 +11,16 @@ RATE = 10 FFT_SAMPLES = 4096 REFERENCE_SPL = 2e-5 # newtons/m^2 SAMPLE_RATE = 44100 -SAMPLE_BUFFER = 4096 # (approx 100ms) +SAMPLE_BUFFER = 4096 # approx 100ms + + +@cache +def get_a_weighting_filter(): + # Calculate the A-weighting filter + # https://en.wikipedia.org/wiki/A-weighting + freqs = np.fft.fftfreq(FFT_SAMPLES, d=1 / SAMPLE_RATE) + A = 12194 ** 2 * freqs ** 4 / ((freqs ** 2 + 20.6 ** 2) * (freqs ** 2 + 12194 ** 2) * np.sqrt((freqs ** 2 + 107.7 ** 2) * (freqs ** 2 + 737.9 ** 2))) + return A / np.max(A) def calculate_spl(measurements): @@ -27,16 +37,8 @@ def apply_a_weighting(measurements: np.ndarray) -> np.ndarray: # Generate a Hanning window of the same length as the audio measurements measurements_windowed = measurements * np.hanning(len(measurements)) - # Calculate the frequency axis for the signal - freqs = np.fft.fftfreq(measurements_windowed.size, d=1 / SAMPLE_RATE) - - # Calculate the A-weighting filter - # https://en.wikipedia.org/wiki/A-weighting - A = 12194 ** 2 * freqs ** 4 / ((freqs ** 2 + 20.6 ** 2) * (freqs ** 2 + 12194 ** 2) * np.sqrt((freqs ** 2 + 107.7 ** 2) * (freqs ** 2 + 737.9 ** 2))) - A /= np.max(A) # Normalize the filter - # Apply the A-weighting filter to the signal - return np.abs(np.fft.ifft(np.fft.fft(measurements_windowed) * A)) + return np.abs(np.fft.ifft(np.fft.fft(measurements_windowed) * get_a_weighting_filter())) class Mic: From cd8a603ad0f14d744d12e2f5f743c7880ce907a3 Mon Sep 17 00:00:00 2001 From: eivegau Date: Thu, 25 Jul 2024 21:47:43 +0100 Subject: [PATCH 104/229] Kia: add missing Optima EUR FW versions (#33027) * Update fingerprints.py * Apply suggestions from code review --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/fingerprints.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index 30e4b9ed74..5f959bd68d 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -765,9 +765,11 @@ FW_VERSIONS = { ], (Ecu.abs, 0x7d1, None): [ b'\xf1\x00JF ESC \x0f 16 \x16\x06\x17 58920-D5080', + b'\xf1\x00JF ESC \t 17 \x16\x06# 58920-D4180', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00JFWGN LDWS AT USA LHD 1.00 1.02 95895-D4100 G21', + b'\xf1\x00JFWGN LKAS AT EUR LHD 1.00 1.01 95895-D4100 G20', ], }, CAR.KIA_OPTIMA_G4_FL: { From ed86910536e7036020a0a54be02e267db36653fe Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 25 Jul 2024 14:20:00 -0700 Subject: [PATCH 105/229] new README (#33073) * commonmark * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * relock * copy paste * Update README.md * looks better like this * cleanup --- .github/workflows/docs.yaml | 2 +- README.md | 56 +++++++++------ docs/mkdocs.yml | 3 + pyproject.toml | 9 ++- uv.lock | 137 +++++++++++++++--------------------- 5 files changed, 103 insertions(+), 104 deletions(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index f5cc0d5003..7fe4263db5 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -29,7 +29,7 @@ jobs: - name: Build docs run: | # TODO: can we install just the "docs" dependency group without the normal deps? - pip install mkdocs mkdocs-terminal + pip install mkdocs==1.4.3 mkdocs-terminal mkdocs-plugin-commonmark cd docs mkdocs build diff --git a/README.md b/README.md index 5afaf6e7d6..8ebc733e63 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,32 @@ -[![openpilot on the comma 3X](https://github.com/commaai/openpilot/assets/8762862/f09e6d29-db2d-4179-80c2-51e8d92bdb5c)](https://comma.ai/shop/comma-3x) +
-What is openpilot? ------- +

openpilot

-[openpilot](http://github.com/commaai/openpilot) is an open source driver assistance system. Currently, openpilot performs the functions of Adaptive Cruise Control (ACC), Automated Lane Centering (ALC), Forward Collision Warning (FCW), and Lane Departure Warning (LDW) for a growing variety of [supported car makes, models, and model years](docs/CARS.md). In addition, while openpilot is engaged, a camera-based Driver Monitoring (DM) feature alerts distracted and asleep drivers. See more about [the vehicle integration](docs/INTEGRATION.md) and [limitations](docs/LIMITATIONS.md). +

+ openpilot is an operating system for robotics. +
+ Currently, it upgrades the driver assistance system in 275+ supported cars. +

+ +

+ Read the docs + · + Contribute + · + Community + · + Try it on a comma 3X +

+ +Quick start: `curl -fsSL openpilot.comma.ai | bash` + +![openpilot tests](https://github.com/commaai/openpilot/actions/workflows/selfdrive_tests.yaml/badge.svg) +[![codecov](https://codecov.io/gh/commaai/openpilot/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/openpilot) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) +[![X Follow](https://img.shields.io/twitter/follow/comma_ai)](https://x.com/comma_ai) +[![Discord](https://img.shields.io/discord/469524606043160576)](https://discord.comma.ai) + +
@@ -49,18 +72,6 @@ Safety and Testing * panda has additional hardware-in-the-loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile). * We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes. -User Data and comma Account ------- - -By default, openpilot uploads the driving data to our servers. You can also access your data through [comma connect](https://connect.comma.ai/). We use your data to train better models and improve openpilot for everyone. - -openpilot is open source software: the user is free to disable data collection if they wish to do so. - -openpilot logs the road-facing cameras, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs. -The driver-facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded. - -By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data. - Licensing ------ @@ -72,9 +83,14 @@ Any user of this software shall indemnify and hold harmless Comma.ai, Inc. and i YOU ARE RESPONSIBLE FOR COMPLYING WITH LOCAL LAWS AND REGULATIONS. NO WARRANTY EXPRESSED OR IMPLIED.** ---- +User Data and comma Account +------ - +By default, openpilot uploads the driving data to our servers. You can also access your data through [comma connect](https://connect.comma.ai/). We use your data to train better models and improve openpilot for everyone. -![openpilot tests](https://github.com/commaai/openpilot/actions/workflows/selfdrive_tests.yaml/badge.svg) -[![codecov](https://codecov.io/gh/commaai/openpilot/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/openpilot) +openpilot is open source software: the user is free to disable data collection if they wish to do so. + +openpilot logs the road-facing cameras, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs. +The driver-facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded. + +By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data. diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 45a1503b0c..92cb501b8b 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -5,6 +5,9 @@ site_url: https://docs.comma.ai strict: true +plugins: + - commonmark + theme: name: terminal features: diff --git a/pyproject.toml b/pyproject.toml index 1226c8345a..f5eb5a4370 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,8 +67,9 @@ dependencies = [ [project.optional-dependencies] docs = [ "Jinja2", - "mkdocs", + "mkdocs==1.4.3", # needed for mkdocs-plugin-commonmark "mkdocs-terminal", + "mkdocs-plugin-commonmark", ] testing = [ @@ -227,7 +228,7 @@ lint.ignore = [ "UP038", # (x, y) -> x|y for isinstance ] line-length = 160 -target-version="py311" +target-version ="py311" exclude = [ "body", "cereal", @@ -239,7 +240,8 @@ exclude = [ "teleoprtc_repo", "third_party", ] -lint.flake8-implicit-str-concat.allow-multiline=false +lint.flake8-implicit-str-concat.allow-multiline = false + [tool.ruff.lint.flake8-tidy-imports.banned-api] "selfdrive".msg = "Use openpilot.selfdrive" "common".msg = "Use openpilot.common" @@ -251,5 +253,6 @@ lint.flake8-implicit-str-concat.allow-multiline=false [tool.coverage.run] concurrency = ["multiprocessing", "thread"] + [tool.ruff.format] quote-style = "preserve" diff --git a/uv.lock b/uv.lock index 8a0dc29b2a..5c0de703f2 100644 --- a/uv.lock +++ b/uv.lock @@ -863,14 +863,14 @@ wheels = [ [[distribution]] name = "importlib-metadata" -version = "8.0.0" +version = "8.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/20/ff/bd28f70283b9cca0cbf0c2a6082acbecd822d1962ae7b2a904861b9965f8/importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812", size = 52667 } +sdist = { url = "https://files.pythonhosted.org/packages/f6/a1/db39a513aa99ab3442010a994eef1cb977a436aded53042e69bee6959f74/importlib_metadata-8.2.0.tar.gz", hash = "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d", size = 53907 } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/ef/38766b2edb096260d9b1b6ad35adaa0bce3b0567abb452b21eb074af88c4/importlib_metadata-8.0.0-py3-none-any.whl", hash = "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f", size = 24769 }, + { url = "https://files.pythonhosted.org/packages/82/47/bb25ec04985d0693da478797c3d8c1092b140f3a53ccb984fbbd38affa5b/importlib_metadata-8.2.0-py3-none-any.whl", hash = "sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369", size = 25920 }, ] [[distribution]] @@ -1059,11 +1059,11 @@ wheels = [ [[distribution]] name = "markdown" -version = "3.6" +version = "3.3.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/22/02/4785861427848cc11e452cc62bb541006a1087cf04a1de83aedd5530b948/Markdown-3.6.tar.gz", hash = "sha256:ed4f41f6daecbeeb96e576ce414c41d2d876daa9a16cb35fa8ed8c2ddfad0224", size = 354715 } +sdist = { url = "https://files.pythonhosted.org/packages/d6/58/79df20de6e67a83f0d0bbfe6c19bb82adf68cdf362885257eb01099f930a/Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874", size = 324130 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/b3/0c0c994fe49cd661084f8d5dc06562af53818cc0abefaca35bdc894577c3/Markdown-3.6-py3-none-any.whl", hash = "sha256:48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f", size = 105381 }, + { url = "https://files.pythonhosted.org/packages/f3/df/ca72f352e15b6f8ce32b74af029f1189abffb906f7c137501ffe69c98a65/Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621", size = 97778 }, ] [[distribution]] @@ -1196,9 +1196,18 @@ dependencies = [ { name = "yapf" }, ] +[[distribution]] +name = "mistletoe" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/96/ea46a376a7c4cd56955ecdfff0ea68de43996a4e6d1aee4599729453bd11/mistletoe-1.4.0.tar.gz", hash = "sha256:1630f906e5e4bbe66fdeb4d29d277e2ea515d642bb18a9b49b136361a9818c9d", size = 107203 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/0f/b5e545f0c7962be90366af3418989b12cf441d9da1e5d89d88f2f3e5cf8f/mistletoe-1.4.0-py3-none-any.whl", hash = "sha256:44a477803861de1237ba22e375c6b617690a31d2902b47279d1f8f7ed498a794", size = 51304 }, +] + [[distribution]] name = "mkdocs" -version = "1.6.0" +version = "1.4.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -1206,32 +1215,29 @@ dependencies = [ { name = "ghp-import" }, { name = "jinja2" }, { name = "markdown" }, - { name = "markupsafe" }, { name = "mergedeep" }, - { name = "mkdocs-get-deps" }, { name = "packaging" }, - { name = "pathspec" }, { name = "pyyaml" }, { name = "pyyaml-env-tag" }, { name = "watchdog" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cc/6b/26b33cc8ad54e8bc0345cddc061c2c5c23e364de0ecd97969df23f95a673/mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512", size = 3888392 } +sdist = { url = "https://files.pythonhosted.org/packages/b0/ef/49b4427e5eec761b77a3c3c421d3fd63010e2798b7401dc0fa2b875ef6b5/mkdocs-1.4.3.tar.gz", hash = "sha256:5955093bbd4dd2e9403c5afaf57324ad8b04f16886512a3ee6ef828956481c57", size = 3624951 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/c0/930dcf5a3e96b9c8e7ad15502603fc61d495479699e2d2c381e3d37294d1/mkdocs-1.6.0-py3-none-any.whl", hash = "sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7", size = 3862264 }, + { url = "https://files.pythonhosted.org/packages/42/7a/5ed794942ace9d00bb77a8036c64c999cda6ebaab57e9b8a6ec1aa5fc900/mkdocs-1.4.3-py3-none-any.whl", hash = "sha256:6ee46d309bda331aac915cd24aab882c179a933bd9e77b80ce7d2eaaa3f689dd", size = 3654464 }, ] [[distribution]] -name = "mkdocs-get-deps" -version = "0.2.0" +name = "mkdocs-plugin-commonmark" +version = "0.0.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "mergedeep" }, - { name = "platformdirs" }, - { name = "pyyaml" }, + { name = "markdown" }, + { name = "mistletoe" }, + { name = "mkdocs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239 } +sdist = { url = "https://files.pythonhosted.org/packages/fa/a1/4aaa744deec61d75dbe3c67c18f6e4c1fa7699bc2661b6eff5f891e83023/mkdocs-plugin-commonmark-0.0.4.tar.gz", hash = "sha256:9034507af26646e95188a130782dd07d65c86507fddd3b47ea340c02683e85e7", size = 10805 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521 }, + { url = "https://files.pythonhosted.org/packages/f9/4a/4333ef1eb57ff130c7715ba0847dbdae471d153d94507004c92c591cb3c5/mkdocs_plugin_commonmark-0.0.4-py3-none-any.whl", hash = "sha256:70a33394d86a04ec97877ca1b2dff6181de3ec01ef4c7add178fa45b327da535", size = 12532 }, ] [[distribution]] @@ -1594,6 +1600,7 @@ dev = [ docs = [ { name = "jinja2" }, { name = "mkdocs" }, + { name = "mkdocs-plugin-commonmark" }, { name = "mkdocs-terminal" }, ] testing = [ @@ -1705,15 +1712,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/31/13/fe468c8c7400a8eca204e6e160a29bf7dcd45a76e20f1c030f3eaa690d93/parameterized-0.8.1-py2.py3-none-any.whl", hash = "sha256:9cbb0b69a03e8695d68b3399a8a5825200976536fe1cb79db60ed6a4c8c9efe9", size = 26354 }, ] -[[distribution]] -name = "pathspec" -version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, -] - [[distribution]] name = "pillow" version = "10.4.0" @@ -2042,15 +2040,15 @@ wheels = [ [[distribution]] name = "pymdown-extensions" -version = "10.8.1" +version = "10.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown" }, { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/09/11/0a1da270c1011194a6efee7ec1ac07d8b75a9706eed4a80675403f6a9d70/pymdown_extensions-10.8.1.tar.gz", hash = "sha256:3ab1db5c9e21728dabf75192d71471f8e50f216627e9a1fa9535ecb0231b9940", size = 812097 } +sdist = { url = "https://files.pythonhosted.org/packages/85/71/5f48080bde77b07ca1eba6d7cb5c5598ac6c8f2a399846159b3c8b45e171/pymdown_extensions-10.4.tar.gz", hash = "sha256:bc46f11749ecd4d6b71cf62396104b4a200bad3498cb0f5dad1b8502fe461a35", size = 785151 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/d7/e19f9bee2729a8d65b9bf822bb69ac364bf782bac8d761c62b4252769ae0/pymdown_extensions-10.8.1-py3-none-any.whl", hash = "sha256:f938326115884f48c6059c67377c46cf631c733ef3629b6eed1349989d1b30cb", size = 250833 }, + { url = "https://files.pythonhosted.org/packages/98/2d/2929de81618c7213176899dd6372d6ec9c8f24337841dd74634fb69864ae/pymdown_extensions-10.4-py3-none-any.whl", hash = "sha256:cfc28d6a09d19448bcbf8eee3ce098c7d17ff99f7bd3069db4819af181212037", size = 240838 }, ] [[distribution]] @@ -4705,7 +4703,7 @@ wheels = [ [[distribution]] name = "pytest" -version = "8.3.1" +version = "8.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -4713,9 +4711,9 @@ dependencies = [ { name = "packaging" }, { name = "pluggy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bc/7f/a6f79e033aa8318b6dfe2173fa6409ee75dafccf409d90884bf921433d88/pytest-8.3.1.tar.gz", hash = "sha256:7e8e5c5abd6e93cb1cc151f23e57adc31fcf8cfd2a3ff2da63e23f732de35db6", size = 1438997 } +sdist = { url = "https://files.pythonhosted.org/packages/b4/8c/9862305bdcd6020bc7b45b1b5e7397a6caf1a33d3025b9a003b39075ffb2/pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce", size = 1439314 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/77/ccea391104f576a6e54a54334fc26d29c28aa0ec85714c781fbd2c34ac86/pytest-8.3.1-py3-none-any.whl", hash = "sha256:e9600ccf4f563976e2c99fa02c7624ab938296551f280835ee6516df8bc4ae8c", size = 341628 }, + { url = "https://files.pythonhosted.org/packages/0f/f9/cf155cf32ca7d6fa3601bc4c5dd19086af4b320b706919d48a4c79081cf9/pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5", size = 341802 }, ] [[distribution]] @@ -4862,16 +4860,15 @@ sdist = { url = "https://files.pythonhosted.org/packages/ef/c6/2c5999de3bb153352 [[distribution]] name = "pytools" -version = "2024.1.10" +version = "2024.1.11" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "platformdirs" }, - { name = "siphash24" }, { name = "typing-extensions", marker = "python_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ee/0f/56e109c0307f831b5d598ad73976aaaa84b4d0e98da29a642e797eaa940c/pytools-2024.1.10.tar.gz", hash = "sha256:9af6f4b045212c49be32bb31fe19606c478ee4b09631886d05a32459f4ce0a12", size = 81741 } +sdist = { url = "https://files.pythonhosted.org/packages/b7/80/188130dc3d1238f35a8a1ed788c42bdf00b9fd00f03a03b150778ceb846f/pytools-2024.1.11.tar.gz", hash = "sha256:fa966e09857bcd9299f961d58fc128e8333e4ac5fcea52473af5aae88f814e38", size = 81917 } wheels = [ - { url = "https://files.pythonhosted.org/packages/66/cf/0a6aaa44b1f9e02b8c0648b5665a82246a93bcc75224c167b4fafa25c093/pytools-2024.1.10-py3-none-any.whl", hash = "sha256:9cabb71038048291400e244e2da441a051d86053339bc484e64e58d8ea263f44", size = 88108 }, + { url = "https://files.pythonhosted.org/packages/60/83/df2f2e6de93798cfd1432aafaad6f23c80a217983b022d0b4bd739194072/pytools-2024.1.11-py3-none-any.whl", hash = "sha256:b3f254dcd6986426c21fcd52803a248e837a34b78a8c4abe09724cb60e0901ea", size = 88206 }, ] [[distribution]] @@ -5049,27 +5046,27 @@ wheels = [ [[distribution]] name = "ruff" -version = "0.5.4" +version = "0.5.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/1a/5955fa22ab088c1f4d8458b4cbc158c6db72143361e8d46e179c48576aab/ruff-0.5.4.tar.gz", hash = "sha256:2795726d5f71c4f4e70653273d1c23a8182f07dd8e48c12de5d867bfb7557eed", size = 2424702 } +sdist = { url = "https://files.pythonhosted.org/packages/95/15/3945cfecfd3de874633d2466327ebb01eabf4f61f962a0dd4bf5ce2dc997/ruff-0.5.5.tar.gz", hash = "sha256:cc5516bdb4858d972fbc31d246bdb390eab8df1a26e2353be2dbc0c2d7f5421a", size = 2434890 } wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/34/2235ecce6794345f42ad334d1b14384c70b202f77509e5678b68a640fe78/ruff-0.5.4-py3-none-linux_armv6l.whl", hash = "sha256:82acef724fc639699b4d3177ed5cc14c2a5aacd92edd578a9e846d5b5ec18ddf", size = 9499774 }, - { url = "https://files.pythonhosted.org/packages/11/23/ffe51028ba274223191d3f96b059108cf7690eb93985a7fdb077c3d1191b/ruff-0.5.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:da62e87637c8838b325e65beee485f71eb36202ce8e3cdbc24b9fcb8b99a37be", size = 8550240 }, - { url = "https://files.pythonhosted.org/packages/28/75/843aa3d10a39ab60fbd63f65c825f647907a9732ac27e24d3f94dd2db618/ruff-0.5.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e98ad088edfe2f3b85a925ee96da652028f093d6b9b56b76fc242d8abb8e2059", size = 8160520 }, - { url = "https://files.pythonhosted.org/packages/19/88/3d0f5244905088cc2fd136fae8ce81f46d145e2449051313c462032d144d/ruff-0.5.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c55efbecc3152d614cfe6c2247a3054cfe358cefbf794f8c79c8575456efe19", size = 9911606 }, - { url = "https://files.pythonhosted.org/packages/1f/ff/6546020836408351e7558dedacc6e5ca7f652f76a9d05ac4882c787d45b1/ruff-0.5.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9b85eaa1f653abd0a70603b8b7008d9e00c9fa1bbd0bf40dad3f0c0bdd06793", size = 9286353 }, - { url = "https://files.pythonhosted.org/packages/b6/bf/51e0c5f12a9bf3c7596cf7f45e1b102f8b49f1da39943e03739890bbf6a4/ruff-0.5.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cf497a47751be8c883059c4613ba2f50dd06ec672692de2811f039432875278", size = 10082929 }, - { url = "https://files.pythonhosted.org/packages/b5/0e/a44cb6edb629788de892fc7bb8ac8b47059df94d7ec9c4e52e04bab5be95/ruff-0.5.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:09c14ed6a72af9ccc8d2e313d7acf7037f0faff43cde4b507e66f14e812e37f7", size = 10832586 }, - { url = "https://files.pythonhosted.org/packages/97/ca/e3810f701ae472e5fe3180d56fe6fcc92ea94c7490097a0f731f5602f26f/ruff-0.5.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:628f6b8f97b8bad2490240aa84f3e68f390e13fabc9af5c0d3b96b485921cd60", size = 10421967 }, - { url = "https://files.pythonhosted.org/packages/01/47/a62df6ccd6e5d019271df203ea6564f2022c49f85c0bf6ada708cd7b4a5e/ruff-0.5.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3520a00c0563d7a7a7c324ad7e2cde2355733dafa9592c671fb2e9e3cd8194c1", size = 11371031 }, - { url = "https://files.pythonhosted.org/packages/a1/02/64f24893eea23c447460e6509e9dd0ae18d7a797f67fee1bafed964ebbae/ruff-0.5.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93789f14ca2244fb91ed481456f6d0bb8af1f75a330e133b67d08f06ad85b516", size = 10103164 }, - { url = "https://files.pythonhosted.org/packages/ca/78/683b6c6976fcc33e4a03a0e234e0b9f9b8682f807a661225c829b248de82/ruff-0.5.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:029454e2824eafa25b9df46882f7f7844d36fd8ce51c1b7f6d97e2615a57bbcc", size = 9920056 }, - { url = "https://files.pythonhosted.org/packages/78/3a/6c67c5d670aae2a51a11713aff819d729ed92cb0b1d962b8df27e4657650/ruff-0.5.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9492320eed573a13a0bc09a2957f17aa733fff9ce5bf00e66e6d4a88ec33813f", size = 9361286 }, - { url = "https://files.pythonhosted.org/packages/0d/f5/da3a0e2fd0bcbdb3d2ff579ef9cb3ca2af71b9bee97fa917c9a9e0500b67/ruff-0.5.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a6e1f62a92c645e2919b65c02e79d1f61e78a58eddaebca6c23659e7c7cb4ac7", size = 9720829 }, - { url = "https://files.pythonhosted.org/packages/4a/56/5062119a5c9e06d98cd6406bfc1eab7616a7c67494a4d05b6052d99dd147/ruff-0.5.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:768fa9208df2bec4b2ce61dbc7c2ddd6b1be9fb48f1f8d3b78b3332c7d71c1ff", size = 10143530 }, - { url = "https://files.pythonhosted.org/packages/e6/76/16f8f1c8d0cba6c96ab6f292146fc0acb6dd633a989f524d3b3ef1ee8364/ruff-0.5.4-py3-none-win32.whl", hash = "sha256:e1e7393e9c56128e870b233c82ceb42164966f25b30f68acbb24ed69ce9c3a4e", size = 7794271 }, - { url = "https://files.pythonhosted.org/packages/82/35/d6c3c83fb8817328db73c15b1836ccb0c3ce56b72d0d01d98b3a452bec58/ruff-0.5.4-py3-none-win_amd64.whl", hash = "sha256:58b54459221fd3f661a7329f177f091eb35cf7a603f01d9eb3eb11cc348d38c4", size = 8579021 }, - { url = "https://files.pythonhosted.org/packages/3c/ef/3e732c0152280775f728ab99691c718ee9a4ae79bf5af1dd9258f7fe7fef/ruff-0.5.4-py3-none-win_arm64.whl", hash = "sha256:bd53da65f1085fb5b307c38fd3c0829e76acf7b2a912d8d79cadcdb4875c1eb7", size = 8034239 }, + { url = "https://files.pythonhosted.org/packages/2c/4d/f9e5e37369b22d74588fe496e82d2aa2fff508f0c05b34c38374194f5a8e/ruff-0.5.5-py3-none-linux_armv6l.whl", hash = "sha256:605d589ec35d1da9213a9d4d7e7a9c761d90bba78fc8790d1c5e65026c1b9eaf", size = 9505926 }, + { url = "https://files.pythonhosted.org/packages/b3/48/ee53a87351dd03472cf1cb8073019a53a7282e4295e7ae62d7f5ae24202a/ruff-0.5.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:00817603822a3e42b80f7c3298c8269e09f889ee94640cd1fc7f9329788d7bf8", size = 8585187 }, + { url = "https://files.pythonhosted.org/packages/a2/ec/2c0bd5ec0965672bb2957abf6e44d93c2c7aab2ceb4251ea77eb9234ffd3/ruff-0.5.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:187a60f555e9f865a2ff2c6984b9afeffa7158ba6e1eab56cb830404c942b0f3", size = 8175846 }, + { url = "https://files.pythonhosted.org/packages/8d/d7/e476f96c013d59af08b7b155f2beee03e7595915718573c724a01681bea8/ruff-0.5.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe26fc46fa8c6e0ae3f47ddccfbb136253c831c3289bba044befe68f467bfb16", size = 9948714 }, + { url = "https://files.pythonhosted.org/packages/dd/da/00269f4905b5ceab77f64ec9ed2e8f848ccba68884b66b2423c9f8962878/ruff-0.5.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ad25dd9c5faac95c8e9efb13e15803cd8bbf7f4600645a60ffe17c73f60779b", size = 9299822 }, + { url = "https://files.pythonhosted.org/packages/c3/ce/8784906480809b5b43cfbb346bddcc3b9e8716fd73927e4d70fb5260c18e/ruff-0.5.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f70737c157d7edf749bcb952d13854e8f745cec695a01bdc6e29c29c288fc36e", size = 10100197 }, + { url = "https://files.pythonhosted.org/packages/42/a4/4f4796e6b440ed42ec8486e19fe9b9489d94f13c2debf49e68ed58af5d0b/ruff-0.5.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:cfd7de17cef6ab559e9f5ab859f0d3296393bc78f69030967ca4d87a541b97a0", size = 10813891 }, + { url = "https://files.pythonhosted.org/packages/a0/a4/9a0084212e0b2810beadd993f1b36f156438465a4d4193fd5bb2ab833892/ruff-0.5.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a09b43e02f76ac0145f86a08e045e2ea452066f7ba064fd6b0cdccb486f7c3e7", size = 10439725 }, + { url = "https://files.pythonhosted.org/packages/8e/f7/4480e739af49f66f04edf2b1dd7ac6fa5e55639491e47267dbfa70d62488/ruff-0.5.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0b856cb19c60cd40198be5d8d4b556228e3dcd545b4f423d1ad812bfdca5884", size = 11358405 }, + { url = "https://files.pythonhosted.org/packages/0e/fd/7a6e01b8098c3375ce694427956a8192c708941051cebd279b988304a753/ruff-0.5.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3687d002f911e8a5faf977e619a034d159a8373514a587249cc00f211c67a091", size = 10130793 }, + { url = "https://files.pythonhosted.org/packages/2f/4a/ba83ca67da7e81a8a191da36f3f6a350243210518c78c2e809fb25cac6c4/ruff-0.5.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ac9dc814e510436e30d0ba535f435a7f3dc97f895f844f5b3f347ec8c228a523", size = 9910666 }, + { url = "https://files.pythonhosted.org/packages/3f/6d/c982a93907559fa5cb62fd68c74b21662a4f088a09ad27f813244c7379c1/ruff-0.5.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:af9bdf6c389b5add40d89b201425b531e0a5cceb3cfdcc69f04d3d531c6be74f", size = 9365153 }, + { url = "https://files.pythonhosted.org/packages/be/a6/b3dbdb4505086d80ab8202c8592ad90a811fc328dc4a5966e065cda12dcc/ruff-0.5.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d40a8533ed545390ef8315b8e25c4bb85739b90bd0f3fe1280a29ae364cc55d8", size = 9736802 }, + { url = "https://files.pythonhosted.org/packages/4d/ba/b850fa0925ce59bc0bce412d18a9633a92126f23153f970437a51be711f0/ruff-0.5.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:cab904683bf9e2ecbbe9ff235bfe056f0eba754d0168ad5407832928d579e7ab", size = 10198368 }, + { url = "https://files.pythonhosted.org/packages/56/db/a9162178c90cada13f4c9bed9860947a1c5a79d7ecadd27250c67681dc81/ruff-0.5.5-py3-none-win32.whl", hash = "sha256:696f18463b47a94575db635ebb4c178188645636f05e934fdf361b74edf1bb2d", size = 7798506 }, + { url = "https://files.pythonhosted.org/packages/c9/5b/13288039ea8190c121b70f1a11be2c4830cb3ebb57dc91d91fc5d3c65fc6/ruff-0.5.5-py3-none-win_amd64.whl", hash = "sha256:50f36d77f52d4c9c2f1361ccbfbd09099a1b2ea5d2b2222c586ab08885cf3445", size = 8611739 }, + { url = "https://files.pythonhosted.org/packages/ba/b3/525847f73ab956053b130ec9f5d1ea078d94282b1d5eda90c09b8a81a935/ruff-0.5.5-py3-none-win_arm64.whl", hash = "sha256:3191317d967af701f1b73a31ed5788795936e423b7acce82a2b63e26eb3e89d6", size = 8039120 }, ] [[distribution]] @@ -5124,15 +5121,15 @@ wheels = [ [[distribution]] name = "sentry-sdk" -version = "2.10.0" +version = "2.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/34/d8/ec3e43d4ce31e4f4cb6adb7210950362d71ce87a96c89934c4ac94f7110f/sentry_sdk-2.10.0.tar.gz", hash = "sha256:545fcc6e36c335faa6d6cda84669b6e17025f31efbf3b2211ec14efe008b75d1", size = 273996 } +sdist = { url = "https://files.pythonhosted.org/packages/6d/b3/39e4cd04b75a1ada788342d0d30a781cf65b5e43da806d5bf2bad4846ea3/sentry_sdk-2.11.0.tar.gz", hash = "sha256:4ca16e9f5c7c6bc2fb2d5c956219f4926b148e511fffdbbde711dc94f1e0468f", size = 276242 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/9e/9298785949269c8930e1fd3707b960da6e1a95a2442b747b8f8cca4578cb/sentry_sdk-2.10.0-py2.py3-none-any.whl", hash = "sha256:87b3d413c87d8e7f816cc9334bff255a83d8b577db2b22042651c30c19c09190", size = 302064 }, + { url = "https://files.pythonhosted.org/packages/bc/3c/a8ab3309d22c1d7142f811882e7d45449696f87c6e4e723b1433b6069b84/sentry_sdk-2.11.0-py2.py3-none-any.whl", hash = "sha256:d964710e2dbe015d9dc4ff0ad16225d68c3b36936b742a6fe0504565b760a3b7", size = 303581 }, ] [[distribution]] @@ -5167,26 +5164,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d4/c3/e98e3eb9f06def32b8e2454ab718cafb99149f023dff023e257125132d6e/shapely-2.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:30e8737983c9d954cd17feb49eb169f02f1da49e24e5171122cf2c2b62d65c95", size = 1442365 }, ] -[[distribution]] -name = "siphash24" -version = "1.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/19/d8/beb5183d1acc5a013d273452eac750b51e40855917a1841dead80fcf3086/siphash24-1.6.tar.gz", hash = "sha256:242d6901a81260f618938635a25ae7f208e744f7ee6c571f1b255c1c4c62917d", size = 19659 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/a5/0ffc51fe2e5f96258f0edfae15944006b09517ad7e98fdcbda05c67c70f6/siphash24-1.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3e1b3963c392a2d63cbe16af9171d789d2f15e69eb8314b21fe1e11bdc08205f", size = 80669 }, - { url = "https://files.pythonhosted.org/packages/80/ea/41d648cbbf3248a30f545f9e41ad5dedee19fcbad1d2baa7e39ae6f2779e/siphash24-1.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:de23d12c8a015904081e347900433a0c4b5e07690dbd0a104ad88929f3b91948", size = 75379 }, - { url = "https://files.pythonhosted.org/packages/48/a7/d6dcc551c8d53e436c58b7ecc96d1de0c0379c21b1e71b2543d38c039c95/siphash24-1.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8be513de01677e57989e028185a16e531942f7a9578d441481abe8b1085c45d6", size = 100466 }, - { url = "https://files.pythonhosted.org/packages/eb/46/b906d7e05e3d84239d6a04e3d5f106d96ab26483951c7cf2c5769ea8c894/siphash24-1.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef89477ce8f2e67fca025ad9b1c85b7498c6959baa7d9a502cbb5d8c7085f5b7", size = 105913 }, - { url = "https://files.pythonhosted.org/packages/4c/98/20159e2be9a957da2dffb3e18648c51ea7a0f09c49b8dce1cb268ca55ca7/siphash24-1.6-cp311-cp311-win32.whl", hash = "sha256:f702e646dc60b7d7915fa37f9357a03a2ec41ffb360b6946baf4801eb9f7e98f", size = 67528 }, - { url = "https://files.pythonhosted.org/packages/0d/0a/d8da621e624f3dbcf9a7a8066c54ddd2f6af437fc23169431caf6f9b403b/siphash24-1.6-cp311-cp311-win_amd64.whl", hash = "sha256:38715f61f0873e4a8b05125e14f349f465c64a1aaf79b6af0ff6f5f420d55dc5", size = 79961 }, - { url = "https://files.pythonhosted.org/packages/12/e4/ed944e92883b45996cf2c94447dd47b899c87674340b081b9e8cb317a88f/siphash24-1.6-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:51eefacbe82f8f48bc603eb97f54bf3819324349b69a9cd131ba02c40b1e6c61", size = 82399 }, - { url = "https://files.pythonhosted.org/packages/f9/d1/6ddbd7ba8972789f60282b9b9b1f88f08d26ef0913906e8ad5a9806c8432/siphash24-1.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c63321003aa1856b1bfd48e6ffbd4bff98afeaacb0fc902cb2ae44b861476335", size = 76253 }, - { url = "https://files.pythonhosted.org/packages/0d/87/0f125c1e069d09c4a39ab09d76fa9d4fe698bde68197627faeb38603f643/siphash24-1.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0ff4d068e9b0b3f138ef8e8b6f5de1990539d9d590e75a9a8beb6887535184a", size = 98184 }, - { url = "https://files.pythonhosted.org/packages/86/57/a274de0a91016cd4f870334a2af1193ffcdb88e34345ca098afea6dd10cb/siphash24-1.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1a671d91095e1872ca9988695200064ccca8db60133638d6061755fe669552", size = 103311 }, - { url = "https://files.pythonhosted.org/packages/5d/d4/b6a0c9f119b22938e36d74e0859167ae76c0ea0f7d7786eb48120b0e129d/siphash24-1.6-cp312-cp312-win32.whl", hash = "sha256:2dab672fcda08149b8c15f82ee74d732386428f53239cdb002ac2ad0a1f2f2bc", size = 68366 }, - { url = "https://files.pythonhosted.org/packages/ef/de/6ebd0f96184f8479e8348dcba93a9f14ff54ac3c6a68866cc77c334d7bdf/siphash24-1.6-cp312-cp312-win_amd64.whl", hash = "sha256:226af78af3b992c953cc4808f2c6a4bba320e91e6c89b34aa2492064fa417ae8", size = 81096 }, -] - [[distribution]] name = "six" version = "1.16.0" From c8622c9553d02486ddea43810e428bce6414ed5d Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 25 Jul 2024 14:27:25 -0700 Subject: [PATCH 106/229] mac's getting there --- .github/workflows/selfdrive_tests.yaml | 3 +-- tools/mac_setup.sh | 19 ++++++------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 1154948ace..a178634321 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -96,7 +96,7 @@ jobs: timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 15 || 30) }} # allow more time when we missed the scons cache build_mac: - name: build macos + name: build macOS runs-on: macos-latest steps: - uses: actions/checkout@v4 @@ -106,7 +106,6 @@ jobs: - name: Install dependencies run: ./tools/mac_setup.sh env: - SKIP_PROMPT: 1 # package install has DeprecationWarnings PYTHONWARNINGS: default - run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV diff --git a/tools/mac_setup.sh b/tools/mac_setup.sh index 9823427e65..d19f1cae86 100755 --- a/tools/mac_setup.sh +++ b/tools/mac_setup.sh @@ -2,19 +2,12 @@ set -e -if [ -z "$SKIP_PROMPT" ]; then - echo "--------------- macOS support ---------------" - echo "Running openpilot natively on macOS is not officially supported." - echo "It might build, some parts of it might work, but it's not fully tested, so there might be some issues." - echo - echo "Check out devcontainers for a seamless experience (see tools/README.md)." - echo "-------------------------------------------------" - echo -n "Are you sure you want to continue? [y/N] " - read -r response - if [[ ! "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then - exit 1 - fi -fi +echo "--------------- macOS support ---------------" +echo "Running openpilot natively on macOS is still a work-in-progress." +echo "It might build, some parts of it might work, but it's not fully tested, so there might be some issues." +echo +echo "Check out devcontainers for a seamless experience (see tools/README.md)." +echo "-------------------------------------------------" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" ROOT="$(cd $DIR/../ && pwd)" From 173a633a75692ae104fa9c6e99501fec4df9ebb7 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Thu, 25 Jul 2024 14:28:41 -0700 Subject: [PATCH 107/229] curl pc installer (#33072) * setup * curl * usable right now * op sim * cleanup * show cmd --- tools/op.sh | 24 ++++++++++++++- tools/setup.sh | 68 ++++++++++++++++++++++++++++--------------- tools/ubuntu_setup.sh | 5 ---- 3 files changed, 68 insertions(+), 29 deletions(-) diff --git a/tools/op.sh b/tools/op.sh index 7ad9697185..42bbb1973d 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -161,14 +161,23 @@ function op_install() { op_check_os op_check_python + echo "Installing dependencies..." if [[ "$OSTYPE" == "linux-gnu"* ]]; then op_run_command $OPENPILOT_ROOT/tools/ubuntu_setup.sh elif [[ "$OSTYPE" == "darwin"* ]]; then op_run_command $OPENPILOT_ROOT/tools/mac_setup.sh fi + echo -e " ↳ [${GREEN}✔${NC}] Dependencies installed successfully.\n" + echo "Getting git submodules..." op_run_command git submodule update --init --recursive + echo -e " ↳ [${GREEN}✔${NC}] Submodules installed successfully.\n" + + echo "Pulling git lfs files..." op_run_command git lfs pull + echo -e " ↳ [${GREEN}✔${NC}] Files pulled successfully.\n" + + op_check ) } @@ -199,7 +208,7 @@ function op_run() { (set -e op_before_cmd - op_run_command $OPENPILOT_ROOT/launch_openpilot.sh + op_run_command $OPENPILOT_ROOT/launch_openpilot.sh $@ ) } @@ -249,6 +258,16 @@ function op_cabana() { ) } +function op_sim() { + (set -e + + op_before_cmd + op_run_command exec $OPENPILOT_ROOT/tools/sim/run_bridge.py & + op_run_command exec $OPENPILOT_ROOT/tools/sim/launch_openpilot.sh + + ) +} + function op_default() { echo "An openpilot helper" echo "" @@ -270,6 +289,7 @@ function op_default() { echo -e " ${BOLD}install${NC} Install requirements to use openpilot" echo -e " ${BOLD}build${NC} Build openpilot" echo -e " ${BOLD}run${NC} Run openpilot" + echo -e " ${BOLD}sim${NC} Run openpilot in a simulator" echo -e " ${BOLD}juggle${NC} Run Plotjuggler" echo -e " ${BOLD}replay${NC} Run replay" echo -e " ${BOLD}cabana${NC} Run cabana" @@ -318,6 +338,7 @@ function _op() { cabana ) shift 1; op_cabana "$@" ;; linter ) shift 1; op_linter "$@" ;; replay ) shift 1; op_replay "$@" ;; + sim ) shift 1; op_sim "$@" ;; --install ) shift 1; op_first_install "$@" ;; * ) op_default "$@" ;; esac @@ -345,6 +366,7 @@ unset -f op_replay unset -f op_cabana unset -f op_check_venv unset -f op_before_cmd +unset -f op_sim unset DRY unset OPENPILOT_ROOT unset NO_VERIFY diff --git a/tools/setup.sh b/tools/setup.sh index 22d10be80b..42b8d6fd4c 100755 --- a/tools/setup.sh +++ b/tools/setup.sh @@ -1,32 +1,54 @@ #!/usr/bin/env bash -set -e +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' -if [ ! -f launch_openpilot.sh ]; then - if [ ! -d openpilot ]; then - git clone --single-branch --recurse-submodules https://github.com/commaai/openpilot.git +if [ -z "$OPENPILOT_ROOT" ]; then + # default to current directory for installation + OPENPILOT_ROOT="$(pwd)/openpilot" +fi + +function check_dir() { + echo "Checking for installation directory..." + if [ -d "$OPENPILOT_ROOT" ]; then + echo -e " ↳ [${RED}✗${NC}] can't install openpilot in $OPENPILOT_ROOT !" + return 1 fi - cd openpilot -fi -if [[ "$OSTYPE" == "darwin"* ]]; then - tools/mac_setup.sh -else - tools/ubuntu_setup.sh -fi + echo -e " ↳ [${GREEN}✔${NC}] Successfully chosen $OPENPILOT_ROOT as installation directory\n" +} -git lfs pull +function check_git() { + echo "Checking for git..." + if ! command -v "git" > /dev/null 2>&1; then + echo -e " ↳ [${RED}✗${NC}] git not found on your system, can't continue!" + return 1 + else + echo -e " ↳ [${GREEN}✔${NC}] git found.\n" + fi +} -source .venv/bin/activate +function git_clone() { + echo "Cloning openpilot..." + if $(git clone --depth=1 https://github.com/commaai/openpilot.git "$OPENPILOT_ROOT"); then + if [[ -f $OPENPILOT_ROOT/launch_openpilot.sh ]]; then + echo -e " ↳ [${GREEN}✔${NC}] Successfully cloned openpilot.\n" + return 0 + fi + fi -echo "Building openpilot" -scons -u -j$(nproc) + echo -e " ↳ [${RED}✗${NC}] failed to clone openpilot!" + return 1 +} -echo -echo "---- OPENPILOT BUILDING DONE ----" -echo "To push changes to your fork, run the following commands:" -echo "git remote remove origin" -echo "git remote add origin git@github.com:/openpilot.git" -echo "git fetch" -echo "git commit -m \"first commit\"" -echo "git push" +function install_with_op() { + cd $OPENPILOT_ROOT + $OPENPILOT_ROOT/tools/op.sh --install + $OPENPILOT_ROOT/tools/op.sh install + + # make op usable right now + alias op="source $OPENPILOT_ROOT/tools/op.sh \"\$@\"" +} + +check_dir && check_git && git_clone && install_with_op diff --git a/tools/ubuntu_setup.sh b/tools/ubuntu_setup.sh index 1bdeb50e0d..f425e14cf2 100755 --- a/tools/ubuntu_setup.sh +++ b/tools/ubuntu_setup.sh @@ -8,8 +8,3 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" $DIR/install_ubuntu_dependencies.sh $DIR/install_python_dependencies.sh - -echo -echo "---- OPENPILOT SETUP DONE ----" -echo "Open a new shell or configure your active shell env by running:" -echo "source ~/.bashrc" From 1989fbd4c4a40188fbb673d2f5e1dd467d255ad5 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Thu, 25 Jul 2024 14:38:47 -0700 Subject: [PATCH 108/229] Update setup.sh --- tools/setup.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/setup.sh b/tools/setup.sh index 42b8d6fd4c..8aca889b8c 100755 --- a/tools/setup.sh +++ b/tools/setup.sh @@ -52,3 +52,8 @@ function install_with_op() { } check_dir && check_git && git_clone && install_with_op + +unset OPENPILOT_ROOT +unset RED +unset GREEN +unset NC From ccd369ee9639beae479704615f198902d58135b9 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 26 Jul 2024 06:05:14 +0800 Subject: [PATCH 109/229] camerad: merge thread functions into one (#33025) merge multiple thread functions into one --- system/camerad/cameras/camera_common.cc | 32 +------------- system/camerad/cameras/camera_common.h | 6 +-- system/camerad/cameras/camera_qcom2.cc | 55 ++++++++++++++----------- system/camerad/cameras/camera_qcom2.h | 11 +++++ 4 files changed, 43 insertions(+), 61 deletions(-) diff --git a/system/camerad/cameras/camera_common.cc b/system/camerad/cameras/camera_common.cc index aef00c1bba..542be29d80 100644 --- a/system/camerad/cameras/camera_common.cc +++ b/system/camerad/cameras/camera_common.cc @@ -244,7 +244,7 @@ static kj::Array yuv420_to_jpeg(const CameraBuf *b, int thumbnail_w return dat; } -static void publish_thumbnail(PubMaster *pm, const CameraBuf *b) { +void publish_thumbnail(PubMaster *pm, const CameraBuf *b) { auto thumbnail = yuv420_to_jpeg(b, b->rgb_width / 4, b->rgb_height / 4); if (thumbnail.size() == 0) return; @@ -284,36 +284,6 @@ float set_exposure_target(const CameraBuf *b, Rect ae_xywh, int x_skip, int y_sk return lum_med / 256.0; } -void *processing_thread(MultiCameraState *cameras, CameraState *cs, process_thread_cb callback) { - const char *thread_name = nullptr; - if (cs == &cameras->road_cam) { - thread_name = "RoadCamera"; - } else if (cs == &cameras->driver_cam) { - thread_name = "DriverCamera"; - } else { - thread_name = "WideRoadCamera"; - } - util::set_thread_name(thread_name); - - uint32_t cnt = 0; - while (!do_exit) { - if (!cs->buf.acquire()) continue; - - callback(cameras, cs, cnt); - - if (cs == &(cameras->road_cam) && cameras->pm && cnt % 100 == 3) { - // this takes 10ms??? - publish_thumbnail(cameras->pm, &(cs->buf)); - } - ++cnt; - } - return NULL; -} - -std::thread start_process_thread(MultiCameraState *cameras, CameraState *cs, process_thread_cb callback) { - return std::thread(processing_thread, cameras, cs, callback); -} - void camerad_thread() { cl_device_id device_id = cl_get_device_id(CL_DEVICE_TYPE_DEFAULT); #ifdef QCOM2 diff --git a/system/camerad/cameras/camera_common.h b/system/camerad/cameras/camera_common.h index f97940b669..d58f4d3195 100644 --- a/system/camerad/cameras/camera_common.h +++ b/system/camerad/cameras/camera_common.h @@ -2,7 +2,6 @@ #include #include -#include #include "cereal/messaging/messaging.h" #include "msgq/visionipc/visionipc_server.h" @@ -69,13 +68,10 @@ public: void queue(size_t buf_idx); }; -typedef void (*process_thread_cb)(MultiCameraState *s, CameraState *c, int cnt); - void fill_frame_data(cereal::FrameData::Builder &framed, const FrameMetadata &frame_data, CameraState *c); kj::Array get_raw_frame_image(const CameraBuf *b); float set_exposure_target(const CameraBuf *b, Rect ae_xywh, int x_skip, int y_skip); -std::thread start_process_thread(MultiCameraState *cameras, CameraState *cs, process_thread_cb callback); - +void publish_thumbnail(PubMaster *pm, const CameraBuf *b); void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_id, cl_context ctx); void cameras_open(MultiCameraState *s); void cameras_run(MultiCameraState *s); diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index 5767bec870..2729aa264c 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -31,6 +31,8 @@ CameraState::CameraState(MultiCameraState *multi_camera_state, const CameraConfi camera_num(config.camera_num), stream_type(config.stream_type), focal_len(config.focal_len), + publish_name(config.publish_name), + init_camera_state(config.init_camera_state), enabled(config.enabled) { } @@ -941,33 +943,36 @@ void CameraState::set_camera_exposure(float grey_frac) { sensors_i2c(exp_reg_array.data(), exp_reg_array.size(), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, ci->data_word); } -static void process_driver_camera(MultiCameraState *s, CameraState *c, int cnt) { - c->set_camera_exposure(set_exposure_target(&c->buf, c->ae_xywh, 2, 4)); +void CameraState::run() { + util::set_thread_name(publish_name); - MessageBuilder msg; - auto framed = msg.initEvent().initDriverCameraState(); - fill_frame_data(framed, c->buf.cur_frame_data, c); + for (uint32_t cnt = 0; !do_exit; ++cnt) { + // Acquire the buffer; continue if acquisition fails + if (!buf.acquire()) continue; - c->ci->processRegisters(c, framed); - s->pm->send("driverCameraState", msg); -} + MessageBuilder msg; + auto framed = (msg.initEvent().*init_camera_state)(); + fill_frame_data(framed, buf.cur_frame_data, this); -void process_road_camera(MultiCameraState *s, CameraState *c, int cnt) { - const CameraBuf *b = &c->buf; + // Log raw frames for road camera + if (env_log_raw_frames && stream_type == VISION_STREAM_ROAD && cnt % 100 == 5) { // no overlap with qlog decimation + framed.setImage(get_raw_frame_image(&buf)); + } + // Log frame id for road and wide road cameras + if (stream_type != VISION_STREAM_DRIVER) { + LOGT(buf.cur_frame_data.frame_id, "%s: Image set", publish_name); + } - MessageBuilder msg; - auto framed = c == &s->road_cam ? msg.initEvent().initRoadCameraState() : msg.initEvent().initWideRoadCameraState(); - fill_frame_data(framed, b->cur_frame_data, c); - if (env_log_raw_frames && c == &s->road_cam && cnt % 100 == 5) { // no overlap with qlog decimation - framed.setImage(get_raw_frame_image(b)); + // Process camera registers and set camera exposure + ci->processRegisters(this, framed); + set_camera_exposure(set_exposure_target(&buf, ae_xywh, 2, stream_type != VISION_STREAM_DRIVER ? 2 : 4)); + + // Send the message + multi_cam_state->pm->send(publish_name, msg); + if (stream_type == VISION_STREAM_ROAD && cnt % 100 == 3) { + publish_thumbnail(multi_cam_state->pm, &buf); // this takes 10ms??? + } } - LOGT(c->buf.cur_frame_data.frame_id, "%s: Image set", c == &s->road_cam ? "RoadCamera" : "WideRoadCamera"); - - c->ci->processRegisters(c, framed); - s->pm->send(c == &s->road_cam ? "roadCameraState" : "wideRoadCameraState", msg); - - const int skip = 2; - c->set_camera_exposure(set_exposure_target(b, c->ae_xywh, skip, skip)); } MultiCameraState::MultiCameraState() @@ -979,9 +984,9 @@ MultiCameraState::MultiCameraState() void cameras_run(MultiCameraState *s) { LOG("-- Starting threads"); std::vector threads; - if (s->driver_cam.enabled) threads.push_back(start_process_thread(s, &s->driver_cam, process_driver_camera)); - if (s->road_cam.enabled) threads.push_back(start_process_thread(s, &s->road_cam, process_road_camera)); - if (s->wide_road_cam.enabled) threads.push_back(start_process_thread(s, &s->wide_road_cam, process_road_camera)); + if (s->driver_cam.enabled) threads.emplace_back(&CameraState::run, &s->driver_cam); + if (s->road_cam.enabled) threads.emplace_back(&CameraState::run, &s->road_cam); + if (s->wide_road_cam.enabled) threads.emplace_back(&CameraState::run, &s->wide_road_cam); // start devices LOG("-- Starting devices"); diff --git a/system/camerad/cameras/camera_qcom2.h b/system/camerad/cameras/camera_qcom2.h index 47981e0753..1b27fb18b8 100644 --- a/system/camerad/cameras/camera_qcom2.h +++ b/system/camerad/cameras/camera_qcom2.h @@ -15,6 +15,8 @@ struct CameraConfig { int camera_num; VisionStreamType stream_type; float focal_len; // millimeters + const char *publish_name; + cereal::FrameData::Builder (cereal::Event::Builder::*init_camera_state)(); bool enabled; }; @@ -22,6 +24,8 @@ const CameraConfig WIDE_ROAD_CAMERA_CONFIG = { .camera_num = 0, .stream_type = VISION_STREAM_WIDE_ROAD, .focal_len = 1.71, + .publish_name = "wideRoadCameraState", + .init_camera_state = &cereal::Event::Builder::initWideRoadCameraState, .enabled = !getenv("DISABLE_WIDE_ROAD"), }; @@ -29,6 +33,8 @@ const CameraConfig ROAD_CAMERA_CONFIG = { .camera_num = 1, .stream_type = VISION_STREAM_ROAD, .focal_len = 8.0, + .publish_name = "roadCameraState", + .init_camera_state = &cereal::Event::Builder::initRoadCameraState, .enabled = !getenv("DISABLE_ROAD"), }; @@ -36,6 +42,8 @@ const CameraConfig DRIVER_CAMERA_CONFIG = { .camera_num = 2, .stream_type = VISION_STREAM_DRIVER, .focal_len = 1.71, + .publish_name = "driverCameraState", + .init_camera_state = &cereal::Event::Builder::initDriverCameraState, .enabled = !getenv("DISABLE_DRIVER"), }; @@ -45,6 +53,8 @@ public: std::unique_ptr ci; bool enabled = true; VisionStreamType stream_type; + const char *publish_name = nullptr; + cereal::FrameData::Builder (cereal::Event::Builder::*init_camera_state)() = nullptr; float focal_len = 0; std::mutex exp_lock; @@ -83,6 +93,7 @@ public: void camera_map_bufs(); void camera_init(VisionIpcServer *v, cl_device_id device_id, cl_context ctx); void camera_close(); + void run(); int32_t session_handle = -1; int32_t sensor_dev_handle = -1; From fb1ad1d26a74e4937801a8b70d8cdce40f2da359 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Thu, 25 Jul 2024 15:13:47 -0700 Subject: [PATCH 110/229] fix pytools (#33076) fix --- pyproject.toml | 1 + uv.lock | 28 +++++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f5eb5a4370..79034e25f0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -111,6 +111,7 @@ dev = [ #pprofile = "*" "pyautogui", "pyopencl; platform_machine != 'aarch64'", # broken on arm64 + "pytools < 2024.1.11; platform_machine != 'aarch64'", # pyopencl use a broken version "pywinctl", "pyprof2calltree", "rerun-sdk", diff --git a/uv.lock b/uv.lock index 5c0de703f2..7d4870c4b1 100644 --- a/uv.lock +++ b/uv.lock @@ -1591,6 +1591,7 @@ dev = [ { name = "pyopencl", marker = "platform_machine != 'aarch64'" }, { name = "pyprof2calltree" }, { name = "pyqt5", marker = "platform_machine == 'x86_64'" }, + { name = "pytools", marker = "platform_machine != 'aarch64'" }, { name = "pywinctl" }, { name = "rerun-sdk" }, { name = "tabulate" }, @@ -4860,15 +4861,16 @@ sdist = { url = "https://files.pythonhosted.org/packages/ef/c6/2c5999de3bb153352 [[distribution]] name = "pytools" -version = "2024.1.11" +version = "2024.1.10" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "platformdirs" }, + { name = "siphash24" }, { name = "typing-extensions", marker = "python_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b7/80/188130dc3d1238f35a8a1ed788c42bdf00b9fd00f03a03b150778ceb846f/pytools-2024.1.11.tar.gz", hash = "sha256:fa966e09857bcd9299f961d58fc128e8333e4ac5fcea52473af5aae88f814e38", size = 81917 } +sdist = { url = "https://files.pythonhosted.org/packages/ee/0f/56e109c0307f831b5d598ad73976aaaa84b4d0e98da29a642e797eaa940c/pytools-2024.1.10.tar.gz", hash = "sha256:9af6f4b045212c49be32bb31fe19606c478ee4b09631886d05a32459f4ce0a12", size = 81741 } wheels = [ - { url = "https://files.pythonhosted.org/packages/60/83/df2f2e6de93798cfd1432aafaad6f23c80a217983b022d0b4bd739194072/pytools-2024.1.11-py3-none-any.whl", hash = "sha256:b3f254dcd6986426c21fcd52803a248e837a34b78a8c4abe09724cb60e0901ea", size = 88206 }, + { url = "https://files.pythonhosted.org/packages/66/cf/0a6aaa44b1f9e02b8c0648b5665a82246a93bcc75224c167b4fafa25c093/pytools-2024.1.10-py3-none-any.whl", hash = "sha256:9cabb71038048291400e244e2da441a051d86053339bc484e64e58d8ea263f44", size = 88108 }, ] [[distribution]] @@ -5164,6 +5166,26 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d4/c3/e98e3eb9f06def32b8e2454ab718cafb99149f023dff023e257125132d6e/shapely-2.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:30e8737983c9d954cd17feb49eb169f02f1da49e24e5171122cf2c2b62d65c95", size = 1442365 }, ] +[[distribution]] +name = "siphash24" +version = "1.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/d8/beb5183d1acc5a013d273452eac750b51e40855917a1841dead80fcf3086/siphash24-1.6.tar.gz", hash = "sha256:242d6901a81260f618938635a25ae7f208e744f7ee6c571f1b255c1c4c62917d", size = 19659 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/a5/0ffc51fe2e5f96258f0edfae15944006b09517ad7e98fdcbda05c67c70f6/siphash24-1.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3e1b3963c392a2d63cbe16af9171d789d2f15e69eb8314b21fe1e11bdc08205f", size = 80669 }, + { url = "https://files.pythonhosted.org/packages/80/ea/41d648cbbf3248a30f545f9e41ad5dedee19fcbad1d2baa7e39ae6f2779e/siphash24-1.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:de23d12c8a015904081e347900433a0c4b5e07690dbd0a104ad88929f3b91948", size = 75379 }, + { url = "https://files.pythonhosted.org/packages/48/a7/d6dcc551c8d53e436c58b7ecc96d1de0c0379c21b1e71b2543d38c039c95/siphash24-1.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8be513de01677e57989e028185a16e531942f7a9578d441481abe8b1085c45d6", size = 100466 }, + { url = "https://files.pythonhosted.org/packages/eb/46/b906d7e05e3d84239d6a04e3d5f106d96ab26483951c7cf2c5769ea8c894/siphash24-1.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef89477ce8f2e67fca025ad9b1c85b7498c6959baa7d9a502cbb5d8c7085f5b7", size = 105913 }, + { url = "https://files.pythonhosted.org/packages/4c/98/20159e2be9a957da2dffb3e18648c51ea7a0f09c49b8dce1cb268ca55ca7/siphash24-1.6-cp311-cp311-win32.whl", hash = "sha256:f702e646dc60b7d7915fa37f9357a03a2ec41ffb360b6946baf4801eb9f7e98f", size = 67528 }, + { url = "https://files.pythonhosted.org/packages/0d/0a/d8da621e624f3dbcf9a7a8066c54ddd2f6af437fc23169431caf6f9b403b/siphash24-1.6-cp311-cp311-win_amd64.whl", hash = "sha256:38715f61f0873e4a8b05125e14f349f465c64a1aaf79b6af0ff6f5f420d55dc5", size = 79961 }, + { url = "https://files.pythonhosted.org/packages/12/e4/ed944e92883b45996cf2c94447dd47b899c87674340b081b9e8cb317a88f/siphash24-1.6-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:51eefacbe82f8f48bc603eb97f54bf3819324349b69a9cd131ba02c40b1e6c61", size = 82399 }, + { url = "https://files.pythonhosted.org/packages/f9/d1/6ddbd7ba8972789f60282b9b9b1f88f08d26ef0913906e8ad5a9806c8432/siphash24-1.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c63321003aa1856b1bfd48e6ffbd4bff98afeaacb0fc902cb2ae44b861476335", size = 76253 }, + { url = "https://files.pythonhosted.org/packages/0d/87/0f125c1e069d09c4a39ab09d76fa9d4fe698bde68197627faeb38603f643/siphash24-1.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0ff4d068e9b0b3f138ef8e8b6f5de1990539d9d590e75a9a8beb6887535184a", size = 98184 }, + { url = "https://files.pythonhosted.org/packages/86/57/a274de0a91016cd4f870334a2af1193ffcdb88e34345ca098afea6dd10cb/siphash24-1.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1a671d91095e1872ca9988695200064ccca8db60133638d6061755fe669552", size = 103311 }, + { url = "https://files.pythonhosted.org/packages/5d/d4/b6a0c9f119b22938e36d74e0859167ae76c0ea0f7d7786eb48120b0e129d/siphash24-1.6-cp312-cp312-win32.whl", hash = "sha256:2dab672fcda08149b8c15f82ee74d732386428f53239cdb002ac2ad0a1f2f2bc", size = 68366 }, + { url = "https://files.pythonhosted.org/packages/ef/de/6ebd0f96184f8479e8348dcba93a9f14ff54ac3c6a68866cc77c334d7bdf/siphash24-1.6-cp312-cp312-win_amd64.whl", hash = "sha256:226af78af3b992c953cc4808f2c6a4bba320e91e6c89b34aa2492064fa417ae8", size = 81096 }, +] + [[distribution]] name = "six" version = "1.16.0" From e5b803f28eb3c63105c3560b2fe07b5fddffbee6 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 25 Jul 2024 16:07:59 -0700 Subject: [PATCH 111/229] cleanup python dependencies (#33077) * cleanup python dependencies * fix ruff --- pyproject.toml | 10 +- tools/latencylogger/latency_logger.py | 13 +- uv.lock | 207 +------------------------- 3 files changed, 9 insertions(+), 221 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 79034e25f0..8288340e5a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,13 +60,14 @@ dependencies = [ "psutil", "pycryptodome", # used in updated/casync, panda, body, and a test - #logreader + # logreader "zstd", ] [project.optional-dependencies] docs = [ "Jinja2", + "natsort", "mkdocs==1.4.3", # needed for mkdocs-plugin-commonmark "mkdocs-terminal", "mkdocs-plugin-commonmark", @@ -95,7 +96,6 @@ dev = [ "av", "azure-identity", "azure-storage-blob", - "breathe", "control", "dictdiffer", "flaky", @@ -103,12 +103,9 @@ dev = [ "lru-dict", "matplotlib", "metadrive-simulator@git+https://github.com/commaai/metadrive@opencv_headless ; platform_machine != 'aarch64'", - "mpld3", - "myst-parser", - "natsort", "opencv-python-headless", "parameterized >=0.8, <0.9", - #pprofile = "*" + #"pprofile", "pyautogui", "pyopencl; platform_machine != 'aarch64'", # broken on arm64 "pytools < 2024.1.11; platform_machine != 'aarch64'", # pyopencl use a broken version @@ -122,7 +119,6 @@ dev = [ # this is only pinned since 5.15.11 is broken "pyqt5 ==5.15.2; platform_machine == 'x86_64'", # no aarch64 wheels for macOS/linux - ] [project.urls] diff --git a/tools/latencylogger/latency_logger.py b/tools/latencylogger/latency_logger.py index 8691149e94..f145cc35e4 100755 --- a/tools/latencylogger/latency_logger.py +++ b/tools/latencylogger/latency_logger.py @@ -3,7 +3,6 @@ import argparse import json import matplotlib.patches as mpatches import matplotlib.pyplot as plt -import mpld3 import sys from bisect import bisect_left, bisect_right from collections import defaultdict @@ -174,7 +173,6 @@ def print_timestamps(timestamps, durations, start_times, relative): print(" "+'%-53s%-53s' %(event, str(time*1000))) def graph_timestamps(timestamps, start_times, end_times, relative, offset_services=False, title=""): - # mpld3 doesn't convert properly to D3 font sizes plt.rcParams.update({'font.size': 18}) t0 = find_t0(start_times) @@ -203,15 +201,14 @@ def graph_timestamps(timestamps, start_times, end_times, relative, offset_servic points['labels'].append(event[0]) ax.broken_barh(service_bars, (i-height/2, height), facecolors=(colors), alpha=0.5, offsets=offsets) - scatter = ax.scatter(points['x'], points['y'], marker='d', edgecolor='black') - tooltip = mpld3.plugins.PointLabelTooltip(scatter, labels=points['labels']) - mpld3.plugins.connect(fig, tooltip) + ax.scatter(points['x'], points['y'], marker='d', edgecolor='black') + for i, label in enumerate(points['labels']): + ax.annotate(label, (points['x'][i], points['y'][i]), textcoords="offset points", xytext=(0,10), ha='center') plt.title(title) - # Set size relative window size is not trivial: https://github.com/mpld3/mpld3/issues/65 fig.set_size_inches(18, 9) plt.legend(handles=[mpatches.Patch(color=colors[i], label=SERVICES[i]) for i in range(len(SERVICES))]) - return fig + plt.show() def get_timestamps(lr): lr = list(lr) @@ -239,4 +236,4 @@ if __name__ == "__main__": data, _ = get_timestamps(lr) print_timestamps(data['timestamp'], data['duration'], data['start'], args.relative) if args.plot: - mpld3.show(graph_timestamps(data['timestamp'], data['start'], data['end'], args.relative, offset_services=args.offset, title=r)) + graph_timestamps(data['timestamp'], data['start'], data['end'], args.relative, offset_services=args.offset, title=r) diff --git a/uv.lock b/uv.lock index 7d4870c4b1..fa873c6313 100644 --- a/uv.lock +++ b/uv.lock @@ -96,15 +96,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17", size = 7617 }, ] -[[distribution]] -name = "alabaster" -version = "0.7.16" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/3e/13dd8e5ed9094e734ac430b5d0eb4f2bb001708a8b7856cbf8e084e001ba/alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65", size = 23776 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/32/34/d4e1c02d3bee589efb5dfa17f88ea08bdb3e3eac12bc475462aec52ed223/alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92", size = 13511 }, -] - [[distribution]] name = "attrs" version = "23.2.0" @@ -179,28 +170,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f4/da/4033cee3855395e84ff73da4b50d3528f9338205299cde89676639387fcc/azure_storage_blob-12.21.0-py3-none-any.whl", hash = "sha256:f9ede187dd5a0ef296b583a7c1861c6938ddd6708d6e70f4203a163c2ab42d43", size = 396449 }, ] -[[distribution]] -name = "babel" -version = "2.15.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/d2/9671b93d623300f0aef82cde40e25357f11330bdde91743891b22a555bed/babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413", size = 9390000 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/45/377f7e32a5c93d94cd56542349b34efab5ca3f9e2fd5a68c5e93169aa32d/Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb", size = 9634913 }, -] - -[[distribution]] -name = "breathe" -version = "4.35.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docutils" }, - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a2/9f/0c6f4ae0608d5edbb1df357c2487edfcbda13e75f4e48a898972592e2e48/breathe-4.35.0.tar.gz", hash = "sha256:5165541c3c67b6c7adde8b3ecfe895c6f7844783c4076b6d8d287e4f33d62386", size = 83358 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/61/faddc25913de74e60e175bcfd962ec83532653c5895c0a06a83a6b5bbf3d/breathe-4.35.0-py3-none-any.whl", hash = "sha256:52c581f42ca4310737f9e435e3851c3d1f15446205a85fbc272f1f97ed74f5be", size = 92955 }, -] - [[distribution]] name = "casadi" version = "3.6.5" @@ -538,15 +507,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/87/a1/8c5287991ddb8d3e4662f71356d9656d91ab3a36618c3dd11b280df0d255/dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50", size = 307696 }, ] -[[distribution]] -name = "docutils" -version = "0.21.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408 }, -] - [[distribution]] name = "ewmhlib" version = "0.2" @@ -838,15 +798,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9c/1f/19ebc343cc71a7ffa78f17018535adc5cbdd87afb31d7c34874680148b32/ifaddr-0.2.0-py3-none-any.whl", hash = "sha256:085e0305cfe6f16ab12d72e2024030f5d52674afad6911bb1eee207177b8a748", size = 12314 }, ] -[[distribution]] -name = "imagesize" -version = "1.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769 }, -] - [[distribution]] name = "import-linter" version = "2.0" @@ -1066,18 +1017,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f3/df/ca72f352e15b6f8ce32b74af029f1189abffb906f7c137501ffe69c98a65/Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621", size = 97778 }, ] -[[distribution]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, -] - [[distribution]] name = "markupsafe" version = "2.1.5" @@ -1137,27 +1076,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e3/31/aeab8a3db1fb22a7d04c5215f872b92451baf7f6595ffd59004aeead0b2c/matplotlib-3.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:44a21d922f78ce40435cb35b43dd7d573cf2a30138d5c4b709d19f00e3907fd7", size = 7974774 }, ] -[[distribution]] -name = "mdit-py-plugins" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/6c/79c52651b22b64dba5c7bbabd7a294cc410bfb2353250dc8ade44d7d8ad8/mdit_py_plugins-0.4.1.tar.gz", hash = "sha256:834b8ac23d1cd60cec703646ffd22ae97b7955a6d596eb1d304be1e251ae499c", size = 42713 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/f7/8a4dcea720a581e69ac8c5a38524baf0e3e2bb5f3819a9ff661464fe7d10/mdit_py_plugins-0.4.1-py3-none-any.whl", hash = "sha256:1020dfe4e6bfc2c79fb49ae4e3f5b297f5ccd20f010187acc52af2921e27dc6a", size = 54794 }, -] - -[[distribution]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, -] - [[distribution]] name = "mergedeep" version = "1.3.4" @@ -1267,19 +1185,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/28/fa/b2ba8229b9381e8f6381c1dcae6f4159a7f72349e414ed19cfbbd1817173/MouseInfo-0.1.3.tar.gz", hash = "sha256:2c62fb8885062b8e520a3cce0a297c657adcc08c60952eb05bc8256ef6f7f6e7", size = 10850 } -[[distribution]] -name = "mpld3" -version = "0.5.10" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jinja2" }, - { name = "matplotlib" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/90/58/19378f4189a034eb3efc17b133426b8551af1d3b2c70d641a63124579629/mpld3-0.5.10.tar.gz", hash = "sha256:a478eb404fa5212505c59133cf272cd9a94105872e605597720e7f84de38fbc7", size = 1027709 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/6a/e3691bcc47485f38b09853207c928130571821d187cf174eed5418d45e82/mpld3-0.5.10-py3-none-any.whl", hash = "sha256:80877acce87ea447380fad7374668737505c8c0684aab05238e7c5dc1fab38c1", size = 202561 }, -] - [[distribution]] name = "mpmath" version = "1.3.0" @@ -1387,23 +1292,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, ] -[[distribution]] -name = "myst-parser" -version = "3.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docutils" }, - { name = "jinja2" }, - { name = "markdown-it-py" }, - { name = "mdit-py-plugins" }, - { name = "pyyaml" }, - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/49/64/e2f13dac02f599980798c01156393b781aec983b52a6e4057ee58f07c43a/myst_parser-3.0.1.tar.gz", hash = "sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87", size = 92392 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/de/21aa8394f16add8f7427f0a1326ccd2b3a2a8a3245c9252bc5ac034c6155/myst_parser-3.0.1-py3-none-any.whl", hash = "sha256:6457aaa33a5d474aca678b8ead9b3dc298e89c68e67012e73146ea6fd54babf1", size = 83163 }, -] - [[distribution]] name = "natsort" version = "8.4.0" @@ -1573,7 +1461,6 @@ dev = [ { name = "av" }, { name = "azure-identity" }, { name = "azure-storage-blob" }, - { name = "breathe" }, { name = "control" }, { name = "dictdiffer" }, { name = "flaky" }, @@ -1582,9 +1469,6 @@ dev = [ { name = "lru-dict" }, { name = "matplotlib" }, { name = "metadrive-simulator", marker = "platform_machine != 'aarch64'" }, - { name = "mpld3" }, - { name = "myst-parser" }, - { name = "natsort" }, { name = "opencv-python-headless" }, { name = "parameterized" }, { name = "pyautogui" }, @@ -1603,6 +1487,7 @@ docs = [ { name = "mkdocs" }, { name = "mkdocs-plugin-commonmark" }, { name = "mkdocs-terminal" }, + { name = "natsort" }, ] testing = [ { name = "coverage" }, @@ -5204,15 +5089,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d6/5b/3ada173f07b4ec9bfa03b779e59ecada48eb7cb1a29f51cfce70edce7f3f/smbus2-0.4.3-py2.py3-none-any.whl", hash = "sha256:a2fc29cfda4081ead2ed61ef2c4fc041d71dd40a8d917e85216f44786fca2d1d", size = 11553 }, ] -[[distribution]] -name = "snowballstemmer" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/44/7b/af302bebf22c749c56c9c3e8ae13190b5b5db37a33d9068652e8f73b7089/snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", size = 86699 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002 }, -] - [[distribution]] name = "sortedcontainers" version = "2.4.0" @@ -5237,87 +5113,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d4/09/bfdd393f1bb1b90b4a6849b84972b7059c95e36818cc489922228d58cc63/sounddevice-0.4.7-py3-none-win_amd64.whl", hash = "sha256:0c8b3543da1496f282b66a7bc54b755577ba638b1af06c146d4ac7f39d86b548", size = 200096 }, ] -[[distribution]] -name = "sphinx" -version = "7.4.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "alabaster" }, - { name = "babel" }, - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "docutils" }, - { name = "imagesize" }, - { name = "jinja2" }, - { name = "packaging" }, - { name = "pygments" }, - { name = "requests" }, - { name = "snowballstemmer" }, - { name = "sphinxcontrib-applehelp" }, - { name = "sphinxcontrib-devhelp" }, - { name = "sphinxcontrib-htmlhelp" }, - { name = "sphinxcontrib-jsmath" }, - { name = "sphinxcontrib-qthelp" }, - { name = "sphinxcontrib-serializinghtml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5b/be/50e50cb4f2eff47df05673d361095cafd95521d2a22521b920c67a372dcb/sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe", size = 8067911 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/ef/153f6803c5d5f8917dbb7f7fcf6d34a871ede3296fa89c2c703f5f8a6c8e/sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239", size = 3401624 }, -] - -[[distribution]] -name = "sphinxcontrib-applehelp" -version = "1.0.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/6b/68f470fc337ed24043fec987b101f25b35010970bd958970c2ae5990859f/sphinxcontrib_applehelp-1.0.8.tar.gz", hash = "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619", size = 19674 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/56/89/fea3fbf6785b388e6cb8a1beaf62f96e80b37311bdeed6e133388a732426/sphinxcontrib_applehelp-1.0.8-py3-none-any.whl", hash = "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4", size = 120035 }, -] - -[[distribution]] -name = "sphinxcontrib-devhelp" -version = "1.0.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/a1/80b7e9f677abc673cb9320bf255ad4e08931ccbc2e66bde4b59bad3809ad/sphinxcontrib_devhelp-1.0.6.tar.gz", hash = "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3", size = 12480 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/52/1049d918d1d1c72857d285c3f0c64c1cbe0be394ce1c93a3d2aa4f39fe3b/sphinxcontrib_devhelp-1.0.6-py3-none-any.whl", hash = "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f", size = 83499 }, -] - -[[distribution]] -name = "sphinxcontrib-htmlhelp" -version = "2.0.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/92/d9/a1c50c8a7b5e12f34bf4d63300a1e2629c29b71603115d900c0fa7c79219/sphinxcontrib_htmlhelp-2.0.6.tar.gz", hash = "sha256:c6597da06185f0e3b4dc952777a04200611ef563882e0c244d27a15ee22afa73", size = 21957 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/b4/6ebbdc57b5b216b400b355f34ef669e9b6b5c31a6ede8cf5ac36f9e8fc0c/sphinxcontrib_htmlhelp-2.0.6-py3-none-any.whl", hash = "sha256:1b9af5a2671a61410a868fce050cab7ca393c218e6205cbc7f590136f207395c", size = 99225 }, -] - -[[distribution]] -name = "sphinxcontrib-jsmath" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071 }, -] - -[[distribution]] -name = "sphinxcontrib-qthelp" -version = "1.0.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/67/f5c7df6457315877202f370450acb28626d033822eec1e8163600612b4ef/sphinxcontrib_qthelp-1.0.8.tar.gz", hash = "sha256:db3f8fa10789c7a8e76d173c23364bdf0ebcd9449969a9e6a3dd31b8b7469f03", size = 16778 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/91/cec9416d27ebe9b8aa83f014a1ac8402c729aed791da67704e10bb2c8f33/sphinxcontrib_qthelp-1.0.8-py3-none-any.whl", hash = "sha256:323d6acc4189af76dfe94edd2a27d458902319b60fcca2aeef3b2180c106a75f", size = 89456 }, -] - -[[distribution]] -name = "sphinxcontrib-serializinghtml" -version = "1.1.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/13/8dd7a7ed9c58e16e20c7f4ce8e4cb6943eb580955236d0c0d00079a73c49/sphinxcontrib_serializinghtml-1.1.10.tar.gz", hash = "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f", size = 15592 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/24/228bb903ea87b9e08ab33470e6102402a644127108c7117ac9c00d849f82/sphinxcontrib_serializinghtml-1.1.10-py3-none-any.whl", hash = "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7", size = 92725 }, -] - [[distribution]] name = "spidev" version = "3.6" From 3c192cbf88f1272622dcf7428fbb8624edb02689 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Thu, 25 Jul 2024 16:57:43 -0700 Subject: [PATCH 112/229] op.sh: improvements (#33078) improvements --- tools/op.sh | 139 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 87 insertions(+), 52 deletions(-) diff --git a/tools/op.sh b/tools/op.sh index 42bbb1973d..c7431c135b 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -6,7 +6,7 @@ UNDERLINE='\033[4m' BOLD='\033[1m' NC='\033[0m' -function op_first_install() { +function op_install() { (set -e echo "Installing op system-wide..." @@ -30,16 +30,22 @@ function op_run_command() { # be default, assume openpilot dir is in current directory OPENPILOT_ROOT=$(pwd) -function op_check_openpilot_dir() { - echo "Checking for openpilot directory..." +function op_get_openpilot_dir() { while [[ "$OPENPILOT_ROOT" != '/' ]]; do if find "$OPENPILOT_ROOT/launch_openpilot.sh" -maxdepth 1 -mindepth 1 &> /dev/null; then - echo -e " ↳ [${GREEN}✔${NC}] openpilot found.\n" return 0 fi OPENPILOT_ROOT="$(readlink -f "$OPENPILOT_ROOT/"..)" done +} + +function op_check_openpilot_dir() { + echo "Checking for openpilot directory..." + if [[ -f "$OPENPILOT_ROOT/launch_openpilot.sh" ]]; then + echo -e " ↳ [${GREEN}✔${NC}] openpilot found.\n" + return 0 + fi echo -e " ↳ [${RED}✗${NC}] openpilot directory not found! Make sure that you are" echo " inside the openpilot directory or specify one with the" @@ -52,28 +58,28 @@ function op_check_git() { echo "Checking for git..." if ! command -v "git" > /dev/null 2>&1; then - echo -e " ↳ [${RED}✗${NC}] git not found on your system!\n" + echo -e " ↳ [${RED}✗${NC}] git not found on your system!" return 1 else - echo -e " ↳ [${GREEN}✔${NC}] git found.\n" + echo -e " ↳ [${GREEN}✔${NC}] git found." fi echo "Checking for git lfs files..." - if [[ $(file -b $OPENPILOT_ROOT/selfdrive/modeld/models/supercombo.onnx) == "ASCII text" ]]; then - echo -e " ↳ [${RED}✗${NC}] git lfs files not found! Run 'git lfs pull'\n" - return 1 + if [[ $(file -b $OPENPILOT_ROOT/selfdrive/modeld/models/supercombo.onnx) == "data" ]]; then + echo -e " ↳ [${GREEN}✔${NC}] git lfs files found." else - echo -e " ↳ [${GREEN}✔${NC}] git lfs files found.\n" + echo -e " ↳ [${RED}✗${NC}] git lfs files not found! Run 'git lfs pull'" + return 1 fi echo "Checking for git submodules..." for name in body msgq_repo opendbc panda rednose_repo tinygrad_repo; do if [[ -z $(ls $OPENPILOT_ROOT/$name) ]]; then - echo -e " ↳ [${RED}✗${NC}] git submodule $name not found! Run 'git submodule update --init --recursive'\n" + echo -e " ↳ [${RED}✗${NC}] git submodule $name not found! Run 'git submodule update --init --recursive'" return 1 fi done - echo -e " ↳ [${GREEN}✔${NC}] git submodules found.\n" + echo -e " ↳ [${GREEN}✔${NC}] git submodules found." ) } @@ -88,22 +94,22 @@ function op_check_os() { source /etc/os-release case "$VERSION_CODENAME" in "jammy" | "kinetic" | "noble" | "focal") - echo -e " ↳ [${GREEN}✔${NC}] Ubuntu $VERSION_CODENAME detected.\n" + echo -e " ↳ [${GREEN}✔${NC}] Ubuntu $VERSION_CODENAME detected." ;; * ) - echo -e " ↳ [${RED}✗${NC}] Incompatible Ubuntu version $VERSION_CODENAME detected!\n" + echo -e " ↳ [${RED}✗${NC}] Incompatible Ubuntu version $VERSION_CODENAME detected!" return 1 ;; esac else - echo -e " ↳ [${RED}✗${NC}] No /etc/os-release on your system. Make sure you're running on Ubuntu, or similar!\n" + echo -e " ↳ [${RED}✗${NC}] No /etc/os-release on your system. Make sure you're running on Ubuntu, or similar!" return 1 fi elif [[ "$OSTYPE" == "darwin"* ]]; then echo -e " ↳ [${GREEN}✔${NC}] macos detected.\n" else - echo -e " ↳ [${RED}✗${NC}] OS type $OSTYPE not supported!\n" + echo -e " ↳ [${RED}✗${NC}] OS type $OSTYPE not supported!" return 1 fi @@ -118,12 +124,12 @@ function op_check_python() { INSTALLED_PYTHON_VERSION=$(python3 --version 2> /dev/null || true) if [[ -z $INSTALLED_PYTHON_VERSION ]]; then - echo -e " ↳ [${RED}✗${NC}] python3 not found on your system. You need python version at least $(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9.]') to continue!\n" + echo -e " ↳ [${RED}✗${NC}] python3 not found on your system. You need python version at least $(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9.]') to continue!" return 1 elif [[ $(echo $INSTALLED_PYTHON_VERSION | tr -d -c '[0-9]') -ge $(($(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9]') * 10)) ]]; then - echo -e " ↳ [${GREEN}✔${NC}] $INSTALLED_PYTHON_VERSION detected.\n" + echo -e " ↳ [${GREEN}✔${NC}] $INSTALLED_PYTHON_VERSION detected." else - echo -e " ↳ [${RED}✗${NC}] You need python version at least $(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9.]') to continue!\n" + echo -e " ↳ [${RED}✗${NC}] You need python version at least $(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9.]') to continue!" return 1 fi @@ -133,9 +139,9 @@ function op_check_python() { function op_check_venv() { echo "Checking for venv..." if source $OPENPILOT_ROOT/.venv/bin/activate; then - echo -e " ↳ [${GREEN}✔${NC}] venv detected.\n" + echo -e " ↳ [${GREEN}✔${NC}] venv detected." else - echo -e " ↳ [${RED}✗${NC}] Can't activate venv in $OPENPILOT_ROOT. Assuming global env!\n" + echo -e " ↳ [${RED}✗${NC}] Can't activate venv in $OPENPILOT_ROOT. Assuming global env!" fi } @@ -144,20 +150,32 @@ function op_before_cmd() { return 0 fi - op_check_openpilot_dir + op_get_openpilot_dir cd $OPENPILOT_ROOT - op_check_git - op_check_os - op_check_venv - op_check_python - echo -e "-----------------------------\n" + + result="$((op_check_openpilot_dir ) 2>&1)" || (echo -e "$result" && return 1) + result="${result}\n$(( op_check_git ) 2>&1)" || (echo -e "$result" && return 1) + result="${result}\n$(( op_check_os ) 2>&1)" || (echo -e "$result" && return 1) + result="${result}\n$(( op_check_venv ) 2>&1)" || (echo -e "$result" && return 1) + + op_activate_venv + + result="${result}\n$(( op_check_python ) 2>&1)" || (echo -e "$result" && return 1) + + if [[ -z $VERBOSE ]]; then + echo -e "Checking system → [${GREEN}✔${NC}] system is good." + else + echo -e "$result" + fi } -function op_install() { +function op_setup() { (set -e - op_check_openpilot_dir + op_get_openpilot_dir cd $OPENPILOT_ROOT + + op_check_openpilot_dir op_check_os op_check_python @@ -182,6 +200,10 @@ function op_install() { ) } +function op_activate_venv() { + source $OPENPILOT_ROOT/.venv/bin/activate &> /dev/null || true +} + function op_venv() { ( set -e @@ -191,7 +213,7 @@ function op_venv() { if [[ "$?" -eq 0 ]]; then # this must be run in the same shell as the user calling "op" - op_check_openpilot_dir > /dev/null + op_get_openpilot_dir op_run_command source $OPENPILOT_ROOT/.venv/bin/activate fi } @@ -199,7 +221,9 @@ function op_venv() { function op_check() { (set -e + VERBOSE=1 op_before_cmd + unset VERBOSE ) } @@ -208,7 +232,7 @@ function op_run() { (set -e op_before_cmd - op_run_command $OPENPILOT_ROOT/launch_openpilot.sh $@ + op_run_command ./launch_openpilot.sh $@ ) } @@ -226,7 +250,7 @@ function op_juggle() { (set -e op_before_cmd - op_run_command $OPENPILOT_ROOT/tools/plotjuggler/juggle.py $@ + op_run_command tools/plotjuggler/juggle.py $@ ) } @@ -244,7 +268,7 @@ function op_replay() { (set -e op_before_cmd - op_run_command $OPENPILOT_ROOT/tools/replay/replay $@ + op_run_command tools/replay/replay $@ ) } @@ -253,7 +277,7 @@ function op_cabana() { (set -e op_before_cmd - op_run_command $OPENPILOT_ROOT/tools/cabana/cabana $@ + op_run_command tools/cabana/cabana $@ ) } @@ -262,8 +286,8 @@ function op_sim() { (set -e op_before_cmd - op_run_command exec $OPENPILOT_ROOT/tools/sim/run_bridge.py & - op_run_command exec $OPENPILOT_ROOT/tools/sim/launch_openpilot.sh + op_run_command exec tools/sim/run_bridge.py & + op_run_command exec tools/sim/launch_openpilot.sh ) } @@ -284,18 +308,18 @@ function op_default() { echo -e "${BOLD}${UNDERLINE}Usage:${NC} op [OPTIONS] " echo "" echo -e "${BOLD}${UNDERLINE}Commands:${NC}" - echo -e " ${BOLD}venv${NC} Activate the virtual environment" - echo -e " ${BOLD}check${NC} Check system requirements (git, os, python) to start using openpilot" - echo -e " ${BOLD}install${NC} Install requirements to use openpilot" - echo -e " ${BOLD}build${NC} Build openpilot" - echo -e " ${BOLD}run${NC} Run openpilot" - echo -e " ${BOLD}sim${NC} Run openpilot in a simulator" - echo -e " ${BOLD}juggle${NC} Run Plotjuggler" - echo -e " ${BOLD}replay${NC} Run replay" - echo -e " ${BOLD}cabana${NC} Run cabana" - echo -e " ${BOLD}linter${NC} Run all the pre-commit checks" - echo -e " ${BOLD}help${NC} Show this message" - echo -e " ${BOLD}--install${NC} Install this tool system wide" + echo -e " ${BOLD}venv${NC} Activate the virtual environment" + echo -e " ${BOLD}check${NC} Check system requirements (git, os, python) to start using openpilot" + echo -e " ${BOLD}setup${NC} Setup requirements to use openpilot" + echo -e " ${BOLD}build${NC} Build openpilot" + echo -e " ${BOLD}run${NC} Run openpilot" + echo -e " ${BOLD}sim${NC} Run openpilot in a simulator" + echo -e " ${BOLD}juggle${NC} Run Plotjuggler" + echo -e " ${BOLD}replay${NC} Run replay" + echo -e " ${BOLD}cabana${NC} Run cabana" + echo -e " ${BOLD}linter${NC} Run all the pre-commit checks" + echo -e " ${BOLD}help${NC} Show this message" + echo -e " ${BOLD}install${NC} Install this tool system wide" echo "" echo -e "${BOLD}${UNDERLINE}Options:${NC}" echo -e " ${BOLD}-d, --dir${NC}" @@ -304,6 +328,8 @@ function op_default() { echo " Don't actually run anything, just print what would be" echo -e " ${BOLD}-n, --no-verify${NC}" echo " Don't run checks before running a command" + echo -e " ${BOLD}-v, --verbose${NC}" + echo " Show the result of all checks before running a command" echo "" echo -e "${BOLD}${UNDERLINE}Examples:${NC}" echo " op --dir /tmp/openpilot check" @@ -325,13 +351,14 @@ function _op() { -d | --dir ) shift 1; OPENPILOT_ROOT="$1"; shift 1 ;; --dry ) shift 1; DRY="1" ;; -n | --no-verify ) shift 1; NO_VERIFY="1" ;; + -v | --verbose ) shift 1; VERBOSE="1" ;; esac # parse Commands case $1 in venv ) shift 1; op_venv "$@" ;; check ) shift 1; op_check "$@" ;; - install ) shift 1; op_install "$@" ;; + setup ) shift 1; op_setup "$@" ;; build ) shift 1; op_build "$@" ;; run ) shift 1; op_run "$@" ;; juggle ) shift 1; op_juggle "$@" ;; @@ -339,7 +366,7 @@ function _op() { linter ) shift 1; op_linter "$@" ;; replay ) shift 1; op_replay "$@" ;; sim ) shift 1; op_sim "$@" ;; - --install ) shift 1; op_first_install "$@" ;; + install ) shift 1; op_install "$@" ;; * ) op_default "$@" ;; esac } @@ -349,7 +376,7 @@ _op $@ # remove from env unset -f _op unset -f op_check -unset -f op_install +unset -f op_setup unset -f op_build unset -f op_run unset -f op_juggle @@ -358,7 +385,7 @@ unset -f op_check_openpilot_dir unset -f op_check_git unset -f op_check_python unset -f op_check_os -unset -f op_first_install +unset -f op_install unset -f op_default unset -f op_run_command unset -f op_linter @@ -367,6 +394,14 @@ unset -f op_cabana unset -f op_check_venv unset -f op_before_cmd unset -f op_sim +unset -f op_activate_venv +unset -f op_get_openpilot_dir unset DRY +unset NC +unset RED +unset GREEN +unset UNDERLINE +unset BOLD unset OPENPILOT_ROOT unset NO_VERIFY +unset VERBOSE From 02e30ac14053212436ea5129030742a8c7dfe3fb Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Thu, 25 Jul 2024 16:59:42 -0700 Subject: [PATCH 113/229] Update setup.sh --- tools/setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/setup.sh b/tools/setup.sh index 8aca889b8c..2091886103 100755 --- a/tools/setup.sh +++ b/tools/setup.sh @@ -44,8 +44,8 @@ function git_clone() { function install_with_op() { cd $OPENPILOT_ROOT - $OPENPILOT_ROOT/tools/op.sh --install $OPENPILOT_ROOT/tools/op.sh install + $OPENPILOT_ROOT/tools/op.sh setup # make op usable right now alias op="source $OPENPILOT_ROOT/tools/op.sh \"\$@\"" From 8827067eaeba384722066caeeee4a35f30026d07 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 25 Jul 2024 18:21:42 -0700 Subject: [PATCH 114/229] op.sh: misc fixups (#33080) * rm run * little more * lint * one more lint * cleanup --- tools/op.sh | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/tools/op.sh b/tools/op.sh index c7431c135b..55cc3d60d9 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -228,15 +228,6 @@ function op_check() { ) } -function op_run() { - (set -e - - op_before_cmd - op_run_command ./launch_openpilot.sh $@ - - ) -} - function op_build() { (set -e @@ -255,7 +246,7 @@ function op_juggle() { ) } -function op_linter() { +function op_lint() { (set -e op_before_cmd @@ -297,7 +288,7 @@ function op_default() { echo "" echo -e "${BOLD}${UNDERLINE}Description:${NC}" echo " op is your entry point for all things related to openpilot development." - echo " op is only a wrapper for scripts, tools and commands already existing." + echo " op is only a wrapper for existing scripts, tools, and commands." echo " op will always show you what it will run on your system." echo "" echo " op will try to find your openpilot directory in the following order:" @@ -308,26 +299,25 @@ function op_default() { echo -e "${BOLD}${UNDERLINE}Usage:${NC} op [OPTIONS] " echo "" echo -e "${BOLD}${UNDERLINE}Commands:${NC}" - echo -e " ${BOLD}venv${NC} Activate the virtual environment" - echo -e " ${BOLD}check${NC} Check system requirements (git, os, python) to start using openpilot" - echo -e " ${BOLD}setup${NC} Setup requirements to use openpilot" + echo -e " ${BOLD}venv${NC} Activate the Python virtual environment" + echo -e " ${BOLD}check${NC} Check the development environment (git, os, python) to start using openpilot" + echo -e " ${BOLD}setup${NC} Install openpilot dependencies" echo -e " ${BOLD}build${NC} Build openpilot" - echo -e " ${BOLD}run${NC} Run openpilot" echo -e " ${BOLD}sim${NC} Run openpilot in a simulator" echo -e " ${BOLD}juggle${NC} Run Plotjuggler" echo -e " ${BOLD}replay${NC} Run replay" echo -e " ${BOLD}cabana${NC} Run cabana" - echo -e " ${BOLD}linter${NC} Run all the pre-commit checks" + echo -e " ${BOLD}lint${NC} Run all the pre-commit checks" echo -e " ${BOLD}help${NC} Show this message" - echo -e " ${BOLD}install${NC} Install this tool system wide" + echo -e " ${BOLD}install${NC} Install the 'op' tool system wide" echo "" echo -e "${BOLD}${UNDERLINE}Options:${NC}" echo -e " ${BOLD}-d, --dir${NC}" echo " Specify the openpilot directory you want to use" echo -e " ${BOLD}--dry${NC}" - echo " Don't actually run anything, just print what would be" + echo " Don't actually run anything, just print what would be run" echo -e " ${BOLD}-n, --no-verify${NC}" - echo " Don't run checks before running a command" + echo " Skip environment check before running commands" echo -e " ${BOLD}-v, --verbose${NC}" echo " Show the result of all checks before running a command" echo "" @@ -358,12 +348,11 @@ function _op() { case $1 in venv ) shift 1; op_venv "$@" ;; check ) shift 1; op_check "$@" ;; - setup ) shift 1; op_setup "$@" ;; + setup ) shift 1; op_setup "$@" ;; build ) shift 1; op_build "$@" ;; - run ) shift 1; op_run "$@" ;; juggle ) shift 1; op_juggle "$@" ;; cabana ) shift 1; op_cabana "$@" ;; - linter ) shift 1; op_linter "$@" ;; + lint ) shift 1; op_lint "$@" ;; replay ) shift 1; op_replay "$@" ;; sim ) shift 1; op_sim "$@" ;; install ) shift 1; op_install "$@" ;; @@ -378,7 +367,6 @@ unset -f _op unset -f op_check unset -f op_setup unset -f op_build -unset -f op_run unset -f op_juggle unset -f op_venv unset -f op_check_openpilot_dir @@ -388,7 +376,7 @@ unset -f op_check_os unset -f op_install unset -f op_default unset -f op_run_command -unset -f op_linter +unset -f op_lint unset -f op_replay unset -f op_cabana unset -f op_check_venv From d128dbe27f9a4b87f6f37d68b22e0a385cf29d70 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 25 Jul 2024 18:59:29 -0700 Subject: [PATCH 115/229] setup.sh: fast git clone (#33081) * setup.sh: filter clone * no submodules --- tools/setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/setup.sh b/tools/setup.sh index 2091886103..9b1ee9c0c1 100755 --- a/tools/setup.sh +++ b/tools/setup.sh @@ -31,7 +31,7 @@ function check_git() { function git_clone() { echo "Cloning openpilot..." - if $(git clone --depth=1 https://github.com/commaai/openpilot.git "$OPENPILOT_ROOT"); then + if $(git clone --filter=blob:none https://github.com/commaai/openpilot.git "$OPENPILOT_ROOT"); then if [[ -f $OPENPILOT_ROOT/launch_openpilot.sh ]]; then echo -e " ↳ [${GREEN}✔${NC}] Successfully cloned openpilot.\n" return 0 From f39c5c22e80740700aa3c9bd8cba2a684903e9d2 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 25 Jul 2024 19:30:40 -0700 Subject: [PATCH 116/229] remove opencv-python-headless (#33082) --- pyproject.toml | 1 - tools/webcam/camera.py | 1 + uv.lock | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8288340e5a..afebfe7a7d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -103,7 +103,6 @@ dev = [ "lru-dict", "matplotlib", "metadrive-simulator@git+https://github.com/commaai/metadrive@opencv_headless ; platform_machine != 'aarch64'", - "opencv-python-headless", "parameterized >=0.8, <0.9", #"pprofile", "pyautogui", diff --git a/tools/webcam/camera.py b/tools/webcam/camera.py index d1d61b64d7..ddff46c5d3 100644 --- a/tools/webcam/camera.py +++ b/tools/webcam/camera.py @@ -1,3 +1,4 @@ +# TODO: remove the cv2 dependency, it's only used here import cv2 as cv import numpy as np diff --git a/uv.lock b/uv.lock index fa873c6313..866cf921ae 100644 --- a/uv.lock +++ b/uv.lock @@ -1469,7 +1469,6 @@ dev = [ { name = "lru-dict" }, { name = "matplotlib" }, { name = "metadrive-simulator", marker = "platform_machine != 'aarch64'" }, - { name = "opencv-python-headless" }, { name = "parameterized" }, { name = "pyautogui" }, { name = "pyopencl", marker = "platform_machine != 'aarch64'" }, From e68bb26e14d4e85f61ab3f58ac9667ca9d6ea565 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 25 Jul 2024 22:05:10 -0700 Subject: [PATCH 117/229] tools: keep re pattern file small (#33084) remove bz2 from re file --- selfdrive/debug/run_process_on_route.py | 3 +-- selfdrive/test/process_replay/model_replay.py | 3 +-- selfdrive/test/process_replay/regen.py | 3 +-- selfdrive/test/process_replay/test_processes.py | 3 +-- tools/lib/helpers.py | 13 ------------- tools/lib/logreader.py | 10 ++++++++++ tools/plotjuggler/juggle.py | 3 +-- 7 files changed, 15 insertions(+), 23 deletions(-) diff --git a/selfdrive/debug/run_process_on_route.py b/selfdrive/debug/run_process_on_route.py index 90db14bc9a..c98763f3c9 100755 --- a/selfdrive/debug/run_process_on_route.py +++ b/selfdrive/debug/run_process_on_route.py @@ -3,8 +3,7 @@ import argparse from openpilot.selfdrive.test.process_replay.process_replay import CONFIGS, replay_process -from openpilot.tools.lib.helpers import save_log -from openpilot.tools.lib.logreader import LogReader +from openpilot.tools.lib.logreader import LogReader, save_log if __name__ == "__main__": parser = argparse.ArgumentParser(description="Run process on route and create new logs", diff --git a/selfdrive/test/process_replay/model_replay.py b/selfdrive/test/process_replay/model_replay.py index 0e43cad820..a58a58107e 100755 --- a/selfdrive/test/process_replay/model_replay.py +++ b/selfdrive/test/process_replay/model_replay.py @@ -10,8 +10,7 @@ from openpilot.tools.lib.openpilotci import BASE_URL, get_url from openpilot.selfdrive.test.process_replay.compare_logs import compare_logs, format_diff from openpilot.selfdrive.test.process_replay.process_replay import get_process_config, replay_process from openpilot.tools.lib.framereader import FrameReader -from openpilot.tools.lib.logreader import LogReader -from openpilot.tools.lib.helpers import save_log +from openpilot.tools.lib.logreader import LogReader, save_log TEST_ROUTE = "2f4452b03ccb98f0|2022-12-03--13-45-30" SEGMENT = 6 diff --git a/selfdrive/test/process_replay/regen.py b/selfdrive/test/process_replay/regen.py index bf7a4bfd97..fe33443b49 100755 --- a/selfdrive/test/process_replay/regen.py +++ b/selfdrive/test/process_replay/regen.py @@ -14,8 +14,7 @@ from openpilot.selfdrive.test.process_replay.vision_meta import DRIVER_CAMERA_FR from openpilot.selfdrive.test.update_ci_routes import upload_route from openpilot.tools.lib.route import Route from openpilot.tools.lib.framereader import FrameReader, BaseFrameReader, FrameType -from openpilot.tools.lib.logreader import LogReader, LogIterable -from openpilot.tools.lib.helpers import save_log +from openpilot.tools.lib.logreader import LogReader, LogIterable, save_log class DummyFrameReader(BaseFrameReader): diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 533ab125f9..3bd58dfacb 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -14,8 +14,7 @@ from openpilot.selfdrive.test.process_replay.compare_logs import compare_logs, f from openpilot.selfdrive.test.process_replay.process_replay import CONFIGS, PROC_REPLAY_DIR, FAKEDATA, replay_process, \ check_openpilot_enabled, check_most_messages_valid from openpilot.tools.lib.filereader import FileReader -from openpilot.tools.lib.logreader import LogReader -from openpilot.tools.lib.helpers import save_log +from openpilot.tools.lib.logreader import LogReader, save_log source_segments = [ ("BODY", "937ccb7243511b65|2022-05-24--16-03-09--1"), # COMMA.COMMA_BODY diff --git a/tools/lib/helpers.py b/tools/lib/helpers.py index e9b4b85e70..7c34e17cb1 100644 --- a/tools/lib/helpers.py +++ b/tools/lib/helpers.py @@ -1,6 +1,3 @@ -import bz2 - - # regex patterns class RE: DONGLE_ID = r'(?P[a-f0-9]{16})' @@ -18,13 +15,3 @@ class RE: EXPLORER_FILE = fr'^(?P{SEGMENT_NAME})--(?P[a-z]+\.[a-z0-9]+)$' OP_SEGMENT_DIR = fr'^(?P{SEGMENT_NAME})$' - - -def save_log(dest, log_msgs, compress=True): - dat = b"".join(msg.as_builder().to_bytes() for msg in log_msgs) - - if compress: - dat = bz2.compress(dat) - - with open(dest, "wb") as f: - f.write(dat) diff --git a/tools/lib/logreader.py b/tools/lib/logreader.py index 07a4b2003e..2df1c05256 100755 --- a/tools/lib/logreader.py +++ b/tools/lib/logreader.py @@ -27,6 +27,16 @@ LogIterable = Iterable[LogMessage] RawLogIterable = Iterable[bytes] +def save_log(dest, log_msgs, compress=True): + dat = b"".join(msg.as_builder().to_bytes() for msg in log_msgs) + + if compress: + dat = bz2.compress(dat) + + with open(dest, "wb") as f: + f.write(dat) + + class _LogFileReader: def __init__(self, fn, canonicalize=True, only_union_types=False, sort_by_time=False, dat=None): self.data_version = None diff --git a/tools/plotjuggler/juggle.py b/tools/plotjuggler/juggle.py index 1d1612a1cd..22854b368d 100755 --- a/tools/plotjuggler/juggle.py +++ b/tools/plotjuggler/juggle.py @@ -12,8 +12,7 @@ from functools import partial from openpilot.common.basedir import BASEDIR from openpilot.selfdrive.car.fingerprints import MIGRATION -from openpilot.tools.lib.helpers import save_log -from openpilot.tools.lib.logreader import LogReader, ReadMode +from openpilot.tools.lib.logreader import LogReader, ReadMode, save_log juggle_dir = os.path.dirname(os.path.realpath(__file__)) From a1dce6ef475c69e446ab1ce13f1aadb26092804c Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Fri, 26 Jul 2024 11:34:36 -0700 Subject: [PATCH 118/229] op.sh: run pytest (#33090) test --- tools/op.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tools/op.sh b/tools/op.sh index 55cc3d60d9..3dd375c960 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -255,6 +255,15 @@ function op_lint() { ) } +function op_test() { + (set -e + + op_before_cmd + op_run_command pytest $@ + + ) +} + function op_replay() { (set -e @@ -308,6 +317,7 @@ function op_default() { echo -e " ${BOLD}replay${NC} Run replay" echo -e " ${BOLD}cabana${NC} Run cabana" echo -e " ${BOLD}lint${NC} Run all the pre-commit checks" + echo -e " ${BOLD}test${NC} Run all unit tests from pytest" echo -e " ${BOLD}help${NC} Show this message" echo -e " ${BOLD}install${NC} Install the 'op' tool system wide" echo "" @@ -353,6 +363,7 @@ function _op() { juggle ) shift 1; op_juggle "$@" ;; cabana ) shift 1; op_cabana "$@" ;; lint ) shift 1; op_lint "$@" ;; + test ) shift 1; op_test "$@" ;; replay ) shift 1; op_replay "$@" ;; sim ) shift 1; op_sim "$@" ;; install ) shift 1; op_install "$@" ;; @@ -384,6 +395,7 @@ unset -f op_before_cmd unset -f op_sim unset -f op_activate_venv unset -f op_get_openpilot_dir +unset -f op_test unset DRY unset NC unset RED From d24b80fca4e554325fe455ac2ea2cfbaafe570e8 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 26 Jul 2024 14:40:14 -0700 Subject: [PATCH 119/229] remove body submodule (#33091) * remove body submodule * little more * fix op --- .gitmodules | 3 --- SConstruct | 1 - body | 1 - release/release_files.py | 2 -- tools/op.sh | 2 +- 5 files changed, 1 insertion(+), 8 deletions(-) delete mode 160000 body diff --git a/.gitmodules b/.gitmodules index e33902db52..20c2c848a6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,9 +10,6 @@ [submodule "rednose_repo"] path = rednose_repo url = ../../commaai/rednose.git -[submodule "body"] - path = body - url = ../../commaai/body.git [submodule "teleoprtc_repo"] path = teleoprtc_repo url = ../../commaai/teleoprtc diff --git a/SConstruct b/SConstruct index 329ebe3308..fb5c43c9ad 100644 --- a/SConstruct +++ b/SConstruct @@ -360,7 +360,6 @@ Export('messaging') # Build other submodules SConscript([ - 'body/board/SConscript', 'opendbc/can/SConscript', 'panda/SConscript', ]) diff --git a/body b/body deleted file mode 160000 index c433da944f..0000000000 --- a/body +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c433da944f0e4d974cd66601effa66a06355debe diff --git a/release/release_files.py b/release/release_files.py index 24ce6d14b3..1590807435 100755 --- a/release/release_files.py +++ b/release/release_files.py @@ -10,8 +10,6 @@ ROOT = HERE + "/.." # - minimizing release download size # - keeping the diff readable blacklist = [ - "body/STL/", - "panda/drivers/", "panda/examples/", "panda/tests/safety/", diff --git a/tools/op.sh b/tools/op.sh index 3dd375c960..d3311c81fa 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -73,7 +73,7 @@ function op_check_git() { fi echo "Checking for git submodules..." - for name in body msgq_repo opendbc panda rednose_repo tinygrad_repo; do + for name in msgq_repo opendbc panda rednose_repo tinygrad_repo; do if [[ -z $(ls $OPENPILOT_ROOT/$name) ]]; then echo -e " ↳ [${RED}✗${NC}] git submodule $name not found! Run 'git submodule update --init --recursive'" return 1 From a1d2e84212904e23a1e3585c1f216ed6b94402a4 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 26 Jul 2024 15:04:57 -0700 Subject: [PATCH 120/229] update tinygrad url to tinygrad/tinygrad (#33093) --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 20c2c848a6..1d5d04577e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -15,4 +15,4 @@ url = ../../commaai/teleoprtc [submodule "tinygrad"] path = tinygrad_repo - url = https://github.com/geohot/tinygrad.git + url = https://github.com/tinygrad/tinygrad.git From 00d9748d9a4cead5c9e968fa9fb607fbf74955e4 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 26 Jul 2024 15:08:36 -0700 Subject: [PATCH 121/229] op.sh: parallel submodule update --- tools/op.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/op.sh b/tools/op.sh index d3311c81fa..faa75951de 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -188,7 +188,7 @@ function op_setup() { echo -e " ↳ [${GREEN}✔${NC}] Dependencies installed successfully.\n" echo "Getting git submodules..." - op_run_command git submodule update --init --recursive + op_run_command git submodule update --jobs 4 --init --recursive echo -e " ↳ [${GREEN}✔${NC}] Submodules installed successfully.\n" echo "Pulling git lfs files..." From 6b5f88a5332b42ceed96e2669208c690f4fde303 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 26 Jul 2024 15:17:14 -0700 Subject: [PATCH 122/229] cleanup macOS dependencies (#33094) --- tools/mac_setup.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/mac_setup.sh b/tools/mac_setup.sh index d19f1cae86..282121ef1d 100755 --- a/tools/mac_setup.sh +++ b/tools/mac_setup.sh @@ -36,12 +36,9 @@ if [[ $(command -v brew) == "" ]]; then fi brew bundle --file=- <<-EOS -brew "catch2" -brew "cmake" brew "cppcheck" brew "git-lfs" brew "zlib" -brew "bzip2" brew "capnp" brew "coreutils" brew "eigen" From eab9cd751c99a0a5046cfb31711daab145f164b2 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Fri, 26 Jul 2024 15:28:13 -0700 Subject: [PATCH 123/229] op.sh: check submodules (#33095) submodules --- tools/op.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/op.sh b/tools/op.sh index faa75951de..6e07965392 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -73,7 +73,7 @@ function op_check_git() { fi echo "Checking for git submodules..." - for name in msgq_repo opendbc panda rednose_repo tinygrad_repo; do + for name in $(git config --file .gitmodules --get-regexp path | awk '{ print $2 }' | tr '\n' ' '); do if [[ -z $(ls $OPENPILOT_ROOT/$name) ]]; then echo -e " ↳ [${RED}✗${NC}] git submodule $name not found! Run 'git submodule update --init --recursive'" return 1 From db2a8e9506bf4b76f34240b79bc5643f1db3e0b1 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 26 Jul 2024 15:58:00 -0700 Subject: [PATCH 124/229] docs: turning the speed blue (#33079) * blue speed * compile * just blue * cleanup --- docs/docs/how-to/first-pr.md | 0 docs/docs/how-to/turn-the-speed-blue.md | 93 ++++++++++++++++++++++ docs/docs/how-to/turning-the-speed-blue.md | 4 - docs/mkdocs.yml | 2 +- 4 files changed, 94 insertions(+), 5 deletions(-) delete mode 100644 docs/docs/how-to/first-pr.md create mode 100644 docs/docs/how-to/turn-the-speed-blue.md delete mode 100644 docs/docs/how-to/turning-the-speed-blue.md diff --git a/docs/docs/how-to/first-pr.md b/docs/docs/how-to/first-pr.md deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs/docs/how-to/turn-the-speed-blue.md b/docs/docs/how-to/turn-the-speed-blue.md new file mode 100644 index 0000000000..28e1a376ac --- /dev/null +++ b/docs/docs/how-to/turn-the-speed-blue.md @@ -0,0 +1,93 @@ +# Turn the speed blue +*A getting started guide for openpilot development* + +In 30 minutes, we'll get an openpilot development environment setup on your computer and make some changes to openpilot's UI. + +And if you have a comma 3/3X, we'll deploy the change to your device for testing. + +## 1. Setup your development environment + +Run this to clone openpilot and install all the dependencies: +```bash +curl -fsSL openpilot.comma.ai | bash +``` + +Then, compile openpilot: +```bash +cd openpilot +scons -j8 +``` + +## 2. Run replay + +We'll run the `replay` tool with the demo route to get data streaming for testing our UI changes. +```bash +# in terminal 1 +tools/replay/replay --demo + +# in terminal 2 +selfdrive/ui/ui +``` + +The openpilot UI should launch and show a replay of the demo route. + +If you have your own comma device, you can replace `--demo` with one of your own routes from comma connect. + +## 3. Make the speed blue + +Search for “mph” with git grep in the `ui` folder. +```bash +$ git grep "mph" selfdrive/ui/ +paint.cc: ui_draw_text(s, s->fb_w/2, 290, s->scene.is_metric ? "km/h" : "mph", 36 * 2.5, COLOR_WHITE_ALPHA(200), "sans-regular"); +``` + +The line right above contains the actual speed. Unfortunately, COLOR_BLUE isn’t defined, but a git grep of COLOR_WHITE shows it’s nvgRGBA(255, 255, 255, 255). Personally, I like a lighter blue, so I went with #8080FF. +```bash +$ git diff +diff --git a/selfdrive/ui/paint.cc b/selfdrive/ui/paint.cc +index 821d95115..cc996eaa1 100644 +--- a/selfdrive/ui/paint.cc ++++ b/selfdrive/ui/paint.cc +@@ -175,8 +175,8 @@ static void ui_draw_vision_speed(UIState *s) { + const float speed = std::max(0.0, (*s->sm)["carState"].getCarState().getVEgo() * (s->scene.is_metric ? 3.6 : 2.2369363)); + const std::string speed_str = std::to_string((int)std::nearbyint(speed)); + nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); +- ui_draw_text(s, s->fb_w/2, 210, speed_str.c_str(), 96 * 2.5, COLOR_WHITE, "sans-bold"); +- ui_draw_text(s, s->fb_w/2, 290, s->scene.is_metric ? "km/h" : "mph", 36 * 2.5, COLOR_WHITE_ALPHA(200), "sans-regular"); ++ ui_draw_text(s, s->fb_w/2, 210, speed_str.c_str(), 96 * 2.5, nvgRGBA(128, 128, 255, 255), "sans-bold"); ++ ui_draw_text(s, s->fb_w/2, 290, s->scene.is_metric ? "km/h" : "mph", 36 * 2.5, nvgRGBA(128, 128, 255, 200), "sans-regular"); + } + + static void ui_draw_vision_event(UIState *s) { +``` + + +## 4. Rebuild UI, and admire your work + +``` +scons -j8 && selfdrive/ui/ui +``` + +![](https://blog.comma.ai/img/blue_speed_ui.png) + +## 5. Push your fork to GitHub + +Click fork on GitHub. Then, push with: +```bash +git remote rm origin +git remote add origin git@github.com:/openpilot.git +git add . +git commit -m "Make the speed blue." +git push --set-upstream origin master +``` + +### 6. Run your fork on device in your car! + +Uninstall openpilot from your device through the settings. Then, enter the URL for your very own installer: +``` +installer.comma.ai//master +``` + +### 7. Admire your work IRL + +![](https://blog.comma.ai/img/c3_blue_ui.jpg) diff --git a/docs/docs/how-to/turning-the-speed-blue.md b/docs/docs/how-to/turning-the-speed-blue.md deleted file mode 100644 index f68faa7b9f..0000000000 --- a/docs/docs/how-to/turning-the-speed-blue.md +++ /dev/null @@ -1,4 +0,0 @@ -This section is for how-to's on common workflows. - -They'll be like this blog post we wrote: -https://blog.comma.ai/turning-the-speed-blue/ diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 92cb501b8b..1e19d286a1 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -17,7 +17,7 @@ nav: - Getting Started: - What is openpilot?: getting-started/what-is-openpilot.md - How-to: - #- Make my first pull request: how-to/first-pr.md + - Turn the speed blue: how-to/turn-the-speed-blue.md - Connect to a comma 3/3X: how-to/connect-to-comma.md - Car Porting: - What is a car port?: car-porting/what-is-a-car-port.md From d7159cd3c77cbb8eba6c347090780f49e6104cb5 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Fri, 26 Jul 2024 16:10:00 -0700 Subject: [PATCH 125/229] op.sh: misc improvements (#33096) * check for install * venv * build --- tools/op.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tools/op.sh b/tools/op.sh index 6e07965392..8533017d8e 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -14,7 +14,8 @@ function op_install() { if [ "$(uname)" == "Darwin" ] && [ $SHELL == "/bin/bash" ]; then RC_FILE="$HOME/.bash_profile" fi - printf "\nalias op='source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/op.sh" \"\$@\"'\n" >> $RC_FILE + CMD="\nalias op='source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/op.sh" \"\$@\"'\n" + grep "alias op=" "$RC_FILE" &> /dev/null || printf "$CMD" >> $RC_FILE echo -e " ↳ [${GREEN}✔${NC}] op installed successfully. Open a new shell to use it.\n" ) @@ -212,6 +213,12 @@ function op_venv() { ) if [[ "$?" -eq 0 ]]; then + + if [[ "${BASH_SOURCE[0]}" = "${0}" ]]; then + echo "Run 'op venv' or 'source op.sh venv' to activate your venv!" + return 1 + fi + # this must be run in the same shell as the user calling "op" op_get_openpilot_dir op_run_command source $OPENPILOT_ROOT/.venv/bin/activate @@ -231,7 +238,9 @@ function op_check() { function op_build() { (set -e + CDIR=$(pwd) op_before_cmd + cd "$CDIR" op_run_command scons $@ ) @@ -311,7 +320,7 @@ function op_default() { echo -e " ${BOLD}venv${NC} Activate the Python virtual environment" echo -e " ${BOLD}check${NC} Check the development environment (git, os, python) to start using openpilot" echo -e " ${BOLD}setup${NC} Install openpilot dependencies" - echo -e " ${BOLD}build${NC} Build openpilot" + echo -e " ${BOLD}build${NC} Run the openpilot build system in the current working directory" echo -e " ${BOLD}sim${NC} Run openpilot in a simulator" echo -e " ${BOLD}juggle${NC} Run Plotjuggler" echo -e " ${BOLD}replay${NC} Run replay" From c8d5a3fe25dfda776adc3daa7020c20f03e8bf5e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 26 Jul 2024 16:25:07 -0700 Subject: [PATCH 126/229] docs: style for external links --- docs/mkdocs.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 1e19d286a1..82db497148 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -26,10 +26,10 @@ nav: - Contributing: - Roadmap: contributing/roadmap.md #- Architecture: contributing/architecture.md - - Contributing: https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md + - Contributing →: https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md - Links: - - Blog: https://blog.comma.ai - - Bounties: https://comma.ai/bounties - - GitHub: https://github.com/commaai - - Discord: https://discord.comma.ai - - X: https://x.com/comma_ai + - Blog →: https://blog.comma.ai + - Bounties →: https://comma.ai/bounties + - GitHub →: https://github.com/commaai + - Discord →: https://discord.comma.ai + - X →: https://x.com/comma_ai From 6f1ea5a1fd5606e3407f32ab3eacd86a02d9a6ab Mon Sep 17 00:00:00 2001 From: ugtthis <142481257+ugtthis@users.noreply.github.com> Date: Fri, 26 Jul 2024 19:29:08 -0700 Subject: [PATCH 127/229] Docs: Added venv step (#33097) --- docs/docs/how-to/turn-the-speed-blue.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/docs/how-to/turn-the-speed-blue.md b/docs/docs/how-to/turn-the-speed-blue.md index 28e1a376ac..f76e9e489e 100644 --- a/docs/docs/how-to/turn-the-speed-blue.md +++ b/docs/docs/how-to/turn-the-speed-blue.md @@ -12,9 +12,14 @@ Run this to clone openpilot and install all the dependencies: curl -fsSL openpilot.comma.ai | bash ``` -Then, compile openpilot: +Navigate to openpilot folder & activate a Python virtual environment ```bash cd openpilot +source .venv/bin/activate +``` + +Then, compile openpilot: +```bash scons -j8 ``` From 7dec7c39bec0b7015c9cc12ee78f07a07ed47ee6 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 26 Jul 2024 19:33:35 -0700 Subject: [PATCH 128/229] uploader: compress with zstd (#32736) * zstd uploader * fix that * fix name of function * comment * log failed * fix comma_api_source for routes with both bz2 and zst rlogs * TODO * 10-14 achieves almost no benefit on qlogs in a few cases, but takes 2x the time * these aren't written out * regen: specify any list of sources ooh this is pretty nice * regen and process replay * damn, actually we don't need all this (cool tho) Revert "regen: specify any list of sources" This reverts commit ceb0b4abed9ad463a9fe98d9b98a05875a52806f. * just let it auto resolve * fix athenad/uploader tests * zst here too * TODOs * yes * Revert "TODOs" This reverts commit 8c7da1dbd0340c72290b5eb5563b642080ddc131. * Revert "zst here too" This reverts commit 23b0023ddfd22c8090be7a7caa09e7026a12aa5c. * Revert "just let it auto resolve" This reverts commit f296d62424227ad05facc62abc18a6f81b474e84. * Revert "regen and process replay" This reverts commit 0768330e96974a42616d229d159780619d049cd0. * revert readme * not in save_log either * lfg * Revert "lfg" This reverts commit 3718559c6c4de7d1f0c80dc9f1a1d335fe679a89. --- system/athena/athenad.py | 17 ++++---- system/athena/tests/test_athenad.py | 59 +++++++++++++++------------ system/loggerd/tests/test_uploader.py | 10 ++--- system/loggerd/uploader.py | 13 +++--- 4 files changed, 53 insertions(+), 46 deletions(-) diff --git a/system/athena/athenad.py b/system/athena/athenad.py index b4f9b8b6a7..96c34b0984 100755 --- a/system/athena/athenad.py +++ b/system/athena/athenad.py @@ -2,7 +2,6 @@ from __future__ import annotations import base64 -import bz2 import hashlib import io import json @@ -15,6 +14,7 @@ import sys import tempfile import threading import time +import zstd from dataclasses import asdict, dataclass, replace from datetime import datetime from functools import partial @@ -35,6 +35,7 @@ from openpilot.common.file_helpers import CallbackReader from openpilot.common.params import Params from openpilot.common.realtime import set_core_affinity from openpilot.system.hardware import HARDWARE, PC +from openpilot.system.loggerd.uploader import LOG_COMPRESSION_LEVEL from openpilot.system.loggerd.xattr_cache import getxattr, setxattr from openpilot.common.swaglog import cloudlog from openpilot.system.version import get_build_metadata @@ -103,8 +104,8 @@ cancelled_uploads: set[str] = set() cur_upload_items: dict[int, UploadItem | None] = {} -def strip_bz2_extension(fn: str) -> str: - if fn.endswith('.bz2'): +def strip_zst_extension(fn: str) -> str: + if fn.endswith('.zst'): return fn[:-4] return fn @@ -283,16 +284,16 @@ def _do_upload(upload_item: UploadItem, callback: Callable = None) -> requests.R path = upload_item.path compress = False - # If file does not exist, but does exist without the .bz2 extension we will compress on the fly - if not os.path.exists(path) and os.path.exists(strip_bz2_extension(path)): - path = strip_bz2_extension(path) + # If file does not exist, but does exist without the .zst extension we will compress on the fly + if not os.path.exists(path) and os.path.exists(strip_zst_extension(path)): + path = strip_zst_extension(path) compress = True with open(path, "rb") as f: content = f.read() if compress: cloudlog.event("athena.upload_handler.compress", fn=path, fn_orig=upload_item.path) - content = bz2.compress(content) + content = zstd.compress(content, LOG_COMPRESSION_LEVEL) with io.BytesIO(content) as data: return requests.put(upload_item.url, @@ -375,7 +376,7 @@ def uploadFilesToUrls(files_data: list[UploadFileDict]) -> UploadFilesToUrlRespo continue path = os.path.join(Paths.log_root(), file.fn) - if not os.path.exists(path) and not os.path.exists(strip_bz2_extension(path)): + if not os.path.exists(path) and not os.path.exists(strip_zst_extension(path)): failed.append(file.fn) continue diff --git a/system/athena/tests/test_athenad.py b/system/athena/tests/test_athenad.py index 48519a0ffd..413255b587 100644 --- a/system/athena/tests/test_athenad.py +++ b/system/athena/tests/test_athenad.py @@ -29,7 +29,7 @@ def seed_athena_server(host, port): with Timeout(2, 'HTTP Server seeding failed'): while True: try: - requests.put(f'http://{host}:{port}/qlog.bz2', data='', timeout=10) + requests.put(f'http://{host}:{port}/qlog.zst', data='', timeout=10) break except requests.exceptions.ConnectionError: time.sleep(0.1) @@ -174,54 +174,59 @@ class TestAthenadMethods: assert resp, 'list empty!' assert len(resp) == len(expected) - def test_strip_bz2_extension(self): + def test_strip_extension(self): + # any requested log file with an invalid extension won't return as existing fn = self._create_file('qlog.bz2') if fn.endswith('.bz2'): - assert athenad.strip_bz2_extension(fn) == fn[:-4] + assert athenad.strip_zst_extension(fn) == fn + + fn = self._create_file('qlog.zst') + if fn.endswith('.zst'): + assert athenad.strip_zst_extension(fn) == fn[:-4] @pytest.mark.parametrize("compress", [True, False]) def test_do_upload(self, host, compress): # random bytes to ensure rather large object post-compression fn = self._create_file('qlog', data=os.urandom(10000 * 1024)) - upload_fn = fn + ('.bz2' if compress else '') + upload_fn = fn + ('.zst' if compress else '') item = athenad.UploadItem(path=upload_fn, url="http://localhost:1238", headers={}, created_at=int(time.time()*1000), id='') with pytest.raises(requests.exceptions.ConnectionError): athenad._do_upload(item) - item = athenad.UploadItem(path=upload_fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='') + item = athenad.UploadItem(path=upload_fn, url=f"{host}/qlog.zst", headers={}, created_at=int(time.time()*1000), id='') resp = athenad._do_upload(item) assert resp.status_code == 201 def test_upload_file_to_url(self, host): - fn = self._create_file('qlog.bz2') + fn = self._create_file('qlog.zst') - resp = dispatcher["uploadFileToUrl"]("qlog.bz2", f"{host}/qlog.bz2", {}) + resp = dispatcher["uploadFileToUrl"]("qlog.zst", f"{host}/qlog.zst", {}) assert resp['enqueued'] == 1 assert 'failed' not in resp - assert {"path": fn, "url": f"{host}/qlog.bz2", "headers": {}}.items() <= resp['items'][0].items() + assert {"path": fn, "url": f"{host}/qlog.zst", "headers": {}}.items() <= resp['items'][0].items() assert resp['items'][0].get('id') is not None assert athenad.upload_queue.qsize() == 1 def test_upload_file_to_url_duplicate(self, host): - self._create_file('qlog.bz2') + self._create_file('qlog.zst') - url1 = f"{host}/qlog.bz2?sig=sig1" - dispatcher["uploadFileToUrl"]("qlog.bz2", url1, {}) + url1 = f"{host}/qlog.zst?sig=sig1" + dispatcher["uploadFileToUrl"]("qlog.zst", url1, {}) # Upload same file again, but with different signature - url2 = f"{host}/qlog.bz2?sig=sig2" - resp = dispatcher["uploadFileToUrl"]("qlog.bz2", url2, {}) + url2 = f"{host}/qlog.zst?sig=sig2" + resp = dispatcher["uploadFileToUrl"]("qlog.zst", url2, {}) assert resp == {'enqueued': 0, 'items': []} def test_upload_file_to_url_does_not_exist(self, host): - not_exists_resp = dispatcher["uploadFileToUrl"]("does_not_exist.bz2", "http://localhost:1238", {}) - assert not_exists_resp == {'enqueued': 0, 'items': [], 'failed': ['does_not_exist.bz2']} + not_exists_resp = dispatcher["uploadFileToUrl"]("does_not_exist.zst", "http://localhost:1238", {}) + assert not_exists_resp == {'enqueued': 0, 'items': [], 'failed': ['does_not_exist.zst']} @with_upload_handler def test_upload_handler(self, host): - fn = self._create_file('qlog.bz2') - item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) + fn = self._create_file('qlog.zst') + item = athenad.UploadItem(path=fn, url=f"{host}/qlog.zst", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) athenad.upload_queue.put_nowait(item) self._wait_for_upload() @@ -236,8 +241,8 @@ class TestAthenadMethods: def test_upload_handler_retry(self, mocker, host, status, retry): mock_put = mocker.patch('requests.put') mock_put.return_value.status_code = status - fn = self._create_file('qlog.bz2') - item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) + fn = self._create_file('qlog.zst') + item = athenad.UploadItem(path=fn, url=f"{host}/qlog.zst", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) athenad.upload_queue.put_nowait(item) self._wait_for_upload() @@ -251,8 +256,8 @@ class TestAthenadMethods: @with_upload_handler def test_upload_handler_timeout(self): """When an upload times out or fails to connect it should be placed back in the queue""" - fn = self._create_file('qlog.bz2') - item = athenad.UploadItem(path=fn, url="http://localhost:44444/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) + fn = self._create_file('qlog.zst') + item = athenad.UploadItem(path=fn, url="http://localhost:44444/qlog.zst", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) item_no_retry = replace(item, retry_count=MAX_RETRY_COUNT) athenad.upload_queue.put_nowait(item_no_retry) @@ -272,7 +277,7 @@ class TestAthenadMethods: @with_upload_handler def test_cancel_upload(self): - item = athenad.UploadItem(path="qlog.bz2", url="http://localhost:44444/qlog.bz2", headers={}, + item = athenad.UploadItem(path="qlog.zst", url="http://localhost:44444/qlog.zst", headers={}, created_at=int(time.time()*1000), id='id', allow_cellular=True) athenad.upload_queue.put_nowait(item) dispatcher["cancelUpload"](item.id) @@ -291,8 +296,8 @@ class TestAthenadMethods: ts = int(t_future.strftime("%s")) * 1000 # Item that would time out if actually uploaded - fn = self._create_file('qlog.bz2') - item = athenad.UploadItem(path=fn, url="http://localhost:44444/qlog.bz2", headers={}, created_at=ts, id='', allow_cellular=True) + fn = self._create_file('qlog.zst') + item = athenad.UploadItem(path=fn, url="http://localhost:44444/qlog.zst", headers={}, created_at=ts, id='', allow_cellular=True) athenad.upload_queue.put_nowait(item) self._wait_for_upload() @@ -306,8 +311,8 @@ class TestAthenadMethods: @with_upload_handler def test_list_upload_queue_current(self, host: str): - fn = self._create_file('qlog.bz2') - item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) + fn = self._create_file('qlog.zst') + item = athenad.UploadItem(path=fn, url=f"{host}/qlog.zst", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) athenad.upload_queue.put_nowait(item) self._wait_for_upload() @@ -317,7 +322,7 @@ class TestAthenadMethods: assert items[0]['current'] def test_list_upload_queue(self): - item = athenad.UploadItem(path="qlog.bz2", url="http://localhost:44444/qlog.bz2", headers={}, + item = athenad.UploadItem(path="qlog.zst", url="http://localhost:44444/qlog.zst", headers={}, created_at=int(time.time()*1000), id='id', allow_cellular=True) athenad.upload_queue.put_nowait(item) diff --git a/system/loggerd/tests/test_uploader.py b/system/loggerd/tests/test_uploader.py index 6591198281..fa71600263 100644 --- a/system/loggerd/tests/test_uploader.py +++ b/system/loggerd/tests/test_uploader.py @@ -62,10 +62,10 @@ class TestUploader(UploaderTestCase): def gen_order(self, seg1: list[int], seg2: list[int], boot=True) -> list[str]: keys = [] if boot: - keys += [f"boot/{self.seg_format.format(i)}.bz2" for i in seg1] - keys += [f"boot/{self.seg_format2.format(i)}.bz2" for i in seg2] - keys += [f"{self.seg_format.format(i)}/qlog.bz2" for i in seg1] - keys += [f"{self.seg_format2.format(i)}/qlog.bz2" for i in seg2] + keys += [f"boot/{self.seg_format.format(i)}.zst" for i in seg1] + keys += [f"boot/{self.seg_format2.format(i)}.zst" for i in seg2] + keys += [f"{self.seg_format.format(i)}/qlog.zst" for i in seg1] + keys += [f"{self.seg_format2.format(i)}/qlog.zst" for i in seg2] return keys def test_upload(self): @@ -159,7 +159,7 @@ class TestUploader(UploaderTestCase): self.join_thread() for f_path in f_paths: - fn = f_path.with_suffix(f_path.suffix.replace(".bz2", "")) + fn = f_path.with_suffix(f_path.suffix.replace(".zst", "")) uploaded = UPLOAD_ATTR_NAME in os.listxattr(fn) and os.getxattr(fn, UPLOAD_ATTR_NAME) == UPLOAD_ATTR_VALUE assert not uploaded, "File upload when locked" diff --git a/system/loggerd/uploader.py b/system/loggerd/uploader.py index 832a227798..ee16193cd2 100755 --- a/system/loggerd/uploader.py +++ b/system/loggerd/uploader.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import bz2 import io import json import os @@ -9,6 +8,7 @@ import threading import time import traceback import datetime +import zstd from typing import BinaryIO from collections.abc import Iterator @@ -26,6 +26,7 @@ UPLOAD_ATTR_NAME = 'user.upload' UPLOAD_ATTR_VALUE = b'1' UPLOAD_QLOG_QCAM_MAX_SIZE = 5 * 1e6 # MB +LOG_COMPRESSION_LEVEL = 10 # little benefit up to level 15. level ~17 is a small step change allow_sleep = bool(os.getenv("UPLOADER_SLEEP", "1")) force_wifi = os.getenv("FORCEWIFI") is not None @@ -83,7 +84,7 @@ class Uploader: self.last_filename = "" self.immediate_folders = ["crash/", "boot/"] - self.immediate_priority = {"qlog": 0, "qlog.bz2": 0, "qcamera.ts": 1} + self.immediate_priority = {"qlog": 0, "qlog.zst": 0, "qcamera.ts": 1} def list_upload_files(self, metered: bool) -> Iterator[tuple[str, str, str]]: r = self.params.get("AthenadRecentlyViewedRoutes", encoding="utf8") @@ -152,8 +153,8 @@ class Uploader: with open(fn, "rb") as f: data: BinaryIO - if key.endswith('.bz2') and not fn.endswith('.bz2'): - compressed = bz2.compress(f.read()) + if key.endswith('.zst') and not fn.endswith('.zst'): + compressed = zstd.compress(f.read(), LOG_COMPRESSION_LEVEL) data = io.BytesIO(compressed) else: data = f @@ -218,8 +219,8 @@ class Uploader: name, key, fn = d # qlogs and bootlogs need to be compressed before uploading - if key.endswith(('qlog', 'rlog')) or (key.startswith('boot/') and not key.endswith('.bz2')): - key += ".bz2" + if key.endswith(('qlog', 'rlog')) or (key.startswith('boot/') and not key.endswith('.zst')): + key += ".zst" return self.upload(name, key, fn, network_type, metered) From 4caecf21439eb65cedb25df589b140c9c09e26fc Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 26 Jul 2024 21:14:06 -0700 Subject: [PATCH 129/229] test_onroad: use zstd compression (#33100) * use zstd in test_onroad * debug * now leans towards 0.4 instead of 0.5 * 5x runs * better * more * Update selfdrive/test/test_onroad.py * revert Jenkinsfile * and this --- selfdrive/test/test_onroad.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 1e4669fb0a..d78d2294ad 100644 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -1,4 +1,3 @@ -import bz2 import math import json import os @@ -9,6 +8,7 @@ import shutil import subprocess import time import numpy as np +import zstd from collections import Counter, defaultdict from functools import cached_property from pathlib import Path @@ -20,9 +20,10 @@ from openpilot.common.basedir import BASEDIR from openpilot.common.timeout import Timeout from openpilot.common.params import Params from openpilot.selfdrive.controls.lib.events import EVENTS, ET -from openpilot.system.hardware import HARDWARE from openpilot.selfdrive.test.helpers import set_params_enabled, release_only +from openpilot.system.hardware import HARDWARE from openpilot.system.hardware.hw import Paths +from openpilot.system.loggerd.uploader import LOG_COMPRESSION_LEVEL from openpilot.tools.lib.logreader import LogReader """ @@ -166,10 +167,10 @@ class TestOnroad: cls.log_sizes = {} for f in cls.log_path.iterdir(): assert f.is_file() - cls.log_sizes[f] = f.stat().st_size / 1e6 + cls.log_sizes[f] = f.stat().st_size / 1e6 if f.name in ("qlog", "rlog"): with open(f, 'rb') as ff: - cls.log_sizes[f] = len(bz2.compress(ff.read())) / 1e6 + cls.log_sizes[f] = len(zstd.compress(ff.read(), LOG_COMPRESSION_LEVEL)) / 1e6 @cached_property @@ -206,7 +207,7 @@ class TestOnroad: if f.name == "qcamera.ts": assert 2.15 < sz < 2.35 elif f.name == "qlog": - assert 0.4 < sz < 0.6 + assert 0.4 < sz < 0.5 elif f.name == "rlog": assert 5 < sz < 50 elif f.name.endswith('.hevc'): From 1b3b5ab75857465f58ec8a687db04c8ee0470e05 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sun, 28 Jul 2024 02:03:47 -0700 Subject: [PATCH 130/229] use zstandard library (#33110) * use zstandard * run 10 * bye bye * this was a little overzealous * clean up --- pyproject.toml | 2 +- selfdrive/test/test_onroad.py | 4 +- system/athena/athenad.py | 2 +- system/loggerd/uploader.py | 2 +- tools/lib/logreader.py | 2 +- uv.lock | 132 ++++++++++++++++++++++------------ 6 files changed, 91 insertions(+), 53 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index afebfe7a7d..dd801994f1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ dependencies = [ "pycryptodome", # used in updated/casync, panda, body, and a test # logreader - "zstd", + "zstandard", ] [project.optional-dependencies] diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index d78d2294ad..e29e241da9 100644 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -8,7 +8,7 @@ import shutil import subprocess import time import numpy as np -import zstd +import zstandard as zstd from collections import Counter, defaultdict from functools import cached_property from pathlib import Path @@ -207,7 +207,7 @@ class TestOnroad: if f.name == "qcamera.ts": assert 2.15 < sz < 2.35 elif f.name == "qlog": - assert 0.4 < sz < 0.5 + assert 0.45 < sz < 0.55 elif f.name == "rlog": assert 5 < sz < 50 elif f.name.endswith('.hevc'): diff --git a/system/athena/athenad.py b/system/athena/athenad.py index 96c34b0984..52e3a29ac8 100755 --- a/system/athena/athenad.py +++ b/system/athena/athenad.py @@ -14,7 +14,7 @@ import sys import tempfile import threading import time -import zstd +import zstandard as zstd from dataclasses import asdict, dataclass, replace from datetime import datetime from functools import partial diff --git a/system/loggerd/uploader.py b/system/loggerd/uploader.py index ee16193cd2..d984936e88 100755 --- a/system/loggerd/uploader.py +++ b/system/loggerd/uploader.py @@ -8,7 +8,7 @@ import threading import time import traceback import datetime -import zstd +import zstandard as zstd from typing import BinaryIO from collections.abc import Iterator diff --git a/tools/lib/logreader.py b/tools/lib/logreader.py index 2df1c05256..0f00596141 100755 --- a/tools/lib/logreader.py +++ b/tools/lib/logreader.py @@ -10,7 +10,7 @@ import sys import tqdm import urllib.parse import warnings -import zstd +import zstandard as zstd from collections.abc import Callable, Iterable, Iterator from urllib.parse import parse_qs, urlparse diff --git a/uv.lock b/uv.lock index 866cf921ae..fa5c364673 100644 --- a/uv.lock +++ b/uv.lock @@ -1422,38 +1422,38 @@ name = "openpilot" version = "0.1.0" source = { editable = "." } dependencies = [ - { name = "aiohttp" }, - { name = "aiortc" }, + { name = "aiohttp", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "aiortc", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "casadi", version = "3.6.5", source = { registry = "https://pypi.org/simple" }, marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, { name = "casadi", version = "3.6.6", source = { url = "https://github.com/commaai/casadi/releases/download/nightly-release-3.6.6/casadi-3.6.6-cp312-none-manylinux2014_aarch64.whl" }, marker = "python_version == '3.12' and platform_machine == 'aarch64'" }, - { name = "cffi" }, - { name = "crcmod" }, - { name = "cython" }, - { name = "future-fstrings" }, - { name = "json-rpc" }, - { name = "libusb1" }, - { name = "numpy" }, - { name = "onnx" }, - { name = "onnxruntime", marker = "platform_machine == 'aarch64' and platform_system == 'Linux'" }, - { name = "onnxruntime-gpu", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "psutil" }, - { name = "pyaudio" }, - { name = "pycapnp" }, - { name = "pycryptodome" }, - { name = "pyjwt" }, - { name = "pyserial" }, - { name = "pyzmq" }, - { name = "requests" }, - { name = "scons" }, - { name = "sentry-sdk" }, - { name = "setuptools" }, - { name = "smbus2" }, - { name = "sounddevice" }, - { name = "spidev", marker = "platform_system == 'Linux'" }, - { name = "sympy" }, - { name = "tqdm" }, - { name = "websocket-client" }, - { name = "zstd" }, + { name = "cffi", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "crcmod", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "cython", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "future-fstrings", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "json-rpc", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "libusb1", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "onnx", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "onnxruntime", marker = "(python_version == '3.12' and platform_machine == 'aarch64' and platform_system == 'Linux') or (python_version == '3.12' and platform_machine == 'aarch64' and platform_system == 'Linux' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64')) or (platform_machine == 'aarch64' and platform_system == 'Linux' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'))" }, + { name = "onnxruntime-gpu", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64')" }, + { name = "psutil", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyaudio", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pycapnp", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pycryptodome", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyjwt", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyserial", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyzmq", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "requests", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "scons", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "sentry-sdk", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "setuptools", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "smbus2", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "sounddevice", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "spidev", marker = "(python_version == '3.12' and platform_machine == 'aarch64' and platform_system == 'Linux') or (python_version == '3.12' and platform_machine == 'aarch64' and platform_system == 'Linux' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64')) or (platform_system == 'Linux' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'))" }, + { name = "sympy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "tqdm", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "websocket-client", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "zstandard", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] [distribution.optional-dependencies] @@ -5322,22 +5322,60 @@ wheels = [ ] [[distribution]] -name = "zstd" -version = "1.5.5.1" +name = "zstandard" +version = "0.23.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/b4/bf8c6a6b73c6b267a13df955f821f041fcc770b56820b135849f33e3b888/zstd-1.5.5.1.tar.gz", hash = "sha256:1ef980abf0e1e072b028d2d76ef95b476632651c96225cf30b619c6eef625672", size = 1106585 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/6f/5b8a828394af6153ec08fd4814c9a4bbae9ec5bce3cb948bb0b9b6872022/zstd-1.5.5.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:022f935a8666e08f0fff6204938a84d9fe4fcd8235a205787275933a07a164fb", size = 287614 }, - { url = "https://files.pythonhosted.org/packages/99/33/a51e2e4e469af134d5a8450d59da05c34017eea9bb16d1d1ed7b83b5ed98/zstd-1.5.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3d15a2d18dac8bcafdde52fdf5d40ecae1f73b7de19b171f42339d2e51346d0", size = 227505 }, - { url = "https://files.pythonhosted.org/packages/cf/1a/ec11fdf56b282ca627c979b5b0c9c2ef14b416c0b2ad4264972c6765b634/zstd-1.5.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45b9c67989f50ba63ffa0c50c9eaa037c2d14abacb0813e838ad705135245b4b", size = 1758942 }, - { url = "https://files.pythonhosted.org/packages/a5/2a/65d09266af0c0a9b077148a6b596c8727de16ef174a6a840a88bc42f8956/zstd-1.5.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97da6a842ba7e4acf8bba7c596057143ee39b3c4a467196c2096d460e44accd6", size = 1784548 }, - { url = "https://files.pythonhosted.org/packages/f6/d4/7621dffe3a34a948dfa7ba40e77657526f967e3dd086608ab083fc8dd0d4/zstd-1.5.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dafd492fb8ee4ae04c81ab00f5f137860e7071f611335dd4cdb1c38bd8f11bc", size = 1638061 }, - { url = "https://files.pythonhosted.org/packages/28/0e/a3668ca3147434fd336f66d3f28553e228a73ea6b736f0ad2e9920b7de85/zstd-1.5.5.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9ee83e0bcbfd776200b026b3b9e86c6c86b8f414749f58d87c85dcf456b27066", size = 1893027 }, - { url = "https://files.pythonhosted.org/packages/dc/3f/0a00f50d1d30293f896a36afbd83de65efd59c023693ea95f27071508d40/zstd-1.5.5.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ae2fd4bc8ea772a7b5f1acd1cac9e34bb9cd8fcde191f170092fdeea779a3a12", size = 1825873 }, - { url = "https://files.pythonhosted.org/packages/f6/2f/3d346dcf2c525f1c3e4b0efebf653cc1da69f287bc4084391fb3a449f691/zstd-1.5.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:edea52a0109f48fd46f4763689d3d356dcafd20ddf6789c559a1bd2e62b40a32", size = 1930928 }, - { url = "https://files.pythonhosted.org/packages/a2/f3/c7d49044609ad59bf4e09cf182215474b229128514885f1f0db82386c5a8/zstd-1.5.5.1-cp311-cp311-win32.whl", hash = "sha256:88410481209520298ec4430e0d1d57e004c45e0b27c3035674fb182ccd2d8b7b", size = 150758 }, - { url = "https://files.pythonhosted.org/packages/af/39/6314d344793ca78556832b281c4a4916362bfca0943ced3eff25221b5385/zstd-1.5.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:dce18aaefbacf8b133367be86beec670baf68c0420bfcca49be08dbdbf933db6", size = 167971 }, - { url = "https://files.pythonhosted.org/packages/e4/1c/b86aeee12cc1edd59f5a2aae7c15c9651f92ff2de59f2eed9b54f3571954/zstd-1.5.5.1-pp27-pypy_73-macosx_10_14_x86_64.whl", hash = "sha256:c63f916732e3e309e49ec95e7a0af5d37ff1321f3df2aac10e507bd2b56fceda", size = 279624 }, - { url = "https://files.pythonhosted.org/packages/50/3c/d0064d52f83ef0b0927ca38a117df1dc413312499f409fcc6314208e2e7b/zstd-1.5.5.1-pp27-pypy_73-manylinux1_x86_64.whl", hash = "sha256:50d4850d758bb033df50722cc13ed913b2afcd5385250be4f3ffb79a26b319c3", size = 253751 }, - { url = "https://files.pythonhosted.org/packages/99/08/222f3f732c4af90239c0f09703d8b82089846451621d27194467f864cf85/zstd-1.5.5.1-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:0412d666515e78a91ada7e2d78e9dd6b25ddda1b41623b145b99653275c7f3ce", size = 253752 }, +dependencies = [ + { name = "cffi", marker = "platform_python_implementation == 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ed/f6/2ac0287b442160a89d726b17a9184a4c615bb5237db763791a7fd16d9df1/zstandard-0.23.0.tar.gz", hash = "sha256:b2d8c62d08e7255f68f7a740bae85b3c9b8e5466baa9cbf7f57f1cde0ac6bc09", size = 681701 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/40/f67e7d2c25a0e2dc1744dd781110b0b60306657f8696cafb7ad7579469bd/zstandard-0.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:34895a41273ad33347b2fc70e1bff4240556de3c46c6ea430a7ed91f9042aa4e", size = 788699 }, + { url = "https://files.pythonhosted.org/packages/e8/46/66d5b55f4d737dd6ab75851b224abf0afe5774976fe511a54d2eb9063a41/zstandard-0.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:77ea385f7dd5b5676d7fd943292ffa18fbf5c72ba98f7d09fc1fb9e819b34c23", size = 633681 }, + { url = "https://files.pythonhosted.org/packages/63/b6/677e65c095d8e12b66b8f862b069bcf1f1d781b9c9c6f12eb55000d57583/zstandard-0.23.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:983b6efd649723474f29ed42e1467f90a35a74793437d0bc64a5bf482bedfa0a", size = 4944328 }, + { url = "https://files.pythonhosted.org/packages/59/cc/e76acb4c42afa05a9d20827116d1f9287e9c32b7ad58cc3af0721ce2b481/zstandard-0.23.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80a539906390591dd39ebb8d773771dc4db82ace6372c4d41e2d293f8e32b8db", size = 5311955 }, + { url = "https://files.pythonhosted.org/packages/78/e4/644b8075f18fc7f632130c32e8f36f6dc1b93065bf2dd87f03223b187f26/zstandard-0.23.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:445e4cb5048b04e90ce96a79b4b63140e3f4ab5f662321975679b5f6360b90e2", size = 5344944 }, + { url = "https://files.pythonhosted.org/packages/76/3f/dbafccf19cfeca25bbabf6f2dd81796b7218f768ec400f043edc767015a6/zstandard-0.23.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd30d9c67d13d891f2360b2a120186729c111238ac63b43dbd37a5a40670b8ca", size = 5442927 }, + { url = "https://files.pythonhosted.org/packages/0c/c3/d24a01a19b6733b9f218e94d1a87c477d523237e07f94899e1c10f6fd06c/zstandard-0.23.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d20fd853fbb5807c8e84c136c278827b6167ded66c72ec6f9a14b863d809211c", size = 4864910 }, + { url = "https://files.pythonhosted.org/packages/1c/a9/cf8f78ead4597264f7618d0875be01f9bc23c9d1d11afb6d225b867cb423/zstandard-0.23.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed1708dbf4d2e3a1c5c69110ba2b4eb6678262028afd6c6fbcc5a8dac9cda68e", size = 4935544 }, + { url = "https://files.pythonhosted.org/packages/2c/96/8af1e3731b67965fb995a940c04a2c20997a7b3b14826b9d1301cf160879/zstandard-0.23.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:be9b5b8659dff1f913039c2feee1aca499cfbc19e98fa12bc85e037c17ec6ca5", size = 5467094 }, + { url = "https://files.pythonhosted.org/packages/ff/57/43ea9df642c636cb79f88a13ab07d92d88d3bfe3e550b55a25a07a26d878/zstandard-0.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:65308f4b4890aa12d9b6ad9f2844b7ee42c7f7a4fd3390425b242ffc57498f48", size = 4860440 }, + { url = "https://files.pythonhosted.org/packages/46/37/edb78f33c7f44f806525f27baa300341918fd4c4af9472fbc2c3094be2e8/zstandard-0.23.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:98da17ce9cbf3bfe4617e836d561e433f871129e3a7ac16d6ef4c680f13a839c", size = 4700091 }, + { url = "https://files.pythonhosted.org/packages/c1/f1/454ac3962671a754f3cb49242472df5c2cced4eb959ae203a377b45b1a3c/zstandard-0.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8ed7d27cb56b3e058d3cf684d7200703bcae623e1dcc06ed1e18ecda39fee003", size = 5208682 }, + { url = "https://files.pythonhosted.org/packages/85/b2/1734b0fff1634390b1b887202d557d2dd542de84a4c155c258cf75da4773/zstandard-0.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:b69bb4f51daf461b15e7b3db033160937d3ff88303a7bc808c67bbc1eaf98c78", size = 5669707 }, + { url = "https://files.pythonhosted.org/packages/52/5a/87d6971f0997c4b9b09c495bf92189fb63de86a83cadc4977dc19735f652/zstandard-0.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:034b88913ecc1b097f528e42b539453fa82c3557e414b3de9d5632c80439a473", size = 5201792 }, + { url = "https://files.pythonhosted.org/packages/79/02/6f6a42cc84459d399bd1a4e1adfc78d4dfe45e56d05b072008d10040e13b/zstandard-0.23.0-cp311-cp311-win32.whl", hash = "sha256:f2d4380bf5f62daabd7b751ea2339c1a21d1c9463f1feb7fc2bdcea2c29c3160", size = 430586 }, + { url = "https://files.pythonhosted.org/packages/be/a2/4272175d47c623ff78196f3c10e9dc7045c1b9caf3735bf041e65271eca4/zstandard-0.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:62136da96a973bd2557f06ddd4e8e807f9e13cbb0bfb9cc06cfe6d98ea90dfe0", size = 495420 }, + { url = "https://files.pythonhosted.org/packages/7b/83/f23338c963bd9de687d47bf32efe9fd30164e722ba27fb59df33e6b1719b/zstandard-0.23.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b4567955a6bc1b20e9c31612e615af6b53733491aeaa19a6b3b37f3b65477094", size = 788713 }, + { url = "https://files.pythonhosted.org/packages/5b/b3/1a028f6750fd9227ee0b937a278a434ab7f7fdc3066c3173f64366fe2466/zstandard-0.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e172f57cd78c20f13a3415cc8dfe24bf388614324d25539146594c16d78fcc8", size = 633459 }, + { url = "https://files.pythonhosted.org/packages/26/af/36d89aae0c1f95a0a98e50711bc5d92c144939efc1f81a2fcd3e78d7f4c1/zstandard-0.23.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0e166f698c5a3e914947388c162be2583e0c638a4703fc6a543e23a88dea3c1", size = 4945707 }, + { url = "https://files.pythonhosted.org/packages/cd/2e/2051f5c772f4dfc0aae3741d5fc72c3dcfe3aaeb461cc231668a4db1ce14/zstandard-0.23.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12a289832e520c6bd4dcaad68e944b86da3bad0d339ef7989fb7e88f92e96072", size = 5306545 }, + { url = "https://files.pythonhosted.org/packages/0a/9e/a11c97b087f89cab030fa71206963090d2fecd8eb83e67bb8f3ffb84c024/zstandard-0.23.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d50d31bfedd53a928fed6707b15a8dbeef011bb6366297cc435accc888b27c20", size = 5337533 }, + { url = "https://files.pythonhosted.org/packages/fc/79/edeb217c57fe1bf16d890aa91a1c2c96b28c07b46afed54a5dcf310c3f6f/zstandard-0.23.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72c68dda124a1a138340fb62fa21b9bf4848437d9ca60bd35db36f2d3345f373", size = 5436510 }, + { url = "https://files.pythonhosted.org/packages/81/4f/c21383d97cb7a422ddf1ae824b53ce4b51063d0eeb2afa757eb40804a8ef/zstandard-0.23.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53dd9d5e3d29f95acd5de6802e909ada8d8d8cfa37a3ac64836f3bc4bc5512db", size = 4859973 }, + { url = "https://files.pythonhosted.org/packages/ab/15/08d22e87753304405ccac8be2493a495f529edd81d39a0870621462276ef/zstandard-0.23.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6a41c120c3dbc0d81a8e8adc73312d668cd34acd7725f036992b1b72d22c1772", size = 4936968 }, + { url = "https://files.pythonhosted.org/packages/eb/fa/f3670a597949fe7dcf38119a39f7da49a8a84a6f0b1a2e46b2f71a0ab83f/zstandard-0.23.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:40b33d93c6eddf02d2c19f5773196068d875c41ca25730e8288e9b672897c105", size = 5467179 }, + { url = "https://files.pythonhosted.org/packages/4e/a9/dad2ab22020211e380adc477a1dbf9f109b1f8d94c614944843e20dc2a99/zstandard-0.23.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9206649ec587e6b02bd124fb7799b86cddec350f6f6c14bc82a2b70183e708ba", size = 4848577 }, + { url = "https://files.pythonhosted.org/packages/08/03/dd28b4484b0770f1e23478413e01bee476ae8227bbc81561f9c329e12564/zstandard-0.23.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76e79bc28a65f467e0409098fa2c4376931fd3207fbeb6b956c7c476d53746dd", size = 4693899 }, + { url = "https://files.pythonhosted.org/packages/2b/64/3da7497eb635d025841e958bcd66a86117ae320c3b14b0ae86e9e8627518/zstandard-0.23.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:66b689c107857eceabf2cf3d3fc699c3c0fe8ccd18df2219d978c0283e4c508a", size = 5199964 }, + { url = "https://files.pythonhosted.org/packages/43/a4/d82decbab158a0e8a6ebb7fc98bc4d903266bce85b6e9aaedea1d288338c/zstandard-0.23.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9c236e635582742fee16603042553d276cca506e824fa2e6489db04039521e90", size = 5655398 }, + { url = "https://files.pythonhosted.org/packages/f2/61/ac78a1263bc83a5cf29e7458b77a568eda5a8f81980691bbc6eb6a0d45cc/zstandard-0.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a8fffdbd9d1408006baaf02f1068d7dd1f016c6bcb7538682622c556e7b68e35", size = 5191313 }, + { url = "https://files.pythonhosted.org/packages/e7/54/967c478314e16af5baf849b6ee9d6ea724ae5b100eb506011f045d3d4e16/zstandard-0.23.0-cp312-cp312-win32.whl", hash = "sha256:dc1d33abb8a0d754ea4763bad944fd965d3d95b5baef6b121c0c9013eaf1907d", size = 430877 }, + { url = "https://files.pythonhosted.org/packages/75/37/872d74bd7739639c4553bf94c84af7d54d8211b626b352bc57f0fd8d1e3f/zstandard-0.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:64585e1dba664dc67c7cdabd56c1e5685233fbb1fc1966cfba2a340ec0dfff7b", size = 495595 }, + { url = "https://files.pythonhosted.org/packages/80/f1/8386f3f7c10261fe85fbc2c012fdb3d4db793b921c9abcc995d8da1b7a80/zstandard-0.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:576856e8594e6649aee06ddbfc738fec6a834f7c85bf7cadd1c53d4a58186ef9", size = 788975 }, + { url = "https://files.pythonhosted.org/packages/16/e8/cbf01077550b3e5dc86089035ff8f6fbbb312bc0983757c2d1117ebba242/zstandard-0.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38302b78a850ff82656beaddeb0bb989a0322a8bbb1bf1ab10c17506681d772a", size = 633448 }, + { url = "https://files.pythonhosted.org/packages/06/27/4a1b4c267c29a464a161aeb2589aff212b4db653a1d96bffe3598f3f0d22/zstandard-0.23.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2240ddc86b74966c34554c49d00eaafa8200a18d3a5b6ffbf7da63b11d74ee2", size = 4945269 }, + { url = "https://files.pythonhosted.org/packages/7c/64/d99261cc57afd9ae65b707e38045ed8269fbdae73544fd2e4a4d50d0ed83/zstandard-0.23.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ef230a8fd217a2015bc91b74f6b3b7d6522ba48be29ad4ea0ca3a3775bf7dd5", size = 5306228 }, + { url = "https://files.pythonhosted.org/packages/7a/cf/27b74c6f22541f0263016a0fd6369b1b7818941de639215c84e4e94b2a1c/zstandard-0.23.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:774d45b1fac1461f48698a9d4b5fa19a69d47ece02fa469825b442263f04021f", size = 5336891 }, + { url = "https://files.pythonhosted.org/packages/fa/18/89ac62eac46b69948bf35fcd90d37103f38722968e2981f752d69081ec4d/zstandard-0.23.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f77fa49079891a4aab203d0b1744acc85577ed16d767b52fc089d83faf8d8ed", size = 5436310 }, + { url = "https://files.pythonhosted.org/packages/a8/a8/5ca5328ee568a873f5118d5b5f70d1f36c6387716efe2e369010289a5738/zstandard-0.23.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac184f87ff521f4840e6ea0b10c0ec90c6b1dcd0bad2f1e4a9a1b4fa177982ea", size = 4859912 }, + { url = "https://files.pythonhosted.org/packages/ea/ca/3781059c95fd0868658b1cf0440edd832b942f84ae60685d0cfdb808bca1/zstandard-0.23.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c363b53e257246a954ebc7c488304b5592b9c53fbe74d03bc1c64dda153fb847", size = 4936946 }, + { url = "https://files.pythonhosted.org/packages/ce/11/41a58986f809532742c2b832c53b74ba0e0a5dae7e8ab4642bf5876f35de/zstandard-0.23.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e7792606d606c8df5277c32ccb58f29b9b8603bf83b48639b7aedf6df4fe8171", size = 5466994 }, + { url = "https://files.pythonhosted.org/packages/83/e3/97d84fe95edd38d7053af05159465d298c8b20cebe9ccb3d26783faa9094/zstandard-0.23.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a0817825b900fcd43ac5d05b8b3079937073d2b1ff9cf89427590718b70dd840", size = 4848681 }, + { url = "https://files.pythonhosted.org/packages/6e/99/cb1e63e931de15c88af26085e3f2d9af9ce53ccafac73b6e48418fd5a6e6/zstandard-0.23.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9da6bc32faac9a293ddfdcb9108d4b20416219461e4ec64dfea8383cac186690", size = 4694239 }, + { url = "https://files.pythonhosted.org/packages/ab/50/b1e703016eebbc6501fc92f34db7b1c68e54e567ef39e6e59cf5fb6f2ec0/zstandard-0.23.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fd7699e8fd9969f455ef2926221e0233f81a2542921471382e77a9e2f2b57f4b", size = 5200149 }, + { url = "https://files.pythonhosted.org/packages/aa/e0/932388630aaba70197c78bdb10cce2c91fae01a7e553b76ce85471aec690/zstandard-0.23.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d477ed829077cd945b01fc3115edd132c47e6540ddcd96ca169facff28173057", size = 5655392 }, + { url = "https://files.pythonhosted.org/packages/02/90/2633473864f67a15526324b007a9f96c96f56d5f32ef2a56cc12f9548723/zstandard-0.23.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa6ce8b52c5987b3e34d5674b0ab529a4602b632ebab0a93b07bfb4dfc8f8a33", size = 5191299 }, + { url = "https://files.pythonhosted.org/packages/b0/4c/315ca5c32da7e2dc3455f3b2caee5c8c2246074a61aac6ec3378a97b7136/zstandard-0.23.0-cp313-cp313-win32.whl", hash = "sha256:a9b07268d0c3ca5c170a385a0ab9fb7fdd9f5fd866be004c4ea39e44edce47dd", size = 430862 }, + { url = "https://files.pythonhosted.org/packages/a2/bf/c6aaba098e2d04781e8f4f7c0ba3c7aa73d00e4c436bcc0cf059a66691d1/zstandard-0.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:f3513916e8c645d0610815c257cbfd3242adfd5c4cfa78be514e5a3ebb42a41b", size = 495578 }, ] From c51f37f63e58fb2bb28aeae711d688e796d36704 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 28 Jul 2024 15:05:36 -0700 Subject: [PATCH 131/229] docs: start roadmap --- docs/docs/contributing/roadmap.md | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/docs/docs/contributing/roadmap.md b/docs/docs/contributing/roadmap.md index 64ccdb3b75..0f536cb515 100644 --- a/docs/docs/contributing/roadmap.md +++ b/docs/docs/contributing/roadmap.md @@ -1,5 +1,29 @@ # Roadmap -Coming soon... +This is the roadmap for the next major openpilot releases. Also check out +* [Milestones](https://github.com/commaai/openpilot/milestones) for minor releases +* [Projects](https://github.com/commaai/openpilot/projects?query=is%3Aopen) for shorter-term projects not tied to releases +* [Bounties](https://comma.ai/bounties) for paid individual issues -For now, check out our GitHub [milestones](https://github.com/commaai/openpilot/milestones) and [bounties](https://comma.ai/bounties). +## openpilot 0.10 + +openpilot 0.10 will be the first release with a driving policy trained in +a [learned simulator](https://youtu.be/EqQNZXqzFSI). + +* Driving model trained in a learned simlator +* Always-on driver monitoring (behind a toggle) +* GPS removed from the driving stack +* 100KB qlogs +* `master-ci` pushed after 1000 hours of hardware-in-the-loop testing +* Car interface code moved into [opendbc](https://github.com/commaai/opendbc) +* openpilot on PC for Linux x86, Linux arm64, and Mac (Apple Silicon) + +## openpilot 1.0 + +openpilot 1.0 will feature a fully end-to-end driving policy. + +* End-to-end longitudinal control in Chill mode +* Automatic Emergency Braking (AEB) +* Driver monitoring with sleep detection +* Rolling updates/releases pushed out by CI +* [panda safety 1.0](https://github.com/orgs/commaai/projects/27) From 583e89d3a4f912911df2f1350cb109baa16c9f22 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Sun, 28 Jul 2024 15:08:27 -0700 Subject: [PATCH 132/229] remove cv2 usage (#33101) remove cv2 --- selfdrive/ui/tests/test_ui/run.py | 3 +-- tools/webcam/camera.py | 28 +++++++++++----------------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/selfdrive/ui/tests/test_ui/run.py b/selfdrive/ui/tests/test_ui/run.py index 98a600eebc..0b1d842499 100644 --- a/selfdrive/ui/tests/test_ui/run.py +++ b/selfdrive/ui/tests/test_ui/run.py @@ -19,7 +19,6 @@ from openpilot.common.realtime import DT_MDL from openpilot.common.transformations.camera import DEVICE_CAMERAS from openpilot.selfdrive.test.helpers import with_processes from openpilot.selfdrive.test.process_replay.vision_meta import meta_from_camera_state -from openpilot.tools.webcam.camera import Camera UI_DELAY = 0.5 # may be slower on CI? @@ -76,7 +75,7 @@ def setup_onroad(click, pm: PubMaster): time.sleep(0.5) # give time for vipc server to start - IMG = Camera.bgr2nv12(np.random.randint(0, 255, (d.fcam.width, d.fcam.height, 3), dtype=np.uint8)) + IMG = np.zeros((int(d.fcam.width*1.5), d.fcam.height), dtype=np.uint8) IMG_BYTES = IMG.flatten().tobytes() cams = ('roadCameraState', 'wideRoadCameraState') diff --git a/tools/webcam/camera.py b/tools/webcam/camera.py index ddff46c5d3..10900b60ff 100644 --- a/tools/webcam/camera.py +++ b/tools/webcam/camera.py @@ -1,6 +1,4 @@ -# TODO: remove the cv2 dependency, it's only used here -import cv2 as cv -import numpy as np +import av class Camera: def __init__(self, cam_type_state, stream_type, camera_id): @@ -12,23 +10,19 @@ class Camera: self.stream_type = stream_type self.cur_frame_id = 0 - self.cap = cv.VideoCapture(camera_id) - self.W = self.cap.get(cv.CAP_PROP_FRAME_WIDTH) - self.H = self.cap.get(cv.CAP_PROP_FRAME_HEIGHT) + self.container = av.open(camera_id) + self.video_stream = self.container.streams.video[0] + self.W = self.video_stream.codec_context.width + self.H = self.video_stream.codec_context.height @classmethod def bgr2nv12(self, bgr): - yuv = cv.cvtColor(bgr, cv.COLOR_BGR2YUV_I420) - uv_row_cnt = yuv.shape[0] // 3 - uv_plane = np.transpose(yuv[uv_row_cnt * 2:].reshape(2, -1), [1, 0]) - yuv[uv_row_cnt * 2:] = uv_plane.reshape(uv_row_cnt, -1) - return yuv + frame = av.VideoFrame.from_ndarray(bgr, format='bgr24') + return frame.reformat(format='nv12').to_ndarray() def read_frames(self): - while True: - sts , frame = self.cap.read() - if not sts: - break - yuv = Camera.bgr2nv12(frame) + for frame in self.container.decode(self.video_stream): + img = frame.to_rgb().to_ndarray()[:,:, ::-1] # convert to bgr24 + yuv = Camera.bgr2nv12(img) yield yuv.data.tobytes() - self.cap.release() + self.container.close() From 4fbac089f81079595df9852eace44cea9de3dd03 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 28 Jul 2024 15:38:38 -0700 Subject: [PATCH 133/229] docs: fix nested structure (#33114) * docs: fix nested structure * test ci * that too * update that * not common mark anymore --- .github/workflows/docs.yaml | 5 ++-- .gitignore | 4 +++- docs/.gitignore | 1 - docs/{README.md => README} | 0 docs/{docs => }/car-porting/brand-port.md | 0 docs/{docs => }/car-porting/model-port.md | 0 .../car-porting/what-is-a-car-port.md | 0 docs/{docs => }/contributing/architecture.md | 0 docs/{docs => }/contributing/roadmap.md | 1 + .../getting-started/what-is-openpilot.md | 0 docs/{docs => }/how-to/connect-to-comma.md | 0 docs/{docs => }/how-to/turn-the-speed-blue.md | 0 docs/{docs => }/index.md | 0 docs/mkdocs.yml => mkdocs.yml | 7 +++--- pyproject.toml | 3 +-- uv.lock | 24 ------------------- 16 files changed, 11 insertions(+), 34 deletions(-) delete mode 100644 docs/.gitignore rename docs/{README.md => README} (100%) rename docs/{docs => }/car-porting/brand-port.md (100%) rename docs/{docs => }/car-porting/model-port.md (100%) rename docs/{docs => }/car-porting/what-is-a-car-port.md (100%) rename docs/{docs => }/contributing/architecture.md (100%) rename docs/{docs => }/contributing/roadmap.md (99%) rename docs/{docs => }/getting-started/what-is-openpilot.md (100%) rename docs/{docs => }/how-to/connect-to-comma.md (100%) rename docs/{docs => }/how-to/turn-the-speed-blue.md (100%) rename docs/{docs => }/index.md (100%) rename docs/mkdocs.yml => mkdocs.yml (95%) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 7fe4263db5..33f61173ff 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -29,8 +29,7 @@ jobs: - name: Build docs run: | # TODO: can we install just the "docs" dependency group without the normal deps? - pip install mkdocs==1.4.3 mkdocs-terminal mkdocs-plugin-commonmark - cd docs + pip install mkdocs mkdocs-terminal mkdocs build # Push to docs.comma.ai @@ -52,7 +51,7 @@ jobs: git rm -rf . # copy over docs - cp -r ../docs/site/ docs/ + cp -r ../docs_site/ docs/ # GitHub pages config touch docs/.nojekyll diff --git a/.gitignore b/.gitignore index ac61591bfd..d66823bb50 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,8 @@ model2.png a.out .hypothesis +/docs_site/ + *.dylib *.DSYM *.d @@ -102,4 +104,4 @@ Pipfile ### VisualStudioCode Patch ### # Ignore all local history of files .history -.ionide \ No newline at end of file +.ionide diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index 46ff2463e0..0000000000 --- a/docs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/site/ diff --git a/docs/README.md b/docs/README similarity index 100% rename from docs/README.md rename to docs/README diff --git a/docs/docs/car-porting/brand-port.md b/docs/car-porting/brand-port.md similarity index 100% rename from docs/docs/car-porting/brand-port.md rename to docs/car-porting/brand-port.md diff --git a/docs/docs/car-porting/model-port.md b/docs/car-porting/model-port.md similarity index 100% rename from docs/docs/car-porting/model-port.md rename to docs/car-porting/model-port.md diff --git a/docs/docs/car-porting/what-is-a-car-port.md b/docs/car-porting/what-is-a-car-port.md similarity index 100% rename from docs/docs/car-porting/what-is-a-car-port.md rename to docs/car-porting/what-is-a-car-port.md diff --git a/docs/docs/contributing/architecture.md b/docs/contributing/architecture.md similarity index 100% rename from docs/docs/contributing/architecture.md rename to docs/contributing/architecture.md diff --git a/docs/docs/contributing/roadmap.md b/docs/contributing/roadmap.md similarity index 99% rename from docs/docs/contributing/roadmap.md rename to docs/contributing/roadmap.md index 0f536cb515..22622a7a96 100644 --- a/docs/docs/contributing/roadmap.md +++ b/docs/contributing/roadmap.md @@ -1,6 +1,7 @@ # Roadmap This is the roadmap for the next major openpilot releases. Also check out + * [Milestones](https://github.com/commaai/openpilot/milestones) for minor releases * [Projects](https://github.com/commaai/openpilot/projects?query=is%3Aopen) for shorter-term projects not tied to releases * [Bounties](https://comma.ai/bounties) for paid individual issues diff --git a/docs/docs/getting-started/what-is-openpilot.md b/docs/getting-started/what-is-openpilot.md similarity index 100% rename from docs/docs/getting-started/what-is-openpilot.md rename to docs/getting-started/what-is-openpilot.md diff --git a/docs/docs/how-to/connect-to-comma.md b/docs/how-to/connect-to-comma.md similarity index 100% rename from docs/docs/how-to/connect-to-comma.md rename to docs/how-to/connect-to-comma.md diff --git a/docs/docs/how-to/turn-the-speed-blue.md b/docs/how-to/turn-the-speed-blue.md similarity index 100% rename from docs/docs/how-to/turn-the-speed-blue.md rename to docs/how-to/turn-the-speed-blue.md diff --git a/docs/docs/index.md b/docs/index.md similarity index 100% rename from docs/docs/index.md rename to docs/index.md diff --git a/docs/mkdocs.yml b/mkdocs.yml similarity index 95% rename from docs/mkdocs.yml rename to mkdocs.yml index 82db497148..3eb02aac8b 100644 --- a/docs/mkdocs.yml +++ b/mkdocs.yml @@ -1,12 +1,13 @@ site_name: openpilot docs -docs_dir: docs repo_url: https://github.com/commaai/openpilot/ site_url: https://docs.comma.ai strict: true +docs_dir: docs +site_dir: docs_site/ -plugins: - - commonmark +#plugins: +# - commonmark theme: name: terminal diff --git a/pyproject.toml b/pyproject.toml index dd801994f1..456e8a8cde 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,9 +68,8 @@ dependencies = [ docs = [ "Jinja2", "natsort", - "mkdocs==1.4.3", # needed for mkdocs-plugin-commonmark + "mkdocs", "mkdocs-terminal", - "mkdocs-plugin-commonmark", ] testing = [ diff --git a/uv.lock b/uv.lock index fa5c364673..980797805f 100644 --- a/uv.lock +++ b/uv.lock @@ -1114,15 +1114,6 @@ dependencies = [ { name = "yapf" }, ] -[[distribution]] -name = "mistletoe" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/11/96/ea46a376a7c4cd56955ecdfff0ea68de43996a4e6d1aee4599729453bd11/mistletoe-1.4.0.tar.gz", hash = "sha256:1630f906e5e4bbe66fdeb4d29d277e2ea515d642bb18a9b49b136361a9818c9d", size = 107203 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/0f/b5e545f0c7962be90366af3418989b12cf441d9da1e5d89d88f2f3e5cf8f/mistletoe-1.4.0-py3-none-any.whl", hash = "sha256:44a477803861de1237ba22e375c6b617690a31d2902b47279d1f8f7ed498a794", size = 51304 }, -] - [[distribution]] name = "mkdocs" version = "1.4.3" @@ -1144,20 +1135,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/42/7a/5ed794942ace9d00bb77a8036c64c999cda6ebaab57e9b8a6ec1aa5fc900/mkdocs-1.4.3-py3-none-any.whl", hash = "sha256:6ee46d309bda331aac915cd24aab882c179a933bd9e77b80ce7d2eaaa3f689dd", size = 3654464 }, ] -[[distribution]] -name = "mkdocs-plugin-commonmark" -version = "0.0.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown" }, - { name = "mistletoe" }, - { name = "mkdocs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fa/a1/4aaa744deec61d75dbe3c67c18f6e4c1fa7699bc2661b6eff5f891e83023/mkdocs-plugin-commonmark-0.0.4.tar.gz", hash = "sha256:9034507af26646e95188a130782dd07d65c86507fddd3b47ea340c02683e85e7", size = 10805 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/4a/4333ef1eb57ff130c7715ba0847dbdae471d153d94507004c92c591cb3c5/mkdocs_plugin_commonmark-0.0.4-py3-none-any.whl", hash = "sha256:70a33394d86a04ec97877ca1b2dff6181de3ec01ef4c7add178fa45b327da535", size = 12532 }, -] - [[distribution]] name = "mkdocs-terminal" version = "4.4.0" @@ -1484,7 +1461,6 @@ dev = [ docs = [ { name = "jinja2" }, { name = "mkdocs" }, - { name = "mkdocs-plugin-commonmark" }, { name = "mkdocs-terminal" }, { name = "natsort" }, ] From 691b948ad02a20e507d5059707f8cde51a94a703 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 28 Jul 2024 16:07:39 -0700 Subject: [PATCH 134/229] docs: readthedocs theme (#33116) * docs: read the docs theme * nav depth --- .github/workflows/docs.yaml | 2 +- docs/how-to/connect-to-comma.md | 4 ++-- docs/how-to/turn-the-speed-blue.md | 4 ++-- mkdocs.yml | 10 +++------- pyproject.toml | 1 - uv.lock | 30 ------------------------------ 6 files changed, 8 insertions(+), 43 deletions(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 33f61173ff..26b60ffec2 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -29,7 +29,7 @@ jobs: - name: Build docs run: | # TODO: can we install just the "docs" dependency group without the normal deps? - pip install mkdocs mkdocs-terminal + pip install mkdocs mkdocs build # Push to docs.comma.ai diff --git a/docs/how-to/connect-to-comma.md b/docs/how-to/connect-to-comma.md index 53460ac990..d9c0c701c8 100644 --- a/docs/how-to/connect-to-comma.md +++ b/docs/how-to/connect-to-comma.md @@ -51,14 +51,14 @@ Host ssh.comma.ai IdentityFile ~/.ssh/my_github_key ``` -## One-off connection +### One-off connection ``` ssh -i ~/.ssh/my_github_key -o ProxyCommand="ssh -i ~/.ssh/my_github_key -W %h:%p -p %p %h@ssh.comma.ai" comma@ffffffffffffffff ``` (Replace `ffffffffffffffff` with your dongle_id) -## ssh.comma.ai host key fingerprint +### ssh.comma.ai host key fingerprint ``` Host key fingerprint is SHA256:X22GOmfjGb9J04IA2+egtdaJ7vW9Fbtmpz9/x8/W1X4 diff --git a/docs/how-to/turn-the-speed-blue.md b/docs/how-to/turn-the-speed-blue.md index f76e9e489e..643023fdf4 100644 --- a/docs/how-to/turn-the-speed-blue.md +++ b/docs/how-to/turn-the-speed-blue.md @@ -86,13 +86,13 @@ git commit -m "Make the speed blue." git push --set-upstream origin master ``` -### 6. Run your fork on device in your car! +## 6. Run your fork on device in your car! Uninstall openpilot from your device through the settings. Then, enter the URL for your very own installer: ``` installer.comma.ai//master ``` -### 7. Admire your work IRL +## 7. Admire your work IRL ![](https://blog.comma.ai/img/c3_blue_ui.jpg) diff --git a/mkdocs.yml b/mkdocs.yml index 3eb02aac8b..b9a901c4d7 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -6,13 +6,9 @@ strict: true docs_dir: docs site_dir: docs_site/ -#plugins: -# - commonmark - theme: - name: terminal - features: - - navigation.side.toc.hide + name: readthedocs + navigation_depth: 3 nav: - Getting Started: @@ -27,7 +23,7 @@ nav: - Contributing: - Roadmap: contributing/roadmap.md #- Architecture: contributing/architecture.md - - Contributing →: https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md + - Contributing Guide →: https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md - Links: - Blog →: https://blog.comma.ai - Bounties →: https://comma.ai/bounties diff --git a/pyproject.toml b/pyproject.toml index 456e8a8cde..86eb08fa1c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,7 +69,6 @@ docs = [ "Jinja2", "natsort", "mkdocs", - "mkdocs-terminal", ] testing = [ diff --git a/uv.lock b/uv.lock index 980797805f..a08ad9c4be 100644 --- a/uv.lock +++ b/uv.lock @@ -1135,22 +1135,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/42/7a/5ed794942ace9d00bb77a8036c64c999cda6ebaab57e9b8a6ec1aa5fc900/mkdocs-1.4.3-py3-none-any.whl", hash = "sha256:6ee46d309bda331aac915cd24aab882c179a933bd9e77b80ce7d2eaaa3f689dd", size = 3654464 }, ] -[[distribution]] -name = "mkdocs-terminal" -version = "4.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jinja2" }, - { name = "markdown" }, - { name = "mkdocs" }, - { name = "pygments" }, - { name = "pymdown-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b3/a4/afa8826c3d6971f3e93cb3669936b25579314fef2a4d648fe72729c9675f/mkdocs_terminal-4.4.0.tar.gz", hash = "sha256:d72b87b3d0edf470695811cb56c440a43b0387212590a5dfb2f26861c6e518d7", size = 619482 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/93/65/7973dfe5ae03dd83a5a4e203b542ebacb16fd0c796e3f93f3cb98c3ffcc2/mkdocs_terminal-4.4.0-py3-none-any.whl", hash = "sha256:b2c94dc651c840e9762a1040d39371a31cc7482f7768e619e317419ebae4e40e", size = 641788 }, -] - [[distribution]] name = "mouseinfo" version = "0.1.3" @@ -1461,7 +1445,6 @@ dev = [ docs = [ { name = "jinja2" }, { name = "mkdocs" }, - { name = "mkdocs-terminal" }, { name = "natsort" }, ] testing = [ @@ -1899,19 +1882,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4c/31/85a58625edc0b6967fe0904c9d89d019bcece3f3e3bf775b9151a8cf9d0d/pylibsrtp-0.10.0-cp38-abi3-win_amd64.whl", hash = "sha256:cd965d4b0e9a77b362526cab119f4d9ce39b83f1f20f46c6af8e694b86fa19a7", size = 1448840 }, ] -[[distribution]] -name = "pymdown-extensions" -version = "10.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown" }, - { name = "pyyaml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/85/71/5f48080bde77b07ca1eba6d7cb5c5598ac6c8f2a399846159b3c8b45e171/pymdown_extensions-10.4.tar.gz", hash = "sha256:bc46f11749ecd4d6b71cf62396104b4a200bad3498cb0f5dad1b8502fe461a35", size = 785151 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/98/2d/2929de81618c7213176899dd6372d6ec9c8f24337841dd74634fb69864ae/pymdown_extensions-10.4-py3-none-any.whl", hash = "sha256:cfc28d6a09d19448bcbf8eee3ce098c7d17ff99f7bd3069db4819af181212037", size = 240838 }, -] - [[distribution]] name = "pymonctl" version = "0.92" From 5ebc65f254f66ff13c679f9f699a92458c41aa8a Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 28 Jul 2024 16:38:38 -0700 Subject: [PATCH 135/229] docs: add concepts section --- docs/concepts/glossary.md | 8 ++++++++ system/loggerd/README.md => docs/concepts/logs.md | 13 ++++++------- docs/concepts/safety.md | 1 + docs/how-to/replay-a-drive.md | 14 ++++++++++++++ mkdocs.yml | 4 ++++ 5 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 docs/concepts/glossary.md rename system/loggerd/README.md => docs/concepts/logs.md (86%) create mode 120000 docs/concepts/safety.md create mode 100644 docs/how-to/replay-a-drive.md diff --git a/docs/concepts/glossary.md b/docs/concepts/glossary.md new file mode 100644 index 0000000000..46e8e834d2 --- /dev/null +++ b/docs/concepts/glossary.md @@ -0,0 +1,8 @@ +# openpilot glossary + +* **route**: +* **segment**: routes are split into one minute chunks called segments. +* **panda**: this is . See the repo. +* **onroad**: +* **offroad**: +* **comma 3X**: diff --git a/system/loggerd/README.md b/docs/concepts/logs.md similarity index 86% rename from system/loggerd/README.md rename to docs/concepts/logs.md index 714e4242a0..46ab2897df 100644 --- a/system/loggerd/README.md +++ b/docs/concepts/logs.md @@ -1,10 +1,8 @@ -# loggerd +# Logging openpilot records routes in one minute chunks called segments. A route starts on the rising edge of ignition and ends on the falling edge. -Check out our [python library](https://github.com/commaai/openpilot/blob/master/tools/lib/logreader.py) for reading openpilot logs. Also checkout our [tools](https://github.com/commaai/openpilot/tree/master/tools) to replay and view your data. These are the same tools we use to debug and develop openpilot. - -## log types +Check out our [Python library](https://github.com/commaai/openpilot/blob/master/tools/lib/logreader.py) for reading openpilot logs. Also checkout our [tools](https://github.com/commaai/openpilot/tree/master/tools) to replay and view your data. These are the same tools we use to debug and develop openpilot. For each segment, openpilot records the following log types: @@ -15,9 +13,10 @@ rlogs contain all the messages passed amongst openpilot's processes. See [cereal ## {f,e,d}camera.hevc Each camera stream is H.265 encoded and written to its respective file. -* fcamera.hevc is the road camera -* ecamera.hevc is the wide road camera -* dcamera.hevc is the driver camera + +* `fcamera.hevc` is the road camera +* `ecamera.hevc` is the wide road camera +* `dcamera.hevc` is the driver camera ## qlog.bz2 & qcamera.ts diff --git a/docs/concepts/safety.md b/docs/concepts/safety.md new file mode 120000 index 0000000000..f286ad4b15 --- /dev/null +++ b/docs/concepts/safety.md @@ -0,0 +1 @@ +../SAFETY.md \ No newline at end of file diff --git a/docs/how-to/replay-a-drive.md b/docs/how-to/replay-a-drive.md new file mode 100644 index 0000000000..084b6bf825 --- /dev/null +++ b/docs/how-to/replay-a-drive.md @@ -0,0 +1,14 @@ +# Replay + +Replaying is a critical tool for openpilot development and debugging. + +## Replaying a route +*Hardware required: none* + +Just run `tools/replay/replay --demo`. + +## Replaying CAN data +*Hardware required: jungle and comma 3/3X* + +1. Connect your PC to a jungle. +2. diff --git a/mkdocs.yml b/mkdocs.yml index b9a901c4d7..8778e28863 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -16,6 +16,10 @@ nav: - How-to: - Turn the speed blue: how-to/turn-the-speed-blue.md - Connect to a comma 3/3X: how-to/connect-to-comma.md + #- Replay a drive: how-to/replay-a-drive.md + - Concepts: + - Logs: concepts/logs.md + - Safety: concepts/safety.md - Car Porting: - What is a car port?: car-porting/what-is-a-car-port.md - Porting a car brand: car-porting/brand-port.md From e24271aa2b1a24eb6586b75eadf02f3358fa74e4 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Mon, 8 Jul 2024 19:10:26 +0200 Subject: [PATCH 136/229] Processor definition check for __APPLE__ has a typo on replay (#32930) (cherry picked from commit 3c74ad145e0145429d782219ac255a26aa2f6135) --- tools/replay/util.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/replay/util.cc b/tools/replay/util.cc index a08b3b3d5e..aaf73749d5 100644 --- a/tools/replay/util.cc +++ b/tools/replay/util.cc @@ -323,7 +323,7 @@ void precise_nano_sleep(int64_t nanoseconds, std::atomic &should_exit) { req.tv_sec = nanoseconds / 1000000000; req.tv_nsec = nanoseconds % 1000000000; while (!should_exit) { -#ifdef __APPLE_ +#ifdef __APPLE__ int ret = nanosleep(&req, &rem); if (ret == 0 || errno != EINTR) break; From 1fb0cb59a61bcbee96d6b3e287979f9545a0d38a Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Tue, 16 Jul 2024 02:59:02 +0000 Subject: [PATCH 137/229] Scons: Build sunnypilot elements with added GPG keys --- .gitlab-ci.yml | 2 ++ SConstruct | 47 ++++++++++++++++++++++++++++++ selfdrive/ui/SConscript | 6 ++++ selfdrive/ui/sunnypilot/SConscript | 10 +++++++ 4 files changed, 65 insertions(+) create mode 100644 selfdrive/ui/sunnypilot/SConscript diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 21958355c5..de50202454 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -129,6 +129,8 @@ build: --exclude='**/selfdrive/ui/**/*.h' --exclude='**/selfdrive/ui/qt/offroad/sunnypilot/' --exclude='**/.git/' + --exclude='**/SConstruct' + --exclude='**/SConscript' --delete-excluded --chown=comma:comma ${BUILD_DIR}/ ${OUTPUT_DIR}/ diff --git a/SConstruct b/SConstruct index da70e4e587..13da37c7a8 100644 --- a/SConstruct +++ b/SConstruct @@ -7,6 +7,8 @@ import numpy as np import SCons.Errors +from openpilot.common.basedir import BASEDIR + SCons.Warnings.warningAsException(True) # pending upstream fix - https://github.com/SCons/scons/issues/4461 @@ -16,6 +18,45 @@ TICI = os.path.isfile('/TICI') AGNOS = TICI UBUNTU_FOCAL = int(subprocess.check_output('[ -f /etc/os-release ] && . /etc/os-release && [ "$ID" = "ubuntu" ] && [ "$VERSION_ID" = "20.04" ] && echo 1 || echo 0', shell=True, encoding='utf-8').rstrip()) Export('UBUNTU_FOCAL') +_DEBUG = False + +def is_internal_developer(debug=False): + def collect_required_gpg_key_ids(keys_dir): + try: + key_ids = [f.split('.')[0] for f in os.listdir(keys_dir) if f.endswith(".gpg")] + if debug: + print(f"SP: Required GPG key IDs: {key_ids}") + return key_ids + except OSError as e: + if debug: + print(f"SP: Failed to read GPG key IDs from {keys_dir}. Error: {e}") + return [] + + def is_key_available(required_gpg_key_ids): + for key_id in required_gpg_key_ids: + try: + result = subprocess.check_output(['gpg', '--list-keys', key_id], stderr=subprocess.STDOUT) + if key_id in result.decode(): + if debug: + print(f"SP: GPG key {key_id} is available.") + return True + except subprocess.CalledProcessError as e: + if debug: + print(f"SP: Failed to list GPG key {key_id}. Error:", e.output.decode().strip()) + return False + + keys_dir = os.path.join(BASEDIR, ".git-crypt/keys/default/0") + required_gpg_key_ids = collect_required_gpg_key_ids(keys_dir) + + sunnypilot = is_key_available(required_gpg_key_ids) + + if sunnypilot: + print("SP: Confirmed sunnypilot internal developer.") + print("SP: Loading sunnypilot elements ...") + elif debug: + print("SP: None of the required GPG keys are available.") + + return sunnypilot Decider('MD5-timestamp') @@ -72,6 +113,12 @@ AddOption('--minimal', default=os.path.exists(File('#.lfsconfig').abspath), # minimal by default on release branch (where there's no LFS) help='the minimum build to run openpilot. no tests, tools, etc.') +AddOption('--sunnypilot', + action='store_true', + dest='sunnypilot', + default=is_internal_developer(_DEBUG), # check if the current user is a sunnypilot developer + help='build sunnypilot elements and other sunnypilot-specific items that are meant for internal development') + ## Architecture name breakdown (arch) ## - larch64: linux tici aarch64 ## - aarch64: linux pc aarch64 diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index e1233b5cbc..f4f5a13919 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -17,6 +17,12 @@ if arch == "Darwin": # FIXME: remove this once we're on 5.15 (24.04) qt_env['CXXFLAGS'] += ["-Wno-deprecated-declarations"] +sp_widgets_src = [] +sp_qt_src = [] +if GetOption('sunnypilot'): + SConscript(['sunnypilot/SConscript']) + Import('sp_widgets_src', 'sp_qt_src') + qt_util = qt_env.Library("qt_util", ["#selfdrive/ui/qt/api.cc", "#selfdrive/ui/qt/util.cc"], LIBS=base_libs) widgets_src = ["ui.cc", "qt/widgets/input.cc", "qt/widgets/wifi.cc", "qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc", diff --git a/selfdrive/ui/sunnypilot/SConscript b/selfdrive/ui/sunnypilot/SConscript new file mode 100644 index 0000000000..4431fc3ea0 --- /dev/null +++ b/selfdrive/ui/sunnypilot/SConscript @@ -0,0 +1,10 @@ +widgets_src = [] + +network_src = [] + +qt_src = [] + +sp_widgets_src = widgets_src + network_src +sp_qt_src = qt_src + +Export('sp_widgets_src', 'sp_qt_src') From fb04ddc9a1090a08cb8da8c7c40e91f11d2b098e Mon Sep 17 00:00:00 2001 From: Jaosn Wen Date: Tue, 16 Jul 2024 00:07:29 -0400 Subject: [PATCH 138/229] Scons: Set `SUNNYPILOT` to `CPPDEFINES` --- selfdrive/ui/SConscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index f4f5a13919..99ec3c161d 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -43,7 +43,7 @@ widgets_src += ["qt/offroad/sunnypilot/display_settings.cc", "qt/offroad/sunnypi widgets_src += ["qt/network/sunnylink/sunnylink_client.cc", "qt/network/sunnylink/services/base_device_service.cc", "qt/network/sunnylink/services/role_service.cc", "qt/network/sunnylink/services/user_service.cc"] -qt_env['CPPDEFINES'] = [] +qt_env['CPPDEFINES'] = ["SUNNYPILOT"] if GetOption('sunnypilot') else [] if maps: base_libs += ['QMapLibre'] widgets_src += ["qt/maps/map_helpers.cc", "qt/maps/map_settings.cc", "qt/maps/map.cc", "qt/maps/map_panel.cc", From e994c2cb9634480ba43cdd89c1c84035707911c8 Mon Sep 17 00:00:00 2001 From: Jaosn Wen Date: Tue, 16 Jul 2024 00:20:45 -0400 Subject: [PATCH 139/229] Scons: Split sunnypilot/Sconscript --- selfdrive/ui/SConscript | 20 +++---------------- selfdrive/ui/sunnypilot/SConscript | 32 +++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 99ec3c161d..3d49b3df14 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -1,6 +1,6 @@ import os import json -Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'transformations', 'UBUNTU_FOCAL') +Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'transformations') base_libs = [common, messaging, visionipc, transformations, 'm', 'OpenCL', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"] @@ -28,20 +28,7 @@ widgets_src = ["ui.cc", "qt/widgets/input.cc", "qt/widgets/wifi.cc", "qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc", "qt/widgets/offroad_alerts.cc", "qt/widgets/prime.cc", "qt/widgets/keyboard.cc", "qt/widgets/scrollview.cc", "qt/widgets/cameraview.cc", "#third_party/qrcode/QrCode.cc", - "qt/request_repeater.cc", "qt/qt_window.cc", "qt/network/networking.cc", "qt/network/wifi_manager.cc"] - -widgets_src += ["qt/offroad/sunnypilot/display_settings.cc", "qt/offroad/sunnypilot/sunnypilot_settings.cc", - "qt/offroad/sunnypilot/vehicle_settings.cc", "qt/offroad/sunnypilot/visuals_settings.cc", - "qt/offroad/sunnypilot/trips_settings.cc", "qt/offroad/sunnypilot/mads_settings.cc", - "qt/offroad/sunnypilot/lane_change_settings.cc", "qt/offroad/sunnypilot/speed_limit_control_settings.cc", - "qt/offroad/sunnypilot/monitoring_settings.cc", "qt/offroad/sunnypilot/osm_settings.cc", - "qt/offroad/sunnypilot/custom_offsets_settings.cc", "qt/widgets/sunnypilot/drive_stats.cc", - "qt/offroad/sunnypilot/software_settings_sp.cc", "qt/offroad/sunnypilot/models_fetcher.cc", - "qt/offroad/sunnypilot/speed_limit_warning_settings.cc", "qt/offroad/sunnypilot/speed_limit_policy_settings.cc", - "qt/offroad/sunnypilot/sunnylink_settings.cc"] - -widgets_src += ["qt/network/sunnylink/sunnylink_client.cc", "qt/network/sunnylink/services/base_device_service.cc", - "qt/network/sunnylink/services/role_service.cc", "qt/network/sunnylink/services/user_service.cc"] + "qt/request_repeater.cc", "qt/qt_window.cc", "qt/network/networking.cc", "qt/network/wifi_manager.cc"] + sp_widgets_src qt_env['CPPDEFINES'] = ["SUNNYPILOT"] if GetOption('sunnypilot') else [] if maps: @@ -59,8 +46,7 @@ qt_src = ["main.cc", "qt/sidebar.cc", "qt/body.cc", "qt/offroad/software_settings.cc", "qt/offroad/onboarding.cc", "qt/offroad/driverview.cc", "qt/offroad/experimental_mode.cc", "qt/onroad/onroad_home.cc", "qt/onroad/annotated_camera.cc", - "qt/onroad/buttons.cc", "qt/onroad/alerts.cc", - "qt/onroad_settings.cc", "qt/onroad_settings_panel.cc"] + "qt/onroad/buttons.cc", "qt/onroad/alerts.cc"] + sp_qt_src # build translation files with open(File("translations/languages.json").abspath) as f: diff --git a/selfdrive/ui/sunnypilot/SConscript b/selfdrive/ui/sunnypilot/SConscript index 4431fc3ea0..9290fcea58 100644 --- a/selfdrive/ui/sunnypilot/SConscript +++ b/selfdrive/ui/sunnypilot/SConscript @@ -1,8 +1,34 @@ -widgets_src = [] +widgets_src = [ + "qt/offroad/sunnypilot/custom_offsets_settings.cc", + "qt/offroad/sunnypilot/display_settings.cc", + "qt/offroad/sunnypilot/lane_change_settings.cc", + "qt/offroad/sunnypilot/mads_settings.cc", + "qt/offroad/sunnypilot/models_fetcher.cc", + "qt/offroad/sunnypilot/monitoring_settings.cc", + "qt/offroad/sunnypilot/osm_settings.cc", + "qt/offroad/sunnypilot/software_settings_sp.cc", + "qt/offroad/sunnypilot/speed_limit_control_settings.cc", + "qt/offroad/sunnypilot/speed_limit_policy_settings.cc", + "qt/offroad/sunnypilot/speed_limit_warning_settings.cc", + "qt/offroad/sunnypilot/sunnypilot_settings.cc", + "qt/offroad/sunnypilot/sunnylink_settings.cc", + "qt/offroad/sunnypilot/trips_settings.cc", + "qt/offroad/sunnypilot/vehicle_settings.cc", + "qt/offroad/sunnypilot/visuals_settings.cc", + "qt/widgets/sunnypilot/drive_stats.cc" +] -network_src = [] +network_src = [ + "qt/network/sunnylink/services/base_device_service.cc", + "qt/network/sunnylink/services/role_service.cc", + "qt/network/sunnylink/services/user_service.cc", + "qt/network/sunnylink/sunnylink_client.cc" +] -qt_src = [] +qt_src = [ + "qt/onroad_settings.cc", + "qt/onroad_settings_panel.cc" +] sp_widgets_src = widgets_src + network_src sp_qt_src = qt_src From 05536bf4395ea80ae04f3b32a267c0ca99e1de42 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Sat, 20 Jul 2024 13:06:34 +0000 Subject: [PATCH 140/229] Driving Model Selector v5: Bug fixes --- selfdrive/modeld/custom_model_metadata.py | 4 ++-- selfdrive/modeld/fill_model_msg.py | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/selfdrive/modeld/custom_model_metadata.py b/selfdrive/modeld/custom_model_metadata.py index 360f7046ad..0469bd189c 100644 --- a/selfdrive/modeld/custom_model_metadata.py +++ b/selfdrive/modeld/custom_model_metadata.py @@ -42,14 +42,14 @@ class CustomModelMetadata: self.params: Params = params self.generation: ModelGeneration = self.read_model_generation_param() - self.capabilities: int = self.get_model_capabilities() + self.capabilities: ModelCapabilities = self.get_model_capabilities() self.valid: bool = self.params.get_bool("CustomDrivingModel") and not SIMULATION and \ self.capabilities != ModelCapabilities.Default def read_model_generation_param(self) -> ModelGeneration: return int(self.params.get('DrivingModelGeneration') or ModelGeneration.default) - def get_model_capabilities(self) -> int: + def get_model_capabilities(self) -> ModelCapabilities: """Returns the model capabilities for a given generation.""" if self.generation == ModelGeneration.five: return ModelCapabilities.DesiredCurvatureV2 diff --git a/selfdrive/modeld/fill_model_msg.py b/selfdrive/modeld/fill_model_msg.py index 39a161ed89..8d2bcc0ef4 100644 --- a/selfdrive/modeld/fill_model_msg.py +++ b/selfdrive/modeld/fill_model_msg.py @@ -68,7 +68,9 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D driving_model_data.frameDropPerc = frame_drop_perc action = driving_model_data.action - action.desiredCurvature = float(net_output_data['desired_curvature'][0,0]) + model_use_lateral_planner = custom_model_valid and custom_model_capabilities & ModelCapabilities.LateralPlannerSolution + if not model_use_lateral_planner: + action.desiredCurvature = float(net_output_data['desired_curvature'][0,0]) modelV2 = extended_msg.modelV2 modelV2.frameId = vipc_frame_id @@ -100,7 +102,7 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D fill_xyz_poly(poly_path, ModelConstants.POLY_PATH_DEGREE, *net_output_data['plan'][0,:,Plan.POSITION].T) # lateral planning - if custom_model_valid and custom_model_capabilities & ModelCapabilities.LateralPlannerSolution: + if model_use_lateral_planner: solution = modelV2.lateralPlannerSolutionDEPRECATED solution.x, solution.y, solution.yaw, solution.yawRate = [net_output_data['lat_planner_solution'][0,:,i].tolist() for i in range(4)] solution.xStd, solution.yStd, solution.yawStd, solution.yawRateStd = [net_output_data['lat_planner_solution_stds'][0,:,i].tolist() for i in range(4)] From 2f3d999c67ef5ead9a7be9b96d67ab6f804305c5 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Thu, 25 Jul 2024 17:16:57 +0000 Subject: [PATCH 141/229] ui: Lead car chevron: Time to Lead Car --- CHANGELOGS.md | 5 +++++ .../ui/qt/offroad/sunnypilot/visuals_settings.cc | 4 ++-- selfdrive/ui/qt/onroad/annotated_camera.cc | 14 +++++++++++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/CHANGELOGS.md b/CHANGELOGS.md index 06a2961de7..2fc99ab8d0 100644 --- a/CHANGELOGS.md +++ b/CHANGELOGS.md @@ -40,6 +40,11 @@ sunnypilot - 0.9.8.0 (2024-xx-xx) * Auto Unlock by Shift to P: All doors are automatically unlocked when shifting the shift lever to P * FIXED: Driving Personality: * Maniac mode now correctly enforced when selected +* UI Updates + * Display Metrics Below Chevron + * NEW❗: Time to Lead Car + * Displays the time to reach the position previously occupied by the lead car + * NEW❗: Display Distance, Speed, and Time to Lead Car simultaneously * Kia Ceed Plug-in Hybrid Non-SCC 2022 support thanks to TerminatorNL! sunnypilot - 0.9.7.1 (2024-06-13) diff --git a/selfdrive/ui/qt/offroad/sunnypilot/visuals_settings.cc b/selfdrive/ui/qt/offroad/sunnypilot/visuals_settings.cc index 46bd84b6d9..742725e8ab 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/visuals_settings.cc +++ b/selfdrive/ui/qt/offroad/sunnypilot/visuals_settings.cc @@ -82,12 +82,12 @@ VisualsPanel::VisualsPanel(QWidget *parent) : ListWidget(parent) { dev_ui_settings->showDescription(); // Visuals: Display Metrics above Chevron - std::vector chevron_info_settings_texts{tr("Off"), tr("Distance"), tr("Speed"), tr("Distance\nSpeed")}; + std::vector chevron_info_settings_texts{tr("Off"), tr("Distance"), tr("Speed"), tr("Time"), tr("All")}; chevron_info_settings = new ButtonParamControl( "ChevronInfo", tr("Display Metrics Below Chevron"), tr("Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control)."), "../assets/offroad/icon_blank.png", chevron_info_settings_texts, - 340 + 300 ); chevron_info_settings->showDescription(); diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc index 009ff76138..bb19798e92 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.cc +++ b/selfdrive/ui/qt/onroad/annotated_camera.cc @@ -1525,20 +1525,28 @@ void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState painter.drawPolygon(chevron, std::size(chevron)); if (num == 0) { // Display metrics to the 0th lead car - int chevron_types = 2; + const int chevron_types = 3; + const int chevron_all = chevron_types + 1; // All metrics QStringList chevron_text[chevron_types]; int position; float val; - if (chevron_data == 1 || chevron_data == 3) { + if (chevron_data == 1 || chevron_data == chevron_all) { position = 0; val = std::max(0.0f, d_rel); chevron_text[position].append(QString::number(val,'f', 0) + " " + "m"); } - if (chevron_data == 2 || chevron_data == 3) { + if (chevron_data == 2 || chevron_data == chevron_all) { position = (chevron_data == 2) ? 0 : 1; val = std::max(0.0f, (v_rel + v_ego) * (is_metric ? static_cast(MS_TO_KPH) : static_cast(MS_TO_MPH))); chevron_text[position].append(QString::number(val,'f', 0) + " " + (is_metric ? "km/h" : "mph")); } + if (chevron_data == 3 || chevron_data == chevron_all) { + position = (chevron_data == 3) ? 0 : 2; + val = (d_rel > 0 && v_ego > 0) ? std::max(0.0f, d_rel / v_ego) : 0.0f; + + QString ttc_str = (val > 0 && val < 200) ? QString::number(val, 'f', 1) + "s" : "---"; + chevron_text[position].append(ttc_str); + } float str_w = 200; // Width of the text box, might need adjustment float str_h = 50; // Height of the text box, adjust as necessary From ca8c74bc0d2444934ba62e6c8005a23ed20e664f Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Thu, 25 Jul 2024 17:23:33 +0000 Subject: [PATCH 142/229] MADS: Use modern button events parsing --- selfdrive/car/__init__.py | 26 ++++++++++++--- selfdrive/car/chrysler/carcontroller.py | 12 ++++--- selfdrive/car/chrysler/carstate.py | 21 ++++++------ selfdrive/car/chrysler/interface.py | 35 ++++++-------------- selfdrive/car/chrysler/values.py | 14 ++++---- selfdrive/car/ford/carstate.py | 24 +++++++------- selfdrive/car/ford/interface.py | 36 ++++++--------------- selfdrive/car/ford/values.py | 21 ++++++------ selfdrive/car/gm/interface.py | 26 ++++++--------- selfdrive/car/honda/interface.py | 11 ++++--- selfdrive/car/hyundai/interface.py | 23 +++++-------- selfdrive/car/interfaces.py | 8 ++++- selfdrive/car/mazda/carcontroller.py | 9 +++--- selfdrive/car/mazda/carstate.py | 21 ++++++------ selfdrive/car/mazda/interface.py | 38 +++++++--------------- selfdrive/car/mazda/values.py | 18 ++++++----- selfdrive/car/nissan/interface.py | 27 ++++------------ selfdrive/car/subaru/interface.py | 27 ++++------------ selfdrive/car/toyota/interface.py | 28 ++++------------ selfdrive/car/volkswagen/carstate.py | 26 ++------------- selfdrive/car/volkswagen/interface.py | 43 ++++++------------------- selfdrive/car/volkswagen/values.py | 10 ------ 22 files changed, 195 insertions(+), 309 deletions(-) diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index 6aebd2bd90..207c90678d 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -43,10 +43,28 @@ def create_button_events(cur_btn: int, prev_btn: int, buttons_dict: dict[int, ca return events -def create_mads_event(mads_event_lock: bool) -> capnp.lib.capnp._DynamicStructBuilder: - be = car.CarState.ButtonEvent(pressed=mads_event_lock) - be.type = ButtonType.altButton1 - return be +class ButtonEvents: + def __init__(self) -> None: + self.is_mads: bool = False + + @staticmethod + def create_cancel_event(long_enabled: bool, prev_long_enabled: bool) -> list[capnp.lib.capnp._DynamicStructBuilder]: + events: list[capnp.lib.capnp._DynamicStructBuilder] = [] + + if not long_enabled and prev_long_enabled: + events.append(car.CarState.ButtonEvent(pressed=True, + type=ButtonType.cancel)) + return events + + def create_mads_event(self, mads_enabled: bool, prev_mads_enabled: bool) -> list[capnp.lib.capnp._DynamicStructBuilder]: + events: list[capnp.lib.capnp._DynamicStructBuilder] = [] + + mads_changed = prev_mads_enabled != mads_enabled + if (mads_changed and not self.is_mads) or (not mads_changed and self.is_mads): + events.append(car.CarState.ButtonEvent(pressed=mads_changed, type=ButtonType.altButton1)) + self.is_mads = not self.is_mads + + return events def gen_empty_fingerprint(): diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index f9277af62e..54bed40b51 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -1,3 +1,5 @@ +from cereal import car + import cereal.messaging as messaging from common.conversions import Conversions as CV from opendbc.can.packer import CANPacker @@ -9,7 +11,7 @@ from openpilot.selfdrive.car.chrysler.values import RAM_CARS, RAM_DT, CarControl from openpilot.selfdrive.car.interfaces import CarControllerBase, FORWARD_GEARS from openpilot.selfdrive.controls.lib.drive_helpers import FCA_V_CRUISE_MIN -BUTTONS_STATES = ["accelCruise", "decelCruise", "cancel", "resumeCruise"] +ButtonType = car.CarState.ButtonEvent.Type class CarController(CarControllerBase): @@ -104,7 +106,7 @@ class CarController(CarControllerBase): self.last_button_frame = CS.button_counter if ram_cars: - if CS.buttonStates["cancel"]: + if any(b.type == ButtonType.cancel for b in CS.out.buttonEvents): can_sends.append(chryslercan.create_cruise_buttons(self.packer, CS.button_counter, das_bus, self.CP, cancel=True)) else: can_sends.append(chryslercan.create_cruise_buttons(self.packer, CS.button_counter, das_bus, self.CP, @@ -189,8 +191,10 @@ class CarController(CarControllerBase): # multikyd methods, sunnyhaibin logic def get_cruise_buttons_status(self, CS): - if not CS.out.cruiseState.enabled or any(CS.buttonStates[button_state] for button_state in BUTTONS_STATES): - self.timer = 40 + if not CS.out.cruiseState.enabled: + for be in CS.out.buttonEvents: + if be.type in (ButtonType.accelCruise, ButtonType.decelCruise, ButtonType.resumeCruise) and be.pressed: + self.timer = 40 elif self.timer: self.timer -= 1 else: diff --git a/selfdrive/car/chrysler/carstate.py b/selfdrive/car/chrysler/carstate.py index d29be9226e..a58681175e 100644 --- a/selfdrive/car/chrysler/carstate.py +++ b/selfdrive/car/chrysler/carstate.py @@ -3,7 +3,7 @@ from openpilot.common.conversions import Conversions as CV from opendbc.can.parser import CANParser from opendbc.can.can_define import CANDefine from openpilot.selfdrive.car.interfaces import CarStateBase -from openpilot.selfdrive.car.chrysler.values import DBC, STEER_THRESHOLD, RAM_CARS, BUTTON_STATES +from openpilot.selfdrive.car.chrysler.values import DBC, STEER_THRESHOLD, RAM_CARS, BUTTONS class CarState(CarStateBase): @@ -29,8 +29,7 @@ class CarState(CarStateBase): self.lkas_heartbit = None self.lkas_disabled = False - self.buttonStates = BUTTON_STATES.copy() - self.buttonStatesPrev = BUTTON_STATES.copy() + self.button_states = {button.event_type: False for button in BUTTONS} def update(self, cp, cp_cam): @@ -41,7 +40,6 @@ class CarState(CarStateBase): self.prev_mads_enabled = self.mads_enabled self.prev_lkas_enabled = self.lkas_enabled - self.buttonStatesPrev = self.buttonStates.copy() # lock info ret.doorOpen = any([cp.vl["BCM_1"]["DOOR_OPEN_FL"], @@ -76,6 +74,16 @@ class CarState(CarStateBase): unit=1, ) + # Buttons + for button in BUTTONS: + state = (cp.vl[button.can_addr][button.can_msg] in button.values) + if self.button_states[button.event_type] != state: + event = car.CarState.ButtonEvent.new_message() + event.type = button.event_type + event.pressed = state + self.button_events.append(event) + self.button_states[button.event_type] = state + # button presses ret.leftBlinker, ret.rightBlinker = ret.leftBlinkerOn, ret.rightBlinkerOn = self.update_blinker_from_stalk(200, cp.vl["STEERING_LEVERS"]["TURN_SIGNALS"] == 1, cp.vl["STEERING_LEVERS"]["TURN_SIGNALS"] == 2) @@ -116,11 +124,6 @@ class CarState(CarStateBase): ret.leftBlindspot = cp.vl["BSM_1"]["LEFT_STATUS"] == 1 ret.rightBlindspot = cp.vl["BSM_1"]["RIGHT_STATUS"] == 1 - self.buttonStates["accelCruise"] = bool(cp.vl["CRUISE_BUTTONS"]["ACC_Accel"]) - self.buttonStates["decelCruise"] = bool(cp.vl["CRUISE_BUTTONS"]["ACC_Decel"]) - self.buttonStates["cancel"] = bool(cp.vl["CRUISE_BUTTONS"]["ACC_Cancel"]) - self.buttonStates["resumeCruise"] = bool(cp.vl["CRUISE_BUTTONS"]["ACC_Resume"]) - self.lkas_car_model = cp_cam.vl["DAS_6"]["CAR_MODEL"] self.button_counter = cp.vl["CRUISE_BUTTONS"]["COUNTER"] self.cruise_buttons = cp.vl["CRUISE_BUTTONS"] diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index d09fa7ac56..d4911375e7 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 from cereal import car from panda import Panda -from openpilot.selfdrive.car import create_button_events, get_safety_config, create_mads_event -from openpilot.selfdrive.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags, ChryslerFlagsSP, BUTTON_STATES +from openpilot.selfdrive.car import create_button_events, get_safety_config +from openpilot.selfdrive.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags, ChryslerFlagsSP from openpilot.selfdrive.car.interfaces import CarInterfaceBase ButtonType = car.CarState.ButtonEvent.Type @@ -13,7 +13,6 @@ GearShifter = car.CarState.GearShifter class CarInterface(CarInterfaceBase): def __init__(self, CP, CarController, CarState): super().__init__(CP, CarController, CarState) - self.buttonStatesPrev = BUTTON_STATES.copy() @staticmethod def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): @@ -94,19 +93,12 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_cam) self.sp_update_params() - buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}) - - for button in self.CS.buttonStates: - if self.CS.buttonStates[button] != self.buttonStatesPrev[button]: - be = car.CarState.ButtonEvent.new_message() - be.type = button - be.pressed = self.CS.buttonStates[button] - buttonEvents.append(be) + self.CS.button_events.extend(create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})) self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled, - buttonEvents, c.vCruise, + self.CS.button_events, c.vCruise, enable_buttons=(ButtonType.accelCruise, ButtonType.decelCruise, ButtonType.resumeCruise) if not self.CP.pcmCruiseSpeed else (ButtonType.accelCruise, ButtonType.decelCruise), resume_button=(ButtonType.resumeCruise,) if not self.CP.pcmCruiseSpeed else @@ -125,7 +117,7 @@ class CarInterface(CarInterfaceBase): self.CS.madsEnabled = self.get_sp_started_mads(ret, self.CS) if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0) or not self.CP.pcmCruiseSpeed: - if any(b.type == ButtonType.cancel for b in buttonEvents): + if any(b.type == ButtonType.cancel for b in self.CS.button_events): self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled) if self.get_sp_pedal_disengage(ret): self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled) @@ -143,17 +135,10 @@ class CarInterface(CarInterfaceBase): ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(self.CS.distance_button)) - # MADS BUTTON - if self.CS.out.madsEnabled != self.CS.madsEnabled: - if self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = False - else: - if not self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = True - - ret.buttonEvents = buttonEvents + ret.buttonEvents = [ + *self.CS.button_events, + *self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON + ] # events events = self.create_common_events(ret, c, extra_gears=[car.CarState.GearShifter.low], pcm_enable=False) @@ -180,6 +165,4 @@ class CarInterface(CarInterfaceBase): ret.events = events.to_msg() - self.buttonStatesPrev = self.CS.buttonStates.copy() - return ret diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 85835d453a..c681040023 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -1,3 +1,4 @@ +from collections import namedtuple from enum import IntFlag from dataclasses import dataclass, field @@ -8,6 +9,7 @@ from openpilot.selfdrive.car.docs_definitions import CarHarness, CarDocs, CarPar from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16 Ecu = car.CarParams.Ecu +Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values']) class ChryslerFlags(IntFlag): @@ -113,12 +115,12 @@ class CarControllerParams: self.STEER_MAX = 261 # higher than this faults the EPS -BUTTON_STATES = { - "accelCruise": False, - "decelCruise": False, - "cancel": False, - "resumeCruise": False, -} +BUTTONS = [ + Button(car.CarState.ButtonEvent.Type.accelCruise, "CRUISE_BUTTONS", "ACC_Accel", [1]), + Button(car.CarState.ButtonEvent.Type.decelCruise, "CRUISE_BUTTONS", "ACC_Decel", [1]), + Button(car.CarState.ButtonEvent.Type.cancel, "CRUISE_BUTTONS", "ACC_Cancel", [1]), + Button(car.CarState.ButtonEvent.Type.resumeCruise, "CRUISE_BUTTONS", "ACC_Resume", [1]), +] STEER_THRESHOLD = 120 diff --git a/selfdrive/car/ford/carstate.py b/selfdrive/car/ford/carstate.py index 21e2f12def..e52454f81d 100644 --- a/selfdrive/car/ford/carstate.py +++ b/selfdrive/car/ford/carstate.py @@ -3,7 +3,7 @@ from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser from openpilot.common.conversions import Conversions as CV from openpilot.selfdrive.car.ford.fordcan import CanBus -from openpilot.selfdrive.car.ford.values import DBC, CarControllerParams, FordFlags, BUTTON_STATES +from openpilot.selfdrive.car.ford.values import DBC, CarControllerParams, FordFlags, BUTTONS from openpilot.selfdrive.car.interfaces import CarStateBase GearShifter = car.CarState.GearShifter @@ -24,15 +24,14 @@ class CarState(CarStateBase): self.lkas_enabled = None self.prev_lkas_enabled = None - self.buttonStates = BUTTON_STATES.copy() - self.buttonStatesPrev = BUTTON_STATES.copy() + + self.button_states = {button.event_type: False for button in BUTTONS} def update(self, cp, cp_cam): ret = car.CarState.new_message() self.prev_mads_enabled = self.mads_enabled self.prev_lkas_enabled = self.lkas_enabled - self.buttonStatesPrev = self.buttonStates.copy() # Occasionally on startup, the ABS module recalibrates the steering pinion offset, so we need to block engagement # The vehicle usually recovers out of this state within a minute of normal driving @@ -87,6 +86,16 @@ class CarState(CarStateBase): else: ret.gearShifter = GearShifter.drive + # Buttons + for button in BUTTONS: + state = (cp.vl[button.can_addr][button.can_msg] in button.values) + if self.button_states[button.event_type] != state: + event = car.CarState.ButtonEvent.new_message() + event.type = button.event_type + event.pressed = state + self.button_events.append(event) + self.button_states[button.event_type] = state + # safety ret.stockFcw = bool(cp_cam.vl["ACCDATA_3"]["FcwVisblWarn_B_Rq"]) ret.stockAeb = bool(cp_cam.vl["ACCDATA_2"]["CmbbBrkDecel_B_Rq"]) @@ -112,13 +121,6 @@ class CarState(CarStateBase): self.lkas_enabled = bool(cp.vl["Steering_Data_FD1"]["TjaButtnOnOffPress"]) - self.buttonStates["accelCruise"] = bool(cp.vl["Steering_Data_FD1"]["CcAslButtnSetIncPress"]) - self.buttonStates["decelCruise"] = bool(cp.vl["Steering_Data_FD1"]["CcAslButtnSetDecPress"]) - self.buttonStates["cancel"] = bool(cp.vl["Steering_Data_FD1"]["CcAslButtnCnclPress"]) - self.buttonStates["setCruise"] = bool(cp.vl["Steering_Data_FD1"]["CcAslButtnSetPress"]) - self.buttonStates["resumeCruise"] = bool(cp.vl["Steering_Data_FD1"]["CcAsllButtnResPress"]) - self.buttonStates["gapAdjustCruise"] = bool(cp.vl["Steering_Data_FD1"]["AccButtnGapTogglePress"]) - # Stock steering buttons so that we can passthru blinkers etc. self.buttons_stock_values = cp.vl["Steering_Data_FD1"] # Stock values from IPMA so that we can retain some stock functionality diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 0c3449dc14..18dd7b4fa3 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -1,9 +1,9 @@ from cereal import car from panda import Panda from openpilot.common.conversions import Conversions as CV -from openpilot.selfdrive.car import create_button_events, get_safety_config, create_mads_event +from openpilot.selfdrive.car import create_button_events, get_safety_config from openpilot.selfdrive.car.ford.fordcan import CanBus -from openpilot.selfdrive.car.ford.values import Ecu, FordFlags, BUTTON_STATES +from openpilot.selfdrive.car.ford.values import Ecu, FordFlags from openpilot.selfdrive.car.interfaces import CarInterfaceBase ButtonType = car.CarState.ButtonEvent.Type @@ -15,8 +15,6 @@ class CarInterface(CarInterfaceBase): def __init__(self, CP, CarController, CarState): super().__init__(CP, CarController, CarState) - self.buttonStatesPrev = BUTTON_STATES.copy() - @staticmethod def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): ret.carName = "ford" @@ -76,19 +74,12 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_cam) self.sp_update_params() - buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}) - - for button in self.CS.buttonStates: - if self.CS.buttonStates[button] != self.buttonStatesPrev[button]: - be = car.CarState.ButtonEvent.new_message() - be.type = button - be.pressed = self.CS.buttonStates[button] - buttonEvents.append(be) + self.CS.button_events.extend(create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})) self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled, - buttonEvents, c.vCruise) + self.CS.button_events, c.vCruise) if ret.cruiseState.available: if self.enable_mads: @@ -101,7 +92,7 @@ class CarInterface(CarInterfaceBase): self.CS.madsEnabled = False if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0): - if any(b.type == ButtonType.cancel for b in buttonEvents): + if any(b.type == ButtonType.cancel for b in self.CS.button_events): self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled) if self.get_sp_pedal_disengage(ret): self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled) @@ -114,16 +105,10 @@ class CarInterface(CarInterfaceBase): ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(self.CS.distance_button)) - if self.CS.out.madsEnabled != self.CS.madsEnabled: - if self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = False - else: - if not self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = True - - ret.buttonEvents = buttonEvents + ret.buttonEvents = [ + *self.CS.button_events, + *self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON + ] events = self.create_common_events(ret, c, extra_gears=[GearShifter.manumatic], pcm_enable=False) @@ -134,7 +119,4 @@ class CarInterface(CarInterfaceBase): ret.events = events.to_msg() - # update previous car states - self.buttonStatesPrev = self.CS.buttonStates.copy() - return ret diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index edfee3ea1b..04bd592e22 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -1,5 +1,6 @@ import copy import re +from collections import namedtuple from dataclasses import dataclass, field, replace from enum import Enum, IntFlag @@ -11,6 +12,7 @@ from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, Ca from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, LiveFwVersions, OfflineFwVersions, Request, StdQueries, p16 Ecu = car.CarParams.Ecu +Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values']) class CarControllerParams: @@ -46,16 +48,6 @@ class FordFlags(IntFlag): CANFD = 1 -BUTTON_STATES = { - "accelCruise": False, - "decelCruise": False, - "cancel": False, - "setCruise": False, - "resumeCruise": False, - "gapAdjustCruise": False -} - - class RADAR: DELPHI_ESR = 'ford_fusion_2018_adas' DELPHI_MRR = 'FORD_CADS' @@ -154,6 +146,15 @@ class CAR(Platforms): ) +BUTTONS = [ + Button(car.CarState.ButtonEvent.Type.accelCruise, "Steering_Data_FD1", "CcAslButtnSetIncPress", [1]), + Button(car.CarState.ButtonEvent.Type.decelCruise, "Steering_Data_FD1", "CcAslButtnSetDecPress", [1]), + Button(car.CarState.ButtonEvent.Type.cancel, "Steering_Data_FD1", "CcAslButtnCnclPress", [1]), + Button(car.CarState.ButtonEvent.Type.setCruise, "Steering_Data_FD1", "CcAslButtnSetPress", [1]), + Button(car.CarState.ButtonEvent.Type.resumeCruise, "Steering_Data_FD1", "CcAsllButtnResPress", [1]), +] + + # FW response contains a combined software and part number # A-Z except no I, O or W # e.g. NZ6A-14C204-AAA diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 22a8d619a6..0e428bc13b 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -6,7 +6,7 @@ from panda import Panda from openpilot.common.basedir import BASEDIR from openpilot.common.conversions import Conversions as CV -from openpilot.selfdrive.car import create_button_events, get_safety_config, create_mads_event +from openpilot.selfdrive.car import create_button_events, get_safety_config from openpilot.selfdrive.car.gm.radar_interface import RADAR_HEADER_MSG from openpilot.selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, CanBus from openpilot.selfdrive.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, FRICTION_THRESHOLD, LatControlInputs, NanoFFModel @@ -206,12 +206,11 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_cam, self.cp_loopback) self.sp_update_params() - buttonEvents = [] distance_button = 0 # Don't add event if transitioning from INIT, unless it's to an actual button if self.CS.cruise_buttons != CruiseButtons.UNPRESS or self.CS.prev_cruise_buttons != CruiseButtons.INIT: - buttonEvents = [ + self.CS.button_events = [ *create_button_events(self.CS.cruise_buttons, self.CS.prev_cruise_buttons, BUTTONS_DICT, unpressed_btn=CruiseButtons.UNPRESS), *create_button_events(self.CS.distance_button, self.CS.prev_distance_button, @@ -222,11 +221,11 @@ class CarInterface(CarInterfaceBase): self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) if not self.CP.pcmCruise: - if any(b.type == ButtonType.accelCruise and b.pressed for b in buttonEvents): + if any(b.type == ButtonType.accelCruise and b.pressed for b in self.CS.button_events): self.CS.accEnabled = True self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled, - buttonEvents, c.vCruise) + self.CS.button_events, c.vCruise) if ret.cruiseState.available: if self.enable_mads: @@ -239,7 +238,7 @@ class CarInterface(CarInterfaceBase): self.CS.madsEnabled = False if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0): - if any(b.type == ButtonType.cancel for b in buttonEvents): + if any(b.type == ButtonType.cancel for b in self.CS.button_events): self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled) if self.get_sp_pedal_disengage(ret): self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled) @@ -252,17 +251,10 @@ class CarInterface(CarInterfaceBase): ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(distance_button)) - # MADS BUTTON - if self.CS.out.madsEnabled != self.CS.madsEnabled: - if self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = False - else: - if not self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = True - - ret.buttonEvents = buttonEvents + ret.buttonEvents = [ + *self.CS.button_events, + *self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON + ] # The ECM allows enabling on falling edge of set, but only rising edge of resume events = self.create_common_events(ret, c, extra_gears=[GearShifter.sport, GearShifter.low, diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 457b095e6a..72ab68647f 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -268,7 +268,7 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_cam, self.cp_body) self.sp_update_params() - buttonEvents = [ + self.CS.button_events = [ *create_button_events(self.CS.cruise_buttons, self.CS.prev_cruise_buttons, BUTTONS_DICT), *create_button_events(self.CS.cruise_setting, self.CS.prev_cruise_setting, SETTINGS_BUTTONS_DICT), ] @@ -276,7 +276,7 @@ class CarInterface(CarInterfaceBase): self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled, - buttonEvents, c.vCruise) + self.CS.button_events, c.vCruise) if ret.cruiseState.available: if self.enable_mads: @@ -289,7 +289,7 @@ class CarInterface(CarInterfaceBase): self.CS.madsEnabled = False if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0) or not self.CP.pcmCruiseSpeed: - if any(b.type == ButtonType.cancel for b in buttonEvents): + if any(b.type == ButtonType.cancel for b in self.CS.button_events): self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled) if self.get_sp_pedal_disengage(ret): self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled) @@ -304,7 +304,10 @@ class CarInterface(CarInterfaceBase): min_enable_speed_pcm=(self.CP.pcmCruise and self.CP.minEnableSpeed > 0 and self.CP.pcmCruiseSpeed), gap_button=(self.CS.cruise_setting == 3)) - ret.buttonEvents = buttonEvents + ret.buttonEvents = [ + *self.CS.button_events, + *self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON + ] # events events = self.create_common_events(ret, c, extra_gears=[GearShifter.sport, GearShifter.low], pcm_enable=False) diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index e801b47771..dbe0b62895 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -7,7 +7,7 @@ from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, HyundaiFlagsSP, CANFD_UNSUPPORTED_LONGITUDINAL_CAR, NON_SCC_CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, \ UNSUPPORTED_LONGITUDINAL_CAR, Buttons from openpilot.selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR -from openpilot.selfdrive.car import create_button_events, get_safety_config, create_mads_event +from openpilot.selfdrive.car import create_button_events, get_safety_config from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.disable_ecu import disable_ecu @@ -205,10 +205,10 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_cam) self.sp_update_params() - buttonEvents = create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT) + self.CS.button_events = create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT) self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled, - buttonEvents, c.vCruise) + self.CS.button_events, c.vCruise) self.CS.mads_enabled = False if not self.mads_main_toggle else self.CS.mads_enabled @@ -231,7 +231,7 @@ class CarInterface(CarInterfaceBase): if not self.CP.pcmCruise or not self.CP.pcmCruiseSpeed: if not self.CP.pcmCruise: - if any(b.type == ButtonType.cancel for b in buttonEvents): + if any(b.type == ButtonType.cancel for b in self.CS.button_events): self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled) if not self.CP.pcmCruiseSpeed: if not ret.cruiseState.enabled: @@ -242,17 +242,10 @@ class CarInterface(CarInterfaceBase): ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=(self.CS.cruise_buttons[-1] == 3)) - # MADS BUTTON - if self.CS.out.madsEnabled != self.CS.madsEnabled: - if self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = False - else: - if not self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = True - - ret.buttonEvents = buttonEvents + ret.buttonEvents = [ + *self.CS.button_events, + *self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON + ] # On some newer model years, the CANCEL button acts as a pause/resume button based on the PCM state # To avoid re-engaging when openpilot cancels, check user engagement intention via buttons diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 5fe64832c8..b8ca13ec86 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -1,3 +1,4 @@ +import capnp import json import os import numpy as np @@ -17,7 +18,7 @@ from openpilot.common.simple_kalman import KF1D, get_kalman_gain from openpilot.common.numpy_fast import clip from openpilot.common.params import Params from openpilot.common.realtime import DT_CTRL -from openpilot.selfdrive.car import apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, STD_CARGO_KG +from openpilot.selfdrive.car import apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, STD_CARGO_KG, ButtonEvents from openpilot.selfdrive.car.values import PLATFORMS from openpilot.selfdrive.controls.lib.desire_helper import get_min_lateral_speed from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, V_CRUISE_UNSET, get_friction @@ -253,6 +254,7 @@ class CarInterfaceBase(ABC): self.last_mads_init = 0. self.madsEnabledInit = False self.madsEnabledInitPrev = False + self.button_events = ButtonEvents() self.lat_torque_nn_model = None eps_firmware = str(next((fw.fwVersion for fw in CP.carFw if fw.ecu == "eps"), "")) @@ -425,6 +427,8 @@ class CarInterfaceBase(ABC): if cp is not None: cp.update_strings(can_strings) + self.CS.button_events = [] + # get CarState ret = self._update(c) @@ -780,6 +784,8 @@ class CarStateBase(ABC): self.prev_mads_enabled = False self.control_initialized = False + self.button_events: list[capnp.lib.capnp._DynamicStructBuilder] = [] + Q = [[0.0, 0.0], [0.0, 100.0]] R = 0.3 A = [[1.0, DT_CTRL], [0.0, 1.0]] diff --git a/selfdrive/car/mazda/carcontroller.py b/selfdrive/car/mazda/carcontroller.py index 9832cebe46..368198e1c8 100644 --- a/selfdrive/car/mazda/carcontroller.py +++ b/selfdrive/car/mazda/carcontroller.py @@ -11,8 +11,7 @@ from openpilot.selfdrive.car.mazda.values import CarControllerParams, Buttons from openpilot.selfdrive.controls.lib.drive_helpers import MAZDA_V_CRUISE_MIN VisualAlert = car.CarControl.HUDControl.VisualAlert - -BUTTONS_STATES = ["accelCruise", "decelCruise", "cancel", "resumeCruise"] +ButtonType = car.CarState.ButtonEvent.Type class CarController(CarControllerBase): @@ -141,8 +140,10 @@ class CarController(CarControllerBase): # multikyd methods, sunnyhaibin logic def get_cruise_buttons_status(self, CS): if not CS.out.cruiseState.enabled: - if any(CS.buttonStates[button_state] for button_state in BUTTONS_STATES): - self.timer = 40 + for be in CS.out.buttonEvents: + if be.type in (ButtonType.accelCruise, ButtonType.resumeCruise, + ButtonType.decelCruise, ButtonType.setCruise) and be.pressed: + self.timer = 40 elif self.timer: self.timer -= 1 else: diff --git a/selfdrive/car/mazda/carstate.py b/selfdrive/car/mazda/carstate.py index dea768c03a..e5808238f8 100644 --- a/selfdrive/car/mazda/carstate.py +++ b/selfdrive/car/mazda/carstate.py @@ -3,7 +3,7 @@ from openpilot.common.conversions import Conversions as CV from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser from openpilot.selfdrive.car.interfaces import CarStateBase -from openpilot.selfdrive.car.mazda.values import DBC, LKAS_LIMITS, MazdaFlags, BUTTON_STATES +from openpilot.selfdrive.car.mazda.values import DBC, LKAS_LIMITS, MazdaFlags, BUTTONS class CarState(CarStateBase): def __init__(self, CP): @@ -24,8 +24,7 @@ class CarState(CarStateBase): self.lkas_enabled = False self.prev_lkas_enabled = False - self.buttonStates = BUTTON_STATES.copy() - self.buttonStatesPrev = BUTTON_STATES.copy() + self.button_states = {button.event_type: False for button in BUTTONS} def update(self, cp, cp_cam): @@ -36,7 +35,6 @@ class CarState(CarStateBase): self.prev_mads_enabled = self.mads_enabled self.prev_lkas_enabled = self.lkas_enabled - self.buttonStatesPrev = self.buttonStates.copy() ret.wheelSpeeds = self.get_wheel_speeds( cp.vl["WHEEL_SPEEDS"]["FL"], @@ -56,6 +54,16 @@ class CarState(CarStateBase): can_gear = int(cp.vl["GEAR"]["GEAR"]) ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(can_gear, None)) + # Buttons + for button in BUTTONS: + state = (cp.vl[button.can_addr][button.can_msg] in button.values) + if self.button_states[button.event_type] != state: + event = car.CarState.ButtonEvent.new_message() + event.type = button.event_type + event.pressed = state + self.button_events.append(event) + self.button_states[button.event_type] = state + ret.genericToggle = bool(cp.vl["BLINK_INFO"]["HIGH_BEAMS"]) ret.leftBlindspot = cp.vl["BSM"]["LEFT_BS_STATUS"] != 0 ret.rightBlindspot = cp.vl["BSM"]["RIGHT_BS_STATUS"] != 0 @@ -114,11 +122,6 @@ class CarState(CarStateBase): self.acc_active_last = ret.cruiseState.enabled - self.buttonStates["accelCruise"] = bool(cp.vl["CRZ_BTNS"]["SET_P"]) - self.buttonStates["decelCruise"] = bool(cp.vl["CRZ_BTNS"]["SET_M"]) - self.buttonStates["cancel"] = bool(cp.vl["CRZ_BTNS"]["CAN_OFF"]) - self.buttonStates["resumeCruise"] = bool(cp.vl["CRZ_BTNS"]["RES"]) - self.crz_btns_counter = cp.vl["CRZ_BTNS"]["CTR"] # camera signals diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py index bb9a3f93a0..9447803ae6 100755 --- a/selfdrive/car/mazda/interface.py +++ b/selfdrive/car/mazda/interface.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 from cereal import car from openpilot.common.conversions import Conversions as CV -from openpilot.selfdrive.car.mazda.values import CAR, LKAS_LIMITS, BUTTON_STATES -from openpilot.selfdrive.car import create_button_events, get_safety_config, create_mads_event +from openpilot.selfdrive.car.mazda.values import CAR, LKAS_LIMITS +from openpilot.selfdrive.car import create_button_events, get_safety_config from openpilot.selfdrive.car.interfaces import CarInterfaceBase ButtonType = car.CarState.ButtonEvent.Type @@ -12,7 +12,6 @@ GearShifter = car.CarState.GearShifter class CarInterface(CarInterfaceBase): def __init__(self, CP, CarController, CarState): super().__init__(CP, CarController, CarState) - self.buttonStatesPrev = BUTTON_STATES.copy() @staticmethod def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): @@ -41,19 +40,15 @@ class CarInterface(CarInterfaceBase): self.sp_update_params() # TODO: add button types for inc and dec - buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}) - - for button in self.CS.buttonStates: - if self.CS.buttonStates[button] != self.buttonStatesPrev[button]: - be = car.CarState.ButtonEvent.new_message() - be.type = button - be.pressed = self.CS.buttonStates[button] - buttonEvents.append(be) + self.CS.button_events = [ + *self.CS.button_events, + *create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}) + ] self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled, - buttonEvents, c.vCruise) + self.CS.button_events, c.vCruise) if ret.cruiseState.available: if self.enable_mads: @@ -66,7 +61,7 @@ class CarInterface(CarInterfaceBase): self.CS.madsEnabled = False if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0) or not self.CP.pcmCruiseSpeed: - if any(b.type == ButtonType.cancel for b in buttonEvents): + if any(b.type == ButtonType.cancel for b in self.CS.button_events): self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled) if self.get_sp_pedal_disengage(ret): self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled) @@ -79,17 +74,10 @@ class CarInterface(CarInterfaceBase): ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(self.CS.distance_button)) - # MADS BUTTON - if self.CS.out.madsEnabled != self.CS.madsEnabled: - if self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = False - else: - if not self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = True - - ret.buttonEvents = buttonEvents + ret.buttonEvents = [ + *self.CS.button_events, + *self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON + ] # events events = self.create_common_events(ret, c, extra_gears=[GearShifter.sport, GearShifter.low, GearShifter.brake], @@ -108,6 +96,4 @@ class CarInterface(CarInterfaceBase): ret.events = events.to_msg() - self.buttonStatesPrev = self.CS.buttonStates.copy() - return ret diff --git a/selfdrive/car/mazda/values.py b/selfdrive/car/mazda/values.py index 2aac951dbb..2889cbb7b2 100644 --- a/selfdrive/car/mazda/values.py +++ b/selfdrive/car/mazda/values.py @@ -1,3 +1,4 @@ +from collections import namedtuple from dataclasses import dataclass, field from enum import IntFlag @@ -8,6 +9,7 @@ from openpilot.selfdrive.car.docs_definitions import CarHarness, CarDocs, CarPar from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = car.CarParams.Ecu +Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values']) # Steer torque limits @@ -26,14 +28,6 @@ class CarControllerParams: pass -BUTTON_STATES = { - "accelCruise": False, - "decelCruise": False, - "cancel": False, - "resumeCruise": False, -} - - @dataclass class MazdaCarDocs(CarDocs): package: str = "All" @@ -98,6 +92,14 @@ class Buttons: CANCEL = 4 +BUTTONS = [ + Button(car.CarState.ButtonEvent.Type.accelCruise, "CRZ_BTNS", "SET_P", [1]), + Button(car.CarState.ButtonEvent.Type.decelCruise, "CRZ_BTNS", "SET_M", [1]), + Button(car.CarState.ButtonEvent.Type.cancel, "CRZ_BTNS", "CAN_OFF", [1]), + Button(car.CarState.ButtonEvent.Type.resumeCruise, "CRZ_BTNS", "RES", [1]), +] + + FW_QUERY_CONFIG = FwQueryConfig( requests=[ # TODO: check data to ensure ABS does not skip ISO-TP frames on bus 0 diff --git a/selfdrive/car/nissan/interface.py b/selfdrive/car/nissan/interface.py index 3d744a41a0..4a9e5a9125 100644 --- a/selfdrive/car/nissan/interface.py +++ b/selfdrive/car/nissan/interface.py @@ -1,6 +1,6 @@ from cereal import car from panda import Panda -from openpilot.selfdrive.car import create_button_events, get_safety_config, create_mads_event +from openpilot.selfdrive.car import create_button_events, get_safety_config from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.nissan.values import CAR @@ -34,7 +34,7 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_adas, self.cp_cam) self.sp_update_params() - buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}) + self.CS.button_events = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}) self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) @@ -53,24 +53,11 @@ class CarInterface(CarInterfaceBase): ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(self.CS.distance_button)) - # CANCEL - if self.CS.out.cruiseState.enabled and not ret.cruiseState.enabled: - be = car.CarState.ButtonEvent.new_message() - be.pressed = True - be.type = ButtonType.cancel - buttonEvents.append(be) - - # MADS BUTTON - if self.CS.out.madsEnabled != self.CS.madsEnabled: - if self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = False - else: - if not self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = True - - ret.buttonEvents = buttonEvents + ret.buttonEvents = [ + *self.CS.button_events, + *self.button_events.create_cancel_event(ret.cruiseState.enabled, self.CS.out.cruiseState.enabled), + *self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON + ] events = self.create_common_events(ret, c, extra_gears=[GearShifter.sport, GearShifter.low, GearShifter.brake], pcm_enable=False) diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index 744c017a96..7eefeb66eb 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -1,6 +1,6 @@ from cereal import car from panda import Panda -from openpilot.selfdrive.car import get_safety_config, create_mads_event +from openpilot.selfdrive.car import get_safety_config from openpilot.selfdrive.car.disable_ecu import disable_ecu from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.subaru.values import CAR, GLOBAL_ES_ADDR, SubaruFlags, SubaruFlagsSP @@ -118,8 +118,6 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_cam, self.cp_body) self.sp_update_params() - buttonEvents = [] - self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) if ret.cruiseState.available: @@ -145,24 +143,11 @@ class CarInterface(CarInterfaceBase): ret, self.CS = self.get_sp_common_state(ret, self.CS) - # CANCEL - if self.CS.out.cruiseState.enabled and not ret.cruiseState.enabled: - be = car.CarState.ButtonEvent.new_message() - be.pressed = True - be.type = ButtonType.cancel - buttonEvents.append(be) - - # MADS BUTTON - if self.CS.out.madsEnabled != self.CS.madsEnabled: - if self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = False - else: - if not self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = True - - ret.buttonEvents = buttonEvents + ret.buttonEvents = [ + *self.CS.button_events, + *self.button_events.create_cancel_event(ret.cruiseState.enabled, self.CS.out.cruiseState.enabled), + *self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON + ] events = self.create_common_events(ret, c, extra_gears=[GearShifter.sport, GearShifter.low], pcm_enable=False) diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 451265f9cd..d8b2516aba 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -5,7 +5,7 @@ from panda import Panda from panda.python import uds from openpilot.selfdrive.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, ToyotaFlagsSP, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \ MIN_ACC_SPEED, EPS_SCALE, UNSUPPORTED_DSU_CAR, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR -from openpilot.selfdrive.car import create_button_events, get_safety_config, create_mads_event +from openpilot.selfdrive.car import create_button_events, get_safety_config from openpilot.selfdrive.car.disable_ecu import disable_ecu from openpilot.selfdrive.car.interfaces import CarInterfaceBase @@ -212,11 +212,10 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_cam) self.sp_update_params() - buttonEvents = [] distance_button = 0 if self.CP.carFingerprint in (TSS2_CAR - RADAR_ACC_CAR) or (self.CP.flags & ToyotaFlags.SMART_DSU and not self.CP.flags & ToyotaFlags.RADAR_CAN_FILTER): - buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}) + self.CS.button_events = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}) distance_button = self.CS.distance_button self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) @@ -245,24 +244,11 @@ class CarInterface(CarInterfaceBase): ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(distance_button)) - # CANCEL - if self.CS.out.cruiseState.enabled and not ret.cruiseState.enabled: - be = car.CarState.ButtonEvent.new_message() - be.pressed = True - be.type = ButtonType.cancel - buttonEvents.append(be) - - # MADS BUTTON - if self.CS.out.madsEnabled != self.CS.madsEnabled: - if self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = False - else: - if not self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = True - - ret.buttonEvents = buttonEvents + ret.buttonEvents = [ + *self.CS.button_events, + *self.button_events.create_cancel_event(ret.cruiseState.enabled, self.CS.out.cruiseState.enabled), + *self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON + ] # events events = self.create_common_events(ret, c, extra_gears=[GearShifter.sport, GearShifter.low, GearShifter.brake], diff --git a/selfdrive/car/volkswagen/carstate.py b/selfdrive/car/volkswagen/carstate.py index 6ec27b8be0..1dc4c0e430 100644 --- a/selfdrive/car/volkswagen/carstate.py +++ b/selfdrive/car/volkswagen/carstate.py @@ -4,7 +4,7 @@ from openpilot.common.conversions import Conversions as CV from openpilot.selfdrive.car.interfaces import CarStateBase from opendbc.can.parser import CANParser from openpilot.selfdrive.car.volkswagen.values import DBC, CANBUS, NetworkLocation, TransmissionType, GearShifter, \ - CarControllerParams, VolkswagenFlags, BUTTON_STATES, VolkswagenFlagsSP + CarControllerParams, VolkswagenFlags, VolkswagenFlagsSP class CarState(CarStateBase): @@ -17,8 +17,6 @@ class CarState(CarStateBase): self.esp_hold_confirmation = False self.upscale_lead_car_signal = False self.eps_stock_values = False - self.buttonStates = BUTTON_STATES.copy() - self.buttonStatesPrev = BUTTON_STATES.copy() def create_button_events(self, pt_cp, buttons): button_events = [] @@ -41,7 +39,6 @@ class CarState(CarStateBase): ret = car.CarState.new_message() self.prev_mads_enabled = self.mads_enabled - self.buttonStatesPrev = self.buttonStates.copy() # Update vehicle speed and acceleration from ABS wheel speeds. ret.wheelSpeeds = self.get_wheel_speeds( @@ -150,18 +147,10 @@ class CarState(CarStateBase): if ret.cruiseState.speed > 90: ret.cruiseState.speed = 0 - # Update control button states for turn signals and ACC controls. - self.buttonStates["accelCruise"] = bool(pt_cp.vl["GRA_ACC_01"]["GRA_Tip_Hoch"]) - self.buttonStates["decelCruise"] = bool(pt_cp.vl["GRA_ACC_01"]["GRA_Tip_Runter"]) - self.buttonStates["cancel"] = bool(pt_cp.vl["GRA_ACC_01"]["GRA_Abbrechen"]) - self.buttonStates["setCruise"] = bool(pt_cp.vl["GRA_ACC_01"]["GRA_Tip_Setzen"]) - self.buttonStates["resumeCruise"] = bool(pt_cp.vl["GRA_ACC_01"]["GRA_Tip_Wiederaufnahme"]) - self.buttonStates["gapAdjustCruise"] = bool(pt_cp.vl["GRA_ACC_01"]["GRA_Verstellung_Zeitluecke"]) - # Update button states for turn signals and ACC controls, capture all ACC button state/config for passthrough ret.leftBlinker = ret.leftBlinkerOn = bool(pt_cp.vl["Blinkmodi_02"]["Comfort_Signal_Left"]) ret.rightBlinker = ret.rightBlinkerOn = bool(pt_cp.vl["Blinkmodi_02"]["Comfort_Signal_Right"]) - ret.buttonEvents = self.create_button_events(pt_cp, self.CCP.BUTTONS) + self.button_events = self.create_button_events(pt_cp, self.CCP.BUTTONS) self.gra_stock_values = pt_cp.vl["GRA_ACC_01"] # Additional safety checks performed in CarInterface. @@ -177,7 +166,6 @@ class CarState(CarStateBase): ret = car.CarState.new_message() self.prev_mads_enabled = self.mads_enabled - self.buttonStatesPrev = self.buttonStates.copy() # Update vehicle speed and acceleration from ABS wheel speeds. ret.wheelSpeeds = self.get_wheel_speeds( @@ -265,18 +253,10 @@ class CarState(CarStateBase): if ret.cruiseState.speed > 70: # 255 kph in m/s == no current setpoint ret.cruiseState.speed = 0 - # Update control button states for turn signals and ACC controls. - self.buttonStates["accelCruise"] = bool(pt_cp.vl["GRA_Neu"]["GRA_Up_kurz"]) - self.buttonStates["decelCruise"] = bool(pt_cp.vl["GRA_Neu"]["GRA_Down_kurz"]) - self.buttonStates["cancel"] = bool(pt_cp.vl["GRA_Neu"]["GRA_Abbrechen"]) - self.buttonStates["setCruise"] = bool(pt_cp.vl["GRA_Neu"]["GRA_Neu_Setzen"]) - self.buttonStates["resumeCruise"] = bool(pt_cp.vl["GRA_Neu"]["GRA_Recall"]) - self.buttonStates["gapAdjustCruise"] = bool(pt_cp.vl["GRA_Neu"]["GRA_Zeitluecke"]) - # Update button states for turn signals and ACC controls, capture all ACC button state/config for passthrough ret.leftBlinker, ret.rightBlinker = ret.leftBlinkerOn, ret.rightBlinkerOn = self.update_blinker_from_stalk(300, pt_cp.vl["Gate_Komf_1"]["GK1_Blinker_li"], pt_cp.vl["Gate_Komf_1"]["GK1_Blinker_re"]) - ret.buttonEvents = self.create_button_events(pt_cp, self.CCP.BUTTONS) + self.button_events = self.create_button_events(pt_cp, self.CCP.BUTTONS) self.gra_stock_values = pt_cp.vl["GRA_Neu"] # Additional safety checks performed in CarInterface. diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index 31dea25cbb..d965cf2e8b 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -1,10 +1,10 @@ from cereal import car from panda import Panda from openpilot.common.params import Params -from openpilot.selfdrive.car import get_safety_config, create_mads_event +from openpilot.selfdrive.car import get_safety_config from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.volkswagen.values import CAR, CANBUS, CarControllerParams, NetworkLocation, TransmissionType, GearShifter, VolkswagenFlags, \ - BUTTON_STATES, VolkswagenFlagsSP + VolkswagenFlagsSP ButtonType = car.CarState.ButtonEvent.Type EventName = car.CarEvent.EventName @@ -21,8 +21,6 @@ class CarInterface(CarInterfaceBase): self.ext_bus = CANBUS.cam self.cp_ext = self.cp_cam - self.buttonStatesPrev = BUTTON_STATES.copy() - @staticmethod def _get_params(ret, candidate: CAR, fingerprint, car_fw, experimental_long, docs): ret.carName = "volkswagen" @@ -117,21 +115,10 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_cam, self.cp_ext, self.CP.transmissionType) self.sp_update_params() - buttonEvents = [] - - # Check for and process state-change events (button press or release) from - # the turn stalk switch or ACC steering wheel/control stalk buttons. - for button in self.CS.buttonStates: - if self.CS.buttonStates[button] != self.buttonStatesPrev[button]: - be = car.CarState.ButtonEvent.new_message() - be.type = button - be.pressed = self.CS.buttonStates[button] - buttonEvents.append(be) - self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled, - buttonEvents, c.vCruise, + self.CS.button_events, c.vCruise, enable_buttons=(ButtonType.setCruise, ButtonType.resumeCruise)) if ret.cruiseState.available: @@ -144,7 +131,7 @@ class CarInterface(CarInterfaceBase): self.CS.madsEnabled = self.get_sp_started_mads(ret, self.CS) if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0) or not self.CP.pcmCruiseSpeed: - if any(b.type == ButtonType.cancel for b in buttonEvents): + if any(b.type == ButtonType.cancel for b in self.CS.button_events): self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled) if self.get_sp_pedal_disengage(ret): self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled) @@ -155,19 +142,13 @@ class CarInterface(CarInterfaceBase): self.CS.accEnabled = False self.CS.accEnabled = ret.cruiseState.enabled or self.CS.accEnabled - ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(self.CS.buttonStates["gapAdjustCruise"])) + ret, self.CS = self.get_sp_common_state(ret, self.CS, + gap_button=any(b.type == ButtonType.gapAdjustCruise and b.pressed for b in self.CS.button_events)) - # MADS BUTTON - if self.CS.out.madsEnabled != self.CS.madsEnabled: - if self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = False - else: - if not self.mads_event_lock: - buttonEvents.append(create_mads_event(self.mads_event_lock)) - self.mads_event_lock = True - - ret.buttonEvents = buttonEvents + ret.buttonEvents = [ + *self.CS.button_events, + *self.button_events.create_mads_event(self.CS.madsEnabled, self.CS.out.madsEnabled) # MADS BUTTON + ] events = self.create_common_events(ret, c, extra_gears=[GearShifter.eco, GearShifter.sport, GearShifter.manumatic], pcm_enable=False, @@ -199,8 +180,4 @@ class CarInterface(CarInterfaceBase): ret.events = events.to_msg() - # update previous car states - self.buttonStatesPrev = self.CS.buttonStates.copy() - return ret - diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 2996db602f..80b7ca0b0b 100644 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -147,16 +147,6 @@ class VolkswagenFlagsSP(IntFlag): SP_CC_ONLY_NO_RADAR = 2 -BUTTON_STATES = { - "accelCruise": False, - "decelCruise": False, - "cancel": False, - "setCruise": False, - "resumeCruise": False, - "gapAdjustCruise": False -} - - @dataclass class VolkswagenMQBPlatformConfig(PlatformConfig): dbc_dict: DbcDict = field(default_factory=lambda: dbc_dict('vw_mqb_2010', None)) From c26fd9d7c0889055f5cc59d649551add35e92ab6 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Fri, 26 Jul 2024 09:24:27 +0000 Subject: [PATCH 143/229] Add new parameters for enabling GitLab runner and Sunnylink uploader --- .gitlab-ci.yml | 4 ++-- common/params.cc | 2 ++ system/manager/manager.py | 2 ++ system/manager/process_config.py | 25 ++++++++++++------------- system/manager/sunnylink.py | 5 +++++ 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index de50202454..2704a7bb28 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -29,13 +29,13 @@ default: - 'git config --global user.name "${GIT_CONFIG_USER_NAME}"' -workflow: # If running on any branch other than main, use the `aws-datacontracts-dev` account; otherwise use `aws-datacontracts` +workflow: # If running on any branch other than main. rules: # We are an MR, but it's a draft, we won't proceed with anything. - if: '$CI_MERGE_REQUEST_TITLE =~ /^wip:/i || $CI_MERGE_REQUEST_TITLE =~ /^draft:/i' when: never # We are a merge request - - if: $CI_MERGE_REQUEST_IID #|| $CI_COMMIT_REF_NAME == "gitlab-pipelines" # TBD once merged + - if: $CI_MERGE_REQUEST_IID variables: EXTRA_VERSION_IDENTIFIER: "-${CI_PIPELINE_IID}" NEW_BRANCH: ${CI_COMMIT_REF_NAME}-prebuilt diff --git a/common/params.cc b/common/params.cc index 054c5d2355..86f18a0a5e 100644 --- a/common/params.cc +++ b/common/params.cc @@ -336,6 +336,8 @@ std::unordered_map keys = { {"SunnylinkCache_Users", PERSISTENT}, {"SunnylinkCache_Roles", PERSISTENT}, + {"EnableGitlabRunner", PERSISTENT | BACKUP}, + {"EnableSunnylinkUploader", PERSISTENT | BACKUP}, // PFEIFER - MAPD {{ {"MapdVersion", PERSISTENT}, diff --git a/system/manager/manager.py b/system/manager/manager.py index 388198736c..032fc0a667 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -117,6 +117,8 @@ def manager_init() -> None: ("CustomDrivingModel", "0"), ("DrivingModelGeneration", "4"), ("LastSunnylinkPingTime", "0"), + ("EnableGitlabRunner", "0"), + ("EnableSunnylinkUploader", "0"), ] if not PC: default_params.append(("LastUpdateTime", datetime.datetime.now(datetime.UTC).replace(tzinfo=None).isoformat().encode('utf8'))) diff --git a/system/manager/process_config.py b/system/manager/process_config.py index 8818d3b851..a718ea021b 100644 --- a/system/manager/process_config.py +++ b/system/manager/process_config.py @@ -6,7 +6,7 @@ from openpilot.system.hardware import PC, TICI from openpilot.selfdrive.modeld.custom_model_metadata import CustomModelMetadata, ModelCapabilities from openpilot.system.manager.process import PythonProcess, NativeProcess, DaemonProcess from openpilot.system.mapd_manager import MAPD_PATH, COMMON_DIR -from openpilot.system.manager.sunnylink import sunnylink_need_register, sunnylink_ready +from openpilot.system.manager.sunnylink import sunnylink_need_register, sunnylink_ready, use_sunnylink_uploader WEBCAM = os.getenv("USE_WEBCAM") is not None @@ -44,6 +44,10 @@ def only_onroad(started: bool, params, CP: car.CarParams) -> bool: def only_offroad(started, params, CP: car.CarParams) -> bool: return not started +def use_gitlab_runner(started, params, CP: car.CarParams) -> bool: + return (not PC and params.get_bool("EnableGitlabRunner") and only_offroad(started, params, CP) + and os.path.exists("./gitlab_runner.sh")) + def model_use_nav(started, params, CP: car.CarParams) -> bool: custom_model_metadata = CustomModelMetadata(params=params, init_only=True) return started and custom_model_metadata.valid and custom_model_metadata.capabilities & ModelCapabilities.NoO @@ -56,6 +60,10 @@ def sunnylink_need_register_shim(started, params, CP: car.CarParams) -> bool: """Shim for sunnylink_need_register to match the process manager signature.""" return sunnylink_need_register(params) +def use_sunnylink_uploader_shim(started, params, CP: car.CarParams) -> bool: + """Shim for use_sunnylink_uploader to match the process manager signature.""" + return use_sunnylink_uploader(params) and os.path.exists("../loggerd/sunnylink_uploader.py") + procs = [ DaemonProcess("manage_athenad", "system.athena.manage_athenad", "AthenadPid"), @@ -112,21 +120,12 @@ procs = [ PythonProcess("webrtcd", "system.webrtc.webrtcd", notcar), PythonProcess("webjoystick", "tools.bodyteleop.web", notcar), + # Sunnypilot devs + NativeProcess("gitlab_runner_start", "system/manager", ["./gitlab_runner.sh", "start"], use_gitlab_runner, sigkill=False), # Sunnylink <3 DaemonProcess("manage_sunnylinkd", "system.athena.manage_sunnylinkd", "SunnylinkdPid"), PythonProcess("sunnylink_registration", "system.manager.sunnylink", sunnylink_need_register_shim), + PythonProcess("sunnylink_uploader", "system.loggerd.sunnylink_uploader", use_sunnylink_uploader_shim), ] -if os.path.exists("../loggerd/sunnylink_uploader.py"): - procs += [ - PythonProcess("sunnylink_uploader", "system.loggerd.sunnylink_uploader", sunnylink_ready_shim), - ] - -if os.path.exists("./gitlab_runner.sh") and not PC: - # Only devs! - procs += [ - NativeProcess("gitlab_runner_start", "system/manager", ["./gitlab_runner.sh", "start"], only_offroad, sigkill=False), - NativeProcess("gitlab_runner_stop", "system/manager", ["./gitlab_runner.sh", "stop"], only_onroad, sigkill=False) - ] - managed_processes = {p.name: p for p in procs} diff --git a/system/manager/sunnylink.py b/system/manager/sunnylink.py index 84161fb817..10a5f95a3d 100755 --- a/system/manager/sunnylink.py +++ b/system/manager/sunnylink.py @@ -27,6 +27,11 @@ def sunnylink_ready(params=Params()) -> bool: return is_sunnylink_enabled and is_registered +def use_sunnylink_uploader(params) -> bool: + """Check if the device is ready to use Sunnylink and the uploader is enabled.""" + return sunnylink_ready(params) and params.get_bool("EnableSunnylinkUploader") + + def sunnylink_need_register(params=Params()) -> bool: """Check if the device needs to be registered with Sunnylink.""" is_sunnylink_enabled, is_registered = get_sunnylink_status(params) From 7e31333b36066235801a077d9a39e5d1a5614635 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Mon, 29 Jul 2024 06:40:23 -0400 Subject: [PATCH 144/229] Add Custom MIT License --- LICENSE.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000000..e7062d77cf --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# Custom MIT License + +Copyright 2024 Haibin Wen, SUNNYPILOT LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to view and modify the Software, subject to the following conditions: + +1. **Permission Required**: Use of the Software, in whole or in part, for any purpose requires explicit written permission from the original author(s). + +2. **Redistribution**: Any redistribution of the Software, modified or unmodified, must retain this license notice and the following acknowledgment: + "This software is licensed under a custom license requiring permission for use." + +3. **Visibility**: Any project that uses the Software must visibly mention the following acknowledgment: + "This project uses software from Haibin Wen and SUNNYPILOT LLC and is licensed under a custom license requiring permission for use." + +4. **No Warranty**: The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Software or the use or other dealings in the Software. + +Contact sunnypilot Support for permission requests. + +--- + +Haibin Wen, SUNNYPILOT LLC From be72a8ed063cf5d595be0a30c9b7aa4da7027c1b Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Mon, 29 Jul 2024 06:26:22 -0400 Subject: [PATCH 145/229] Revert "Toyota: Auto Brake Hold" This reverts commit 15d94a01 --- CHANGELOGS.md | 3 - cereal/car.capnp | 1 - common/params.cc | 1 - panda | 2 +- selfdrive/car/card.py | 3 - selfdrive/car/toyota/carcontroller.py | 31 - selfdrive/car/toyota/carstate.py | 9 - selfdrive/car/toyota/interface.py | 8 - selfdrive/car/toyota/toyotacan.py | 34 - selfdrive/car/toyota/values.py | 1 - selfdrive/controls/lib/events.py | 8 - .../qt/offroad/sunnypilot/vehicle_settings.cc | 15 +- selfdrive/ui/translations/main_ar.ts | 2129 +++++++++++++++- selfdrive/ui/translations/main_de.ts | 2129 +++++++++++++++- selfdrive/ui/translations/main_es.ts | 2211 ++++++++++++++++- selfdrive/ui/translations/main_fr.ts | 2129 +++++++++++++++- selfdrive/ui/translations/main_ja.ts | 2129 +++++++++++++++- selfdrive/ui/translations/main_ko.ts | 2129 +++++++++++++++- selfdrive/ui/translations/main_pt-BR.ts | 2129 +++++++++++++++- selfdrive/ui/translations/main_th.ts | 2129 +++++++++++++++- selfdrive/ui/translations/main_tr.ts | 2125 +++++++++++++++- selfdrive/ui/translations/main_zh-CHS.ts | 2129 +++++++++++++++- selfdrive/ui/translations/main_zh-CHT.ts | 2129 +++++++++++++++- system/manager/manager.py | 1 - 24 files changed, 23383 insertions(+), 231 deletions(-) diff --git a/CHANGELOGS.md b/CHANGELOGS.md index 2fc99ab8d0..650d149843 100644 --- a/CHANGELOGS.md +++ b/CHANGELOGS.md @@ -32,9 +32,6 @@ sunnypilot - 0.9.8.0 (2024-xx-xx) * In response to the official deprecation of support for Smart DSU (SDSU) and Radar CAN Filter in the upstream ([commaai/openpilot#32777](https://github.com/commaai/openpilot/pull/32777)), sunnypilot will continue maintaining software support for Smart DSU (SDSU) and Radar CAN Filter * UPDATED: Continued support for Mapbox navigation * In response to the official temporary deprecation of support for Mapbox navigation in the upstream ([commaai/openpilot#32773](https://github.com/commaai/openpilot/pull/32773)), sunnypilot will continue maintaining software support for Mapbox navigation -* NEW❗: Toyota - Automatic Brake Hold (AHB) thanks to AlexandreSato! - * When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold - * NOTE: Only for Toyota/Lexus vehicles with TSS2/LSS2 * NEW❗: Toyota - Automatic Door Locking and Unlocking thanks to AlexandreSato, cydia2020, and dragonpilot-community! * Auto Lock by Speed: All doors are automatically locked when vehicle speed is approximately 6 mph (10 km/h) or higher * Auto Unlock by Shift to P: All doors are automatically unlocked when shifting the shift lever to P diff --git a/cereal/car.capnp b/cereal/car.capnp index 0ee2be7499..e77e8c2943 100644 --- a/cereal/car.capnp +++ b/cereal/car.capnp @@ -137,7 +137,6 @@ struct CarEvent @0x9b1657f34caf3ad3 { speedLimitPreActive @139; speedLimitConfirmed @140; torqueNNLoad @141; - spAutoBrakeHold @142; radarCanErrorDEPRECATED @15; communityFeatureDisallowedDEPRECATED @62; diff --git a/common/params.cc b/common/params.cc index 86f18a0a5e..7d12b9937e 100644 --- a/common/params.cc +++ b/common/params.cc @@ -318,7 +318,6 @@ std::unordered_map keys = { {"TorqueFriction", PERSISTENT | BACKUP}, {"TorqueMaxLatAccel", PERSISTENT | BACKUP}, {"TorquedOverride", PERSISTENT | BACKUP}, - {"ToyotaAutoHold", PERSISTENT | BACKUP}, {"ToyotaAutoLockBySpeed", PERSISTENT | BACKUP}, {"ToyotaAutoUnlockByShifter", PERSISTENT | BACKUP}, {"ToyotaEnhancedBsm", PERSISTENT | BACKUP}, diff --git a/panda b/panda index ff1ef85735..5d92bdc6de 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit ff1ef85735c053529a840436d33ab5f16840724e +Subproject commit 5d92bdc6dee1f1bba5062f551bf6938f40723d81 diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index 63e7d22da4..98be4bf82f 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -56,7 +56,6 @@ class Car: self.mads_disengage_lateral_on_brake = self.params.get_bool("DisengageLateralOnBrake") self.mads_dlob = self.enable_mads and self.mads_disengage_lateral_on_brake self.mads_ndlob = self.enable_mads and not self.mads_disengage_lateral_on_brake - self.sp_toyota_auto_brake_hold = self.params.get_bool("ToyotaAutoHold") self.CP.alternativeExperience = 0 if not self.disengage_on_accelerator: self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS @@ -64,8 +63,6 @@ class Car: self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.ENABLE_MADS elif self.mads_ndlob: self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.MADS_DISABLE_DISENGAGE_LATERAL_ON_BRAKE - if self.sp_toyota_auto_brake_hold: - self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.ALLOW_AEB if self.CP.customStockLongAvailable and self.CP.pcmCruise and self.params.get_bool("CustomStockLong"): self.CP.pcmCruiseSpeed = False diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 210ae23fa1..89f5992961 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -61,12 +61,6 @@ class CarController(CarControllerBase): self.right_blindspot_debug_enabled = False self.last_blindspot_frame = 0 - if CP.spFlags & ToyotaFlagsSP.SP_AUTO_BRAKE_HOLD: - self.brake_hold_active: bool = False - self._brake_hold_counter: int = 0 - self._brake_hold_reset: bool = False - self._prev_brake_pressed: bool = False - self._auto_lock_by_speed = self.param_s.get_bool("ToyotaAutoLockBySpeed") self._auto_unlock_by_shifter = self.param_s.get_bool("ToyotaAutoUnlockByShifter") self._auto_lock_speed = 10 * (CV.KPH_TO_MS if self._is_metric else CV.MPH_TO_MS) @@ -187,9 +181,6 @@ class CarController(CarControllerBase): self.last_standstill = CS.out.standstill - if self.CP.spFlags & ToyotaFlagsSP.SP_AUTO_BRAKE_HOLD: - can_sends.extend(self.create_auto_brake_hold_messages(CS)) - # handle UI messages fcw_alert = hud_control.visualAlert == VisualAlert.fcw steer_alert = hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) @@ -308,25 +299,3 @@ class CarController(CarControllerBase): # print("bsm poll right") return can_sends - - # auto brake hold (https://github.com/AlexandreSato/) - def create_auto_brake_hold_messages(self, CS: car.CarState, brake_hold_allowed_timer: int = 100): - can_sends = [] - disallowed_gears = [GearShifter.park, GearShifter.reverse] - brake_hold_allowed = CS.out.standstill and CS.out.cruiseState.available and not CS.out.gasPressed and \ - not CS.out.cruiseState.enabled and (CS.out.gearShifter not in disallowed_gears) - - if brake_hold_allowed: - self._brake_hold_counter += 1 - self.brake_hold_active = self._brake_hold_counter > brake_hold_allowed_timer and not self._brake_hold_reset - self._brake_hold_reset = not self._prev_brake_pressed and CS.out.brakePressed and not self._brake_hold_reset - else: - self._brake_hold_counter = 0 - self.brake_hold_active = False - self._brake_hold_reset = False - self._prev_brake_pressed = CS.out.brakePressed - - if self.frame % 2 == 0: - can_sends.append(toyotacan.create_brake_hold_command(self.packer, self.frame, CS.pre_collision_2, self.brake_hold_active)) - - return can_sends diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index 456282982b..fded06c1dc 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -79,9 +79,6 @@ class CarState(CarStateBase): self._right_blindspot_d2 = 0 self._right_blindspot_counter = 0 - if CP.spFlags & ToyotaFlagsSP.SP_AUTO_BRAKE_HOLD: - self.pre_collision_2 = {} - self.frame = 0 def update(self, cp, cp_cam): @@ -263,9 +260,6 @@ class CarState(CarStateBase): if self.CP.spFlags & ToyotaFlagsSP.SP_ENHANCED_BSM and self.frame > 199: ret.leftBlindspot, ret.rightBlindspot = self.sp_get_enhanced_bsm(cp) - if self.CP.spFlags & ToyotaFlagsSP.SP_AUTO_BRAKE_HOLD: - self.pre_collision_2 = copy.copy(cp_cam.vl["PRE_COLLISION_2"]) - self._update_traffic_signals(cp_cam) ret.cruiseState.speedLimit = self._calculate_speed_limit() self.frame += 1 @@ -469,7 +463,4 @@ class CarState(CarStateBase): ("PCS_HUD", 1), ] - if CP.spFlags & ToyotaFlagsSP.SP_AUTO_BRAKE_HOLD: - messages.append(("PRE_COLLISION_2", 33)) - return CANParser(DBC[CP.carFingerprint]["pt"], messages, 2) diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index d8b2516aba..1b0528d12c 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -195,9 +195,6 @@ class CarInterface(CarInterfaceBase): if candidate == CAR.TOYOTA_PRIUS_TSS2: ret.spFlags |= ToyotaFlagsSP.SP_NEED_DEBUG_BSM.value - if Params().get_bool("ToyotaAutoHold") and candidate in (TSS2_CAR - RADAR_ACC_CAR): - ret.spFlags |= ToyotaFlagsSP.SP_AUTO_BRAKE_HOLD.value - return ret @staticmethod @@ -275,11 +272,6 @@ class CarInterface(CarInterfaceBase): # while in standstill, send a user alert events.add(EventName.manualRestart) - # auto brake hold - if self.CP.spFlags & ToyotaFlagsSP.SP_AUTO_BRAKE_HOLD: - if self.CC.brake_hold_active and not ret.brakeHoldActive: - events.add(EventName.spAutoBrakeHold) - ret.events = events.to_msg() return ret diff --git a/selfdrive/car/toyota/toyotacan.py b/selfdrive/car/toyota/toyotacan.py index 979879e368..abde32bc07 100644 --- a/selfdrive/car/toyota/toyotacan.py +++ b/selfdrive/car/toyota/toyotacan.py @@ -130,37 +130,3 @@ def create_set_bsm_debug_mode(lr_blindspot, enabled): def create_bsm_polling_status(lr_blindspot): return make_can_msg(0x750, lr_blindspot + b"\x02\x21\x69\x00\x00\x00\x00", 0) - - -# auto brake hold -def create_brake_hold_command(packer, frame, pre_collision_2, brake_hold_active): - # forward PRE_COLLISION_2 when auto brake hold is not active - values = {s: pre_collision_2[s] for s in [ - "DSS1GDRV", - "DS1STAT2", - "DS1STBK2", - "PCSWAR", - "PCSALM", - "PCSOPR", - "PCSABK", - "PBATRGR", - "PPTRGR", - "IBTRGR", - "CLEXTRGR", - "IRLT_REQ", - "BRKHLD", - "AVSTRGR", - "VGRSTRGR", - "PREFILL", - "PBRTRGR", - "PCSDIS", - "PBPREPMP", - ]} - - if brake_hold_active: - values = { - "DSS1GDRV": 0x3FF, - "PBRTRGR": frame % 730 < 727, # cut actuation for 3 frames - } - - return packer.make_can_msg("PRE_COLLISION_2", 0, values) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index b4b277cc08..6952bb41bd 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -64,7 +64,6 @@ class ToyotaFlagsSP(IntFlag): SP_ZSS = 1 SP_ENHANCED_BSM = 2 SP_NEED_DEBUG_BSM = 4 - SP_AUTO_BRAKE_HOLD = 8 class Footnote(Enum): diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 0ef232f5fe..50a092445c 100755 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -744,14 +744,6 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { ET.NO_ENTRY: NoEntryAlert("Brake Hold Active"), }, - EventName.spAutoBrakeHold: { - ET.PERMANENT: Alert( - "sunnypilot Brake Hold Active", - "", - AlertStatus.normal, AlertSize.small, - Priority.LOWEST, VisualAlert.none, AudibleAlert.prompt, 0.), - }, - EventName.parkBrake: { ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage), ET.NO_ENTRY: NoEntryAlert("Parking Brake Engaged"), diff --git a/selfdrive/ui/qt/offroad/sunnypilot/vehicle_settings.cc b/selfdrive/ui/qt/offroad/sunnypilot/vehicle_settings.cc index ef0954c1ed..dd5d457926 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/vehicle_settings.cc +++ b/selfdrive/ui/qt/offroad/sunnypilot/vehicle_settings.cc @@ -124,19 +124,7 @@ SPVehiclesTogglesPanel::SPVehiclesTogglesPanel(VehiclePanel *parent) : ListWidge toyotaTss2LongTune->setConfirmation(true, false); addItem(toyotaTss2LongTune); - auto toyotaAbh = new ParamControl( - "ToyotaAutoHold", - tr("Enable Automatic Brake Hold (AHB)"), - QString("%1

%2

%3") - .arg(tr("WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK.")) - .arg(tr("When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold.")) - .arg(tr("Changing this setting takes effect when the car is powered off.")), - "../assets/offroad/icon_blank.png" - ); - toyotaAbh->setConfirmation(true, false); - addItem(toyotaAbh); - - toyotaEnhancedBsm = new ParamControl( + toyotaEnhancedBsm = new ParamControlSP( "ToyotaEnhancedBsm", tr("Enable Enhanced Blind Spot Monitor"), "", @@ -188,7 +176,6 @@ SPVehiclesTogglesPanel::SPVehiclesTogglesPanel(VehiclePanel *parent) : ListWidge is_onroad = !offroad; hkgSmoothStop->setEnabled(offroad); toyotaTss2LongTune->setEnabled(offroad); - toyotaAbh->setEnabled(offroad); toyotaEnhancedBsm->setEnabled(offroad); toyotaSngHack->setEnabled(offroad); volkswagenCCOnly->setEnabled(offroad); diff --git a/selfdrive/ui/translations/main_ar.ts b/selfdrive/ui/translations/main_ar.ts index d8146723a4..7dae31a53e 100644 --- a/selfdrive/ui/translations/main_ar.ts +++ b/selfdrive/ui/translations/main_ar.ts @@ -87,6 +87,89 @@ من أجل "%1" + + AdvancedNetworkingSP + + Back + السابق + + + Enable Tethering + تمكين الربط + + + Retain hotspot/tethering state + + + + Enabling this toggle will retain the hotspot/tethering toggle state across reboots. + + + + Tethering Password + كلمة مرور الربط + + + EDIT + تعديل + + + Enter new tethering password + أدخل كلمة مرور الربط الجديدة + + + IP Address + عنوان IP + + + Enable Roaming + تمكين التجوال + + + APN Setting + إعدادات APN + + + Enter APN + إدخال APN + + + leave blank for automatic configuration + اتركه فارغاً من أجل التكوين التلقائي + + + Cellular Metered + محدود بالاتصال الخلوي + + + Prevent large data uploads when on a metered connection + منع تحميل البيانات الكبيرة عندما يكون الاتصال محدوداً + + + Hidden Network + شبكة مخفية + + + CONNECT + الاتصال + + + Enter SSID + أدخل SSID + + + Enter password + أدخل كلمة المرور + + + for "%1" + من أجل "%1" + + + Ngrok Service + + + AnnotatedCameraWidget @@ -103,11 +186,119 @@ SPEED - SPEED + SPEED LIMIT - LIMIT + LIMIT + + + + AnnotatedCameraWidgetSP + + km/h + كم/س + + + mph + ميل/س + + + MAX + MAX + + + SPEED + SPEED + + + LIMIT + LIMIT + + + + AutoLaneChangeTimer + + Auto Lane Change by Blinker + + + + Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. +Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. + + + + s + + + + Off + + + + Nudge + + + + Nudgeless + + + + + BackupSettings + + Settings backed up for sunnylink Device ID: + + + + Settings updated successfully, but no additional data was returned by the server. + + + + OOPS! We made a booboo. + + + + Please try again later. + + + + Settings restored. Confirm to restart the interface. + + + + No settings found to restore. + + + + + BrightnessControl + + Brightness + + + + Manually adjusts the global brightness of the screen. + + + + Auto + + + + + CameraOffset + + Camera Offset - Laneful Only + + + + Hack to trick vehicle to be left or right biased in its lane. Decreasing the value will make the car keep more left, increasing will make it keep more right. Changes take effect immediately. Default: +4 cm + + + + cm + @@ -121,11 +312,18 @@ إلغاء + + CustomOffsetsSettings + + Back + السابق + + DeclinePage You must accept the Terms and Conditions in order to use openpilot. - يجب عليك قبول الشروط والأحكام من أجل استخدام openpilot. + يجب عليك قبول الشروط والأحكام من أجل استخدام openpilot. Back @@ -135,6 +333,10 @@ Decline, uninstall %1 رفض، إلغاء التثبيت %1 + + You must accept the Terms and Conditions in order to use sunnypilot. + + DestinationWidget @@ -247,7 +449,7 @@ openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required. - يحتاج openpilot أن يتم ضبط الجهاز ضمن حدود 4 درجات يميناً أو يساراً و5 درجات نحو الأعلى أو 9 نحو الأسفل. يقوم openpilot بالمعايرة باستمرار، ونادراً ما يحتاج إلى عملية إعادة الضبط. + يحتاج openpilot أن يتم ضبط الجهاز ضمن حدود 4 درجات يميناً أو يساراً و5 درجات نحو الأعلى أو 9 نحو الأسفل. يقوم openpilot بالمعايرة باستمرار، ونادراً ما يحتاج إلى عملية إعادة الضبط. Your device is pointed %1° %2 and %3° %4. @@ -305,6 +507,155 @@ PAIR إقران + + sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. sunnypilot is continuously calibrating, resetting is rarely required. + + + + + DevicePanelSP + + TOGGLE + + + + Enable or disable PIN requirement for Fleet Manager access. + + + + Are you sure you want to turn off PIN requirement? + + + + Turn Off + + + + Error Troubleshoot + + + + VIEW + عرض + + + Display error from the tmux session when an error has occurred from a system process. + + + + Reset Access Tokens for Map Services + + + + RESET + إعادة الضبط + + + Reset self-service access tokens for Mapbox, Amap, and Google Maps. + + + + Are you sure you want to reset access tokens for all map services? + + + + Reset + إعادة الضبط + + + Reset sunnypilot Settings + + + + Are you sure you want to reset all sunnypilot settings? + + + + Toggle Onroad/Offroad + + + + OFF + + + + Are you sure you want to unforce offroad? + + + + Unforce + + + + Are you sure you want to force offroad? + + + + Force + + + + Disengage to Force Offroad + + + + Unforce Offroad + + + + Force Offroad + + + + Fleet Manager PIN: + + + + + DisplayPanel + + Driving Screen Off: Non-Critical Events + + + + When <b>Driving Screen Off Timer</b> is not set to <b>"Always On"</b>: + + + + Enabled: Wake the brightness of the screen to display all events. + + + + Disabled: Wake the brightness of the screen to display critical events. + + + + + DriveStats + + Drives + + + + Hours + + + + ALL TIME + + + + PAST WEEK + + + + KM + + + + Miles + + DriverViewWindow @@ -349,6 +700,79 @@ جارٍ التثبيت... + + LaneChangeSettings + + Back + السابق + + + Pause Lateral Below Speed with Blinker + + + + Enable this toggle to pause lateral actuation with blinker when traveling below the desired speed selected below. + + + + Auto Lane Change: Delay with Blind Spot + + + + Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. + + + + Block Lane Change: Road Edge Detection + + + + Enable this toggle to block lane change when road edge is detected on the stalk actuated side. + + + + + MadsSettings + + Enable ACC+MADS with RES+/SET- + + + + Engage both M.A.D.S. and ACC with a single press of RES+ or SET- button. + + + + Note: Once M.A.D.S. is engaged via this mode, it will remain engaged until it is manually disabled via the M.A.D.S. button or car shut off. + + + + Toggle M.A.D.S. with Cruise Main + + + + Allows M.A.D.S. engagement/disengagement with "Cruise Main" cruise control button from the steering wheel. + + + + Remain Active + + + + Pause Steering + + + + Steering Mode After Braking + + + + Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. + +Remain Active: ALC will remain active even after the brake pedal is pressed. +Pause Steering: ALC will be paused after the brake pedal is manually pressed. + + + MapETA @@ -390,6 +814,63 @@ بانتظار الطريق + + MapWindowSP + + Map Loading + تحميل الخريطة + + + Waiting for GPS + بانتظار GPS + + + Waiting for route + بانتظار الطريق + + + + MaxTimeOffroad + + Max Time Offroad + + + + Device is automatically turned off after a set time when the engine is turned off (off-road) after driving (on-road). + + + + s + + + + m + م + + + hr + س + + + Always On + + + + Immediate + + + + + MonitoringPanel + + Enable Hands on Wheel Monitoring + + + + Monitor and alert when driver is not keeping the hands on the steering wheel. + + + MultiOptionDialog @@ -420,6 +901,33 @@ كلمة مرور خاطئة + + NetworkingSP + + Scan + + + + Scanning... + + + + Advanced + متقدم + + + Enter password + أدخل كلمة المرور + + + for "%1" + من أجل "%1" + + + Wrong password + كلمة مرور خاطئة + + OffroadAlert @@ -472,6 +980,16 @@ openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. لقد اكتشف openpilot تغييراً في موقع تركيب الجهاز. تأكد من تثبيت الجهاز بشكل كامل في موقعه وتثبيته بإحكام على الزجاج الأمامي. + + OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. + +%1 + + + + sunnypilot is now in Forced Offroad mode. sunnypilot won't start until Forced Offroad mode is disabled. Go to "Settings" -> "Device" -> "Unforce Offroad" to exit Force Offroad mode. + + OffroadHome @@ -511,6 +1029,186 @@ إعادة التشغيل + + OnroadScreenOff + + Driving Screen Off Timer + + + + Turn off the device screen or reduce brightness to protect the screen after driving starts. It automatically brightens or turns on when a touch or event occurs. + + + + s + + + + min + د + + + Always On + + + + + OnroadScreenOffBrightness + + Driving Screen Off Brightness (%) + + + + When using the Driving Screen Off feature, the brightness is reduced according to the automatic brightness ratio. + + + + Dark + + + + + OnroadSettings + + ONROAD OPTIONS + + + + <b>ONROAD SETTINGS | SUNNYPILOT</b> + + + + + OsmPanel + + Mapd Version + + + + Offline Maps ETA + + + + Time Elapsed + + + + Downloaded Maps + + + + DELETE + + + + This will delete ALL downloaded maps + +Are you sure you want to delete all the maps? + + + + Yes, delete all the maps. + + + + Database Update + + + + CHECK + التحقق + + + Country + + + + SELECT + اختيار + + + Fetching Country list... + + + + State + + + + Fetching State list... + + + + All + + + + REFRESH + + + + UPDATE + تحديث + + + Download starting... + + + + Error: Invalid download. Retry. + + + + Download complete! + + + + + +Warning: You are on a metered connection! + + + + This will start the download process and it might take a while to complete. + + + + Continue on Metered + + + + Start Download + + + + m + + + + s + + + + Calculating... + + + + Downloaded + + + + Calculating ETA... + + + + Ready + + + + Time remaining: + + + PairingPopup @@ -541,6 +1239,51 @@ إلغاء + + ParamControlSP + + Enable + تمكين + + + Cancel + إلغاء + + + + PathOffset + + Path Offset + + + + Hack to trick the model path to be left or right biased of the lane. Decreasing the value will shift the model more left, increasing will shift the model more right. Changes take effect immediately. + + + + cm + + + + + PauseLateralSpeed + + Pause lateral actuation with blinker when traveling below the desired speed selected. Default is 20 MPH or 32 km/h. + + + + Default + + + + km/h + كم/س + + + mph + ميل/س + + PrimeAdWidget @@ -595,7 +1338,7 @@ openpilot - openpilot + openpilot %n minute(s) ago @@ -650,6 +1393,30 @@ now الآن + + sunnypilot + + + + Update downloaded. Ready to reboot. + + + + Update: Check and Download Update + + + + Reboot: Reboot Device + + + + Update + + + + Updating... + + Reset @@ -692,6 +1459,131 @@ This may take up to a minute. تم تفعيل إعادة ضبط النظام. اضغط على تأكيد لمسح جميع المحتويات والإعدادات. اضغط على إلغاء لاستئناف التمهيد. + + SPVehiclesTogglesPanel + + Hyundai/Kia/Genesis + + + + HKG CAN: Smoother Stopping Performance (Beta) + + + + Smoother stopping behind a stopped car or desired stopping event. This is only applicable to HKG CAN platforms using openpilot longitudinal control. + + + + Subaru + + + + Manual Parking Brake: Stop and Go (Beta) + + + + Experimental feature to enable stop and go for Subaru Global models with manual handbrake. Models with electric parking brake should keep this disabled. Thanks to martinl for this implementation! + + + + Toyota/Lexus + + + + Enable Stock Toyota Longitudinal Control + + + + sunnypilot will <b>not</b> take over control of gas and brakes. Stock Toyota longitudinal control will be used. + + + + Allow M.A.D.S. toggling w/ LKAS Button (Beta) + + + + Allows M.A.D.S. engagement/disengagement with "LKAS" button from the steering wheel. + + + + Note: Enabling this toggle may have unexpected behavior with steering control. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Toyota TSS2 Longitudinal: Custom Tuning + + + + Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + + + Enable Enhanced Blind Spot Monitor + + + + Enable Toyota Stop and Go Hack + + + + sunnypilot will allow some Toyota/Lexus cars to auto resume during stop and go traffic. This feature is only applicable to certain models. Use at your own risk. + + + + Enable Toyota Door Auto Locking + + + + sunnypilot will attempt to lock the doors when drive above 10 km/h (6.2 mph). +Reboot Required. + + + + Enable Toyota Door Auto Unlocking + + + + sunnypilot will attempt to unlock the doors when shift to gear P. +Reboot Required. + + + + Volkswagen + + + + Enable CC Only support + + + + sunnypilot supports Volkswagen MQB CC only platforms with this toggle enabled. Only enable this toggle if your car does not have ACC from the factory. + + + + Start the car to check car compatibility + + + + This platform is already supported, therefore no need to enable this toggle + + + + This platform is not supported + + + + This platform can be supported + + + + sunnypilot will use debugging CAN messages to receive unfiltered BSM signals, allowing detection of more objects. + + + + Tested on RAV4 TSS1, Lexus LSS1, Toyota TSS1/1.5, and Prius TSS2. + + + SettingsWindow @@ -715,6 +1607,61 @@ This may take up to a minute. البرنامج + + SettingsWindowSP + + × + × + + + Device + الجهاز + + + Network + الشبكة + + + sunnylink + + + + Toggles + المثبتتات + + + Software + البرنامج + + + sunnypilot + + + + OSM + + + + Monitoring + + + + Visuals + + + + Display + + + + Trips + + + + Vehicle + + + Setup @@ -908,6 +1855,100 @@ This may take up to a minute. 5G + + SidebarSP + + TEMP + درجة الحرارة + + + HIGH + مرتفع + + + GOOD + جيد + + + OK + موافق + + + DISABLED + + + + OFFLINE + غير متصل + + + REGIST... + + + + ONLINE + متصل + + + ERROR + خطأ + + + SUNNYLINK + + + + + SlcSettings + + Auto + + + + User Confirm + + + + Engage Mode + + + + Default + + + + Fixed + + + + Percentage + + + + Limit Offset + + + + Set speed limit slightly higher than actual speed limit for a more natural drive. + + + + This platform defaults to <b>Auto</b> mode. <b>User Confirm</b> mode is not supported on this platform. + + + + Select the desired mode to set the cruising speed to the speed limit: + + + + Auto: Automatic speed adjustment on motorways based on speed limit data. + + + + User Confirm: Inform the driver to change set speed of Adaptive Cruise Control to help the driver stay within the speed limit. + + + SoftwarePanel @@ -983,6 +2024,233 @@ This may take up to a minute. أحدث نسخة، آخر تحقق %1 + + SoftwarePanelSP + + Driving Model + + + + SELECT + اختيار + + + PENDING + + + + Downloading Driving model + + + + (CACHED) + + + + Driving model + + + + downloaded + + + + Downloading Navigation model + + + + Navigation model + + + + Downloading Metadata model + + + + Metadata model + + + + Downloads have failed, please try swapping the model! + + + + Failed: + + + + Fetching models... + + + + Select a Driving Model + + + + Download has started in the background. + + + + We STRONGLY suggest you to reset calibration. Would you like to do that now? + + + + Reset Calibration + إعادة ضبط المعايرة + + + Warning: You are on a metered connection! + + + + Continue + متابعة + + + on Metered + + + + + SpeedLimitPolicySettings + + Speed Limit Source Policy + + + + Nav + + + + Only + + + + Map + + + + Car + + + + First + + + + Select the precedence order of sources. Utilized by Speed Limit Control and Speed Limit Warning + + + + Nav Only: Data from Mapbox active navigation only. + + + + Map Only: Data from OpenStreetMap only. + + + + Car Only: Data from the car's built-in sources (if available). + + + + Nav First: Nav -> Map -> Car + + + + Map First: Map -> Nav -> Car + + + + Car First: Car -> Nav -> Map + + + + + SpeedLimitValueOffset + + km/h + كم/س + + + mph + ميل/س + + + + SpeedLimitWarningSettings + + Off + + + + Display + + + + Chime + + + + Speed Limit Warning + + + + Warning with speed limit flash + + + + When Speed Limit Warning is enabled, the speed limit sign will alert the driver when the cruising speed is faster than then speed limit plus the offset. + + + + Default + + + + Fixed + + + + Percentage + + + + Warning Offset + + + + Select the desired offset to warn the driver when the vehicle is driving faster than the speed limit. + + + + Off: When the cruising speed is faster than the speed limit plus the offset, there will be no warning. + + + + Display: The speed on the speed limit sign turns red to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + Chime: The speed on the speed limit sign turns red and chimes to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + + SpeedLimitWarningValueOffset + + N/A + غير متاح + + + km/h + كم/س + + + mph + ميل/س + + SshControl @@ -1029,6 +2297,399 @@ This may take up to a minute. تمكين SSH + + SunnylinkPanel + + Enable sunnylink + + + + Device ID + + + + N/A + غير متاح + + + This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. + + + + 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 + + + + 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. + + + + Sponsor Status + + + + SPONSOR + + + + Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. + + + + Pair GitHub Account + + + + PAIR + إقران + + + Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. + + + + sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. + + + + Manage Settings + + + + Backup Settings + + + + Are you sure you want to backup sunnypilot settings? + + + + Back Up + + + + Restore Settings + + + + Are you sure you want to restore the last backed up sunnypilot settings? + + + + Restore + + + + THANKS + + + + Not Sponsor + + + + Paired + + + + Not Paired + + + + Backing up... + + + + Restoring... + + + + + SunnylinkSponsorPopup + + Scan the QR code to login to your GitHub account + + + + Follow the prompts to complete the pairing process + + + + Re-enter the "sunnylink" panel to verify sponsorship status + + + + If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot + + + + Scan the QR code to visit sunnyhaibin's GitHub Sponsors page + + + + Choose your sponsorship tier and confirm your support + + + + Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status + + + + Pair your GitHub account + + + + Early Access: Become a sunnypilot Sponsor + + + + + SunnypilotPanel + + Enable M.A.D.S. + + + + Enable the beloved M.A.D.S. feature. Disable toggle to revert back to stock openpilot engagement/disengagement. + + + + Laneless for Curves in "Auto" Mode + + + + While in Auto Lane, switch to Laneless for current/future curves. + + + + Speed Limit Control (SLC) + + + + When you engage ACC, you will be prompted to set the cruising speed to the speed limit of the road adjusted by the Offset and Source Policy specified, or the current driving speed. The maximum cruising speed will always be the MAX set speed. + + + + Enable Vision-based Turn Speed Control (V-TSC) + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Enable Map Data Turn Speed Control (M-TSC) (Beta) + + + + Use curvature information from map data to define speed limits to take turns ahead. + + + + ACC +/-: Long Press Reverse + + + + Change the ACC +/- buttons behavior with cruise speed change in sunnypilot. + + + + Disabled (Stock): Short=1, Long = 5 (imperial) / 10 (metric) + + + + Enabled: Short = 5 (imperial) / 10 (metric), Long=1 + + + + Custom Offsets + + + + Neural Network Lateral Control (NNLC) + + + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Enable Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying FRICTION and LAT_ACCEL_FACTOR below will override the offline values indicated in the YAML files within "selfdrive/torque_data". The values will also be used live when "Override Self-Tune" toggle is enabled. + + + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Quiet Drive 🤫 + + + + sunnypilot will display alerts but only play the most important warning sounds. This feature can be toggled while the car is on. + + + + Green Traffic Light Chime (Beta) + + + + A chime will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. If you are waiting behind another vehicle, the chime will play once the vehicle advances unless ACC is engaged. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Vehicle Departure Alert + + + + Enable this will notify when the leading vehicle drives away. + + + + Customize M.A.D.S. + + + + Customize Lane Change + + + + Customize Offsets + + + + Customize Speed Limit Control + + + + Customize Warning + + + + Customize Source + + + + Laneful + + + + Laneless + + + + Auto + + + + Dynamic Lane Profile + + + + Speed Limit Assist + + + + Real-time and Offline + + + + Offline Only + + + + Dynamic Lane Profile is not available with the current Driving Model + + + + Custom Offsets is not available with the current Driving Model + + + + NNLC is currently not available on this platform. + + + + Match: "Exact" is ideal, but "Fuzzy" is fine too. Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server if there are any issues: + + + + Start the car to check car compatibility + + + + NNLC Not Loaded + + + + NNLC Loaded + + + + Fuzzy + + + + Exact + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server and donate logs to get NNLC loaded for your car: + + + + Match + + + + Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server with feedback, or to provide log data for your car if your car is currently unsupported: + + + + Add custom offsets to Camera and Path in sunnypilot. + + + + Default is Laneless. In Auto mode, sunnnypilot dynamically chooses between Laneline or Laneless model based on lane recognition confidence level on road and certain conditions. + + + TermsPage @@ -1048,15 +2709,30 @@ This may take up to a minute. أوافق + + TermsPageSP + + Terms & Conditions + الشروط والأحكام + + + Decline + رفض + + + Scroll to accept + قم بالتمرير للقبول + + TogglesPanel Enable openpilot - تمكين openpilot + تمكين openpilot Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. - استخدم نظام openpilot من أجل الضبط التكيفي للسرعة والحفاظ على مساعدة السائق للبقاء في المسار. انتباهك مطلوب في جميع الأوقات مع استخدام هذه الميزة. يعمل هذا التغيير في الإعدادات عند إيقاف تشغيل السيارة. + استخدم نظام openpilot من أجل الضبط التكيفي للسرعة والحفاظ على مساعدة السائق للبقاء في المسار. انتباهك مطلوب في جميع الأوقات مع استخدام هذه الميزة. يعمل هذا التغيير في الإعدادات عند إيقاف تشغيل السيارة. Enable Lane Departure Warnings @@ -1092,19 +2768,19 @@ This may take up to a minute. Show ETA in 24h Format - إظهار الوقت المقدر للوصول بصيغة 24 ساعة + إظهار الوقت المقدر للوصول بصيغة 24 ساعة Use 24h format instead of am/pm - استخدام صيغة 24 ساعة بدلاً من صباحاً/مساء + استخدام صيغة 24 ساعة بدلاً من صباحاً/مساء Show Map on Left Side of UI - عرض الخريطة على الجانب الأيسر من واجهة المستخدم + عرض الخريطة على الجانب الأيسر من واجهة المستخدم Show map on left side when in split screen view. - عرض الخريطة عل الجانب الأيسر عندما تكون وضعية العرض بطريقة الشاشة المنقسمة. + عرض الخريطة عل الجانب الأيسر عندما تكون وضعية العرض بطريقة الشاشة المنقسمة. openpilot Longitudinal Control (Alpha) @@ -1186,6 +2862,252 @@ This may take up to a minute. Enable driver monitoring even when openpilot is not engaged. + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + + TogglesPanelSP + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + openpilot Longitudinal Control (Alpha) + التحكم الطولي openpilot (ألفا) + + + WARNING: sunnypilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + + + + On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to sunnypilot longitudinal control. Enabling Experimental mode is recommended when enabling sunnypilot longitudinal control alpha. + + + + Custom Stock Longitudinal Control + + + + When enabled, sunnypilot will attempt to control stock longitudinal control with ACC button presses. +This feature must be used along with SLC, and/or V-TSC, and/or M-TSC. + + + + Experimental Mode + الوضع التجريبي + + + Enable Dynamic Experimental Control + + + + Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. + + + + Enable Dynamic Personality + + + + Enable this to allow sunnypilot to dynamically adjust following distance and reaction based on your "Driving Personality" setting. Instead of predefined settings for each personality, every personality now adapts dynamically according to your speed and the distance to the lead car. + + + + Disengage on Accelerator Pedal + فك الارتباط عن دواسة الوقود + + + When enabled, pressing the accelerator pedal will disengage openpilot. + عند تمكين هذه الميزة، فإن الضغط على دواسة الوقود سيؤدي إلى فك ارتباط openpilot. + + + Enable Lane Departure Warnings + قم بتمكين تحذيرات مغادرة المسار + + + Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). + تلقي التنبيهات من أجل الالتفاف للعودة إلى المسار عندما تنحرف سيارتك فوق الخط المحدد للمسار دون تشغيل إشارة الانعطاف عند القيادة لمسافة تزيد عن 31 ميل/سا (50 كم/سا). + + + Always-On Driver Monitoring + + + + Enable driver monitoring even when sunnypilot is not engaged. + + + + Record and Upload Driver Camera + تسجيل وتحميل كاميرا السائق + + + Upload data from the driver facing camera and help improve the driver monitoring algorithm. + تحميل البيانات من الكاميرا المواجهة للسائق، والمساعدة في تحسين خوارزمية مراقبة السائق. + + + Disable Onroad Uploads + + + + Disable uploads completely when onroad. Necessary to avoid high data usage when connected to Wi-Fi hotspot. Turn on this feature if you are looking to utilize map-based features, such as Speed Limit Control (SLC) and Map-based Turn Speed Control (MTSC). + + + + Use Metric System + استخدام النظام المتري + + + Display speed in km/h instead of mph. + عرض السرعة بواحدات كم/سا بدلاً من ميل/سا. + + + Show ETA in 24h Format + إظهار الوقت المقدر للوصول بصيغة 24 ساعة + + + Use 24h format instead of am/pm + استخدام صيغة 24 ساعة بدلاً من صباحاً/مساء + + + Show Map on Left Side of UI + عرض الخريطة على الجانب الأيسر من واجهة المستخدم + + + Show map on left side when in split screen view. + عرض الخريطة عل الجانب الأيسر عندما تكون وضعية العرض بطريقة الشاشة المنقسمة. + + + Aggressive + الهجومي + + + Moderate + + + + Standard + القياسي + + + Relaxed + الراحة + + + Driving Personality + شخصية القيادة + + + Standard is recommended. In moderate/aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + + + + Sport + + + + Normal + + + + Eco + + + + Stock + + + + Acceleration Personality + + + + Normal is recommended. In sport mode, sunnypilot will provide aggressive acceleration for a dynamic driving experience. In eco mode, sunnypilot will apply smoother and more relaxed acceleration. On supported cars, you can cycle through these acceleration personality within Onroad Settings on the driving screen. + + + + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + يتم وضع openpilot بشكل قياسي في <b>وضعية الراحة</b>. يمكن الوضع التجريبي <b>ميزات المستوى ألفا</b> التي لا تكون جاهزة في وضع الراحة: + + + End-to-End Longitudinal Control + التحكم الطولي من طرف إلى طرف + + + Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + + + + New Driving Visualization + تصور القيادة الديد + + + The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. + + + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + الوضع التجريبي غير متوفر حالياً في هذه السيارة نظراً لاستخدام رصيد التحكم التكيفي بالسرعة من أجل التحكم الطولي. + + + openpilot longitudinal control may come in a future update. + قد يتم الحصول على التحكم الطولي في openpilot في عمليات التحديث المستقبلية. + + + An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. + + + + + TorqueFriction + + FRICTION + + + + Adjust Friction for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueMaxLatAccel + + LAT_ACCEL_FACTOR + + + + Adjust Max Lateral Acceleration for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + Updater @@ -1222,6 +3144,168 @@ This may take up to a minute. فشل التحديث + + VehiclePanel + + Updating this setting takes effect when the car is powered off. + + + + Select your car + + + + + VisualsPanel + + Display Braking Status + + + + Enable this will turn the current speed value to red while the brake is used. + + + + Display Stand Still Timer + + + + Enable this will display time spent at a stop (i.e., at a stop lights, stop signs, traffic congestions). + + + + Display DM Camera in Reverse Gear + + + + Show Driver Monitoring camera while the car is in reverse gear. + + + + OSM: Show debug UI elements + + + + OSM: Show UI elements that aid debugging. + + + + Display Feature Status + + + + Display the statuses of certain features on the driving screen. + + + + Enable Onroad Settings + + + + Display the Onroad Settings button on the driving screen to adjust feature options on the driving screen, without navigating into the settings menu. + + + + Speedometer: Display True Speed + + + + Display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Display End-to-end Longitudinal Status (Beta) + + + + Enable this will display an icon that appears when the End-to-end model decides to start or stop. + + + + Navigation: Display in Full Screen + + + + Enable this will display the built-in navigation in full screen.<br>To switch back to driving view, <font color='yellow'>tap on the border edge</font>. + + + + Map: Display 3D Buildings + + + + Parse and display 3D buildings on map. Thanks to jakethesnake420 for this implementation. + + + + Off + + + + 5 Metrics + + + + 10 Metrics + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + + + Distance + + + + Speed + + + + Display Metrics Below Chevron + + + + Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + + + RAM + + + + CPU + + + + GPU + + + + Max + + + + Display Temperature on Sidebar + + + + Time + + + + All + + + WiFiPromptWidget @@ -1268,4 +3352,27 @@ This may take up to a minute. نسيان + + WifiUISP + + Scanning for networks... + يتم البحث عن شبكات... + + + CONNECTING... + يتم الاتصال... + + + FORGET + نسيان هذه الشبكة + + + Forget Wi-Fi Network "%1"? + هل تريد نسيان شبكة الواي فاي "%1"؟ + + + Forget + نسيان + + diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index 010aa4d304..6b8fd1efc1 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -87,6 +87,89 @@ für "%1" + + AdvancedNetworkingSP + + Back + Zurück + + + Enable Tethering + Tethering aktivieren + + + Retain hotspot/tethering state + + + + Enabling this toggle will retain the hotspot/tethering toggle state across reboots. + + + + Tethering Password + Tethering Passwort + + + EDIT + ÄNDERN + + + Enter new tethering password + Neues tethering Passwort eingeben + + + IP Address + IP Adresse + + + Enable Roaming + Roaming aktivieren + + + APN Setting + APN Einstellungen + + + Enter APN + APN eingeben + + + leave blank for automatic configuration + für automatische Konfiguration leer lassen + + + Cellular Metered + Getaktete Verbindung + + + Prevent large data uploads when on a metered connection + Hochladen großer Dateien über getaktete Verbindungen unterbinden + + + Hidden Network + + + + CONNECT + CONNECT + + + Enter SSID + SSID eingeben + + + Enter password + Passwort eingeben + + + for "%1" + für "%1" + + + Ngrok Service + + + AnnotatedCameraWidget @@ -103,11 +186,119 @@ SPEED - Geschwindigkeit + Geschwindigkeit LIMIT - LIMIT + LIMIT + + + + AnnotatedCameraWidgetSP + + km/h + km/h + + + mph + mph + + + MAX + MAX + + + SPEED + Geschwindigkeit + + + LIMIT + LIMIT + + + + AutoLaneChangeTimer + + Auto Lane Change by Blinker + + + + Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. +Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. + + + + s + + + + Off + + + + Nudge + + + + Nudgeless + + + + + BackupSettings + + Settings backed up for sunnylink Device ID: + + + + Settings updated successfully, but no additional data was returned by the server. + + + + OOPS! We made a booboo. + + + + Please try again later. + + + + Settings restored. Confirm to restart the interface. + + + + No settings found to restore. + + + + + BrightnessControl + + Brightness + + + + Manually adjusts the global brightness of the screen. + + + + Auto + + + + + CameraOffset + + Camera Offset - Laneful Only + + + + Hack to trick vehicle to be left or right biased in its lane. Decreasing the value will make the car keep more left, increasing will make it keep more right. Changes take effect immediately. Default: +4 cm + + + + cm + @@ -121,11 +312,18 @@ Abbrechen + + CustomOffsetsSettings + + Back + Zurück + + DeclinePage You must accept the Terms and Conditions in order to use openpilot. - Du musst die Nutzungsbedingungen akzeptieren, um Openpilot zu benutzen. + Du musst die Nutzungsbedingungen akzeptieren, um Openpilot zu benutzen. Back @@ -135,6 +333,10 @@ Decline, uninstall %1 Ablehnen, deinstallieren %1 + + You must accept the Terms and Conditions in order to use sunnypilot. + + DestinationWidget @@ -247,7 +449,7 @@ openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required. - Damit Openpilot funktioniert, darf die Installationsposition nicht mehr als 4° nach rechts/links, 5° nach oben und 9° nach unten abweichen. Openpilot kalibriert sich durchgehend, ein Zurücksetzen ist selten notwendig. + Damit Openpilot funktioniert, darf die Installationsposition nicht mehr als 4° nach rechts/links, 5° nach oben und 9° nach unten abweichen. Openpilot kalibriert sich durchgehend, ein Zurücksetzen ist selten notwendig. Your device is pointed %1° %2 and %3° %4. @@ -305,6 +507,155 @@ PAIR + + sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. sunnypilot is continuously calibrating, resetting is rarely required. + + + + + DevicePanelSP + + TOGGLE + + + + Enable or disable PIN requirement for Fleet Manager access. + + + + Are you sure you want to turn off PIN requirement? + + + + Turn Off + + + + Error Troubleshoot + + + + VIEW + ANSEHEN + + + Display error from the tmux session when an error has occurred from a system process. + + + + Reset Access Tokens for Map Services + + + + RESET + RESET + + + Reset self-service access tokens for Mapbox, Amap, and Google Maps. + + + + Are you sure you want to reset access tokens for all map services? + + + + Reset + Zurücksetzen + + + Reset sunnypilot Settings + + + + Are you sure you want to reset all sunnypilot settings? + + + + Toggle Onroad/Offroad + + + + OFF + + + + Are you sure you want to unforce offroad? + + + + Unforce + + + + Are you sure you want to force offroad? + + + + Force + + + + Disengage to Force Offroad + + + + Unforce Offroad + + + + Force Offroad + + + + Fleet Manager PIN: + + + + + DisplayPanel + + Driving Screen Off: Non-Critical Events + + + + When <b>Driving Screen Off Timer</b> is not set to <b>"Always On"</b>: + + + + Enabled: Wake the brightness of the screen to display all events. + + + + Disabled: Wake the brightness of the screen to display critical events. + + + + + DriveStats + + Drives + + + + Hours + + + + ALL TIME + + + + PAST WEEK + + + + KM + + + + Miles + + DriverViewWindow @@ -345,6 +696,79 @@ Installiere... + + LaneChangeSettings + + Back + Zurück + + + Pause Lateral Below Speed with Blinker + + + + Enable this toggle to pause lateral actuation with blinker when traveling below the desired speed selected below. + + + + Auto Lane Change: Delay with Blind Spot + + + + Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. + + + + Block Lane Change: Road Edge Detection + + + + Enable this toggle to block lane change when road edge is detected on the stalk actuated side. + + + + + MadsSettings + + Enable ACC+MADS with RES+/SET- + + + + Engage both M.A.D.S. and ACC with a single press of RES+ or SET- button. + + + + Note: Once M.A.D.S. is engaged via this mode, it will remain engaged until it is manually disabled via the M.A.D.S. button or car shut off. + + + + Toggle M.A.D.S. with Cruise Main + + + + Allows M.A.D.S. engagement/disengagement with "Cruise Main" cruise control button from the steering wheel. + + + + Remain Active + + + + Pause Steering + + + + Steering Mode After Braking + + + + Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. + +Remain Active: ALC will remain active even after the brake pedal is pressed. +Pause Steering: ALC will be paused after the brake pedal is manually pressed. + + + MapETA @@ -386,6 +810,63 @@ + + MapWindowSP + + Map Loading + Karte wird geladen + + + Waiting for GPS + Warten auf GPS + + + Waiting for route + + + + + MaxTimeOffroad + + Max Time Offroad + + + + Device is automatically turned off after a set time when the engine is turned off (off-road) after driving (on-road). + + + + s + + + + m + m + + + hr + std + + + Always On + + + + Immediate + + + + + MonitoringPanel + + Enable Hands on Wheel Monitoring + + + + Monitor and alert when driver is not keeping the hands on the steering wheel. + + + MultiOptionDialog @@ -416,6 +897,33 @@ Falsches Passwort + + NetworkingSP + + Scan + + + + Scanning... + + + + Advanced + Erweitert + + + Enter password + Passwort eingeben + + + for "%1" + für "%1" + + + Wrong password + Falsches Passwort + + OffroadAlert @@ -467,6 +975,16 @@ Device temperature too high. System cooling down before starting. Current internal component temperature: %1 + + OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. + +%1 + + + + sunnypilot is now in Forced Offroad mode. sunnypilot won't start until Forced Offroad mode is disabled. Go to "Settings" -> "Device" -> "Unforce Offroad" to exit Force Offroad mode. + + OffroadHome @@ -506,6 +1024,186 @@ + + OnroadScreenOff + + Driving Screen Off Timer + + + + Turn off the device screen or reduce brightness to protect the screen after driving starts. It automatically brightens or turns on when a touch or event occurs. + + + + s + + + + min + min + + + Always On + + + + + OnroadScreenOffBrightness + + Driving Screen Off Brightness (%) + + + + When using the Driving Screen Off feature, the brightness is reduced according to the automatic brightness ratio. + + + + Dark + + + + + OnroadSettings + + ONROAD OPTIONS + + + + <b>ONROAD SETTINGS | SUNNYPILOT</b> + + + + + OsmPanel + + Mapd Version + + + + Offline Maps ETA + + + + Time Elapsed + + + + Downloaded Maps + + + + DELETE + + + + This will delete ALL downloaded maps + +Are you sure you want to delete all the maps? + + + + Yes, delete all the maps. + + + + Database Update + + + + CHECK + ÜBERPRÜFEN + + + Country + + + + SELECT + AUSWÄHLEN + + + Fetching Country list... + + + + State + + + + Fetching State list... + + + + All + + + + REFRESH + + + + UPDATE + Aktualisieren + + + Download starting... + + + + Error: Invalid download. Retry. + + + + Download complete! + + + + + +Warning: You are on a metered connection! + + + + This will start the download process and it might take a while to complete. + + + + Continue on Metered + + + + Start Download + + + + m + + + + s + + + + Calculating... + + + + Downloaded + + + + Calculating ETA... + + + + Ready + + + + Time remaining: + + + PairingPopup @@ -536,6 +1234,51 @@ Aktivieren + + ParamControlSP + + Enable + Aktivieren + + + Cancel + Abbrechen + + + + PathOffset + + Path Offset + + + + Hack to trick the model path to be left or right biased of the lane. Decreasing the value will shift the model more left, increasing will shift the model more right. Changes take effect immediately. + + + + cm + + + + + PauseLateralSpeed + + Pause lateral actuation with blinker when traveling below the desired speed selected. Default is 20 MPH or 32 km/h. + + + + Default + + + + km/h + km/h + + + mph + mph + + PrimeAdWidget @@ -590,7 +1333,7 @@ openpilot - openpilot + openpilot %n minute(s) ago @@ -633,6 +1376,30 @@ now + + sunnypilot + + + + Update downloaded. Ready to reboot. + + + + Update: Check and Download Update + + + + Reboot: Reboot Device + + + + Update + + + + Updating... + + Reset @@ -674,6 +1441,131 @@ This may take up to a minute. + + SPVehiclesTogglesPanel + + Hyundai/Kia/Genesis + + + + HKG CAN: Smoother Stopping Performance (Beta) + + + + Smoother stopping behind a stopped car or desired stopping event. This is only applicable to HKG CAN platforms using openpilot longitudinal control. + + + + Subaru + + + + Manual Parking Brake: Stop and Go (Beta) + + + + Experimental feature to enable stop and go for Subaru Global models with manual handbrake. Models with electric parking brake should keep this disabled. Thanks to martinl for this implementation! + + + + Toyota/Lexus + + + + Enable Stock Toyota Longitudinal Control + + + + sunnypilot will <b>not</b> take over control of gas and brakes. Stock Toyota longitudinal control will be used. + + + + Allow M.A.D.S. toggling w/ LKAS Button (Beta) + + + + Allows M.A.D.S. engagement/disengagement with "LKAS" button from the steering wheel. + + + + Note: Enabling this toggle may have unexpected behavior with steering control. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Toyota TSS2 Longitudinal: Custom Tuning + + + + Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + + + Enable Enhanced Blind Spot Monitor + + + + Enable Toyota Stop and Go Hack + + + + sunnypilot will allow some Toyota/Lexus cars to auto resume during stop and go traffic. This feature is only applicable to certain models. Use at your own risk. + + + + Enable Toyota Door Auto Locking + + + + sunnypilot will attempt to lock the doors when drive above 10 km/h (6.2 mph). +Reboot Required. + + + + Enable Toyota Door Auto Unlocking + + + + sunnypilot will attempt to unlock the doors when shift to gear P. +Reboot Required. + + + + Volkswagen + + + + Enable CC Only support + + + + sunnypilot supports Volkswagen MQB CC only platforms with this toggle enabled. Only enable this toggle if your car does not have ACC from the factory. + + + + Start the car to check car compatibility + + + + This platform is already supported, therefore no need to enable this toggle + + + + This platform is not supported + + + + This platform can be supported + + + + sunnypilot will use debugging CAN messages to receive unfiltered BSM signals, allowing detection of more objects. + + + + Tested on RAV4 TSS1, Lexus LSS1, Toyota TSS1/1.5, and Prius TSS2. + + + SettingsWindow @@ -697,6 +1589,61 @@ This may take up to a minute. Software + + SettingsWindowSP + + × + x + + + Device + Gerät + + + Network + Netzwerk + + + sunnylink + + + + Toggles + Schalter + + + Software + Software + + + sunnypilot + + + + OSM + + + + Monitoring + + + + Visuals + + + + Display + + + + Trips + + + + Vehicle + + + Setup @@ -891,6 +1838,100 @@ This may take up to a minute. 5G + + SidebarSP + + TEMP + TEMP + + + HIGH + HOCH + + + GOOD + GUT + + + OK + OK + + + DISABLED + + + + OFFLINE + OFFLINE + + + REGIST... + + + + ONLINE + ONLINE + + + ERROR + FEHLER + + + SUNNYLINK + + + + + SlcSettings + + Auto + + + + User Confirm + + + + Engage Mode + + + + Default + + + + Fixed + + + + Percentage + + + + Limit Offset + + + + Set speed limit slightly higher than actual speed limit for a more natural drive. + + + + This platform defaults to <b>Auto</b> mode. <b>User Confirm</b> mode is not supported on this platform. + + + + Select the desired mode to set the cruising speed to the speed limit: + + + + Auto: Automatic speed adjustment on motorways based on speed limit data. + + + + User Confirm: Inform the driver to change set speed of Adaptive Cruise Control to help the driver stay within the speed limit. + + + SoftwarePanel @@ -967,6 +2008,233 @@ This may take up to a minute. + + SoftwarePanelSP + + Driving Model + + + + SELECT + AUSWÄHLEN + + + PENDING + + + + Downloading Driving model + + + + (CACHED) + + + + Driving model + + + + downloaded + + + + Downloading Navigation model + + + + Navigation model + + + + Downloading Metadata model + + + + Metadata model + + + + Downloads have failed, please try swapping the model! + + + + Failed: + + + + Fetching models... + + + + Select a Driving Model + + + + Download has started in the background. + + + + We STRONGLY suggest you to reset calibration. Would you like to do that now? + + + + Reset Calibration + Neu kalibrieren + + + Warning: You are on a metered connection! + + + + Continue + Fortsetzen + + + on Metered + + + + + SpeedLimitPolicySettings + + Speed Limit Source Policy + + + + Nav + + + + Only + + + + Map + + + + Car + + + + First + + + + Select the precedence order of sources. Utilized by Speed Limit Control and Speed Limit Warning + + + + Nav Only: Data from Mapbox active navigation only. + + + + Map Only: Data from OpenStreetMap only. + + + + Car Only: Data from the car's built-in sources (if available). + + + + Nav First: Nav -> Map -> Car + + + + Map First: Map -> Nav -> Car + + + + Car First: Car -> Nav -> Map + + + + + SpeedLimitValueOffset + + km/h + km/h + + + mph + mph + + + + SpeedLimitWarningSettings + + Off + + + + Display + + + + Chime + + + + Speed Limit Warning + + + + Warning with speed limit flash + + + + When Speed Limit Warning is enabled, the speed limit sign will alert the driver when the cruising speed is faster than then speed limit plus the offset. + + + + Default + + + + Fixed + + + + Percentage + + + + Warning Offset + + + + Select the desired offset to warn the driver when the vehicle is driving faster than the speed limit. + + + + Off: When the cruising speed is faster than the speed limit plus the offset, there will be no warning. + + + + Display: The speed on the speed limit sign turns red to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + Chime: The speed on the speed limit sign turns red and chimes to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + + SpeedLimitWarningValueOffset + + N/A + Nicht verfügbar + + + km/h + km/h + + + mph + mph + + SshControl @@ -1013,6 +2281,399 @@ This may take up to a minute. SSH aktivieren + + SunnylinkPanel + + Enable sunnylink + + + + Device ID + + + + N/A + Nicht verfügbar + + + This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. + + + + 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 + + + + 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. + + + + Sponsor Status + + + + SPONSOR + + + + Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. + + + + Pair GitHub Account + + + + PAIR + + + + Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. + + + + sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. + + + + Manage Settings + + + + Backup Settings + + + + Are you sure you want to backup sunnypilot settings? + + + + Back Up + + + + Restore Settings + + + + Are you sure you want to restore the last backed up sunnypilot settings? + + + + Restore + + + + THANKS + + + + Not Sponsor + + + + Paired + + + + Not Paired + + + + Backing up... + + + + Restoring... + + + + + SunnylinkSponsorPopup + + Scan the QR code to login to your GitHub account + + + + Follow the prompts to complete the pairing process + + + + Re-enter the "sunnylink" panel to verify sponsorship status + + + + If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot + + + + Scan the QR code to visit sunnyhaibin's GitHub Sponsors page + + + + Choose your sponsorship tier and confirm your support + + + + Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status + + + + Pair your GitHub account + + + + Early Access: Become a sunnypilot Sponsor + + + + + SunnypilotPanel + + Enable M.A.D.S. + + + + Enable the beloved M.A.D.S. feature. Disable toggle to revert back to stock openpilot engagement/disengagement. + + + + Laneless for Curves in "Auto" Mode + + + + While in Auto Lane, switch to Laneless for current/future curves. + + + + Speed Limit Control (SLC) + + + + When you engage ACC, you will be prompted to set the cruising speed to the speed limit of the road adjusted by the Offset and Source Policy specified, or the current driving speed. The maximum cruising speed will always be the MAX set speed. + + + + Enable Vision-based Turn Speed Control (V-TSC) + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Enable Map Data Turn Speed Control (M-TSC) (Beta) + + + + Use curvature information from map data to define speed limits to take turns ahead. + + + + ACC +/-: Long Press Reverse + + + + Change the ACC +/- buttons behavior with cruise speed change in sunnypilot. + + + + Disabled (Stock): Short=1, Long = 5 (imperial) / 10 (metric) + + + + Enabled: Short = 5 (imperial) / 10 (metric), Long=1 + + + + Custom Offsets + + + + Neural Network Lateral Control (NNLC) + + + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Enable Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying FRICTION and LAT_ACCEL_FACTOR below will override the offline values indicated in the YAML files within "selfdrive/torque_data". The values will also be used live when "Override Self-Tune" toggle is enabled. + + + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Quiet Drive 🤫 + + + + sunnypilot will display alerts but only play the most important warning sounds. This feature can be toggled while the car is on. + + + + Green Traffic Light Chime (Beta) + + + + A chime will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. If you are waiting behind another vehicle, the chime will play once the vehicle advances unless ACC is engaged. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Vehicle Departure Alert + + + + Enable this will notify when the leading vehicle drives away. + + + + Customize M.A.D.S. + + + + Customize Lane Change + + + + Customize Offsets + + + + Customize Speed Limit Control + + + + Customize Warning + + + + Customize Source + + + + Laneful + + + + Laneless + + + + Auto + + + + Dynamic Lane Profile + + + + Speed Limit Assist + + + + Real-time and Offline + + + + Offline Only + + + + Dynamic Lane Profile is not available with the current Driving Model + + + + Custom Offsets is not available with the current Driving Model + + + + NNLC is currently not available on this platform. + + + + Match: "Exact" is ideal, but "Fuzzy" is fine too. Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server if there are any issues: + + + + Start the car to check car compatibility + + + + NNLC Not Loaded + + + + NNLC Loaded + + + + Fuzzy + + + + Exact + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server and donate logs to get NNLC loaded for your car: + + + + Match + + + + Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server with feedback, or to provide log data for your car if your car is currently unsupported: + + + + Add custom offsets to Camera and Path in sunnypilot. + + + + Default is Laneless. In Auto mode, sunnnypilot dynamically chooses between Laneline or Laneless model based on lane recognition confidence level on road and certain conditions. + + + TermsPage @@ -1032,15 +2693,30 @@ This may take up to a minute. Zustimmen + + TermsPageSP + + Terms & Conditions + Benutzungsbedingungen + + + Decline + Ablehnen + + + Scroll to accept + Scrolle herunter um zu akzeptieren + + TogglesPanel Enable openpilot - Openpilot aktivieren + Openpilot aktivieren Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. - Benutze das Openpilot System als adaptiven Tempomaten und Spurhalteassistenten. Deine Aufmerksamkeit ist jederzeit erforderlich, um diese Funktion zu nutzen. Diese Einstellung wird übernommen, wenn das Auto aus ist. + Benutze das Openpilot System als adaptiven Tempomaten und Spurhalteassistenten. Deine Aufmerksamkeit ist jederzeit erforderlich, um diese Funktion zu nutzen. Diese Einstellung wird übernommen, wenn das Auto aus ist. Enable Lane Departure Warnings @@ -1072,21 +2748,21 @@ This may take up to a minute. Use 24h format instead of am/pm - Benutze das 24Stunden Format anstatt am/pm + Benutze das 24Stunden Format anstatt am/pm Show Map on Left Side of UI Too long for UI - Zeige die Karte auf der linken Seite + Zeige die Karte auf der linken Seite Show map on left side when in split screen view. - Zeige die Karte auf der linken Seite der Benutzeroberfläche bei geteilten Bildschirm. + Zeige die Karte auf der linken Seite der Benutzeroberfläche bei geteilten Bildschirm. Show ETA in 24h Format Too long for UI - Zeige die Ankunftszeit im 24 Stunden Format + Zeige die Ankunftszeit im 24 Stunden Format Experimental Mode @@ -1172,6 +2848,252 @@ This may take up to a minute. Enable driver monitoring even when openpilot is not engaged. + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + + TogglesPanelSP + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + openpilot Longitudinal Control (Alpha) + + + + WARNING: sunnypilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + + + + On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to sunnypilot longitudinal control. Enabling Experimental mode is recommended when enabling sunnypilot longitudinal control alpha. + + + + Custom Stock Longitudinal Control + + + + When enabled, sunnypilot will attempt to control stock longitudinal control with ACC button presses. +This feature must be used along with SLC, and/or V-TSC, and/or M-TSC. + + + + Experimental Mode + Experimenteller Modus + + + Enable Dynamic Experimental Control + + + + Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. + + + + Enable Dynamic Personality + + + + Enable this to allow sunnypilot to dynamically adjust following distance and reaction based on your "Driving Personality" setting. Instead of predefined settings for each personality, every personality now adapts dynamically according to your speed and the distance to the lead car. + + + + Disengage on Accelerator Pedal + Bei Gasbetätigung ausschalten + + + When enabled, pressing the accelerator pedal will disengage openpilot. + Wenn aktiviert, deaktiviert sich Openpilot sobald das Gaspedal betätigt wird. + + + Enable Lane Departure Warnings + Spurverlassenswarnungen aktivieren + + + Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). + Erhalte Warnungen, zurück in die Spur zu lenken, wenn dein Auto über eine erkannte Fahrstreifenmarkierung ohne aktivierten Blinker mit mehr als 50 km/h fährt. + + + Always-On Driver Monitoring + + + + Enable driver monitoring even when sunnypilot is not engaged. + + + + Record and Upload Driver Camera + Fahrerkamera aufnehmen und hochladen + + + Upload data from the driver facing camera and help improve the driver monitoring algorithm. + Lade Daten der Fahreraufmerksamkeitsüberwachungskamera hoch, um die Fahreraufmerksamkeitsüberwachungsalgorithmen zu verbessern. + + + Disable Onroad Uploads + + + + Disable uploads completely when onroad. Necessary to avoid high data usage when connected to Wi-Fi hotspot. Turn on this feature if you are looking to utilize map-based features, such as Speed Limit Control (SLC) and Map-based Turn Speed Control (MTSC). + + + + Use Metric System + Benutze das metrische System + + + Display speed in km/h instead of mph. + Zeige die Geschwindigkeit in km/h anstatt von mph. + + + Show ETA in 24h Format + Zeige die Ankunftszeit im 24 Stunden Format + + + Use 24h format instead of am/pm + Benutze das 24Stunden Format anstatt am/pm + + + Show Map on Left Side of UI + Zeige die Karte auf der linken Seite + + + Show map on left side when in split screen view. + Zeige die Karte auf der linken Seite der Benutzeroberfläche bei geteilten Bildschirm. + + + Aggressive + + + + Moderate + + + + Standard + + + + Relaxed + + + + Driving Personality + + + + Standard is recommended. In moderate/aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + + + + Sport + + + + Normal + + + + Eco + + + + Stock + + + + Acceleration Personality + + + + Normal is recommended. In sport mode, sunnypilot will provide aggressive acceleration for a dynamic driving experience. In eco mode, sunnypilot will apply smoother and more relaxed acceleration. On supported cars, you can cycle through these acceleration personality within Onroad Settings on the driving screen. + + + + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + Openpilot fährt standardmäßig im <b>entspannten Modus</b>. Der Experimentelle Modus aktiviert<b>Alpha-level Funktionen</b>, die noch nicht für den entspannten Modus bereit sind. Die experimentellen Funktionen sind die Folgenden: + + + End-to-End Longitudinal Control + + + + Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + + + + New Driving Visualization + Neue Fahrvisualisierung + + + The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. + + + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + Der experimentelle Modus ist momentan für dieses Auto nicht verfügbar da es den eingebauten adaptiven Tempomaten des Autos benutzt. + + + openpilot longitudinal control may come in a future update. + + + + An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. + + + + + TorqueFriction + + FRICTION + + + + Adjust Friction for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueMaxLatAccel + + LAT_ACCEL_FACTOR + + + + Adjust Max Lateral Acceleration for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + Updater @@ -1208,6 +3130,168 @@ This may take up to a minute. Aktualisierung fehlgeschlagen + + VehiclePanel + + Updating this setting takes effect when the car is powered off. + + + + Select your car + + + + + VisualsPanel + + Display Braking Status + + + + Enable this will turn the current speed value to red while the brake is used. + + + + Display Stand Still Timer + + + + Enable this will display time spent at a stop (i.e., at a stop lights, stop signs, traffic congestions). + + + + Display DM Camera in Reverse Gear + + + + Show Driver Monitoring camera while the car is in reverse gear. + + + + OSM: Show debug UI elements + + + + OSM: Show UI elements that aid debugging. + + + + Display Feature Status + + + + Display the statuses of certain features on the driving screen. + + + + Enable Onroad Settings + + + + Display the Onroad Settings button on the driving screen to adjust feature options on the driving screen, without navigating into the settings menu. + + + + Speedometer: Display True Speed + + + + Display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Display End-to-end Longitudinal Status (Beta) + + + + Enable this will display an icon that appears when the End-to-end model decides to start or stop. + + + + Navigation: Display in Full Screen + + + + Enable this will display the built-in navigation in full screen.<br>To switch back to driving view, <font color='yellow'>tap on the border edge</font>. + + + + Map: Display 3D Buildings + + + + Parse and display 3D buildings on map. Thanks to jakethesnake420 for this implementation. + + + + Off + + + + 5 Metrics + + + + 10 Metrics + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + + + Distance + + + + Speed + + + + Display Metrics Below Chevron + + + + Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + + + RAM + + + + CPU + + + + GPU + + + + Max + + + + Display Temperature on Sidebar + + + + Time + + + + All + + + WiFiPromptWidget @@ -1254,4 +3338,27 @@ This may take up to a minute. Vergessen + + WifiUISP + + Scanning for networks... + Suche nach Netzwerken... + + + CONNECTING... + VERBINDEN... + + + FORGET + VERGESSEN + + + Forget Wi-Fi Network "%1"? + WLAN Netzwerk "%1" vergessen? + + + Forget + Vergessen + + diff --git a/selfdrive/ui/translations/main_es.ts b/selfdrive/ui/translations/main_es.ts index ee262c0953..6527ddfc12 100644 --- a/selfdrive/ui/translations/main_es.ts +++ b/selfdrive/ui/translations/main_es.ts @@ -87,6 +87,89 @@ para "%1" + + AdvancedNetworkingSP + + Back + + + + Enable Tethering + Activar Tether + + + Retain hotspot/tethering state + + + + Enabling this toggle will retain the hotspot/tethering toggle state across reboots. + + + + Tethering Password + Contraseña de Tethering + + + EDIT + EDITAR + + + Enter new tethering password + Nueva contraseña de tethering + + + IP Address + Dirección IP + + + Enable Roaming + Activar Roaming + + + APN Setting + Configuración de APN + + + Enter APN + Insertar APN + + + leave blank for automatic configuration + dejar en blanco para configuración automática + + + Cellular Metered + Plano de datos limitado + + + Prevent large data uploads when on a metered connection + Evitar grandes descargas de datos cuando tiene una conexión limitada + + + Hidden Network + Red Oculta + + + CONNECT + + + + Enter SSID + Ingrese SSID + + + Enter password + + + + for "%1" + para "%1" + + + Ngrok Service + + + AnnotatedCameraWidget @@ -103,11 +186,119 @@ SPEED - VELOCIDAD + VELOCIDAD LIMIT - LIMITE + LIMITE + + + + AnnotatedCameraWidgetSP + + km/h + km/h + + + mph + mph + + + MAX + MAX + + + SPEED + VELOCIDAD + + + LIMIT + LIMITE + + + + AutoLaneChangeTimer + + Auto Lane Change by Blinker + + + + Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. +Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. + + + + s + + + + Off + + + + Nudge + + + + Nudgeless + + + + + BackupSettings + + Settings backed up for sunnylink Device ID: + + + + Settings updated successfully, but no additional data was returned by the server. + + + + OOPS! We made a booboo. + + + + Please try again later. + + + + Settings restored. Confirm to restart the interface. + + + + No settings found to restore. + + + + + BrightnessControl + + Brightness + + + + Manually adjusts the global brightness of the screen. + + + + Auto + + + + + CameraOffset + + Camera Offset - Laneful Only + + + + Hack to trick vehicle to be left or right biased in its lane. Decreasing the value will make the car keep more left, increasing will make it keep more right. Changes take effect immediately. Default: +4 cm + + + + cm + @@ -121,11 +312,18 @@ Cancelar + + CustomOffsetsSettings + + Back + + + DeclinePage You must accept the Terms and Conditions in order to use openpilot. - Debe aceptar los terminos y condiciones para poder utilizar openpilot. + Debe aceptar los terminos y condiciones para poder utilizar openpilot. Back @@ -135,6 +333,37 @@ Decline, uninstall %1 Rechazar, desinstalar %1 + + You must accept the Terms and Conditions in order to use sunnypilot. + + + + + DestinationWidget + + Home + + + + Work + + + + No destination set + + + + home + + + + work + + + + No %1 location set + + DevicePanel @@ -240,7 +469,7 @@ openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required. - openpilot requiere que el dispositivo sea montado entre 4° izquierda o derecha y entre 5° arriba o 9° abajo. openpilot está constantemente en calibración, reiniciar es rara vez necesario. + openpilot requiere que el dispositivo sea montado entre 4° izquierda o derecha y entre 5° arriba o 9° abajo. openpilot está constantemente en calibración, reiniciar es rara vez necesario. Your device is pointed %1° %2 and %3° %4. @@ -278,6 +507,155 @@ Disengage to Power Off Desactivar para apagar + + sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. sunnypilot is continuously calibrating, resetting is rarely required. + + + + + DevicePanelSP + + TOGGLE + + + + Enable or disable PIN requirement for Fleet Manager access. + + + + Are you sure you want to turn off PIN requirement? + + + + Turn Off + + + + Error Troubleshoot + + + + VIEW + VER + + + Display error from the tmux session when an error has occurred from a system process. + + + + Reset Access Tokens for Map Services + + + + RESET + REINICIAR + + + Reset self-service access tokens for Mapbox, Amap, and Google Maps. + + + + Are you sure you want to reset access tokens for all map services? + + + + Reset + Reiniciar + + + Reset sunnypilot Settings + + + + Are you sure you want to reset all sunnypilot settings? + + + + Toggle Onroad/Offroad + + + + OFF + + + + Are you sure you want to unforce offroad? + + + + Unforce + + + + Are you sure you want to force offroad? + + + + Force + + + + Disengage to Force Offroad + + + + Unforce Offroad + + + + Force Offroad + + + + Fleet Manager PIN: + + + + + DisplayPanel + + Driving Screen Off: Non-Critical Events + + + + When <b>Driving Screen Off Timer</b> is not set to <b>"Always On"</b>: + + + + Enabled: Wake the brightness of the screen to display all events. + + + + Disabled: Wake the brightness of the screen to display critical events. + + + + + DriveStats + + Drives + + + + Hours + + + + ALL TIME + + + + PAST WEEK + + + + KM + + + + Miles + + DriverViewWindow @@ -318,6 +696,177 @@ Instalando... + + LaneChangeSettings + + Back + + + + Pause Lateral Below Speed with Blinker + + + + Enable this toggle to pause lateral actuation with blinker when traveling below the desired speed selected below. + + + + Auto Lane Change: Delay with Blind Spot + + + + Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. + + + + Block Lane Change: Road Edge Detection + + + + Enable this toggle to block lane change when road edge is detected on the stalk actuated side. + + + + + MadsSettings + + Enable ACC+MADS with RES+/SET- + + + + Engage both M.A.D.S. and ACC with a single press of RES+ or SET- button. + + + + Note: Once M.A.D.S. is engaged via this mode, it will remain engaged until it is manually disabled via the M.A.D.S. button or car shut off. + + + + Toggle M.A.D.S. with Cruise Main + + + + Allows M.A.D.S. engagement/disengagement with "Cruise Main" cruise control button from the steering wheel. + + + + Remain Active + + + + Pause Steering + + + + Steering Mode After Braking + + + + Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. + +Remain Active: ALC will remain active even after the brake pedal is pressed. +Pause Steering: ALC will be paused after the brake pedal is manually pressed. + + + + + MapETA + + eta + + + + min + + + + hr + + + + + MapSettings + + NAVIGATION + + + + Manage at connect.comma.ai + + + + + MapWindow + + Map Loading + + + + Waiting for GPS + + + + Waiting for route + + + + + MapWindowSP + + Map Loading + + + + Waiting for GPS + + + + Waiting for route + + + + + MaxTimeOffroad + + Max Time Offroad + + + + Device is automatically turned off after a set time when the engine is turned off (off-road) after driving (on-road). + + + + s + + + + m + + + + hr + + + + Always On + + + + Immediate + + + + + MonitoringPanel + + Enable Hands on Wheel Monitoring + + + + Monitor and alert when driver is not keeping the hands on the steering wheel. + + + MultiOptionDialog @@ -348,6 +897,33 @@ Contraseña equivocada + + NetworkingSP + + Scan + + + + Scanning... + + + + Advanced + Avanzado + + + Enter password + + + + for "%1" + para "%1" + + + Wrong password + Contraseña equivocada + + OffroadAlert @@ -400,6 +976,16 @@ openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. openpilot detectó un cambio en la posición de montaje del dispositivo. Asegúrese de que el dispositivo esté completamente asentado en el soporte y que el soporte esté firmemente asegurado al parabrisas. + + OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. + +%1 + + + + sunnypilot is now in Forced Offroad mode. sunnypilot won't start until Forced Offroad mode is disabled. Go to "Settings" -> "Device" -> "Unforce Offroad" to exit Force Offroad mode. + + OffroadHome @@ -439,6 +1025,186 @@ Reiniciar Dispositivo + + OnroadScreenOff + + Driving Screen Off Timer + + + + Turn off the device screen or reduce brightness to protect the screen after driving starts. It automatically brightens or turns on when a touch or event occurs. + + + + s + + + + min + + + + Always On + + + + + OnroadScreenOffBrightness + + Driving Screen Off Brightness (%) + + + + When using the Driving Screen Off feature, the brightness is reduced according to the automatic brightness ratio. + + + + Dark + + + + + OnroadSettings + + ONROAD OPTIONS + + + + <b>ONROAD SETTINGS | SUNNYPILOT</b> + + + + + OsmPanel + + Mapd Version + + + + Offline Maps ETA + + + + Time Elapsed + + + + Downloaded Maps + + + + DELETE + + + + This will delete ALL downloaded maps + +Are you sure you want to delete all the maps? + + + + Yes, delete all the maps. + + + + Database Update + + + + CHECK + VERIFICAR + + + Country + + + + SELECT + SELECCIONAR + + + Fetching Country list... + + + + State + + + + Fetching State list... + + + + All + + + + REFRESH + + + + UPDATE + ACTUALIZAR + + + Download starting... + + + + Error: Invalid download. Retry. + + + + Download complete! + + + + + +Warning: You are on a metered connection! + + + + This will start the download process and it might take a while to complete. + + + + Continue on Metered + + + + Start Download + + + + m + + + + s + + + + Calculating... + + + + Downloaded + + + + Calculating ETA... + + + + Ready + + + + Time remaining: + + + PairingPopup @@ -469,6 +1235,51 @@ Cancelar + + ParamControlSP + + Enable + Activar + + + Cancel + Cancelar + + + + PathOffset + + Path Offset + + + + Hack to trick the model path to be left or right biased of the lane. Decreasing the value will shift the model more left, increasing will shift the model more right. Changes take effect immediately. + + + + cm + + + + + PauseLateralSpeed + + Pause lateral actuation with blinker when traveling below the desired speed selected. Default is 20 MPH or 32 km/h. + + + + Default + + + + km/h + km/h + + + mph + mph + + PrimeAdWidget @@ -497,7 +1308,11 @@ Remote snapshots - Istantánea remota + Istantánea remota + + + Turn-by-turn navigation + @@ -523,7 +1338,7 @@ openpilot - openpilot + openpilot now @@ -550,6 +1365,46 @@ hace %n días + + km + + + + m + + + + mi + + + + ft + + + + sunnypilot + + + + Update downloaded. Ready to reboot. + + + + Update: Check and Download Update + + + + Reboot: Reboot Device + + + + Update + + + + Updating... + + Reset @@ -592,6 +1447,131 @@ Esto puede tardar hasta un minuto. No es posible montar una partición de datos. Partición corrompida. Confirme para borrar y reiniciar su dispositivo. + + SPVehiclesTogglesPanel + + Hyundai/Kia/Genesis + + + + HKG CAN: Smoother Stopping Performance (Beta) + + + + Smoother stopping behind a stopped car or desired stopping event. This is only applicable to HKG CAN platforms using openpilot longitudinal control. + + + + Subaru + + + + Manual Parking Brake: Stop and Go (Beta) + + + + Experimental feature to enable stop and go for Subaru Global models with manual handbrake. Models with electric parking brake should keep this disabled. Thanks to martinl for this implementation! + + + + Toyota/Lexus + + + + Enable Stock Toyota Longitudinal Control + + + + sunnypilot will <b>not</b> take over control of gas and brakes. Stock Toyota longitudinal control will be used. + + + + Allow M.A.D.S. toggling w/ LKAS Button (Beta) + + + + Allows M.A.D.S. engagement/disengagement with "LKAS" button from the steering wheel. + + + + Note: Enabling this toggle may have unexpected behavior with steering control. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Toyota TSS2 Longitudinal: Custom Tuning + + + + Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + + + Enable Enhanced Blind Spot Monitor + + + + Enable Toyota Stop and Go Hack + + + + sunnypilot will allow some Toyota/Lexus cars to auto resume during stop and go traffic. This feature is only applicable to certain models. Use at your own risk. + + + + Enable Toyota Door Auto Locking + + + + sunnypilot will attempt to lock the doors when drive above 10 km/h (6.2 mph). +Reboot Required. + + + + Enable Toyota Door Auto Unlocking + + + + sunnypilot will attempt to unlock the doors when shift to gear P. +Reboot Required. + + + + Volkswagen + + + + Enable CC Only support + + + + sunnypilot supports Volkswagen MQB CC only platforms with this toggle enabled. Only enable this toggle if your car does not have ACC from the factory. + + + + Start the car to check car compatibility + + + + This platform is already supported, therefore no need to enable this toggle + + + + This platform is not supported + + + + This platform can be supported + + + + sunnypilot will use debugging CAN messages to receive unfiltered BSM signals, allowing detection of more objects. + + + + Tested on RAV4 TSS1, Lexus LSS1, Toyota TSS1/1.5, and Prius TSS2. + + + SettingsWindow @@ -615,6 +1595,61 @@ Esto puede tardar hasta un minuto. Software + + SettingsWindowSP + + × + × + + + Device + Dispositivo + + + Network + Red + + + sunnylink + + + + Toggles + Ajustes + + + Software + Software + + + sunnypilot + + + + OSM + + + + Monitoring + + + + Visuals + + + + Display + + + + Trips + + + + Vehicle + + + Setup @@ -808,6 +1843,100 @@ Esto puede tardar hasta un minuto. 5G + + SidebarSP + + TEMP + TEMP + + + HIGH + ALTA + + + GOOD + BUENO + + + OK + OK + + + DISABLED + + + + OFFLINE + SIN LINEA + + + REGIST... + + + + ONLINE + EN LINEA + + + ERROR + ERROR + + + SUNNYLINK + + + + + SlcSettings + + Auto + + + + User Confirm + + + + Engage Mode + + + + Default + + + + Fixed + + + + Percentage + + + + Limit Offset + + + + Set speed limit slightly higher than actual speed limit for a more natural drive. + + + + This platform defaults to <b>Auto</b> mode. <b>User Confirm</b> mode is not supported on this platform. + + + + Select the desired mode to set the cruising speed to the speed limit: + + + + Auto: Automatic speed adjustment on motorways based on speed limit data. + + + + User Confirm: Inform the driver to change set speed of Adaptive Cruise Control to help the driver stay within the speed limit. + + + SoftwarePanel @@ -883,6 +2012,233 @@ Esto puede tardar hasta un minuto. actualizado, último chequeo %1 + + SoftwarePanelSP + + Driving Model + + + + SELECT + SELECCIONAR + + + PENDING + + + + Downloading Driving model + + + + (CACHED) + + + + Driving model + + + + downloaded + + + + Downloading Navigation model + + + + Navigation model + + + + Downloading Metadata model + + + + Metadata model + + + + Downloads have failed, please try swapping the model! + + + + Failed: + + + + Fetching models... + + + + Select a Driving Model + + + + Download has started in the background. + + + + We STRONGLY suggest you to reset calibration. Would you like to do that now? + + + + Reset Calibration + Reiniciar Calibración + + + Warning: You are on a metered connection! + + + + Continue + Continuar + + + on Metered + + + + + SpeedLimitPolicySettings + + Speed Limit Source Policy + + + + Nav + + + + Only + + + + Map + + + + Car + + + + First + + + + Select the precedence order of sources. Utilized by Speed Limit Control and Speed Limit Warning + + + + Nav Only: Data from Mapbox active navigation only. + + + + Map Only: Data from OpenStreetMap only. + + + + Car Only: Data from the car's built-in sources (if available). + + + + Nav First: Nav -> Map -> Car + + + + Map First: Map -> Nav -> Car + + + + Car First: Car -> Nav -> Map + + + + + SpeedLimitValueOffset + + km/h + km/h + + + mph + mph + + + + SpeedLimitWarningSettings + + Off + + + + Display + + + + Chime + + + + Speed Limit Warning + + + + Warning with speed limit flash + + + + When Speed Limit Warning is enabled, the speed limit sign will alert the driver when the cruising speed is faster than then speed limit plus the offset. + + + + Default + + + + Fixed + + + + Percentage + + + + Warning Offset + + + + Select the desired offset to warn the driver when the vehicle is driving faster than the speed limit. + + + + Off: When the cruising speed is faster than the speed limit plus the offset, there will be no warning. + + + + Display: The speed on the speed limit sign turns red to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + Chime: The speed on the speed limit sign turns red and chimes to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + + SpeedLimitWarningValueOffset + + N/A + N/A + + + km/h + km/h + + + mph + mph + + SshControl @@ -929,6 +2285,399 @@ Esto puede tardar hasta un minuto. Habilitar SSH + + SunnylinkPanel + + Enable sunnylink + + + + Device ID + + + + N/A + N/A + + + This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. + + + + 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 + + + + 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. + + + + Sponsor Status + + + + SPONSOR + + + + Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. + + + + Pair GitHub Account + + + + PAIR + EMPAREJAR + + + Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. + + + + sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. + + + + Manage Settings + + + + Backup Settings + + + + Are you sure you want to backup sunnypilot settings? + + + + Back Up + + + + Restore Settings + + + + Are you sure you want to restore the last backed up sunnypilot settings? + + + + Restore + + + + THANKS + + + + Not Sponsor + + + + Paired + + + + Not Paired + + + + Backing up... + + + + Restoring... + + + + + SunnylinkSponsorPopup + + Scan the QR code to login to your GitHub account + + + + Follow the prompts to complete the pairing process + + + + Re-enter the "sunnylink" panel to verify sponsorship status + + + + If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot + + + + Scan the QR code to visit sunnyhaibin's GitHub Sponsors page + + + + Choose your sponsorship tier and confirm your support + + + + Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status + + + + Pair your GitHub account + + + + Early Access: Become a sunnypilot Sponsor + + + + + SunnypilotPanel + + Enable M.A.D.S. + + + + Enable the beloved M.A.D.S. feature. Disable toggle to revert back to stock openpilot engagement/disengagement. + + + + Laneless for Curves in "Auto" Mode + + + + While in Auto Lane, switch to Laneless for current/future curves. + + + + Speed Limit Control (SLC) + + + + When you engage ACC, you will be prompted to set the cruising speed to the speed limit of the road adjusted by the Offset and Source Policy specified, or the current driving speed. The maximum cruising speed will always be the MAX set speed. + + + + Enable Vision-based Turn Speed Control (V-TSC) + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Enable Map Data Turn Speed Control (M-TSC) (Beta) + + + + Use curvature information from map data to define speed limits to take turns ahead. + + + + ACC +/-: Long Press Reverse + + + + Change the ACC +/- buttons behavior with cruise speed change in sunnypilot. + + + + Disabled (Stock): Short=1, Long = 5 (imperial) / 10 (metric) + + + + Enabled: Short = 5 (imperial) / 10 (metric), Long=1 + + + + Custom Offsets + + + + Neural Network Lateral Control (NNLC) + + + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Enable Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying FRICTION and LAT_ACCEL_FACTOR below will override the offline values indicated in the YAML files within "selfdrive/torque_data". The values will also be used live when "Override Self-Tune" toggle is enabled. + + + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Quiet Drive 🤫 + + + + sunnypilot will display alerts but only play the most important warning sounds. This feature can be toggled while the car is on. + + + + Green Traffic Light Chime (Beta) + + + + A chime will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. If you are waiting behind another vehicle, the chime will play once the vehicle advances unless ACC is engaged. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Vehicle Departure Alert + + + + Enable this will notify when the leading vehicle drives away. + + + + Customize M.A.D.S. + + + + Customize Lane Change + + + + Customize Offsets + + + + Customize Speed Limit Control + + + + Customize Warning + + + + Customize Source + + + + Laneful + + + + Laneless + + + + Auto + + + + Dynamic Lane Profile + + + + Speed Limit Assist + + + + Real-time and Offline + + + + Offline Only + + + + Dynamic Lane Profile is not available with the current Driving Model + + + + Custom Offsets is not available with the current Driving Model + + + + NNLC is currently not available on this platform. + + + + Match: "Exact" is ideal, but "Fuzzy" is fine too. Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server if there are any issues: + + + + Start the car to check car compatibility + + + + NNLC Not Loaded + + + + NNLC Loaded + + + + Fuzzy + + + + Exact + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server and donate logs to get NNLC loaded for your car: + + + + Match + + + + Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server with feedback, or to provide log data for your car if your car is currently unsupported: + + + + Add custom offsets to Camera and Path in sunnypilot. + + + + Default is Laneless. In Auto mode, sunnnypilot dynamically chooses between Laneline or Laneless model based on lane recognition confidence level on road and certain conditions. + + + TermsPage @@ -948,15 +2697,30 @@ Esto puede tardar hasta un minuto. Aceptar + + TermsPageSP + + Terms & Conditions + Terminos & Condiciones + + + Decline + Rechazar + + + Scroll to accept + Desliza para aceptar + + TogglesPanel Enable openpilot - Activar openpilot + Activar openpilot Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. - Utilice el sistema openpilot para control de crucero adaptativo y asistencia al conductor para mantenerse en el carril. Se requiere su atención en todo momento para utilizar esta función. Cambiar esta configuración solo tendrá efecto con el auto apagado. + Utilice el sistema openpilot para control de crucero adaptativo y asistencia al conductor para mantenerse en el carril. Se requiere su atención en todo momento para utilizar esta función. Cambiar esta configuración solo tendrá efecto con el auto apagado. openpilot Longitudinal Control (Alpha) @@ -1070,6 +2834,252 @@ Esto puede tardar hasta un minuto. Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. Activar el control longitudinal experimental para permitir el modo Experimental. + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + + TogglesPanelSP + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + openpilot Longitudinal Control (Alpha) + Control longitudinal de openpilot (Alfa) + + + WARNING: sunnypilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + + + + On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to sunnypilot longitudinal control. Enabling Experimental mode is recommended when enabling sunnypilot longitudinal control alpha. + + + + Custom Stock Longitudinal Control + + + + When enabled, sunnypilot will attempt to control stock longitudinal control with ACC button presses. +This feature must be used along with SLC, and/or V-TSC, and/or M-TSC. + + + + Experimental Mode + Modo Experimental + + + Enable Dynamic Experimental Control + + + + Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. + + + + Enable Dynamic Personality + + + + Enable this to allow sunnypilot to dynamically adjust following distance and reaction based on your "Driving Personality" setting. Instead of predefined settings for each personality, every personality now adapts dynamically according to your speed and the distance to the lead car. + + + + Disengage on Accelerator Pedal + Desactivar con el Acelerador + + + When enabled, pressing the accelerator pedal will disengage openpilot. + Cuando esté activado, presionar el acelerador deshabilitará el openpilot. + + + Enable Lane Departure Warnings + Activar Aviso de Salida de Carril + + + Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). + Recibir alertas para volver dentro del carril cuando su vehículo se sale fuera del carril sin que esté activado la señal de giro mientras esté conduciendo por encima de 50 km/h (31 mph). + + + Always-On Driver Monitoring + Monitoreo del Conductor Siempre Activo + + + Enable driver monitoring even when sunnypilot is not engaged. + + + + Record and Upload Driver Camera + Grabar y Subir Cámara del Conductor + + + Upload data from the driver facing camera and help improve the driver monitoring algorithm. + Subir datos de la cámara del conductor para ayudar a mejorar el algoritmo de monitorización del conductor. + + + Disable Onroad Uploads + + + + Disable uploads completely when onroad. Necessary to avoid high data usage when connected to Wi-Fi hotspot. Turn on this feature if you are looking to utilize map-based features, such as Speed Limit Control (SLC) and Map-based Turn Speed Control (MTSC). + + + + Use Metric System + Usar Sistema Métrico + + + Display speed in km/h instead of mph. + Mostrar velocidad en km/h en vez de mph. + + + Show ETA in 24h Format + + + + Use 24h format instead of am/pm + + + + Show Map on Left Side of UI + + + + Show map on left side when in split screen view. + + + + Aggressive + Agresivo + + + Moderate + + + + Standard + Estándar + + + Relaxed + Relajado + + + Driving Personality + Personalidad de conducción + + + Standard is recommended. In moderate/aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + + + + Sport + + + + Normal + + + + Eco + + + + Stock + + + + Acceleration Personality + + + + Normal is recommended. In sport mode, sunnypilot will provide aggressive acceleration for a dynamic driving experience. In eco mode, sunnypilot will apply smoother and more relaxed acceleration. On supported cars, you can cycle through these acceleration personality within Onroad Settings on the driving screen. + + + + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + openpilot por defecto conduce en <b>modo chill</b>. El modo Experimental activa <b>recursos de nível-alfa</b> que no están listos para el modo chill. Los recursos del modo expeimental están listados abajo: + + + End-to-End Longitudinal Control + 🌮 Control Longitudinal de Punta a Punta 🌮 + + + Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + + + + New Driving Visualization + Nueva Visualización de la conducción + + + The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. + La visualización de la conducción cambiará a la cámara que enfoca la carretera a velocidades bajas para mostrar mejor los giros. El logo del modo experimental se mostrará en la esquina superior derecha. + + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + El modo Experimental no está disponible actualmente para este auto, ya que el ACC del auto está siendo usado para el control longitudinal. + + + openpilot longitudinal control may come in a future update. + El control longitudinal de openpilot podrá llegar en futuras actualizaciones. + + + An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. + + + + + TorqueFriction + + FRICTION + + + + Adjust Friction for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueMaxLatAccel + + LAT_ACCEL_FACTOR + + + + Adjust Max Lateral Acceleration for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + Updater @@ -1106,6 +3116,168 @@ Esto puede tardar hasta un minuto. Actualización fallida + + VehiclePanel + + Updating this setting takes effect when the car is powered off. + + + + Select your car + + + + + VisualsPanel + + Display Braking Status + + + + Enable this will turn the current speed value to red while the brake is used. + + + + Display Stand Still Timer + + + + Enable this will display time spent at a stop (i.e., at a stop lights, stop signs, traffic congestions). + + + + Display DM Camera in Reverse Gear + + + + Show Driver Monitoring camera while the car is in reverse gear. + + + + OSM: Show debug UI elements + + + + OSM: Show UI elements that aid debugging. + + + + Display Feature Status + + + + Display the statuses of certain features on the driving screen. + + + + Enable Onroad Settings + + + + Display the Onroad Settings button on the driving screen to adjust feature options on the driving screen, without navigating into the settings menu. + + + + Speedometer: Display True Speed + + + + Display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Display End-to-end Longitudinal Status (Beta) + + + + Enable this will display an icon that appears when the End-to-end model decides to start or stop. + + + + Navigation: Display in Full Screen + + + + Enable this will display the built-in navigation in full screen.<br>To switch back to driving view, <font color='yellow'>tap on the border edge</font>. + + + + Map: Display 3D Buildings + + + + Parse and display 3D buildings on map. Thanks to jakethesnake420 for this implementation. + + + + Off + + + + 5 Metrics + + + + 10 Metrics + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + + + Distance + + + + Speed + + + + Display Metrics Below Chevron + + + + Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + + + RAM + + + + CPU + + + + GPU + + + + Max + + + + Display Temperature on Sidebar + + + + Time + + + + All + + + WiFiPromptWidget @@ -1152,4 +3324,27 @@ Esto puede tardar hasta un minuto. Olvidar + + WifiUISP + + Scanning for networks... + Buscando redes... + + + CONNECTING... + CONECTANDO... + + + FORGET + OLVIDAR + + + Forget Wi-Fi Network "%1"? + Olvidar Red Wi-Fi "%1"? + + + Forget + Olvidar + + diff --git a/selfdrive/ui/translations/main_fr.ts b/selfdrive/ui/translations/main_fr.ts index dde6adadd3..0071a33e47 100644 --- a/selfdrive/ui/translations/main_fr.ts +++ b/selfdrive/ui/translations/main_fr.ts @@ -87,6 +87,89 @@ pour "%1" + + AdvancedNetworkingSP + + Back + Retour + + + Enable Tethering + Activer le partage de connexion + + + Retain hotspot/tethering state + + + + Enabling this toggle will retain the hotspot/tethering toggle state across reboots. + + + + Tethering Password + Mot de passe du partage de connexion + + + EDIT + MODIFIER + + + Enter new tethering password + Entrez le nouveau mot de passe du partage de connexion + + + IP Address + Adresse IP + + + Enable Roaming + Activer l'itinérance + + + APN Setting + Paramètre APN + + + Enter APN + Entrer le nom du point d'accès + + + leave blank for automatic configuration + laisser vide pour une configuration automatique + + + Cellular Metered + Connexion cellulaire limitée + + + Prevent large data uploads when on a metered connection + Éviter les transferts de données importants sur une connexion limitée + + + Hidden Network + Réseau Caché + + + CONNECT + CONNECTER + + + Enter SSID + Entrer le SSID + + + Enter password + Entrer le mot de passe + + + for "%1" + pour "%1" + + + Ngrok Service + + + AnnotatedCameraWidget @@ -103,11 +186,119 @@ SPEED - VITESSE + VITESSE LIMIT - LIMITE + LIMITE + + + + AnnotatedCameraWidgetSP + + km/h + km/h + + + mph + mi/h + + + MAX + MAX + + + SPEED + VITESSE + + + LIMIT + LIMITE + + + + AutoLaneChangeTimer + + Auto Lane Change by Blinker + + + + Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. +Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. + + + + s + + + + Off + + + + Nudge + + + + Nudgeless + + + + + BackupSettings + + Settings backed up for sunnylink Device ID: + + + + Settings updated successfully, but no additional data was returned by the server. + + + + OOPS! We made a booboo. + + + + Please try again later. + + + + Settings restored. Confirm to restart the interface. + + + + No settings found to restore. + + + + + BrightnessControl + + Brightness + + + + Manually adjusts the global brightness of the screen. + + + + Auto + + + + + CameraOffset + + Camera Offset - Laneful Only + + + + Hack to trick vehicle to be left or right biased in its lane. Decreasing the value will make the car keep more left, increasing will make it keep more right. Changes take effect immediately. Default: +4 cm + + + + cm + @@ -121,11 +312,18 @@ Annuler + + CustomOffsetsSettings + + Back + Retour + + DeclinePage You must accept the Terms and Conditions in order to use openpilot. - Vous devez accepter les conditions générales pour utiliser openpilot. + Vous devez accepter les conditions générales pour utiliser openpilot. Back @@ -135,6 +333,10 @@ Decline, uninstall %1 Refuser, désinstaller %1 + + You must accept the Terms and Conditions in order to use sunnypilot. + + DestinationWidget @@ -255,7 +457,7 @@ openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required. - openpilot nécessite que l'appareil soit monté à 4° à gauche ou à droite et à 5° vers le haut ou 9° vers le bas. openpilot se calibre en continu, la réinitialisation est rarement nécessaire. + openpilot nécessite que l'appareil soit monté à 4° à gauche ou à droite et à 5° vers le haut ou 9° vers le bas. openpilot se calibre en continu, la réinitialisation est rarement nécessaire. Your device is pointed %1° %2 and %3° %4. @@ -305,6 +507,155 @@ PAIR + + sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. sunnypilot is continuously calibrating, resetting is rarely required. + + + + + DevicePanelSP + + TOGGLE + + + + Enable or disable PIN requirement for Fleet Manager access. + + + + Are you sure you want to turn off PIN requirement? + + + + Turn Off + + + + Error Troubleshoot + + + + VIEW + VOIR + + + Display error from the tmux session when an error has occurred from a system process. + + + + Reset Access Tokens for Map Services + + + + RESET + RÉINITIALISER + + + Reset self-service access tokens for Mapbox, Amap, and Google Maps. + + + + Are you sure you want to reset access tokens for all map services? + + + + Reset + Réinitialiser + + + Reset sunnypilot Settings + + + + Are you sure you want to reset all sunnypilot settings? + + + + Toggle Onroad/Offroad + + + + OFF + + + + Are you sure you want to unforce offroad? + + + + Unforce + + + + Are you sure you want to force offroad? + + + + Force + + + + Disengage to Force Offroad + + + + Unforce Offroad + + + + Force Offroad + + + + Fleet Manager PIN: + + + + + DisplayPanel + + Driving Screen Off: Non-Critical Events + + + + When <b>Driving Screen Off Timer</b> is not set to <b>"Always On"</b>: + + + + Enabled: Wake the brightness of the screen to display all events. + + + + Disabled: Wake the brightness of the screen to display critical events. + + + + + DriveStats + + Drives + + + + Hours + + + + ALL TIME + + + + PAST WEEK + + + + KM + + + + Miles + + DriverViewWindow @@ -345,6 +696,79 @@ Installation... + + LaneChangeSettings + + Back + Retour + + + Pause Lateral Below Speed with Blinker + + + + Enable this toggle to pause lateral actuation with blinker when traveling below the desired speed selected below. + + + + Auto Lane Change: Delay with Blind Spot + + + + Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. + + + + Block Lane Change: Road Edge Detection + + + + Enable this toggle to block lane change when road edge is detected on the stalk actuated side. + + + + + MadsSettings + + Enable ACC+MADS with RES+/SET- + + + + Engage both M.A.D.S. and ACC with a single press of RES+ or SET- button. + + + + Note: Once M.A.D.S. is engaged via this mode, it will remain engaged until it is manually disabled via the M.A.D.S. button or car shut off. + + + + Toggle M.A.D.S. with Cruise Main + + + + Allows M.A.D.S. engagement/disengagement with "Cruise Main" cruise control button from the steering wheel. + + + + Remain Active + + + + Pause Steering + + + + Steering Mode After Braking + + + + Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. + +Remain Active: ALC will remain active even after the brake pedal is pressed. +Pause Steering: ALC will be paused after the brake pedal is manually pressed. + + + MapETA @@ -386,6 +810,63 @@ En attente d'un trajet + + MapWindowSP + + Map Loading + Chargement de la carte + + + Waiting for GPS + En attente du GPS + + + Waiting for route + En attente d'un trajet + + + + MaxTimeOffroad + + Max Time Offroad + + + + Device is automatically turned off after a set time when the engine is turned off (off-road) after driving (on-road). + + + + s + + + + m + m + + + hr + h + + + Always On + + + + Immediate + + + + + MonitoringPanel + + Enable Hands on Wheel Monitoring + + + + Monitor and alert when driver is not keeping the hands on the steering wheel. + + + MultiOptionDialog @@ -416,6 +897,33 @@ Mot de passe incorrect + + NetworkingSP + + Scan + + + + Scanning... + + + + Advanced + Avancé + + + Enter password + Entrer le mot de passe + + + for "%1" + pour "%1" + + + Wrong password + Mot de passe incorrect + + OffroadAlert @@ -468,6 +976,16 @@ openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. openpilot a détecté un changement dans la position de montage de l'appareil. Assurez-vous que l'appareil est totalement inséré dans le support et que le support est fermement fixé au pare-brise. + + OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. + +%1 + + + + sunnypilot is now in Forced Offroad mode. sunnypilot won't start until Forced Offroad mode is disabled. Go to "Settings" -> "Device" -> "Unforce Offroad" to exit Force Offroad mode. + + OffroadHome @@ -507,6 +1025,186 @@ + + OnroadScreenOff + + Driving Screen Off Timer + + + + Turn off the device screen or reduce brightness to protect the screen after driving starts. It automatically brightens or turns on when a touch or event occurs. + + + + s + + + + min + min + + + Always On + + + + + OnroadScreenOffBrightness + + Driving Screen Off Brightness (%) + + + + When using the Driving Screen Off feature, the brightness is reduced according to the automatic brightness ratio. + + + + Dark + + + + + OnroadSettings + + ONROAD OPTIONS + + + + <b>ONROAD SETTINGS | SUNNYPILOT</b> + + + + + OsmPanel + + Mapd Version + + + + Offline Maps ETA + + + + Time Elapsed + + + + Downloaded Maps + + + + DELETE + + + + This will delete ALL downloaded maps + +Are you sure you want to delete all the maps? + + + + Yes, delete all the maps. + + + + Database Update + + + + CHECK + VÉRIFIER + + + Country + + + + SELECT + SÉLECTIONNER + + + Fetching Country list... + + + + State + + + + Fetching State list... + + + + All + + + + REFRESH + + + + UPDATE + MISE À JOUR + + + Download starting... + + + + Error: Invalid download. Retry. + + + + Download complete! + + + + + +Warning: You are on a metered connection! + + + + This will start the download process and it might take a while to complete. + + + + Continue on Metered + + + + Start Download + + + + m + + + + s + + + + Calculating... + + + + Downloaded + + + + Calculating ETA... + + + + Ready + + + + Time remaining: + + + PairingPopup @@ -537,6 +1235,51 @@ Annuler + + ParamControlSP + + Enable + Activer + + + Cancel + Annuler + + + + PathOffset + + Path Offset + + + + Hack to trick the model path to be left or right biased of the lane. Decreasing the value will shift the model more left, increasing will shift the model more right. Changes take effect immediately. + + + + cm + + + + + PauseLateralSpeed + + Pause lateral actuation with blinker when traveling below the desired speed selected. Default is 20 MPH or 32 km/h. + + + + Default + + + + km/h + km/h + + + mph + mi/h + + PrimeAdWidget @@ -591,7 +1334,7 @@ openpilot - openpilot + openpilot %n minute(s) ago @@ -634,6 +1377,30 @@ now + + sunnypilot + + + + Update downloaded. Ready to reboot. + + + + Update: Check and Download Update + + + + Reboot: Reboot Device + + + + Update + + + + Updating... + + Reset @@ -676,6 +1443,131 @@ Cela peut prendre jusqu'à une minute. + + SPVehiclesTogglesPanel + + Hyundai/Kia/Genesis + + + + HKG CAN: Smoother Stopping Performance (Beta) + + + + Smoother stopping behind a stopped car or desired stopping event. This is only applicable to HKG CAN platforms using openpilot longitudinal control. + + + + Subaru + + + + Manual Parking Brake: Stop and Go (Beta) + + + + Experimental feature to enable stop and go for Subaru Global models with manual handbrake. Models with electric parking brake should keep this disabled. Thanks to martinl for this implementation! + + + + Toyota/Lexus + + + + Enable Stock Toyota Longitudinal Control + + + + sunnypilot will <b>not</b> take over control of gas and brakes. Stock Toyota longitudinal control will be used. + + + + Allow M.A.D.S. toggling w/ LKAS Button (Beta) + + + + Allows M.A.D.S. engagement/disengagement with "LKAS" button from the steering wheel. + + + + Note: Enabling this toggle may have unexpected behavior with steering control. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Toyota TSS2 Longitudinal: Custom Tuning + + + + Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + + + Enable Enhanced Blind Spot Monitor + + + + Enable Toyota Stop and Go Hack + + + + sunnypilot will allow some Toyota/Lexus cars to auto resume during stop and go traffic. This feature is only applicable to certain models. Use at your own risk. + + + + Enable Toyota Door Auto Locking + + + + sunnypilot will attempt to lock the doors when drive above 10 km/h (6.2 mph). +Reboot Required. + + + + Enable Toyota Door Auto Unlocking + + + + sunnypilot will attempt to unlock the doors when shift to gear P. +Reboot Required. + + + + Volkswagen + + + + Enable CC Only support + + + + sunnypilot supports Volkswagen MQB CC only platforms with this toggle enabled. Only enable this toggle if your car does not have ACC from the factory. + + + + Start the car to check car compatibility + + + + This platform is already supported, therefore no need to enable this toggle + + + + This platform is not supported + + + + This platform can be supported + + + + sunnypilot will use debugging CAN messages to receive unfiltered BSM signals, allowing detection of more objects. + + + + Tested on RAV4 TSS1, Lexus LSS1, Toyota TSS1/1.5, and Prius TSS2. + + + SettingsWindow @@ -699,6 +1591,61 @@ Cela peut prendre jusqu'à une minute. Logiciel + + SettingsWindowSP + + × + × + + + Device + Appareil + + + Network + Réseau + + + sunnylink + + + + Toggles + Options + + + Software + Logiciel + + + sunnypilot + + + + OSM + + + + Monitoring + + + + Visuals + + + + Display + + + + Trips + + + + Vehicle + + + Setup @@ -892,6 +1839,100 @@ Cela peut prendre jusqu'à une minute. 5G + + SidebarSP + + TEMP + TEMP + + + HIGH + HAUT + + + GOOD + BON + + + OK + OK + + + DISABLED + + + + OFFLINE + HORS LIGNE + + + REGIST... + + + + ONLINE + EN LIGNE + + + ERROR + ERREUR + + + SUNNYLINK + + + + + SlcSettings + + Auto + + + + User Confirm + + + + Engage Mode + + + + Default + + + + Fixed + + + + Percentage + + + + Limit Offset + + + + Set speed limit slightly higher than actual speed limit for a more natural drive. + + + + This platform defaults to <b>Auto</b> mode. <b>User Confirm</b> mode is not supported on this platform. + + + + Select the desired mode to set the cruising speed to the speed limit: + + + + Auto: Automatic speed adjustment on motorways based on speed limit data. + + + + User Confirm: Inform the driver to change set speed of Adaptive Cruise Control to help the driver stay within the speed limit. + + + SoftwarePanel @@ -967,6 +2008,233 @@ Cela peut prendre jusqu'à une minute. à jour, dernière vérification %1 + + SoftwarePanelSP + + Driving Model + + + + SELECT + SÉLECTIONNER + + + PENDING + + + + Downloading Driving model + + + + (CACHED) + + + + Driving model + + + + downloaded + + + + Downloading Navigation model + + + + Navigation model + + + + Downloading Metadata model + + + + Metadata model + + + + Downloads have failed, please try swapping the model! + + + + Failed: + + + + Fetching models... + + + + Select a Driving Model + + + + Download has started in the background. + + + + We STRONGLY suggest you to reset calibration. Would you like to do that now? + + + + Reset Calibration + Réinitialiser la calibration + + + Warning: You are on a metered connection! + + + + Continue + Continuer + + + on Metered + + + + + SpeedLimitPolicySettings + + Speed Limit Source Policy + + + + Nav + + + + Only + + + + Map + + + + Car + + + + First + + + + Select the precedence order of sources. Utilized by Speed Limit Control and Speed Limit Warning + + + + Nav Only: Data from Mapbox active navigation only. + + + + Map Only: Data from OpenStreetMap only. + + + + Car Only: Data from the car's built-in sources (if available). + + + + Nav First: Nav -> Map -> Car + + + + Map First: Map -> Nav -> Car + + + + Car First: Car -> Nav -> Map + + + + + SpeedLimitValueOffset + + km/h + km/h + + + mph + mi/h + + + + SpeedLimitWarningSettings + + Off + + + + Display + + + + Chime + + + + Speed Limit Warning + + + + Warning with speed limit flash + + + + When Speed Limit Warning is enabled, the speed limit sign will alert the driver when the cruising speed is faster than then speed limit plus the offset. + + + + Default + + + + Fixed + + + + Percentage + + + + Warning Offset + + + + Select the desired offset to warn the driver when the vehicle is driving faster than the speed limit. + + + + Off: When the cruising speed is faster than the speed limit plus the offset, there will be no warning. + + + + Display: The speed on the speed limit sign turns red to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + Chime: The speed on the speed limit sign turns red and chimes to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + + SpeedLimitWarningValueOffset + + N/A + N/A + + + km/h + km/h + + + mph + mi/h + + SshControl @@ -1013,6 +2281,399 @@ Cela peut prendre jusqu'à une minute. Activer SSH + + SunnylinkPanel + + Enable sunnylink + + + + Device ID + + + + N/A + N/A + + + This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. + + + + 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 + + + + 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. + + + + Sponsor Status + + + + SPONSOR + + + + Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. + + + + Pair GitHub Account + + + + PAIR + + + + Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. + + + + sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. + + + + Manage Settings + + + + Backup Settings + + + + Are you sure you want to backup sunnypilot settings? + + + + Back Up + + + + Restore Settings + + + + Are you sure you want to restore the last backed up sunnypilot settings? + + + + Restore + + + + THANKS + + + + Not Sponsor + + + + Paired + + + + Not Paired + + + + Backing up... + + + + Restoring... + + + + + SunnylinkSponsorPopup + + Scan the QR code to login to your GitHub account + + + + Follow the prompts to complete the pairing process + + + + Re-enter the "sunnylink" panel to verify sponsorship status + + + + If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot + + + + Scan the QR code to visit sunnyhaibin's GitHub Sponsors page + + + + Choose your sponsorship tier and confirm your support + + + + Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status + + + + Pair your GitHub account + + + + Early Access: Become a sunnypilot Sponsor + + + + + SunnypilotPanel + + Enable M.A.D.S. + + + + Enable the beloved M.A.D.S. feature. Disable toggle to revert back to stock openpilot engagement/disengagement. + + + + Laneless for Curves in "Auto" Mode + + + + While in Auto Lane, switch to Laneless for current/future curves. + + + + Speed Limit Control (SLC) + + + + When you engage ACC, you will be prompted to set the cruising speed to the speed limit of the road adjusted by the Offset and Source Policy specified, or the current driving speed. The maximum cruising speed will always be the MAX set speed. + + + + Enable Vision-based Turn Speed Control (V-TSC) + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Enable Map Data Turn Speed Control (M-TSC) (Beta) + + + + Use curvature information from map data to define speed limits to take turns ahead. + + + + ACC +/-: Long Press Reverse + + + + Change the ACC +/- buttons behavior with cruise speed change in sunnypilot. + + + + Disabled (Stock): Short=1, Long = 5 (imperial) / 10 (metric) + + + + Enabled: Short = 5 (imperial) / 10 (metric), Long=1 + + + + Custom Offsets + + + + Neural Network Lateral Control (NNLC) + + + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Enable Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying FRICTION and LAT_ACCEL_FACTOR below will override the offline values indicated in the YAML files within "selfdrive/torque_data". The values will also be used live when "Override Self-Tune" toggle is enabled. + + + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Quiet Drive 🤫 + + + + sunnypilot will display alerts but only play the most important warning sounds. This feature can be toggled while the car is on. + + + + Green Traffic Light Chime (Beta) + + + + A chime will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. If you are waiting behind another vehicle, the chime will play once the vehicle advances unless ACC is engaged. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Vehicle Departure Alert + + + + Enable this will notify when the leading vehicle drives away. + + + + Customize M.A.D.S. + + + + Customize Lane Change + + + + Customize Offsets + + + + Customize Speed Limit Control + + + + Customize Warning + + + + Customize Source + + + + Laneful + + + + Laneless + + + + Auto + + + + Dynamic Lane Profile + + + + Speed Limit Assist + + + + Real-time and Offline + + + + Offline Only + + + + Dynamic Lane Profile is not available with the current Driving Model + + + + Custom Offsets is not available with the current Driving Model + + + + NNLC is currently not available on this platform. + + + + Match: "Exact" is ideal, but "Fuzzy" is fine too. Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server if there are any issues: + + + + Start the car to check car compatibility + + + + NNLC Not Loaded + + + + NNLC Loaded + + + + Fuzzy + + + + Exact + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server and donate logs to get NNLC loaded for your car: + + + + Match + + + + Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server with feedback, or to provide log data for your car if your car is currently unsupported: + + + + Add custom offsets to Camera and Path in sunnypilot. + + + + Default is Laneless. In Auto mode, sunnnypilot dynamically chooses between Laneline or Laneless model based on lane recognition confidence level on road and certain conditions. + + + TermsPage @@ -1032,15 +2693,30 @@ Cela peut prendre jusqu'à une minute. Accepter + + TermsPageSP + + Terms & Conditions + Termes & Conditions + + + Decline + Refuser + + + Scroll to accept + Faire défiler pour accepter + + TogglesPanel Enable openpilot - Activer openpilot + Activer openpilot Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. - Utilisez le système openpilot pour le régulateur de vitesse adaptatif et l'assistance au maintien de voie. Votre attention est requise en permanence pour utiliser cette fonctionnalité. La modification de ce paramètre prend effet lorsque la voiture est éteinte. + Utilisez le système openpilot pour le régulateur de vitesse adaptatif et l'assistance au maintien de voie. Votre attention est requise en permanence pour utiliser cette fonctionnalité. La modification de ce paramètre prend effet lorsque la voiture est éteinte. openpilot Longitudinal Control (Alpha) @@ -1092,19 +2768,19 @@ Cela peut prendre jusqu'à une minute. Show ETA in 24h Format - Afficher l'heure d'arrivée en format 24h + Afficher l'heure d'arrivée en format 24h Use 24h format instead of am/pm - Utiliser le format 24h plutôt que am/pm + Utiliser le format 24h plutôt que am/pm Show Map on Left Side of UI - Afficher la carte à gauche de l'interface + Afficher la carte à gauche de l'interface Show map on left side when in split screen view. - Afficher la carte à gauche en mode écran scindé. + Afficher la carte à gauche en mode écran scindé. Aggressive @@ -1170,6 +2846,252 @@ Cela peut prendre jusqu'à une minute. Enable driver monitoring even when openpilot is not engaged. + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + + TogglesPanelSP + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + openpilot Longitudinal Control (Alpha) + Contrôle longitudinal openpilot (Alpha) + + + WARNING: sunnypilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + + + + On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to sunnypilot longitudinal control. Enabling Experimental mode is recommended when enabling sunnypilot longitudinal control alpha. + + + + Custom Stock Longitudinal Control + + + + When enabled, sunnypilot will attempt to control stock longitudinal control with ACC button presses. +This feature must be used along with SLC, and/or V-TSC, and/or M-TSC. + + + + Experimental Mode + Mode expérimental + + + Enable Dynamic Experimental Control + + + + Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. + + + + Enable Dynamic Personality + + + + Enable this to allow sunnypilot to dynamically adjust following distance and reaction based on your "Driving Personality" setting. Instead of predefined settings for each personality, every personality now adapts dynamically according to your speed and the distance to the lead car. + + + + Disengage on Accelerator Pedal + Désengager avec la pédale d'accélérateur + + + When enabled, pressing the accelerator pedal will disengage openpilot. + Lorsqu'il est activé, appuyer sur la pédale d'accélérateur désengagera openpilot. + + + Enable Lane Departure Warnings + Activer les avertissements de sortie de voie + + + Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). + Recevez des alertes pour revenir dans la voie lorsque votre véhicule dérive au-delà d'une ligne de voie détectée sans clignotant activé en roulant à plus de 31 mph (50 km/h). + + + Always-On Driver Monitoring + + + + Enable driver monitoring even when sunnypilot is not engaged. + + + + Record and Upload Driver Camera + Enregistrer et télécharger la caméra conducteur + + + Upload data from the driver facing camera and help improve the driver monitoring algorithm. + Publiez les données de la caméra orientée vers le conducteur et aidez à améliorer l'algorithme de surveillance du conducteur. + + + Disable Onroad Uploads + + + + Disable uploads completely when onroad. Necessary to avoid high data usage when connected to Wi-Fi hotspot. Turn on this feature if you are looking to utilize map-based features, such as Speed Limit Control (SLC) and Map-based Turn Speed Control (MTSC). + + + + Use Metric System + Utiliser le système métrique + + + Display speed in km/h instead of mph. + Afficher la vitesse en km/h au lieu de mph. + + + Show ETA in 24h Format + Afficher l'heure d'arrivée en format 24h + + + Use 24h format instead of am/pm + Utiliser le format 24h plutôt que am/pm + + + Show Map on Left Side of UI + Afficher la carte à gauche de l'interface + + + Show map on left side when in split screen view. + Afficher la carte à gauche en mode écran scindé. + + + Aggressive + Aggressif + + + Moderate + + + + Standard + Standard + + + Relaxed + Détendu + + + Driving Personality + Personnalité de conduite + + + Standard is recommended. In moderate/aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + + + + Sport + + + + Normal + + + + Eco + + + + Stock + + + + Acceleration Personality + + + + Normal is recommended. In sport mode, sunnypilot will provide aggressive acceleration for a dynamic driving experience. In eco mode, sunnypilot will apply smoother and more relaxed acceleration. On supported cars, you can cycle through these acceleration personality within Onroad Settings on the driving screen. + + + + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + Par défaut, openpilot conduit en <b>mode détente</b>. Le mode expérimental permet d'activer des <b>fonctionnalités alpha</b> qui ne sont pas prêtes pour le mode détente. Les fonctionnalités expérimentales sont listées ci-dessous : + + + End-to-End Longitudinal Control + Contrôle longitudinal de bout en bout + + + Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + + + + New Driving Visualization + Nouvelle visualisation de la conduite + + + The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. + La visualisation de la conduite passera sur la caméra grand angle dirigée vers la route à faible vitesse afin de mieux montrer certains virages. Le logo du mode expérimental s'affichera également dans le coin supérieur droit. + + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + Le mode expérimental est actuellement indisponible pour cette voiture car le régulateur de vitesse adaptatif d'origine est utilisé pour le contrôle longitudinal. + + + openpilot longitudinal control may come in a future update. + Le contrôle longitudinal openpilot pourrait être disponible dans une future mise à jour. + + + An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. + + + + + TorqueFriction + + FRICTION + + + + Adjust Friction for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueMaxLatAccel + + LAT_ACCEL_FACTOR + + + + Adjust Max Lateral Acceleration for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + Updater @@ -1206,6 +3128,168 @@ Cela peut prendre jusqu'à une minute. Échec de la mise à jour + + VehiclePanel + + Updating this setting takes effect when the car is powered off. + + + + Select your car + + + + + VisualsPanel + + Display Braking Status + + + + Enable this will turn the current speed value to red while the brake is used. + + + + Display Stand Still Timer + + + + Enable this will display time spent at a stop (i.e., at a stop lights, stop signs, traffic congestions). + + + + Display DM Camera in Reverse Gear + + + + Show Driver Monitoring camera while the car is in reverse gear. + + + + OSM: Show debug UI elements + + + + OSM: Show UI elements that aid debugging. + + + + Display Feature Status + + + + Display the statuses of certain features on the driving screen. + + + + Enable Onroad Settings + + + + Display the Onroad Settings button on the driving screen to adjust feature options on the driving screen, without navigating into the settings menu. + + + + Speedometer: Display True Speed + + + + Display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Display End-to-end Longitudinal Status (Beta) + + + + Enable this will display an icon that appears when the End-to-end model decides to start or stop. + + + + Navigation: Display in Full Screen + + + + Enable this will display the built-in navigation in full screen.<br>To switch back to driving view, <font color='yellow'>tap on the border edge</font>. + + + + Map: Display 3D Buildings + + + + Parse and display 3D buildings on map. Thanks to jakethesnake420 for this implementation. + + + + Off + + + + 5 Metrics + + + + 10 Metrics + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + + + Distance + + + + Speed + + + + Display Metrics Below Chevron + + + + Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + + + RAM + + + + CPU + + + + GPU + + + + Max + + + + Display Temperature on Sidebar + + + + Time + + + + All + + + WiFiPromptWidget @@ -1252,4 +3336,27 @@ Cela peut prendre jusqu'à une minute. Oublier + + WifiUISP + + Scanning for networks... + Recherche de réseaux... + + + CONNECTING... + CONNEXION... + + + FORGET + OUBLIER + + + Forget Wi-Fi Network "%1"? + Oublier le réseau Wi-Fi "%1" ? + + + Forget + Oublier + + diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index e0fb60620b..5db645c9f4 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -87,6 +87,89 @@ ネットワーク名:%1 + + AdvancedNetworkingSP + + Back + 戻る + + + Enable Tethering + テザリングを有効化 + + + Retain hotspot/tethering state + + + + Enabling this toggle will retain the hotspot/tethering toggle state across reboots. + + + + Tethering Password + テザリングパスワード + + + EDIT + 編集 + + + Enter new tethering password + 新しいテザリングパスワードを入力 + + + IP Address + IP アドレス + + + Enable Roaming + ローミングを有効化 + + + APN Setting + APN 設定 + + + Enter APN + APN を入力 + + + leave blank for automatic configuration + 自動で設定するには、空白のままにしてください。 + + + Cellular Metered + 従量制通信設定 + + + Prevent large data uploads when on a metered connection + 大量のデータのアップロードを防止します。 + + + Hidden Network + + + + CONNECT + 接続 + + + Enter SSID + SSID を入力 + + + Enter password + パスワードを入力 + + + for "%1" + ネットワーク名:%1 + + + Ngrok Service + + + AnnotatedCameraWidget @@ -103,11 +186,119 @@ SPEED - 速度 + 速度 LIMIT - 制限速度 + 制限速度 + + + + AnnotatedCameraWidgetSP + + km/h + km/h + + + mph + mph + + + MAX + 最高速度 + + + SPEED + 速度 + + + LIMIT + 制限速度 + + + + AutoLaneChangeTimer + + Auto Lane Change by Blinker + + + + Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. +Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. + + + + s + + + + Off + + + + Nudge + + + + Nudgeless + + + + + BackupSettings + + Settings backed up for sunnylink Device ID: + + + + Settings updated successfully, but no additional data was returned by the server. + + + + OOPS! We made a booboo. + + + + Please try again later. + + + + Settings restored. Confirm to restart the interface. + + + + No settings found to restore. + + + + + BrightnessControl + + Brightness + + + + Manually adjusts the global brightness of the screen. + + + + Auto + + + + + CameraOffset + + Camera Offset - Laneful Only + + + + Hack to trick vehicle to be left or right biased in its lane. Decreasing the value will make the car keep more left, increasing will make it keep more right. Changes take effect immediately. Default: +4 cm + + + + cm + @@ -121,11 +312,18 @@ キャンセル + + CustomOffsetsSettings + + Back + 戻る + + DeclinePage You must accept the Terms and Conditions in order to use openpilot. - openpilot をご利用される前に、利用規約に同意する必要があります。 + openpilot をご利用される前に、利用規約に同意する必要があります。 Back @@ -135,6 +333,10 @@ Decline, uninstall %1 拒否して %1 をアンインストール + + You must accept the Terms and Conditions in order to use sunnypilot. + + DestinationWidget @@ -247,7 +449,7 @@ openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required. - openpilotの本体は、左右4°以内、上5°、下9°以内の角度で取付ける必要があります。継続してキャリブレーションを続けているので、手動でリセットを行う必要はほぼありません。 + openpilotの本体は、左右4°以内、上5°、下9°以内の角度で取付ける必要があります。継続してキャリブレーションを続けているので、手動でリセットを行う必要はほぼありません。 Your device is pointed %1° %2 and %3° %4. @@ -305,6 +507,155 @@ PAIR + + sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. sunnypilot is continuously calibrating, resetting is rarely required. + + + + + DevicePanelSP + + TOGGLE + + + + Enable or disable PIN requirement for Fleet Manager access. + + + + Are you sure you want to turn off PIN requirement? + + + + Turn Off + + + + Error Troubleshoot + + + + VIEW + 見る + + + Display error from the tmux session when an error has occurred from a system process. + + + + Reset Access Tokens for Map Services + + + + RESET + リセット + + + Reset self-service access tokens for Mapbox, Amap, and Google Maps. + + + + Are you sure you want to reset access tokens for all map services? + + + + Reset + リセット + + + Reset sunnypilot Settings + + + + Are you sure you want to reset all sunnypilot settings? + + + + Toggle Onroad/Offroad + + + + OFF + + + + Are you sure you want to unforce offroad? + + + + Unforce + + + + Are you sure you want to force offroad? + + + + Force + + + + Disengage to Force Offroad + + + + Unforce Offroad + + + + Force Offroad + + + + Fleet Manager PIN: + + + + + DisplayPanel + + Driving Screen Off: Non-Critical Events + + + + When <b>Driving Screen Off Timer</b> is not set to <b>"Always On"</b>: + + + + Enabled: Wake the brightness of the screen to display all events. + + + + Disabled: Wake the brightness of the screen to display critical events. + + + + + DriveStats + + Drives + + + + Hours + + + + ALL TIME + + + + PAST WEEK + + + + KM + + + + Miles + + DriverViewWindow @@ -344,6 +695,79 @@ インストールしています... + + LaneChangeSettings + + Back + 戻る + + + Pause Lateral Below Speed with Blinker + + + + Enable this toggle to pause lateral actuation with blinker when traveling below the desired speed selected below. + + + + Auto Lane Change: Delay with Blind Spot + + + + Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. + + + + Block Lane Change: Road Edge Detection + + + + Enable this toggle to block lane change when road edge is detected on the stalk actuated side. + + + + + MadsSettings + + Enable ACC+MADS with RES+/SET- + + + + Engage both M.A.D.S. and ACC with a single press of RES+ or SET- button. + + + + Note: Once M.A.D.S. is engaged via this mode, it will remain engaged until it is manually disabled via the M.A.D.S. button or car shut off. + + + + Toggle M.A.D.S. with Cruise Main + + + + Allows M.A.D.S. engagement/disengagement with "Cruise Main" cruise control button from the steering wheel. + + + + Remain Active + + + + Pause Steering + + + + Steering Mode After Braking + + + + Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. + +Remain Active: ALC will remain active even after the brake pedal is pressed. +Pause Steering: ALC will be paused after the brake pedal is manually pressed. + + + MapETA @@ -385,6 +809,63 @@ + + MapWindowSP + + Map Loading + マップを読み込んでいます + + + Waiting for GPS + GPS信号を探しています + + + Waiting for route + + + + + MaxTimeOffroad + + Max Time Offroad + + + + Device is automatically turned off after a set time when the engine is turned off (off-road) after driving (on-road). + + + + s + + + + m + メートル + + + hr + 時間 + + + Always On + + + + Immediate + + + + + MonitoringPanel + + Enable Hands on Wheel Monitoring + + + + Monitor and alert when driver is not keeping the hands on the steering wheel. + + + MultiOptionDialog @@ -415,6 +896,33 @@ パスワードが間違っています + + NetworkingSP + + Scan + + + + Scanning... + + + + Advanced + 詳細 + + + Enter password + パスワードを入力 + + + for "%1" + ネットワーク名:%1 + + + Wrong password + パスワードが間違っています + + OffroadAlert @@ -466,6 +974,16 @@ Device temperature too high. System cooling down before starting. Current internal component temperature: %1 + + OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. + +%1 + + + + sunnypilot is now in Forced Offroad mode. sunnypilot won't start until Forced Offroad mode is disabled. Go to "Settings" -> "Device" -> "Unforce Offroad" to exit Force Offroad mode. + + OffroadHome @@ -505,6 +1023,186 @@ + + OnroadScreenOff + + Driving Screen Off Timer + + + + Turn off the device screen or reduce brightness to protect the screen after driving starts. It automatically brightens or turns on when a touch or event occurs. + + + + s + + + + min + + + + Always On + + + + + OnroadScreenOffBrightness + + Driving Screen Off Brightness (%) + + + + When using the Driving Screen Off feature, the brightness is reduced according to the automatic brightness ratio. + + + + Dark + + + + + OnroadSettings + + ONROAD OPTIONS + + + + <b>ONROAD SETTINGS | SUNNYPILOT</b> + + + + + OsmPanel + + Mapd Version + + + + Offline Maps ETA + + + + Time Elapsed + + + + Downloaded Maps + + + + DELETE + + + + This will delete ALL downloaded maps + +Are you sure you want to delete all the maps? + + + + Yes, delete all the maps. + + + + Database Update + + + + CHECK + 確認 + + + Country + + + + SELECT + 選択 + + + Fetching Country list... + + + + State + + + + Fetching State list... + + + + All + + + + REFRESH + + + + UPDATE + 更新 + + + Download starting... + + + + Error: Invalid download. Retry. + + + + Download complete! + + + + + +Warning: You are on a metered connection! + + + + This will start the download process and it might take a while to complete. + + + + Continue on Metered + + + + Start Download + + + + m + + + + s + + + + Calculating... + + + + Downloaded + + + + Calculating ETA... + + + + Ready + + + + Time remaining: + + + PairingPopup @@ -535,6 +1233,51 @@ を有効化 + + ParamControlSP + + Enable + を有効化 + + + Cancel + キャンセル + + + + PathOffset + + Path Offset + + + + Hack to trick the model path to be left or right biased of the lane. Decreasing the value will shift the model more left, increasing will shift the model more right. Changes take effect immediately. + + + + cm + + + + + PauseLateralSpeed + + Pause lateral actuation with blinker when traveling below the desired speed selected. Default is 20 MPH or 32 km/h. + + + + Default + + + + km/h + km/h + + + mph + mph + + PrimeAdWidget @@ -589,7 +1332,7 @@ openpilot - openpilot + openpilot %n minute(s) ago @@ -629,6 +1372,30 @@ now + + sunnypilot + + + + Update downloaded. Ready to reboot. + + + + Update: Check and Download Update + + + + Reboot: Reboot Device + + + + Update + + + + Updating... + + Reset @@ -670,6 +1437,131 @@ This may take up to a minute. + + SPVehiclesTogglesPanel + + Hyundai/Kia/Genesis + + + + HKG CAN: Smoother Stopping Performance (Beta) + + + + Smoother stopping behind a stopped car or desired stopping event. This is only applicable to HKG CAN platforms using openpilot longitudinal control. + + + + Subaru + + + + Manual Parking Brake: Stop and Go (Beta) + + + + Experimental feature to enable stop and go for Subaru Global models with manual handbrake. Models with electric parking brake should keep this disabled. Thanks to martinl for this implementation! + + + + Toyota/Lexus + + + + Enable Stock Toyota Longitudinal Control + + + + sunnypilot will <b>not</b> take over control of gas and brakes. Stock Toyota longitudinal control will be used. + + + + Allow M.A.D.S. toggling w/ LKAS Button (Beta) + + + + Allows M.A.D.S. engagement/disengagement with "LKAS" button from the steering wheel. + + + + Note: Enabling this toggle may have unexpected behavior with steering control. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Toyota TSS2 Longitudinal: Custom Tuning + + + + Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + + + Enable Enhanced Blind Spot Monitor + + + + Enable Toyota Stop and Go Hack + + + + sunnypilot will allow some Toyota/Lexus cars to auto resume during stop and go traffic. This feature is only applicable to certain models. Use at your own risk. + + + + Enable Toyota Door Auto Locking + + + + sunnypilot will attempt to lock the doors when drive above 10 km/h (6.2 mph). +Reboot Required. + + + + Enable Toyota Door Auto Unlocking + + + + sunnypilot will attempt to unlock the doors when shift to gear P. +Reboot Required. + + + + Volkswagen + + + + Enable CC Only support + + + + sunnypilot supports Volkswagen MQB CC only platforms with this toggle enabled. Only enable this toggle if your car does not have ACC from the factory. + + + + Start the car to check car compatibility + + + + This platform is already supported, therefore no need to enable this toggle + + + + This platform is not supported + + + + This platform can be supported + + + + sunnypilot will use debugging CAN messages to receive unfiltered BSM signals, allowing detection of more objects. + + + + Tested on RAV4 TSS1, Lexus LSS1, Toyota TSS1/1.5, and Prius TSS2. + + + SettingsWindow @@ -693,6 +1585,61 @@ This may take up to a minute. ソフトウェア + + SettingsWindowSP + + × + × + + + Device + デバイス + + + Network + ネットワーク + + + sunnylink + + + + Toggles + 機能設定 + + + Software + ソフトウェア + + + sunnypilot + + + + OSM + + + + Monitoring + + + + Visuals + + + + Display + + + + Trips + + + + Vehicle + + + Setup @@ -886,6 +1833,100 @@ This may take up to a minute. 5G + + SidebarSP + + TEMP + 温度 + + + HIGH + 高温 + + + GOOD + 最適 + + + OK + OK + + + DISABLED + + + + OFFLINE + オフライン + + + REGIST... + + + + ONLINE + オンライン + + + ERROR + エラー + + + SUNNYLINK + + + + + SlcSettings + + Auto + + + + User Confirm + + + + Engage Mode + + + + Default + + + + Fixed + + + + Percentage + + + + Limit Offset + + + + Set speed limit slightly higher than actual speed limit for a more natural drive. + + + + This platform defaults to <b>Auto</b> mode. <b>User Confirm</b> mode is not supported on this platform. + + + + Select the desired mode to set the cruising speed to the speed limit: + + + + Auto: Automatic speed adjustment on motorways based on speed limit data. + + + + User Confirm: Inform the driver to change set speed of Adaptive Cruise Control to help the driver stay within the speed limit. + + + SoftwarePanel @@ -961,6 +2002,233 @@ This may take up to a minute. + + SoftwarePanelSP + + Driving Model + + + + SELECT + 選択 + + + PENDING + + + + Downloading Driving model + + + + (CACHED) + + + + Driving model + + + + downloaded + + + + Downloading Navigation model + + + + Navigation model + + + + Downloading Metadata model + + + + Metadata model + + + + Downloads have failed, please try swapping the model! + + + + Failed: + + + + Fetching models... + + + + Select a Driving Model + + + + Download has started in the background. + + + + We STRONGLY suggest you to reset calibration. Would you like to do that now? + + + + Reset Calibration + キャリブレーションをリセット + + + Warning: You are on a metered connection! + + + + Continue + 続ける + + + on Metered + + + + + SpeedLimitPolicySettings + + Speed Limit Source Policy + + + + Nav + + + + Only + + + + Map + + + + Car + + + + First + + + + Select the precedence order of sources. Utilized by Speed Limit Control and Speed Limit Warning + + + + Nav Only: Data from Mapbox active navigation only. + + + + Map Only: Data from OpenStreetMap only. + + + + Car Only: Data from the car's built-in sources (if available). + + + + Nav First: Nav -> Map -> Car + + + + Map First: Map -> Nav -> Car + + + + Car First: Car -> Nav -> Map + + + + + SpeedLimitValueOffset + + km/h + km/h + + + mph + mph + + + + SpeedLimitWarningSettings + + Off + + + + Display + + + + Chime + + + + Speed Limit Warning + + + + Warning with speed limit flash + + + + When Speed Limit Warning is enabled, the speed limit sign will alert the driver when the cruising speed is faster than then speed limit plus the offset. + + + + Default + + + + Fixed + + + + Percentage + + + + Warning Offset + + + + Select the desired offset to warn the driver when the vehicle is driving faster than the speed limit. + + + + Off: When the cruising speed is faster than the speed limit plus the offset, there will be no warning. + + + + Display: The speed on the speed limit sign turns red to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + Chime: The speed on the speed limit sign turns red and chimes to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + + SpeedLimitWarningValueOffset + + N/A + N/A + + + km/h + km/h + + + mph + mph + + SshControl @@ -1007,6 +2275,399 @@ This may take up to a minute. SSH を有効化 + + SunnylinkPanel + + Enable sunnylink + + + + Device ID + + + + N/A + N/A + + + This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. + + + + 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 + + + + 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. + + + + Sponsor Status + + + + SPONSOR + + + + Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. + + + + Pair GitHub Account + + + + PAIR + + + + Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. + + + + sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. + + + + Manage Settings + + + + Backup Settings + + + + Are you sure you want to backup sunnypilot settings? + + + + Back Up + + + + Restore Settings + + + + Are you sure you want to restore the last backed up sunnypilot settings? + + + + Restore + + + + THANKS + + + + Not Sponsor + + + + Paired + + + + Not Paired + + + + Backing up... + + + + Restoring... + + + + + SunnylinkSponsorPopup + + Scan the QR code to login to your GitHub account + + + + Follow the prompts to complete the pairing process + + + + Re-enter the "sunnylink" panel to verify sponsorship status + + + + If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot + + + + Scan the QR code to visit sunnyhaibin's GitHub Sponsors page + + + + Choose your sponsorship tier and confirm your support + + + + Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status + + + + Pair your GitHub account + + + + Early Access: Become a sunnypilot Sponsor + + + + + SunnypilotPanel + + Enable M.A.D.S. + + + + Enable the beloved M.A.D.S. feature. Disable toggle to revert back to stock openpilot engagement/disengagement. + + + + Laneless for Curves in "Auto" Mode + + + + While in Auto Lane, switch to Laneless for current/future curves. + + + + Speed Limit Control (SLC) + + + + When you engage ACC, you will be prompted to set the cruising speed to the speed limit of the road adjusted by the Offset and Source Policy specified, or the current driving speed. The maximum cruising speed will always be the MAX set speed. + + + + Enable Vision-based Turn Speed Control (V-TSC) + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Enable Map Data Turn Speed Control (M-TSC) (Beta) + + + + Use curvature information from map data to define speed limits to take turns ahead. + + + + ACC +/-: Long Press Reverse + + + + Change the ACC +/- buttons behavior with cruise speed change in sunnypilot. + + + + Disabled (Stock): Short=1, Long = 5 (imperial) / 10 (metric) + + + + Enabled: Short = 5 (imperial) / 10 (metric), Long=1 + + + + Custom Offsets + + + + Neural Network Lateral Control (NNLC) + + + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Enable Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying FRICTION and LAT_ACCEL_FACTOR below will override the offline values indicated in the YAML files within "selfdrive/torque_data". The values will also be used live when "Override Self-Tune" toggle is enabled. + + + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Quiet Drive 🤫 + + + + sunnypilot will display alerts but only play the most important warning sounds. This feature can be toggled while the car is on. + + + + Green Traffic Light Chime (Beta) + + + + A chime will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. If you are waiting behind another vehicle, the chime will play once the vehicle advances unless ACC is engaged. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Vehicle Departure Alert + + + + Enable this will notify when the leading vehicle drives away. + + + + Customize M.A.D.S. + + + + Customize Lane Change + + + + Customize Offsets + + + + Customize Speed Limit Control + + + + Customize Warning + + + + Customize Source + + + + Laneful + + + + Laneless + + + + Auto + + + + Dynamic Lane Profile + + + + Speed Limit Assist + + + + Real-time and Offline + + + + Offline Only + + + + Dynamic Lane Profile is not available with the current Driving Model + + + + Custom Offsets is not available with the current Driving Model + + + + NNLC is currently not available on this platform. + + + + Match: "Exact" is ideal, but "Fuzzy" is fine too. Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server if there are any issues: + + + + Start the car to check car compatibility + + + + NNLC Not Loaded + + + + NNLC Loaded + + + + Fuzzy + + + + Exact + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server and donate logs to get NNLC loaded for your car: + + + + Match + + + + Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server with feedback, or to provide log data for your car if your car is currently unsupported: + + + + Add custom offsets to Camera and Path in sunnypilot. + + + + Default is Laneless. In Auto mode, sunnnypilot dynamically chooses between Laneline or Laneless model based on lane recognition confidence level on road and certain conditions. + + + TermsPage @@ -1026,15 +2687,30 @@ This may take up to a minute. 同意 + + TermsPageSP + + Terms & Conditions + 利用規約 + + + Decline + 拒否 + + + Scroll to accept + スクロールして同意 + + TogglesPanel Enable openpilot - openpilot を有効化 + openpilot を有効化 Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. - openpilotによるアダプティブクルーズコントロールとレーンキーピングドライバーアシストを利用します。この機能を利用する際は、常に前方への注意が必要です。この設定を変更すると、車の電源が切れた時に反映されます。 + openpilotによるアダプティブクルーズコントロールとレーンキーピングドライバーアシストを利用します。この機能を利用する際は、常に前方への注意が必要です。この設定を変更すると、車の電源が切れた時に反映されます。 Enable Lane Departure Warnings @@ -1070,19 +2746,19 @@ This may take up to a minute. Show ETA in 24h Format - 24時間表示 + 24時間表示 Use 24h format instead of am/pm - AM/PM の代わりに24時間形式を使用します + AM/PM の代わりに24時間形式を使用します Show Map on Left Side of UI - ディスプレイの左側にマップを表示 + ディスプレイの左側にマップを表示 Show map on left side when in split screen view. - 分割画面表示の場合、ディスプレイの左側にマップを表示します。 + 分割画面表示の場合、ディスプレイの左側にマップを表示します。 Experimental Mode @@ -1164,6 +2840,252 @@ This may take up to a minute. Enable driver monitoring even when openpilot is not engaged. + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + + TogglesPanelSP + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + openpilot Longitudinal Control (Alpha) + + + + WARNING: sunnypilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + + + + On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to sunnypilot longitudinal control. Enabling Experimental mode is recommended when enabling sunnypilot longitudinal control alpha. + + + + Custom Stock Longitudinal Control + + + + When enabled, sunnypilot will attempt to control stock longitudinal control with ACC button presses. +This feature must be used along with SLC, and/or V-TSC, and/or M-TSC. + + + + Experimental Mode + 実験モード + + + Enable Dynamic Experimental Control + + + + Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. + + + + Enable Dynamic Personality + + + + Enable this to allow sunnypilot to dynamically adjust following distance and reaction based on your "Driving Personality" setting. Instead of predefined settings for each personality, every personality now adapts dynamically according to your speed and the distance to the lead car. + + + + Disengage on Accelerator Pedal + アクセルを踏むと openpilot を中断 + + + When enabled, pressing the accelerator pedal will disengage openpilot. + この機能を有効化すると、openpilotを利用中にアクセルを踏むとopenpilotによる運転サポートを中断します。 + + + Enable Lane Departure Warnings + 車線逸脱警報機能を有効化 + + + Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). + 時速31マイル(50km)を超えるスピードで走行中、ウインカーを作動させずに検出された車線ライン上に車両が触れた場合、手動で車線内に戻るように警告を行います。 + + + Always-On Driver Monitoring + + + + Enable driver monitoring even when sunnypilot is not engaged. + + + + Record and Upload Driver Camera + 車内カメラの録画とアップロード + + + Upload data from the driver facing camera and help improve the driver monitoring algorithm. + 車内カメラの映像をアップロードし、ドライバー監視システムのアルゴリズムの向上に役立てます。 + + + Disable Onroad Uploads + + + + Disable uploads completely when onroad. Necessary to avoid high data usage when connected to Wi-Fi hotspot. Turn on this feature if you are looking to utilize map-based features, such as Speed Limit Control (SLC) and Map-based Turn Speed Control (MTSC). + + + + Use Metric System + メートル法を使用 + + + Display speed in km/h instead of mph. + 速度は mph ではなく km/h で表示されます。 + + + Show ETA in 24h Format + 24時間表示 + + + Use 24h format instead of am/pm + AM/PM の代わりに24時間形式を使用します + + + Show Map on Left Side of UI + ディスプレイの左側にマップを表示 + + + Show map on left side when in split screen view. + 分割画面表示の場合、ディスプレイの左側にマップを表示します。 + + + Aggressive + + + + Moderate + + + + Standard + + + + Relaxed + + + + Driving Personality + + + + Standard is recommended. In moderate/aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + + + + Sport + + + + Normal + + + + Eco + + + + Stock + + + + Acceleration Personality + + + + Normal is recommended. In sport mode, sunnypilot will provide aggressive acceleration for a dynamic driving experience. In eco mode, sunnypilot will apply smoother and more relaxed acceleration. On supported cars, you can cycle through these acceleration personality within Onroad Settings on the driving screen. + + + + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + openpilotは標準ではゆっくりとくつろげる運転を提供します。この実験モードを有効にすると、以下のくつろげる段階ではない開発中の機能を利用する事ができます。 + + + End-to-End Longitudinal Control + + + + Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + + + + New Driving Visualization + 新しい運転画面 + + + The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. + + + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + この車のACCがアクセル制御を行うため実験モードを利用することができません。 + + + openpilot longitudinal control may come in a future update. + + + + An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. + + + + + TorqueFriction + + FRICTION + + + + Adjust Friction for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueMaxLatAccel + + LAT_ACCEL_FACTOR + + + + Adjust Max Lateral Acceleration for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + Updater @@ -1200,6 +3122,168 @@ This may take up to a minute. 更新失敗 + + VehiclePanel + + Updating this setting takes effect when the car is powered off. + + + + Select your car + + + + + VisualsPanel + + Display Braking Status + + + + Enable this will turn the current speed value to red while the brake is used. + + + + Display Stand Still Timer + + + + Enable this will display time spent at a stop (i.e., at a stop lights, stop signs, traffic congestions). + + + + Display DM Camera in Reverse Gear + + + + Show Driver Monitoring camera while the car is in reverse gear. + + + + OSM: Show debug UI elements + + + + OSM: Show UI elements that aid debugging. + + + + Display Feature Status + + + + Display the statuses of certain features on the driving screen. + + + + Enable Onroad Settings + + + + Display the Onroad Settings button on the driving screen to adjust feature options on the driving screen, without navigating into the settings menu. + + + + Speedometer: Display True Speed + + + + Display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Display End-to-end Longitudinal Status (Beta) + + + + Enable this will display an icon that appears when the End-to-end model decides to start or stop. + + + + Navigation: Display in Full Screen + + + + Enable this will display the built-in navigation in full screen.<br>To switch back to driving view, <font color='yellow'>tap on the border edge</font>. + + + + Map: Display 3D Buildings + + + + Parse and display 3D buildings on map. Thanks to jakethesnake420 for this implementation. + + + + Off + + + + 5 Metrics + + + + 10 Metrics + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + + + Distance + + + + Speed + + + + Display Metrics Below Chevron + + + + Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + + + RAM + + + + CPU + + + + GPU + + + + Max + + + + Display Temperature on Sidebar + + + + Time + + + + All + + + WiFiPromptWidget @@ -1246,4 +3330,27 @@ This may take up to a minute. 削除 + + WifiUISP + + Scanning for networks... + ネットワークをスキャン中... + + + CONNECTING... + 接続中... + + + FORGET + 削除 + + + Forget Wi-Fi Network "%1"? + Wi-Fiネットワーク%1を削除してもよろしいですか? + + + Forget + 削除 + + diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 56fc5014ee..1a55d59a3b 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -87,6 +87,89 @@ "%1"에 접속하려면 비밀번호가 필요합니다 + + AdvancedNetworkingSP + + Back + 뒤로 + + + Enable Tethering + 테더링 사용 + + + Retain hotspot/tethering state + + + + Enabling this toggle will retain the hotspot/tethering toggle state across reboots. + + + + Tethering Password + 테더링 비밀번호 + + + EDIT + 편집 + + + Enter new tethering password + 새 테더링 비밀번호를 입력하세요 + + + IP Address + IP 주소 + + + Enable Roaming + 로밍 사용 + + + APN Setting + APN 설정 + + + Enter APN + APN 입력 + + + leave blank for automatic configuration + 자동 설정하려면 빈 칸으로 두세요 + + + Cellular Metered + 데이터 요금제 + + + Prevent large data uploads when on a metered connection + 데이터 요금제 연결 시 대용량 데이터 업로드를 방지합니다 + + + Hidden Network + 숨겨진 네트워크 + + + CONNECT + + + + Enter SSID + SSID 입력 + + + Enter password + 비밀번호를 입력하세요 + + + for "%1" + "%1"에 접속하려면 비밀번호가 필요합니다 + + + Ngrok Service + + + AnnotatedCameraWidget @@ -103,11 +186,119 @@ SPEED - SPEED + SPEED LIMIT - LIMIT + LIMIT + + + + AnnotatedCameraWidgetSP + + km/h + km/h + + + mph + mph + + + MAX + MAX + + + SPEED + SPEED + + + LIMIT + LIMIT + + + + AutoLaneChangeTimer + + Auto Lane Change by Blinker + + + + Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. +Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. + + + + s + + + + Off + + + + Nudge + + + + Nudgeless + + + + + BackupSettings + + Settings backed up for sunnylink Device ID: + + + + Settings updated successfully, but no additional data was returned by the server. + + + + OOPS! We made a booboo. + + + + Please try again later. + + + + Settings restored. Confirm to restart the interface. + + + + No settings found to restore. + + + + + BrightnessControl + + Brightness + + + + Manually adjusts the global brightness of the screen. + + + + Auto + + + + + CameraOffset + + Camera Offset - Laneful Only + + + + Hack to trick vehicle to be left or right biased in its lane. Decreasing the value will make the car keep more left, increasing will make it keep more right. Changes take effect immediately. Default: +4 cm + + + + cm + @@ -121,11 +312,18 @@ 취소 + + CustomOffsetsSettings + + Back + 뒤로 + + DeclinePage You must accept the Terms and Conditions in order to use openpilot. - openpilot을 사용하려면 이용약관에 동의해야 합니다. + openpilot을 사용하려면 이용약관에 동의해야 합니다. Back @@ -135,6 +333,10 @@ Decline, uninstall %1 거절, %1 제거 + + You must accept the Terms and Conditions in order to use sunnypilot. + + DestinationWidget @@ -247,7 +449,7 @@ openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required. - openpilot 장치는 좌우 4°, 위로 5°, 아래로 9° 이내 각도로 장착되어야 합니다. openpilot은 지속적으로 자동 보정되며 재설정은 거의 필요하지 않습니다. + openpilot 장치는 좌우 4°, 위로 5°, 아래로 9° 이내 각도로 장착되어야 합니다. openpilot은 지속적으로 자동 보정되며 재설정은 거의 필요하지 않습니다. Your device is pointed %1° %2 and %3° %4. @@ -305,6 +507,155 @@ PAIR 동기화 + + sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. sunnypilot is continuously calibrating, resetting is rarely required. + + + + + DevicePanelSP + + TOGGLE + + + + Enable or disable PIN requirement for Fleet Manager access. + + + + Are you sure you want to turn off PIN requirement? + + + + Turn Off + + + + Error Troubleshoot + + + + VIEW + 보기 + + + Display error from the tmux session when an error has occurred from a system process. + + + + Reset Access Tokens for Map Services + + + + RESET + 초기화 + + + Reset self-service access tokens for Mapbox, Amap, and Google Maps. + + + + Are you sure you want to reset access tokens for all map services? + + + + Reset + 초기화 + + + Reset sunnypilot Settings + + + + Are you sure you want to reset all sunnypilot settings? + + + + Toggle Onroad/Offroad + + + + OFF + + + + Are you sure you want to unforce offroad? + + + + Unforce + + + + Are you sure you want to force offroad? + + + + Force + + + + Disengage to Force Offroad + + + + Unforce Offroad + + + + Force Offroad + + + + Fleet Manager PIN: + + + + + DisplayPanel + + Driving Screen Off: Non-Critical Events + + + + When <b>Driving Screen Off Timer</b> is not set to <b>"Always On"</b>: + + + + Enabled: Wake the brightness of the screen to display all events. + + + + Disabled: Wake the brightness of the screen to display critical events. + + + + + DriveStats + + Drives + + + + Hours + + + + ALL TIME + + + + PAST WEEK + + + + KM + + + + Miles + + DriverViewWindow @@ -344,6 +695,79 @@ 설치 중... + + LaneChangeSettings + + Back + 뒤로 + + + Pause Lateral Below Speed with Blinker + + + + Enable this toggle to pause lateral actuation with blinker when traveling below the desired speed selected below. + + + + Auto Lane Change: Delay with Blind Spot + + + + Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. + + + + Block Lane Change: Road Edge Detection + + + + Enable this toggle to block lane change when road edge is detected on the stalk actuated side. + + + + + MadsSettings + + Enable ACC+MADS with RES+/SET- + + + + Engage both M.A.D.S. and ACC with a single press of RES+ or SET- button. + + + + Note: Once M.A.D.S. is engaged via this mode, it will remain engaged until it is manually disabled via the M.A.D.S. button or car shut off. + + + + Toggle M.A.D.S. with Cruise Main + + + + Allows M.A.D.S. engagement/disengagement with "Cruise Main" cruise control button from the steering wheel. + + + + Remain Active + + + + Pause Steering + + + + Steering Mode After Braking + + + + Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. + +Remain Active: ALC will remain active even after the brake pedal is pressed. +Pause Steering: ALC will be paused after the brake pedal is manually pressed. + + + MapETA @@ -385,6 +809,63 @@ 경로를 기다리는 중 + + MapWindowSP + + Map Loading + 지도 로딩 중 + + + Waiting for GPS + GPS 수신 중 + + + Waiting for route + 경로를 기다리는 중 + + + + MaxTimeOffroad + + Max Time Offroad + + + + Device is automatically turned off after a set time when the engine is turned off (off-road) after driving (on-road). + + + + s + + + + m + m + + + hr + 시간 + + + Always On + + + + Immediate + + + + + MonitoringPanel + + Enable Hands on Wheel Monitoring + + + + Monitor and alert when driver is not keeping the hands on the steering wheel. + + + MultiOptionDialog @@ -415,6 +896,33 @@ 비밀번호가 틀렸습니다 + + NetworkingSP + + Scan + + + + Scanning... + + + + Advanced + 고급 설정 + + + Enter password + 비밀번호를 입력하세요 + + + for "%1" + "%1"에 접속하려면 비밀번호가 필요합니다 + + + Wrong password + 비밀번호가 틀렸습니다 + + OffroadAlert @@ -467,6 +975,16 @@ Device temperature too high. System cooling down before starting. Current internal component temperature: %1 장치 온도가 너무 높습니다. 시작하기 전에 온도를 낮춰주세요. 현재 내부 부품 온도: %1 + + OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. + +%1 + + + + sunnypilot is now in Forced Offroad mode. sunnypilot won't start until Forced Offroad mode is disabled. Go to "Settings" -> "Device" -> "Unforce Offroad" to exit Force Offroad mode. + + OffroadHome @@ -506,6 +1024,186 @@ 장치를 재부팅하세요 + + OnroadScreenOff + + Driving Screen Off Timer + + + + Turn off the device screen or reduce brightness to protect the screen after driving starts. It automatically brightens or turns on when a touch or event occurs. + + + + s + + + + min + + + + Always On + + + + + OnroadScreenOffBrightness + + Driving Screen Off Brightness (%) + + + + When using the Driving Screen Off feature, the brightness is reduced according to the automatic brightness ratio. + + + + Dark + + + + + OnroadSettings + + ONROAD OPTIONS + + + + <b>ONROAD SETTINGS | SUNNYPILOT</b> + + + + + OsmPanel + + Mapd Version + + + + Offline Maps ETA + + + + Time Elapsed + + + + Downloaded Maps + + + + DELETE + + + + This will delete ALL downloaded maps + +Are you sure you want to delete all the maps? + + + + Yes, delete all the maps. + + + + Database Update + + + + CHECK + 확인 + + + Country + + + + SELECT + 선택 + + + Fetching Country list... + + + + State + + + + Fetching State list... + + + + All + + + + REFRESH + + + + UPDATE + 업데이트 + + + Download starting... + + + + Error: Invalid download. Retry. + + + + Download complete! + + + + + +Warning: You are on a metered connection! + + + + This will start the download process and it might take a while to complete. + + + + Continue on Metered + + + + Start Download + + + + m + + + + s + + + + Calculating... + + + + Downloaded + + + + Calculating ETA... + + + + Ready + + + + Time remaining: + + + PairingPopup @@ -536,6 +1234,51 @@ 활성화 + + ParamControlSP + + Enable + 활성화 + + + Cancel + 취소 + + + + PathOffset + + Path Offset + + + + Hack to trick the model path to be left or right biased of the lane. Decreasing the value will shift the model more left, increasing will shift the model more right. Changes take effect immediately. + + + + cm + + + + + PauseLateralSpeed + + Pause lateral actuation with blinker when traveling below the desired speed selected. Default is 20 MPH or 32 km/h. + + + + Default + + + + km/h + km/h + + + mph + mph + + PrimeAdWidget @@ -590,7 +1333,7 @@ openpilot - openpilot + openpilot %n minute(s) ago @@ -630,6 +1373,30 @@ now now + + sunnypilot + + + + Update downloaded. Ready to reboot. + + + + Update: Check and Download Update + + + + Reboot: Reboot Device + + + + Update + + + + Updating... + + Reset @@ -672,6 +1439,131 @@ This may take up to a minute. 시스템 재설정이 시작되었습니다. 모든 콘텐츠와 설정을 지우려면 확인을 누르시고 부팅을 재개하려면 취소를 누르세요. + + SPVehiclesTogglesPanel + + Hyundai/Kia/Genesis + + + + HKG CAN: Smoother Stopping Performance (Beta) + + + + Smoother stopping behind a stopped car or desired stopping event. This is only applicable to HKG CAN platforms using openpilot longitudinal control. + + + + Subaru + + + + Manual Parking Brake: Stop and Go (Beta) + + + + Experimental feature to enable stop and go for Subaru Global models with manual handbrake. Models with electric parking brake should keep this disabled. Thanks to martinl for this implementation! + + + + Toyota/Lexus + + + + Enable Stock Toyota Longitudinal Control + + + + sunnypilot will <b>not</b> take over control of gas and brakes. Stock Toyota longitudinal control will be used. + + + + Allow M.A.D.S. toggling w/ LKAS Button (Beta) + + + + Allows M.A.D.S. engagement/disengagement with "LKAS" button from the steering wheel. + + + + Note: Enabling this toggle may have unexpected behavior with steering control. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Toyota TSS2 Longitudinal: Custom Tuning + + + + Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + + + Enable Enhanced Blind Spot Monitor + + + + Enable Toyota Stop and Go Hack + + + + sunnypilot will allow some Toyota/Lexus cars to auto resume during stop and go traffic. This feature is only applicable to certain models. Use at your own risk. + + + + Enable Toyota Door Auto Locking + + + + sunnypilot will attempt to lock the doors when drive above 10 km/h (6.2 mph). +Reboot Required. + + + + Enable Toyota Door Auto Unlocking + + + + sunnypilot will attempt to unlock the doors when shift to gear P. +Reboot Required. + + + + Volkswagen + + + + Enable CC Only support + + + + sunnypilot supports Volkswagen MQB CC only platforms with this toggle enabled. Only enable this toggle if your car does not have ACC from the factory. + + + + Start the car to check car compatibility + + + + This platform is already supported, therefore no need to enable this toggle + + + + This platform is not supported + + + + This platform can be supported + + + + sunnypilot will use debugging CAN messages to receive unfiltered BSM signals, allowing detection of more objects. + + + + Tested on RAV4 TSS1, Lexus LSS1, Toyota TSS1/1.5, and Prius TSS2. + + + SettingsWindow @@ -695,6 +1587,61 @@ This may take up to a minute. 소프트웨어 + + SettingsWindowSP + + × + × + + + Device + 장치 + + + Network + 네트워크 + + + sunnylink + + + + Toggles + 토글 + + + Software + 소프트웨어 + + + sunnypilot + + + + OSM + + + + Monitoring + + + + Visuals + + + + Display + + + + Trips + + + + Vehicle + + + Setup @@ -888,6 +1835,100 @@ This may take up to a minute. 5G + + SidebarSP + + TEMP + 온도 + + + HIGH + 높음 + + + GOOD + 좋음 + + + OK + OK + + + DISABLED + + + + OFFLINE + 연결 안됨 + + + REGIST... + + + + ONLINE + 온라인 + + + ERROR + 오류 + + + SUNNYLINK + + + + + SlcSettings + + Auto + + + + User Confirm + + + + Engage Mode + + + + Default + + + + Fixed + + + + Percentage + + + + Limit Offset + + + + Set speed limit slightly higher than actual speed limit for a more natural drive. + + + + This platform defaults to <b>Auto</b> mode. <b>User Confirm</b> mode is not supported on this platform. + + + + Select the desired mode to set the cruising speed to the speed limit: + + + + Auto: Automatic speed adjustment on motorways based on speed limit data. + + + + User Confirm: Inform the driver to change set speed of Adaptive Cruise Control to help the driver stay within the speed limit. + + + SoftwarePanel @@ -963,6 +2004,233 @@ This may take up to a minute. 업데이트 안함 + + SoftwarePanelSP + + Driving Model + + + + SELECT + 선택 + + + PENDING + + + + Downloading Driving model + + + + (CACHED) + + + + Driving model + + + + downloaded + + + + Downloading Navigation model + + + + Navigation model + + + + Downloading Metadata model + + + + Metadata model + + + + Downloads have failed, please try swapping the model! + + + + Failed: + + + + Fetching models... + + + + Select a Driving Model + + + + Download has started in the background. + + + + We STRONGLY suggest you to reset calibration. Would you like to do that now? + + + + Reset Calibration + 캘리브레이션 초기화 + + + Warning: You are on a metered connection! + + + + Continue + 계속 + + + on Metered + + + + + SpeedLimitPolicySettings + + Speed Limit Source Policy + + + + Nav + + + + Only + + + + Map + + + + Car + + + + First + + + + Select the precedence order of sources. Utilized by Speed Limit Control and Speed Limit Warning + + + + Nav Only: Data from Mapbox active navigation only. + + + + Map Only: Data from OpenStreetMap only. + + + + Car Only: Data from the car's built-in sources (if available). + + + + Nav First: Nav -> Map -> Car + + + + Map First: Map -> Nav -> Car + + + + Car First: Car -> Nav -> Map + + + + + SpeedLimitValueOffset + + km/h + km/h + + + mph + mph + + + + SpeedLimitWarningSettings + + Off + + + + Display + + + + Chime + + + + Speed Limit Warning + + + + Warning with speed limit flash + + + + When Speed Limit Warning is enabled, the speed limit sign will alert the driver when the cruising speed is faster than then speed limit plus the offset. + + + + Default + + + + Fixed + + + + Percentage + + + + Warning Offset + + + + Select the desired offset to warn the driver when the vehicle is driving faster than the speed limit. + + + + Off: When the cruising speed is faster than the speed limit plus the offset, there will be no warning. + + + + Display: The speed on the speed limit sign turns red to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + Chime: The speed on the speed limit sign turns red and chimes to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + + SpeedLimitWarningValueOffset + + N/A + N/A + + + km/h + km/h + + + mph + mph + + SshControl @@ -1009,6 +2277,399 @@ This may take up to a minute. SSH 사용 + + SunnylinkPanel + + Enable sunnylink + + + + Device ID + + + + N/A + N/A + + + This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. + + + + 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 + + + + 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. + + + + Sponsor Status + + + + SPONSOR + + + + Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. + + + + Pair GitHub Account + + + + PAIR + 동기화 + + + Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. + + + + sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. + + + + Manage Settings + + + + Backup Settings + + + + Are you sure you want to backup sunnypilot settings? + + + + Back Up + + + + Restore Settings + + + + Are you sure you want to restore the last backed up sunnypilot settings? + + + + Restore + + + + THANKS + + + + Not Sponsor + + + + Paired + + + + Not Paired + + + + Backing up... + + + + Restoring... + + + + + SunnylinkSponsorPopup + + Scan the QR code to login to your GitHub account + + + + Follow the prompts to complete the pairing process + + + + Re-enter the "sunnylink" panel to verify sponsorship status + + + + If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot + + + + Scan the QR code to visit sunnyhaibin's GitHub Sponsors page + + + + Choose your sponsorship tier and confirm your support + + + + Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status + + + + Pair your GitHub account + + + + Early Access: Become a sunnypilot Sponsor + + + + + SunnypilotPanel + + Enable M.A.D.S. + + + + Enable the beloved M.A.D.S. feature. Disable toggle to revert back to stock openpilot engagement/disengagement. + + + + Laneless for Curves in "Auto" Mode + + + + While in Auto Lane, switch to Laneless for current/future curves. + + + + Speed Limit Control (SLC) + + + + When you engage ACC, you will be prompted to set the cruising speed to the speed limit of the road adjusted by the Offset and Source Policy specified, or the current driving speed. The maximum cruising speed will always be the MAX set speed. + + + + Enable Vision-based Turn Speed Control (V-TSC) + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Enable Map Data Turn Speed Control (M-TSC) (Beta) + + + + Use curvature information from map data to define speed limits to take turns ahead. + + + + ACC +/-: Long Press Reverse + + + + Change the ACC +/- buttons behavior with cruise speed change in sunnypilot. + + + + Disabled (Stock): Short=1, Long = 5 (imperial) / 10 (metric) + + + + Enabled: Short = 5 (imperial) / 10 (metric), Long=1 + + + + Custom Offsets + + + + Neural Network Lateral Control (NNLC) + + + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Enable Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying FRICTION and LAT_ACCEL_FACTOR below will override the offline values indicated in the YAML files within "selfdrive/torque_data". The values will also be used live when "Override Self-Tune" toggle is enabled. + + + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Quiet Drive 🤫 + + + + sunnypilot will display alerts but only play the most important warning sounds. This feature can be toggled while the car is on. + + + + Green Traffic Light Chime (Beta) + + + + A chime will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. If you are waiting behind another vehicle, the chime will play once the vehicle advances unless ACC is engaged. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Vehicle Departure Alert + + + + Enable this will notify when the leading vehicle drives away. + + + + Customize M.A.D.S. + + + + Customize Lane Change + + + + Customize Offsets + + + + Customize Speed Limit Control + + + + Customize Warning + + + + Customize Source + + + + Laneful + + + + Laneless + + + + Auto + + + + Dynamic Lane Profile + + + + Speed Limit Assist + + + + Real-time and Offline + + + + Offline Only + + + + Dynamic Lane Profile is not available with the current Driving Model + + + + Custom Offsets is not available with the current Driving Model + + + + NNLC is currently not available on this platform. + + + + Match: "Exact" is ideal, but "Fuzzy" is fine too. Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server if there are any issues: + + + + Start the car to check car compatibility + + + + NNLC Not Loaded + + + + NNLC Loaded + + + + Fuzzy + + + + Exact + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server and donate logs to get NNLC loaded for your car: + + + + Match + + + + Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server with feedback, or to provide log data for your car if your car is currently unsupported: + + + + Add custom offsets to Camera and Path in sunnypilot. + + + + Default is Laneless. In Auto mode, sunnnypilot dynamically chooses between Laneline or Laneless model based on lane recognition confidence level on road and certain conditions. + + + TermsPage @@ -1028,15 +2689,30 @@ This may take up to a minute. 동의 + + TermsPageSP + + Terms & Conditions + 이용약관 + + + Decline + 거절 + + + Scroll to accept + 동의하려면 아래로 스크롤하세요 + + TogglesPanel Enable openpilot - openpilot 사용 + openpilot 사용 Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. - 어댑티브 크루즈 컨트롤 및 차로 유지 보조를 위해 openpilot 시스템을 사용할 수 있습니다. 이 기능을 사용할 때에는 언제나 주의를 기울여야 합니다. 설정을 변경하면 차량 시동이 꺼졌을 때 적용됩니다. + 어댑티브 크루즈 컨트롤 및 차로 유지 보조를 위해 openpilot 시스템을 사용할 수 있습니다. 이 기능을 사용할 때에는 언제나 주의를 기울여야 합니다. 설정을 변경하면 차량 시동이 꺼졌을 때 적용됩니다. Enable Lane Departure Warnings @@ -1072,19 +2748,19 @@ This may take up to a minute. Show ETA in 24h Format - 24시간 형식으로 도착 예정 시간 표시 + 24시간 형식으로 도착 예정 시간 표시 Use 24h format instead of am/pm - 오전/오후 대신 24시간 형식 사용 + 오전/오후 대신 24시간 형식 사용 Show Map on Left Side of UI - UI 왼쪽에 지도 표시 + UI 왼쪽에 지도 표시 Show map on left side when in split screen view. - 분할 화면 보기에서 지도를 왼쪽에 표시합니다. + 분할 화면 보기에서 지도를 왼쪽에 표시합니다. Experimental Mode @@ -1166,6 +2842,252 @@ This may take up to a minute. Enable driver monitoring even when openpilot is not engaged. + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + + TogglesPanelSP + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + openpilot Longitudinal Control (Alpha) + openpilot 가감속 제어 (알파) + + + WARNING: sunnypilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + + + + On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to sunnypilot longitudinal control. Enabling Experimental mode is recommended when enabling sunnypilot longitudinal control alpha. + + + + Custom Stock Longitudinal Control + + + + When enabled, sunnypilot will attempt to control stock longitudinal control with ACC button presses. +This feature must be used along with SLC, and/or V-TSC, and/or M-TSC. + + + + Experimental Mode + 실험 모드 + + + Enable Dynamic Experimental Control + + + + Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. + + + + Enable Dynamic Personality + + + + Enable this to allow sunnypilot to dynamically adjust following distance and reaction based on your "Driving Personality" setting. Instead of predefined settings for each personality, every personality now adapts dynamically according to your speed and the distance to the lead car. + + + + Disengage on Accelerator Pedal + 가속페달 조작 시 해제 + + + When enabled, pressing the accelerator pedal will disengage openpilot. + 활성화된 경우 가속 페달을 밟으면 openpilot이 해제됩니다. + + + Enable Lane Departure Warnings + 차선 이탈 경고 활성화 + + + Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). + 차량이 50km/h(31mph) 이상의 속도로 주행할 때 방향지시등이 켜지지 않은 상태에서 차선을 벗어나면 경고합니다. + + + Always-On Driver Monitoring + + + + Enable driver monitoring even when sunnypilot is not engaged. + + + + Record and Upload Driver Camera + 운전자 카메라 녹화 및 업로드 + + + Upload data from the driver facing camera and help improve the driver monitoring algorithm. + 운전자 카메라의 영상 데이터를 업로드하여 운전자 모니터링 알고리즘을 개선합니다. + + + Disable Onroad Uploads + + + + Disable uploads completely when onroad. Necessary to avoid high data usage when connected to Wi-Fi hotspot. Turn on this feature if you are looking to utilize map-based features, such as Speed Limit Control (SLC) and Map-based Turn Speed Control (MTSC). + + + + Use Metric System + 미터법 사용 + + + Display speed in km/h instead of mph. + mph 대신 km/h로 속도를 표시합니다. + + + Show ETA in 24h Format + 24시간 형식으로 도착 예정 시간 표시 + + + Use 24h format instead of am/pm + 오전/오후 대신 24시간 형식 사용 + + + Show Map on Left Side of UI + UI 왼쪽에 지도 표시 + + + Show map on left side when in split screen view. + 분할 화면 보기에서 지도를 왼쪽에 표시합니다. + + + Aggressive + 공격적 + + + Moderate + + + + Standard + 표준 + + + Relaxed + 편안한 + + + Driving Personality + 주행 모드 + + + Standard is recommended. In moderate/aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + + + + Sport + + + + Normal + + + + Eco + + + + Stock + + + + Acceleration Personality + + + + Normal is recommended. In sport mode, sunnypilot will provide aggressive acceleration for a dynamic driving experience. In eco mode, sunnypilot will apply smoother and more relaxed acceleration. On supported cars, you can cycle through these acceleration personality within Onroad Settings on the driving screen. + + + + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + openpilot은 기본적으로 <b>안정 모드</b>로 주행합니다. 실험 모드는 안정화되지 않은 <b>알파 수준의 기능</b>을 활성화합니다. 실험 모드의 기능은 아래와 같습니다: + + + End-to-End Longitudinal Control + E2E 가감속 제어 + + + Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + + + + New Driving Visualization + 새로운 주행 시각화 + + + The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. + + + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + 차량에 장착된 ACC로 가감속을 제어하기 때문에 현재 이 차량에서는 실험 모드를 사용할 수 없습니다. + + + openpilot longitudinal control may come in a future update. + openpilot 가감속 제어는 향후 업데이트에서 지원될 수 있습니다. + + + An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. + + + + + TorqueFriction + + FRICTION + + + + Adjust Friction for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueMaxLatAccel + + LAT_ACCEL_FACTOR + + + + Adjust Max Lateral Acceleration for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + Updater @@ -1202,6 +3124,168 @@ This may take up to a minute. 업데이트 실패 + + VehiclePanel + + Updating this setting takes effect when the car is powered off. + + + + Select your car + + + + + VisualsPanel + + Display Braking Status + + + + Enable this will turn the current speed value to red while the brake is used. + + + + Display Stand Still Timer + + + + Enable this will display time spent at a stop (i.e., at a stop lights, stop signs, traffic congestions). + + + + Display DM Camera in Reverse Gear + + + + Show Driver Monitoring camera while the car is in reverse gear. + + + + OSM: Show debug UI elements + + + + OSM: Show UI elements that aid debugging. + + + + Display Feature Status + + + + Display the statuses of certain features on the driving screen. + + + + Enable Onroad Settings + + + + Display the Onroad Settings button on the driving screen to adjust feature options on the driving screen, without navigating into the settings menu. + + + + Speedometer: Display True Speed + + + + Display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Display End-to-end Longitudinal Status (Beta) + + + + Enable this will display an icon that appears when the End-to-end model decides to start or stop. + + + + Navigation: Display in Full Screen + + + + Enable this will display the built-in navigation in full screen.<br>To switch back to driving view, <font color='yellow'>tap on the border edge</font>. + + + + Map: Display 3D Buildings + + + + Parse and display 3D buildings on map. Thanks to jakethesnake420 for this implementation. + + + + Off + + + + 5 Metrics + + + + 10 Metrics + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + + + Distance + + + + Speed + + + + Display Metrics Below Chevron + + + + Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + + + RAM + + + + CPU + + + + GPU + + + + Max + + + + Display Temperature on Sidebar + + + + Time + + + + All + + + WiFiPromptWidget @@ -1248,4 +3332,27 @@ This may take up to a minute. 삭제 + + WifiUISP + + Scanning for networks... + 네트워크 검색 중... + + + CONNECTING... + 연결 중... + + + FORGET + 삭제 + + + Forget Wi-Fi Network "%1"? + Wi-Fi "%1"에 자동으로 연결하지 않겠습니까? + + + Forget + 삭제 + + diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index feaa6e86a1..856ef26ca8 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -87,6 +87,89 @@ para "%1" + + AdvancedNetworkingSP + + Back + Voltar + + + Enable Tethering + Ativar Tether + + + Retain hotspot/tethering state + + + + Enabling this toggle will retain the hotspot/tethering toggle state across reboots. + + + + Tethering Password + Senha Tethering + + + EDIT + EDITAR + + + Enter new tethering password + Insira nova senha tethering + + + IP Address + Endereço IP + + + Enable Roaming + Ativar Roaming + + + APN Setting + APN Config + + + Enter APN + Insira APN + + + leave blank for automatic configuration + deixe em branco para configuração automática + + + Cellular Metered + Plano de Dados Limitado + + + Prevent large data uploads when on a metered connection + Evite grandes uploads de dados quando estiver em uma conexão limitada + + + Hidden Network + Rede Oculta + + + CONNECT + + + + Enter SSID + Digite o SSID + + + Enter password + Insira a senha + + + for "%1" + para "%1" + + + Ngrok Service + + + AnnotatedCameraWidget @@ -103,11 +186,119 @@ SPEED - MAX + MAX LIMIT - VELO + VELO + + + + AnnotatedCameraWidgetSP + + km/h + km/h + + + mph + mph + + + MAX + LIMITE + + + SPEED + MAX + + + LIMIT + VELO + + + + AutoLaneChangeTimer + + Auto Lane Change by Blinker + + + + Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. +Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. + + + + s + + + + Off + + + + Nudge + + + + Nudgeless + + + + + BackupSettings + + Settings backed up for sunnylink Device ID: + + + + Settings updated successfully, but no additional data was returned by the server. + + + + OOPS! We made a booboo. + + + + Please try again later. + + + + Settings restored. Confirm to restart the interface. + + + + No settings found to restore. + + + + + BrightnessControl + + Brightness + + + + Manually adjusts the global brightness of the screen. + + + + Auto + + + + + CameraOffset + + Camera Offset - Laneful Only + + + + Hack to trick vehicle to be left or right biased in its lane. Decreasing the value will make the car keep more left, increasing will make it keep more right. Changes take effect immediately. Default: +4 cm + + + + cm + @@ -121,11 +312,18 @@ Cancelar + + CustomOffsetsSettings + + Back + Voltar + + DeclinePage You must accept the Terms and Conditions in order to use openpilot. - Você precisa aceitar os Termos e Condições para utilizar openpilot. + Você precisa aceitar os Termos e Condições para utilizar openpilot. Back @@ -135,6 +333,10 @@ Decline, uninstall %1 Rejeitar, desintalar %1 + + You must accept the Terms and Conditions in order to use sunnypilot. + + DestinationWidget @@ -247,7 +449,7 @@ openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required. - O openpilot requer que o dispositivo seja montado dentro de 4° esquerda ou direita e dentro de 5° para cima ou 9° para baixo. O openpilot está continuamente calibrando, resetar raramente é necessário. + O openpilot requer que o dispositivo seja montado dentro de 4° esquerda ou direita e dentro de 5° para cima ou 9° para baixo. O openpilot está continuamente calibrando, resetar raramente é necessário. Your device is pointed %1° %2 and %3° %4. @@ -305,6 +507,155 @@ PAIR PAREAR + + sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. sunnypilot is continuously calibrating, resetting is rarely required. + + + + + DevicePanelSP + + TOGGLE + + + + Enable or disable PIN requirement for Fleet Manager access. + + + + Are you sure you want to turn off PIN requirement? + + + + Turn Off + + + + Error Troubleshoot + + + + VIEW + VER + + + Display error from the tmux session when an error has occurred from a system process. + + + + Reset Access Tokens for Map Services + + + + RESET + RESET + + + Reset self-service access tokens for Mapbox, Amap, and Google Maps. + + + + Are you sure you want to reset access tokens for all map services? + + + + Reset + Resetar + + + Reset sunnypilot Settings + + + + Are you sure you want to reset all sunnypilot settings? + + + + Toggle Onroad/Offroad + + + + OFF + + + + Are you sure you want to unforce offroad? + + + + Unforce + + + + Are you sure you want to force offroad? + + + + Force + + + + Disengage to Force Offroad + + + + Unforce Offroad + + + + Force Offroad + + + + Fleet Manager PIN: + + + + + DisplayPanel + + Driving Screen Off: Non-Critical Events + + + + When <b>Driving Screen Off Timer</b> is not set to <b>"Always On"</b>: + + + + Enabled: Wake the brightness of the screen to display all events. + + + + Disabled: Wake the brightness of the screen to display critical events. + + + + + DriveStats + + Drives + + + + Hours + + + + ALL TIME + + + + PAST WEEK + + + + KM + + + + Miles + + DriverViewWindow @@ -345,6 +696,79 @@ Instalando... + + LaneChangeSettings + + Back + Voltar + + + Pause Lateral Below Speed with Blinker + + + + Enable this toggle to pause lateral actuation with blinker when traveling below the desired speed selected below. + + + + Auto Lane Change: Delay with Blind Spot + + + + Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. + + + + Block Lane Change: Road Edge Detection + + + + Enable this toggle to block lane change when road edge is detected on the stalk actuated side. + + + + + MadsSettings + + Enable ACC+MADS with RES+/SET- + + + + Engage both M.A.D.S. and ACC with a single press of RES+ or SET- button. + + + + Note: Once M.A.D.S. is engaged via this mode, it will remain engaged until it is manually disabled via the M.A.D.S. button or car shut off. + + + + Toggle M.A.D.S. with Cruise Main + + + + Allows M.A.D.S. engagement/disengagement with "Cruise Main" cruise control button from the steering wheel. + + + + Remain Active + + + + Pause Steering + + + + Steering Mode After Braking + + + + Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. + +Remain Active: ALC will remain active even after the brake pedal is pressed. +Pause Steering: ALC will be paused after the brake pedal is manually pressed. + + + MapETA @@ -386,6 +810,63 @@ Aguardando rota + + MapWindowSP + + Map Loading + Carregando Mapa + + + Waiting for GPS + Aguardando GPS + + + Waiting for route + Aguardando rota + + + + MaxTimeOffroad + + Max Time Offroad + + + + Device is automatically turned off after a set time when the engine is turned off (off-road) after driving (on-road). + + + + s + + + + m + m + + + hr + hr + + + Always On + + + + Immediate + + + + + MonitoringPanel + + Enable Hands on Wheel Monitoring + + + + Monitor and alert when driver is not keeping the hands on the steering wheel. + + + MultiOptionDialog @@ -416,6 +897,33 @@ Senha incorreta + + NetworkingSP + + Scan + + + + Scanning... + + + + Advanced + Avançado + + + Enter password + Insira a senha + + + for "%1" + para "%1" + + + Wrong password + Senha incorreta + + OffroadAlert @@ -468,6 +976,16 @@ Device temperature too high. System cooling down before starting. Current internal component temperature: %1 Temperatura do dispositivo muito alta. O sistema está sendo resfriado antes de iniciar. A temperatura atual do componente interno é: %1 + + OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. + +%1 + + + + sunnypilot is now in Forced Offroad mode. sunnypilot won't start until Forced Offroad mode is disabled. Go to "Settings" -> "Device" -> "Unforce Offroad" to exit Force Offroad mode. + + OffroadHome @@ -507,6 +1025,186 @@ Reinicie o Dispositivo + + OnroadScreenOff + + Driving Screen Off Timer + + + + Turn off the device screen or reduce brightness to protect the screen after driving starts. It automatically brightens or turns on when a touch or event occurs. + + + + s + + + + min + min + + + Always On + + + + + OnroadScreenOffBrightness + + Driving Screen Off Brightness (%) + + + + When using the Driving Screen Off feature, the brightness is reduced according to the automatic brightness ratio. + + + + Dark + + + + + OnroadSettings + + ONROAD OPTIONS + + + + <b>ONROAD SETTINGS | SUNNYPILOT</b> + + + + + OsmPanel + + Mapd Version + + + + Offline Maps ETA + + + + Time Elapsed + + + + Downloaded Maps + + + + DELETE + + + + This will delete ALL downloaded maps + +Are you sure you want to delete all the maps? + + + + Yes, delete all the maps. + + + + Database Update + + + + CHECK + VERIFICAR + + + Country + + + + SELECT + SELECIONE + + + Fetching Country list... + + + + State + + + + Fetching State list... + + + + All + + + + REFRESH + + + + UPDATE + ATUALIZAÇÃO + + + Download starting... + + + + Error: Invalid download. Retry. + + + + Download complete! + + + + + +Warning: You are on a metered connection! + + + + This will start the download process and it might take a while to complete. + + + + Continue on Metered + + + + Start Download + + + + m + + + + s + + + + Calculating... + + + + Downloaded + + + + Calculating ETA... + + + + Ready + + + + Time remaining: + + + PairingPopup @@ -537,6 +1235,51 @@ Ativar + + ParamControlSP + + Enable + Ativar + + + Cancel + Cancelar + + + + PathOffset + + Path Offset + + + + Hack to trick the model path to be left or right biased of the lane. Decreasing the value will shift the model more left, increasing will shift the model more right. Changes take effect immediately. + + + + cm + + + + + PauseLateralSpeed + + Pause lateral actuation with blinker when traveling below the desired speed selected. Default is 20 MPH or 32 km/h. + + + + Default + + + + km/h + km/h + + + mph + mph + + PrimeAdWidget @@ -591,7 +1334,7 @@ openpilot - openpilot + openpilot %n minute(s) ago @@ -634,6 +1377,30 @@ now agora + + sunnypilot + + + + Update downloaded. Ready to reboot. + + + + Update: Check and Download Update + + + + Reboot: Reboot Device + + + + Update + + + + Updating... + + Reset @@ -676,6 +1443,131 @@ Isso pode levar até um minuto. Reinicialização do sistema acionada. Pressione confirmar para apagar todo o conteúdo e configurações. Pressione cancel para retomar a inicialização. + + SPVehiclesTogglesPanel + + Hyundai/Kia/Genesis + + + + HKG CAN: Smoother Stopping Performance (Beta) + + + + Smoother stopping behind a stopped car or desired stopping event. This is only applicable to HKG CAN platforms using openpilot longitudinal control. + + + + Subaru + + + + Manual Parking Brake: Stop and Go (Beta) + + + + Experimental feature to enable stop and go for Subaru Global models with manual handbrake. Models with electric parking brake should keep this disabled. Thanks to martinl for this implementation! + + + + Toyota/Lexus + + + + Enable Stock Toyota Longitudinal Control + + + + sunnypilot will <b>not</b> take over control of gas and brakes. Stock Toyota longitudinal control will be used. + + + + Allow M.A.D.S. toggling w/ LKAS Button (Beta) + + + + Allows M.A.D.S. engagement/disengagement with "LKAS" button from the steering wheel. + + + + Note: Enabling this toggle may have unexpected behavior with steering control. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Toyota TSS2 Longitudinal: Custom Tuning + + + + Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + + + Enable Enhanced Blind Spot Monitor + + + + Enable Toyota Stop and Go Hack + + + + sunnypilot will allow some Toyota/Lexus cars to auto resume during stop and go traffic. This feature is only applicable to certain models. Use at your own risk. + + + + Enable Toyota Door Auto Locking + + + + sunnypilot will attempt to lock the doors when drive above 10 km/h (6.2 mph). +Reboot Required. + + + + Enable Toyota Door Auto Unlocking + + + + sunnypilot will attempt to unlock the doors when shift to gear P. +Reboot Required. + + + + Volkswagen + + + + Enable CC Only support + + + + sunnypilot supports Volkswagen MQB CC only platforms with this toggle enabled. Only enable this toggle if your car does not have ACC from the factory. + + + + Start the car to check car compatibility + + + + This platform is already supported, therefore no need to enable this toggle + + + + This platform is not supported + + + + This platform can be supported + + + + sunnypilot will use debugging CAN messages to receive unfiltered BSM signals, allowing detection of more objects. + + + + Tested on RAV4 TSS1, Lexus LSS1, Toyota TSS1/1.5, and Prius TSS2. + + + SettingsWindow @@ -699,6 +1591,61 @@ Isso pode levar até um minuto. Software + + SettingsWindowSP + + × + × + + + Device + Dispositivo + + + Network + Rede + + + sunnylink + + + + Toggles + Ajustes + + + Software + Software + + + sunnypilot + + + + OSM + + + + Monitoring + + + + Visuals + + + + Display + + + + Trips + + + + Vehicle + + + Setup @@ -892,6 +1839,100 @@ Isso pode levar até um minuto. 5G + + SidebarSP + + TEMP + TEMP + + + HIGH + ALTA + + + GOOD + BOA + + + OK + OK + + + DISABLED + + + + OFFLINE + OFFLINE + + + REGIST... + + + + ONLINE + ONLINE + + + ERROR + ERRO + + + SUNNYLINK + + + + + SlcSettings + + Auto + + + + User Confirm + + + + Engage Mode + + + + Default + + + + Fixed + + + + Percentage + + + + Limit Offset + + + + Set speed limit slightly higher than actual speed limit for a more natural drive. + + + + This platform defaults to <b>Auto</b> mode. <b>User Confirm</b> mode is not supported on this platform. + + + + Select the desired mode to set the cruising speed to the speed limit: + + + + Auto: Automatic speed adjustment on motorways based on speed limit data. + + + + User Confirm: Inform the driver to change set speed of Adaptive Cruise Control to help the driver stay within the speed limit. + + + SoftwarePanel @@ -967,6 +2008,233 @@ Isso pode levar até um minuto. nunca + + SoftwarePanelSP + + Driving Model + + + + SELECT + SELECIONE + + + PENDING + + + + Downloading Driving model + + + + (CACHED) + + + + Driving model + + + + downloaded + + + + Downloading Navigation model + + + + Navigation model + + + + Downloading Metadata model + + + + Metadata model + + + + Downloads have failed, please try swapping the model! + + + + Failed: + + + + Fetching models... + + + + Select a Driving Model + + + + Download has started in the background. + + + + We STRONGLY suggest you to reset calibration. Would you like to do that now? + + + + Reset Calibration + Reinicializar Calibragem + + + Warning: You are on a metered connection! + + + + Continue + Continuar + + + on Metered + + + + + SpeedLimitPolicySettings + + Speed Limit Source Policy + + + + Nav + + + + Only + + + + Map + + + + Car + + + + First + + + + Select the precedence order of sources. Utilized by Speed Limit Control and Speed Limit Warning + + + + Nav Only: Data from Mapbox active navigation only. + + + + Map Only: Data from OpenStreetMap only. + + + + Car Only: Data from the car's built-in sources (if available). + + + + Nav First: Nav -> Map -> Car + + + + Map First: Map -> Nav -> Car + + + + Car First: Car -> Nav -> Map + + + + + SpeedLimitValueOffset + + km/h + km/h + + + mph + mph + + + + SpeedLimitWarningSettings + + Off + + + + Display + + + + Chime + + + + Speed Limit Warning + + + + Warning with speed limit flash + + + + When Speed Limit Warning is enabled, the speed limit sign will alert the driver when the cruising speed is faster than then speed limit plus the offset. + + + + Default + + + + Fixed + + + + Percentage + + + + Warning Offset + + + + Select the desired offset to warn the driver when the vehicle is driving faster than the speed limit. + + + + Off: When the cruising speed is faster than the speed limit plus the offset, there will be no warning. + + + + Display: The speed on the speed limit sign turns red to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + Chime: The speed on the speed limit sign turns red and chimes to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + + SpeedLimitWarningValueOffset + + N/A + N/A + + + km/h + km/h + + + mph + mph + + SshControl @@ -1013,6 +2281,399 @@ Isso pode levar até um minuto. Habilitar SSH + + SunnylinkPanel + + Enable sunnylink + + + + Device ID + + + + N/A + N/A + + + This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. + + + + 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 + + + + 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. + + + + Sponsor Status + + + + SPONSOR + + + + Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. + + + + Pair GitHub Account + + + + PAIR + PAREAR + + + Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. + + + + sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. + + + + Manage Settings + + + + Backup Settings + + + + Are you sure you want to backup sunnypilot settings? + + + + Back Up + + + + Restore Settings + + + + Are you sure you want to restore the last backed up sunnypilot settings? + + + + Restore + + + + THANKS + + + + Not Sponsor + + + + Paired + + + + Not Paired + + + + Backing up... + + + + Restoring... + + + + + SunnylinkSponsorPopup + + Scan the QR code to login to your GitHub account + + + + Follow the prompts to complete the pairing process + + + + Re-enter the "sunnylink" panel to verify sponsorship status + + + + If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot + + + + Scan the QR code to visit sunnyhaibin's GitHub Sponsors page + + + + Choose your sponsorship tier and confirm your support + + + + Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status + + + + Pair your GitHub account + + + + Early Access: Become a sunnypilot Sponsor + + + + + SunnypilotPanel + + Enable M.A.D.S. + + + + Enable the beloved M.A.D.S. feature. Disable toggle to revert back to stock openpilot engagement/disengagement. + + + + Laneless for Curves in "Auto" Mode + + + + While in Auto Lane, switch to Laneless for current/future curves. + + + + Speed Limit Control (SLC) + + + + When you engage ACC, you will be prompted to set the cruising speed to the speed limit of the road adjusted by the Offset and Source Policy specified, or the current driving speed. The maximum cruising speed will always be the MAX set speed. + + + + Enable Vision-based Turn Speed Control (V-TSC) + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Enable Map Data Turn Speed Control (M-TSC) (Beta) + + + + Use curvature information from map data to define speed limits to take turns ahead. + + + + ACC +/-: Long Press Reverse + + + + Change the ACC +/- buttons behavior with cruise speed change in sunnypilot. + + + + Disabled (Stock): Short=1, Long = 5 (imperial) / 10 (metric) + + + + Enabled: Short = 5 (imperial) / 10 (metric), Long=1 + + + + Custom Offsets + + + + Neural Network Lateral Control (NNLC) + + + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Enable Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying FRICTION and LAT_ACCEL_FACTOR below will override the offline values indicated in the YAML files within "selfdrive/torque_data". The values will also be used live when "Override Self-Tune" toggle is enabled. + + + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Quiet Drive 🤫 + + + + sunnypilot will display alerts but only play the most important warning sounds. This feature can be toggled while the car is on. + + + + Green Traffic Light Chime (Beta) + + + + A chime will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. If you are waiting behind another vehicle, the chime will play once the vehicle advances unless ACC is engaged. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Vehicle Departure Alert + + + + Enable this will notify when the leading vehicle drives away. + + + + Customize M.A.D.S. + + + + Customize Lane Change + + + + Customize Offsets + + + + Customize Speed Limit Control + + + + Customize Warning + + + + Customize Source + + + + Laneful + + + + Laneless + + + + Auto + + + + Dynamic Lane Profile + + + + Speed Limit Assist + + + + Real-time and Offline + + + + Offline Only + + + + Dynamic Lane Profile is not available with the current Driving Model + + + + Custom Offsets is not available with the current Driving Model + + + + NNLC is currently not available on this platform. + + + + Match: "Exact" is ideal, but "Fuzzy" is fine too. Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server if there are any issues: + + + + Start the car to check car compatibility + + + + NNLC Not Loaded + + + + NNLC Loaded + + + + Fuzzy + + + + Exact + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server and donate logs to get NNLC loaded for your car: + + + + Match + + + + Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server with feedback, or to provide log data for your car if your car is currently unsupported: + + + + Add custom offsets to Camera and Path in sunnypilot. + + + + Default is Laneless. In Auto mode, sunnnypilot dynamically chooses between Laneline or Laneless model based on lane recognition confidence level on road and certain conditions. + + + TermsPage @@ -1032,15 +2693,30 @@ Isso pode levar até um minuto. Concordo + + TermsPageSP + + Terms & Conditions + Termos & Condições + + + Decline + Declinar + + + Scroll to accept + Role a tela para aceitar + + TogglesPanel Enable openpilot - Ativar openpilot + Ativar openpilot Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. - Use o sistema openpilot para controle de cruzeiro adaptativo e assistência ao motorista de manutenção de faixa. Sua atenção é necessária o tempo todo para usar esse recurso. A alteração desta configuração tem efeito quando o carro é desligado. + Use o sistema openpilot para controle de cruzeiro adaptativo e assistência ao motorista de manutenção de faixa. Sua atenção é necessária o tempo todo para usar esse recurso. A alteração desta configuração tem efeito quando o carro é desligado. Enable Lane Departure Warnings @@ -1076,19 +2752,19 @@ Isso pode levar até um minuto. Show ETA in 24h Format - Mostrar ETA em Formato 24h + Mostrar ETA em Formato 24h Use 24h format instead of am/pm - Use o formato 24h em vez de am/pm + Use o formato 24h em vez de am/pm Show Map on Left Side of UI - Exibir Mapa no Lado Esquerdo + Exibir Mapa no Lado Esquerdo Show map on left side when in split screen view. - Exibir mapa do lado esquerdo quando a tela for dividida. + Exibir mapa do lado esquerdo quando a tela for dividida. Experimental Mode @@ -1170,6 +2846,252 @@ Isso pode levar até um minuto. Enable driver monitoring even when openpilot is not engaged. Habilite o monitoramento do motorista mesmo quando o openpilot não estiver acionado. + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + + TogglesPanelSP + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + openpilot Longitudinal Control (Alpha) + Controle Longitudinal openpilot (Embrionário) + + + WARNING: sunnypilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + + + + On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to sunnypilot longitudinal control. Enabling Experimental mode is recommended when enabling sunnypilot longitudinal control alpha. + + + + Custom Stock Longitudinal Control + + + + When enabled, sunnypilot will attempt to control stock longitudinal control with ACC button presses. +This feature must be used along with SLC, and/or V-TSC, and/or M-TSC. + + + + Experimental Mode + Modo Experimental + + + Enable Dynamic Experimental Control + + + + Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. + + + + Enable Dynamic Personality + + + + Enable this to allow sunnypilot to dynamically adjust following distance and reaction based on your "Driving Personality" setting. Instead of predefined settings for each personality, every personality now adapts dynamically according to your speed and the distance to the lead car. + + + + Disengage on Accelerator Pedal + Desacionar com Pedal do Acelerador + + + When enabled, pressing the accelerator pedal will disengage openpilot. + Quando ativado, pressionar o pedal do acelerador desacionará o openpilot. + + + Enable Lane Departure Warnings + Ativar Avisos de Saída de Faixa + + + Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). + Receba alertas para voltar para a pista se o seu veículo sair da faixa e a seta não tiver sido acionada previamente quando em velocidades superiores a 50 km/h. + + + Always-On Driver Monitoring + Monitoramento do Motorista Sempre Ativo + + + Enable driver monitoring even when sunnypilot is not engaged. + + + + Record and Upload Driver Camera + Gravar e Upload Câmera Motorista + + + Upload data from the driver facing camera and help improve the driver monitoring algorithm. + Upload dados da câmera voltada para o motorista e ajude a melhorar o algoritmo de monitoramentor. + + + Disable Onroad Uploads + + + + Disable uploads completely when onroad. Necessary to avoid high data usage when connected to Wi-Fi hotspot. Turn on this feature if you are looking to utilize map-based features, such as Speed Limit Control (SLC) and Map-based Turn Speed Control (MTSC). + + + + Use Metric System + Usar Sistema Métrico + + + Display speed in km/h instead of mph. + Exibir velocidade em km/h invés de mph. + + + Show ETA in 24h Format + Mostrar ETA em Formato 24h + + + Use 24h format instead of am/pm + Use o formato 24h em vez de am/pm + + + Show Map on Left Side of UI + Exibir Mapa no Lado Esquerdo + + + Show map on left side when in split screen view. + Exibir mapa do lado esquerdo quando a tela for dividida. + + + Aggressive + Disputa + + + Moderate + + + + Standard + Neutro + + + Relaxed + Calmo + + + Driving Personality + Temperamento de Direção + + + Standard is recommended. In moderate/aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + + + + Sport + + + + Normal + + + + Eco + + + + Stock + + + + Acceleration Personality + + + + Normal is recommended. In sport mode, sunnypilot will provide aggressive acceleration for a dynamic driving experience. In eco mode, sunnypilot will apply smoother and more relaxed acceleration. On supported cars, you can cycle through these acceleration personality within Onroad Settings on the driving screen. + + + + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + openpilot por padrão funciona em <b>modo chill</b>. modo Experimental ativa <b>recursos de nível-embrionário</b> que não estão prontos para o modo chill. Recursos experimentais estão listados abaixo: + + + End-to-End Longitudinal Control + Controle Longitudinal de Ponta a Ponta + + + Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + + + + New Driving Visualization + Nova Visualização de Condução + + + The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. + A visualização de condução fará a transição para a câmera grande angular voltada para a estrada em baixas velocidades para mostrar melhor algumas curvas. O logotipo do modo Experimental também será mostrado no canto superior direito. + + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + O modo Experimental está atualmente indisponível para este carro já que o ACC original do carro é usado para controle longitudinal. + + + openpilot longitudinal control may come in a future update. + O controle longitudinal openpilot poderá vir em uma atualização futura. + + + An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. + + + + + TorqueFriction + + FRICTION + + + + Adjust Friction for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueMaxLatAccel + + LAT_ACCEL_FACTOR + + + + Adjust Max Lateral Acceleration for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + Updater @@ -1206,6 +3128,168 @@ Isso pode levar até um minuto. Falha na atualização + + VehiclePanel + + Updating this setting takes effect when the car is powered off. + + + + Select your car + + + + + VisualsPanel + + Display Braking Status + + + + Enable this will turn the current speed value to red while the brake is used. + + + + Display Stand Still Timer + + + + Enable this will display time spent at a stop (i.e., at a stop lights, stop signs, traffic congestions). + + + + Display DM Camera in Reverse Gear + + + + Show Driver Monitoring camera while the car is in reverse gear. + + + + OSM: Show debug UI elements + + + + OSM: Show UI elements that aid debugging. + + + + Display Feature Status + + + + Display the statuses of certain features on the driving screen. + + + + Enable Onroad Settings + + + + Display the Onroad Settings button on the driving screen to adjust feature options on the driving screen, without navigating into the settings menu. + + + + Speedometer: Display True Speed + + + + Display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Display End-to-end Longitudinal Status (Beta) + + + + Enable this will display an icon that appears when the End-to-end model decides to start or stop. + + + + Navigation: Display in Full Screen + + + + Enable this will display the built-in navigation in full screen.<br>To switch back to driving view, <font color='yellow'>tap on the border edge</font>. + + + + Map: Display 3D Buildings + + + + Parse and display 3D buildings on map. Thanks to jakethesnake420 for this implementation. + + + + Off + + + + 5 Metrics + + + + 10 Metrics + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + + + Distance + + + + Speed + + + + Display Metrics Below Chevron + + + + Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + + + RAM + + + + CPU + + + + GPU + + + + Max + + + + Display Temperature on Sidebar + + + + Time + + + + All + + + WiFiPromptWidget @@ -1252,4 +3336,27 @@ Isso pode levar até um minuto. Esquecer + + WifiUISP + + Scanning for networks... + Procurando redes... + + + CONNECTING... + CONECTANDO... + + + FORGET + ESQUECER + + + Forget Wi-Fi Network "%1"? + Esquecer Rede Wi-Fi "%1"? + + + Forget + Esquecer + + diff --git a/selfdrive/ui/translations/main_th.ts b/selfdrive/ui/translations/main_th.ts index e594a6975f..220b6575c4 100644 --- a/selfdrive/ui/translations/main_th.ts +++ b/selfdrive/ui/translations/main_th.ts @@ -87,6 +87,89 @@ สำหรับ "%1" + + AdvancedNetworkingSP + + Back + ย้อนกลับ + + + Enable Tethering + ปล่อยฮอตสปอต + + + Retain hotspot/tethering state + + + + Enabling this toggle will retain the hotspot/tethering toggle state across reboots. + + + + Tethering Password + รหัสผ่านฮอตสปอต + + + EDIT + แก้ไข + + + Enter new tethering password + ป้อนรหัสผ่านฮอตสปอตใหม่ + + + IP Address + หมายเลขไอพี + + + Enable Roaming + เปิดใช้งานโรมมิ่ง + + + APN Setting + ตั้งค่า APN + + + Enter APN + ป้อนค่า APN + + + leave blank for automatic configuration + เว้นว่างเพื่อตั้งค่าอัตโนมัติ + + + Cellular Metered + ลดการส่งข้อมูลผ่านเซลลูล่าร์ + + + Prevent large data uploads when on a metered connection + ปิดการอัพโหลดข้อมูลขนาดใหญ่เมื่อเชื่อมต่อผ่านเซลลูล่าร์ + + + Hidden Network + เครือข่ายที่ซ่อนอยู่ + + + CONNECT + เชื่อมต่อ + + + Enter SSID + ป้อนค่า SSID + + + Enter password + ใส่รหัสผ่าน + + + for "%1" + สำหรับ "%1" + + + Ngrok Service + + + AnnotatedCameraWidget @@ -103,11 +186,119 @@ SPEED - ความเร็ว + ความเร็ว LIMIT - จำกัด + จำกัด + + + + AnnotatedCameraWidgetSP + + km/h + กม./ชม. + + + mph + ไมล์/ชม. + + + MAX + สูงสุด + + + SPEED + ความเร็ว + + + LIMIT + จำกัด + + + + AutoLaneChangeTimer + + Auto Lane Change by Blinker + + + + Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. +Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. + + + + s + + + + Off + + + + Nudge + + + + Nudgeless + + + + + BackupSettings + + Settings backed up for sunnylink Device ID: + + + + Settings updated successfully, but no additional data was returned by the server. + + + + OOPS! We made a booboo. + + + + Please try again later. + + + + Settings restored. Confirm to restart the interface. + + + + No settings found to restore. + + + + + BrightnessControl + + Brightness + + + + Manually adjusts the global brightness of the screen. + + + + Auto + + + + + CameraOffset + + Camera Offset - Laneful Only + + + + Hack to trick vehicle to be left or right biased in its lane. Decreasing the value will make the car keep more left, increasing will make it keep more right. Changes take effect immediately. Default: +4 cm + + + + cm + @@ -121,11 +312,18 @@ ยกเลิก + + CustomOffsetsSettings + + Back + ย้อนกลับ + + DeclinePage You must accept the Terms and Conditions in order to use openpilot. - คุณต้องยอมรับเงื่อนไขและข้อตกลง เพื่อใช้งาน openpilot + คุณต้องยอมรับเงื่อนไขและข้อตกลง เพื่อใช้งาน openpilot Back @@ -135,6 +333,10 @@ Decline, uninstall %1 ปฏิเสธ และถอนการติดตั้ง %1 + + You must accept the Terms and Conditions in order to use sunnypilot. + + DestinationWidget @@ -247,7 +449,7 @@ openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required. - openpilot กำหนดให้ติดตั้งอุปกรณ์ โดยสามารถเอียงด้านซ้ายหรือขวาไม่เกิน 4° และเอียงขึ้นด้านบนไม่เกิน 5° หรือเอียงลงด้านล่างไม่เกิน 9° openpilot ทำการคาลิเบรทอย่างต่อเนื่อง แทบจะไม่จำเป็นต้องทำการรีเซ็ตการคาลิเบรท + openpilot กำหนดให้ติดตั้งอุปกรณ์ โดยสามารถเอียงด้านซ้ายหรือขวาไม่เกิน 4° และเอียงขึ้นด้านบนไม่เกิน 5° หรือเอียงลงด้านล่างไม่เกิน 9° openpilot ทำการคาลิเบรทอย่างต่อเนื่อง แทบจะไม่จำเป็นต้องทำการรีเซ็ตการคาลิเบรท Your device is pointed %1° %2 and %3° %4. @@ -305,6 +507,155 @@ PAIR จับคู่ + + sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. sunnypilot is continuously calibrating, resetting is rarely required. + + + + + DevicePanelSP + + TOGGLE + + + + Enable or disable PIN requirement for Fleet Manager access. + + + + Are you sure you want to turn off PIN requirement? + + + + Turn Off + + + + Error Troubleshoot + + + + VIEW + ดู + + + Display error from the tmux session when an error has occurred from a system process. + + + + Reset Access Tokens for Map Services + + + + RESET + รีเซ็ต + + + Reset self-service access tokens for Mapbox, Amap, and Google Maps. + + + + Are you sure you want to reset access tokens for all map services? + + + + Reset + รีเซ็ต + + + Reset sunnypilot Settings + + + + Are you sure you want to reset all sunnypilot settings? + + + + Toggle Onroad/Offroad + + + + OFF + + + + Are you sure you want to unforce offroad? + + + + Unforce + + + + Are you sure you want to force offroad? + + + + Force + + + + Disengage to Force Offroad + + + + Unforce Offroad + + + + Force Offroad + + + + Fleet Manager PIN: + + + + + DisplayPanel + + Driving Screen Off: Non-Critical Events + + + + When <b>Driving Screen Off Timer</b> is not set to <b>"Always On"</b>: + + + + Enabled: Wake the brightness of the screen to display all events. + + + + Disabled: Wake the brightness of the screen to display critical events. + + + + + DriveStats + + Drives + + + + Hours + + + + ALL TIME + + + + PAST WEEK + + + + KM + + + + Miles + + DriverViewWindow @@ -344,6 +695,79 @@ กำลังติดตั้ง... + + LaneChangeSettings + + Back + ย้อนกลับ + + + Pause Lateral Below Speed with Blinker + + + + Enable this toggle to pause lateral actuation with blinker when traveling below the desired speed selected below. + + + + Auto Lane Change: Delay with Blind Spot + + + + Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. + + + + Block Lane Change: Road Edge Detection + + + + Enable this toggle to block lane change when road edge is detected on the stalk actuated side. + + + + + MadsSettings + + Enable ACC+MADS with RES+/SET- + + + + Engage both M.A.D.S. and ACC with a single press of RES+ or SET- button. + + + + Note: Once M.A.D.S. is engaged via this mode, it will remain engaged until it is manually disabled via the M.A.D.S. button or car shut off. + + + + Toggle M.A.D.S. with Cruise Main + + + + Allows M.A.D.S. engagement/disengagement with "Cruise Main" cruise control button from the steering wheel. + + + + Remain Active + + + + Pause Steering + + + + Steering Mode After Braking + + + + Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. + +Remain Active: ALC will remain active even after the brake pedal is pressed. +Pause Steering: ALC will be paused after the brake pedal is manually pressed. + + + MapETA @@ -385,6 +809,63 @@ กำลังรอเส้นทาง + + MapWindowSP + + Map Loading + กำลังโหลดแผนที่ + + + Waiting for GPS + กำลังรอสัญญาณ GPS + + + Waiting for route + กำลังรอเส้นทาง + + + + MaxTimeOffroad + + Max Time Offroad + + + + Device is automatically turned off after a set time when the engine is turned off (off-road) after driving (on-road). + + + + s + + + + m + ม. + + + hr + ชม. + + + Always On + + + + Immediate + + + + + MonitoringPanel + + Enable Hands on Wheel Monitoring + + + + Monitor and alert when driver is not keeping the hands on the steering wheel. + + + MultiOptionDialog @@ -415,6 +896,33 @@ รหัสผ่านผิด + + NetworkingSP + + Scan + + + + Scanning... + + + + Advanced + ขั้นสูง + + + Enter password + ใส่รหัสผ่าน + + + for "%1" + สำหรับ "%1" + + + Wrong password + รหัสผ่านผิด + + OffroadAlert @@ -467,6 +975,16 @@ openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. openpilot ตรวจพบการเปลี่ยนแปลงของตำแหน่งที่ติดตั้ง กรุณาตรวจสอบว่าได้เลื่อนอุปกรณ์เข้ากับจุดติดตั้งจนสุดแล้ว และจุดติดตั้งได้ยึดติดกับกระจกหน้าอย่างแน่นหนา + + OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. + +%1 + + + + sunnypilot is now in Forced Offroad mode. sunnypilot won't start until Forced Offroad mode is disabled. Go to "Settings" -> "Device" -> "Unforce Offroad" to exit Force Offroad mode. + + OffroadHome @@ -506,6 +1024,186 @@ รีบูตอุปกรณ์ + + OnroadScreenOff + + Driving Screen Off Timer + + + + Turn off the device screen or reduce brightness to protect the screen after driving starts. It automatically brightens or turns on when a touch or event occurs. + + + + s + + + + min + นาที + + + Always On + + + + + OnroadScreenOffBrightness + + Driving Screen Off Brightness (%) + + + + When using the Driving Screen Off feature, the brightness is reduced according to the automatic brightness ratio. + + + + Dark + + + + + OnroadSettings + + ONROAD OPTIONS + + + + <b>ONROAD SETTINGS | SUNNYPILOT</b> + + + + + OsmPanel + + Mapd Version + + + + Offline Maps ETA + + + + Time Elapsed + + + + Downloaded Maps + + + + DELETE + + + + This will delete ALL downloaded maps + +Are you sure you want to delete all the maps? + + + + Yes, delete all the maps. + + + + Database Update + + + + CHECK + ตรวจสอบ + + + Country + + + + SELECT + เลือก + + + Fetching Country list... + + + + State + + + + Fetching State list... + + + + All + + + + REFRESH + + + + UPDATE + อัปเดต + + + Download starting... + + + + Error: Invalid download. Retry. + + + + Download complete! + + + + + +Warning: You are on a metered connection! + + + + This will start the download process and it might take a while to complete. + + + + Continue on Metered + + + + Start Download + + + + m + + + + s + + + + Calculating... + + + + Downloaded + + + + Calculating ETA... + + + + Ready + + + + Time remaining: + + + PairingPopup @@ -536,6 +1234,51 @@ ยกเลิก + + ParamControlSP + + Enable + เปิดใช้งาน + + + Cancel + ยกเลิก + + + + PathOffset + + Path Offset + + + + Hack to trick the model path to be left or right biased of the lane. Decreasing the value will shift the model more left, increasing will shift the model more right. Changes take effect immediately. + + + + cm + + + + + PauseLateralSpeed + + Pause lateral actuation with blinker when traveling below the desired speed selected. Default is 20 MPH or 32 km/h. + + + + Default + + + + km/h + กม./ชม. + + + mph + ไมล์/ชม. + + PrimeAdWidget @@ -590,7 +1333,7 @@ openpilot - openpilot + openpilot %n minute(s) ago @@ -630,6 +1373,30 @@ now ตอนนี้ + + sunnypilot + + + + Update downloaded. Ready to reboot. + + + + Update: Check and Download Update + + + + Reboot: Reboot Device + + + + Update + + + + Updating... + + Reset @@ -672,6 +1439,131 @@ This may take up to a minute. ระบบถูกรีเซ็ต กดยืนยันเพื่อลบข้อมูลและการตั้งค่าทั้งหมด กดยกเลิกเพื่อบูตต่อ + + SPVehiclesTogglesPanel + + Hyundai/Kia/Genesis + + + + HKG CAN: Smoother Stopping Performance (Beta) + + + + Smoother stopping behind a stopped car or desired stopping event. This is only applicable to HKG CAN platforms using openpilot longitudinal control. + + + + Subaru + + + + Manual Parking Brake: Stop and Go (Beta) + + + + Experimental feature to enable stop and go for Subaru Global models with manual handbrake. Models with electric parking brake should keep this disabled. Thanks to martinl for this implementation! + + + + Toyota/Lexus + + + + Enable Stock Toyota Longitudinal Control + + + + sunnypilot will <b>not</b> take over control of gas and brakes. Stock Toyota longitudinal control will be used. + + + + Allow M.A.D.S. toggling w/ LKAS Button (Beta) + + + + Allows M.A.D.S. engagement/disengagement with "LKAS" button from the steering wheel. + + + + Note: Enabling this toggle may have unexpected behavior with steering control. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Toyota TSS2 Longitudinal: Custom Tuning + + + + Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + + + Enable Enhanced Blind Spot Monitor + + + + Enable Toyota Stop and Go Hack + + + + sunnypilot will allow some Toyota/Lexus cars to auto resume during stop and go traffic. This feature is only applicable to certain models. Use at your own risk. + + + + Enable Toyota Door Auto Locking + + + + sunnypilot will attempt to lock the doors when drive above 10 km/h (6.2 mph). +Reboot Required. + + + + Enable Toyota Door Auto Unlocking + + + + sunnypilot will attempt to unlock the doors when shift to gear P. +Reboot Required. + + + + Volkswagen + + + + Enable CC Only support + + + + sunnypilot supports Volkswagen MQB CC only platforms with this toggle enabled. Only enable this toggle if your car does not have ACC from the factory. + + + + Start the car to check car compatibility + + + + This platform is already supported, therefore no need to enable this toggle + + + + This platform is not supported + + + + This platform can be supported + + + + sunnypilot will use debugging CAN messages to receive unfiltered BSM signals, allowing detection of more objects. + + + + Tested on RAV4 TSS1, Lexus LSS1, Toyota TSS1/1.5, and Prius TSS2. + + + SettingsWindow @@ -695,6 +1587,61 @@ This may take up to a minute. ซอฟต์แวร์ + + SettingsWindowSP + + × + × + + + Device + อุปกรณ์ + + + Network + เครือข่าย + + + sunnylink + + + + Toggles + ตัวเลือก + + + Software + ซอฟต์แวร์ + + + sunnypilot + + + + OSM + + + + Monitoring + + + + Visuals + + + + Display + + + + Trips + + + + Vehicle + + + Setup @@ -888,6 +1835,100 @@ This may take up to a minute. 5G + + SidebarSP + + TEMP + อุณหภูมิ + + + HIGH + สูง + + + GOOD + ดี + + + OK + พอใช้ + + + DISABLED + + + + OFFLINE + ออฟไลน์ + + + REGIST... + + + + ONLINE + ออนไลน์ + + + ERROR + เกิดข้อผิดพลาด + + + SUNNYLINK + + + + + SlcSettings + + Auto + + + + User Confirm + + + + Engage Mode + + + + Default + + + + Fixed + + + + Percentage + + + + Limit Offset + + + + Set speed limit slightly higher than actual speed limit for a more natural drive. + + + + This platform defaults to <b>Auto</b> mode. <b>User Confirm</b> mode is not supported on this platform. + + + + Select the desired mode to set the cruising speed to the speed limit: + + + + Auto: Automatic speed adjustment on motorways based on speed limit data. + + + + User Confirm: Inform the driver to change set speed of Adaptive Cruise Control to help the driver stay within the speed limit. + + + SoftwarePanel @@ -963,6 +2004,233 @@ This may take up to a minute. ล่าสุดแล้ว ตรวจสอบครั้งสุดท้ายเมื่อ %1 + + SoftwarePanelSP + + Driving Model + + + + SELECT + เลือก + + + PENDING + + + + Downloading Driving model + + + + (CACHED) + + + + Driving model + + + + downloaded + + + + Downloading Navigation model + + + + Navigation model + + + + Downloading Metadata model + + + + Metadata model + + + + Downloads have failed, please try swapping the model! + + + + Failed: + + + + Fetching models... + + + + Select a Driving Model + + + + Download has started in the background. + + + + We STRONGLY suggest you to reset calibration. Would you like to do that now? + + + + Reset Calibration + รีเซ็ตการคาลิเบรท + + + Warning: You are on a metered connection! + + + + Continue + ดำเนินการต่อ + + + on Metered + + + + + SpeedLimitPolicySettings + + Speed Limit Source Policy + + + + Nav + + + + Only + + + + Map + + + + Car + + + + First + + + + Select the precedence order of sources. Utilized by Speed Limit Control and Speed Limit Warning + + + + Nav Only: Data from Mapbox active navigation only. + + + + Map Only: Data from OpenStreetMap only. + + + + Car Only: Data from the car's built-in sources (if available). + + + + Nav First: Nav -> Map -> Car + + + + Map First: Map -> Nav -> Car + + + + Car First: Car -> Nav -> Map + + + + + SpeedLimitValueOffset + + km/h + กม./ชม. + + + mph + ไมล์/ชม. + + + + SpeedLimitWarningSettings + + Off + + + + Display + + + + Chime + + + + Speed Limit Warning + + + + Warning with speed limit flash + + + + When Speed Limit Warning is enabled, the speed limit sign will alert the driver when the cruising speed is faster than then speed limit plus the offset. + + + + Default + + + + Fixed + + + + Percentage + + + + Warning Offset + + + + Select the desired offset to warn the driver when the vehicle is driving faster than the speed limit. + + + + Off: When the cruising speed is faster than the speed limit plus the offset, there will be no warning. + + + + Display: The speed on the speed limit sign turns red to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + Chime: The speed on the speed limit sign turns red and chimes to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + + SpeedLimitWarningValueOffset + + N/A + ไม่มี + + + km/h + กม./ชม. + + + mph + ไมล์/ชม. + + SshControl @@ -1009,6 +2277,399 @@ This may take up to a minute. เปิดใช้งาน SSH + + SunnylinkPanel + + Enable sunnylink + + + + Device ID + + + + N/A + ไม่มี + + + This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. + + + + 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 + + + + 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. + + + + Sponsor Status + + + + SPONSOR + + + + Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. + + + + Pair GitHub Account + + + + PAIR + จับคู่ + + + Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. + + + + sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. + + + + Manage Settings + + + + Backup Settings + + + + Are you sure you want to backup sunnypilot settings? + + + + Back Up + + + + Restore Settings + + + + Are you sure you want to restore the last backed up sunnypilot settings? + + + + Restore + + + + THANKS + + + + Not Sponsor + + + + Paired + + + + Not Paired + + + + Backing up... + + + + Restoring... + + + + + SunnylinkSponsorPopup + + Scan the QR code to login to your GitHub account + + + + Follow the prompts to complete the pairing process + + + + Re-enter the "sunnylink" panel to verify sponsorship status + + + + If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot + + + + Scan the QR code to visit sunnyhaibin's GitHub Sponsors page + + + + Choose your sponsorship tier and confirm your support + + + + Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status + + + + Pair your GitHub account + + + + Early Access: Become a sunnypilot Sponsor + + + + + SunnypilotPanel + + Enable M.A.D.S. + + + + Enable the beloved M.A.D.S. feature. Disable toggle to revert back to stock openpilot engagement/disengagement. + + + + Laneless for Curves in "Auto" Mode + + + + While in Auto Lane, switch to Laneless for current/future curves. + + + + Speed Limit Control (SLC) + + + + When you engage ACC, you will be prompted to set the cruising speed to the speed limit of the road adjusted by the Offset and Source Policy specified, or the current driving speed. The maximum cruising speed will always be the MAX set speed. + + + + Enable Vision-based Turn Speed Control (V-TSC) + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Enable Map Data Turn Speed Control (M-TSC) (Beta) + + + + Use curvature information from map data to define speed limits to take turns ahead. + + + + ACC +/-: Long Press Reverse + + + + Change the ACC +/- buttons behavior with cruise speed change in sunnypilot. + + + + Disabled (Stock): Short=1, Long = 5 (imperial) / 10 (metric) + + + + Enabled: Short = 5 (imperial) / 10 (metric), Long=1 + + + + Custom Offsets + + + + Neural Network Lateral Control (NNLC) + + + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Enable Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying FRICTION and LAT_ACCEL_FACTOR below will override the offline values indicated in the YAML files within "selfdrive/torque_data". The values will also be used live when "Override Self-Tune" toggle is enabled. + + + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Quiet Drive 🤫 + + + + sunnypilot will display alerts but only play the most important warning sounds. This feature can be toggled while the car is on. + + + + Green Traffic Light Chime (Beta) + + + + A chime will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. If you are waiting behind another vehicle, the chime will play once the vehicle advances unless ACC is engaged. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Vehicle Departure Alert + + + + Enable this will notify when the leading vehicle drives away. + + + + Customize M.A.D.S. + + + + Customize Lane Change + + + + Customize Offsets + + + + Customize Speed Limit Control + + + + Customize Warning + + + + Customize Source + + + + Laneful + + + + Laneless + + + + Auto + + + + Dynamic Lane Profile + + + + Speed Limit Assist + + + + Real-time and Offline + + + + Offline Only + + + + Dynamic Lane Profile is not available with the current Driving Model + + + + Custom Offsets is not available with the current Driving Model + + + + NNLC is currently not available on this platform. + + + + Match: "Exact" is ideal, but "Fuzzy" is fine too. Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server if there are any issues: + + + + Start the car to check car compatibility + + + + NNLC Not Loaded + + + + NNLC Loaded + + + + Fuzzy + + + + Exact + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server and donate logs to get NNLC loaded for your car: + + + + Match + + + + Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server with feedback, or to provide log data for your car if your car is currently unsupported: + + + + Add custom offsets to Camera and Path in sunnypilot. + + + + Default is Laneless. In Auto mode, sunnnypilot dynamically chooses between Laneline or Laneless model based on lane recognition confidence level on road and certain conditions. + + + TermsPage @@ -1028,15 +2689,30 @@ This may take up to a minute. ยอมรับ + + TermsPageSP + + Terms & Conditions + ข้อตกลงและเงื่อนไข + + + Decline + ปฏิเสธ + + + Scroll to accept + เลื่อนเพื่อตอบรับข้อตกลง + + TogglesPanel Enable openpilot - เปิดใช้งาน openpilot + เปิดใช้งาน openpilot Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. - ใช้ระบบ openpilot สำหรับระบบควบคุมความเร็วอัตโนมัติ และระบบช่วยควบคุมรถให้อยู่ในเลน คุณจำเป็นต้องให้ความสนใจตลอดเวลาที่ใช้คุณสมบัตินี้ การเปลี่ยนการตั้งค่านี้จะมีผลเมื่อคุณดับเครื่องยนต์ + ใช้ระบบ openpilot สำหรับระบบควบคุมความเร็วอัตโนมัติ และระบบช่วยควบคุมรถให้อยู่ในเลน คุณจำเป็นต้องให้ความสนใจตลอดเวลาที่ใช้คุณสมบัตินี้ การเปลี่ยนการตั้งค่านี้จะมีผลเมื่อคุณดับเครื่องยนต์ Enable Lane Departure Warnings @@ -1072,19 +2748,19 @@ This may take up to a minute. Show ETA in 24h Format - แสดงเวลา ETA ในรูปแบบ 24 ชั่วโมง + แสดงเวลา ETA ในรูปแบบ 24 ชั่วโมง Use 24h format instead of am/pm - ใช้รูปแบบเวลา 24 ชั่วโมง แทน am/pm + ใช้รูปแบบเวลา 24 ชั่วโมง แทน am/pm Show Map on Left Side of UI - แสดงแผนที่ที่ด้านซ้ายของหน้าจอ + แสดงแผนที่ที่ด้านซ้ายของหน้าจอ Show map on left side when in split screen view. - แสดงแผนที่ด้านซ้ายของหน้าจอเมื่ออยู่ในโหมดแบ่งหน้าจอ + แสดงแผนที่ด้านซ้ายของหน้าจอเมื่ออยู่ในโหมดแบ่งหน้าจอ Experimental Mode @@ -1166,6 +2842,252 @@ This may take up to a minute. Enable driver monitoring even when openpilot is not engaged. + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + + TogglesPanelSP + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + openpilot Longitudinal Control (Alpha) + ระบบควบคุมการเร่ง/เบรคโดย openpilot (Alpha) + + + WARNING: sunnypilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + + + + On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to sunnypilot longitudinal control. Enabling Experimental mode is recommended when enabling sunnypilot longitudinal control alpha. + + + + Custom Stock Longitudinal Control + + + + When enabled, sunnypilot will attempt to control stock longitudinal control with ACC button presses. +This feature must be used along with SLC, and/or V-TSC, and/or M-TSC. + + + + Experimental Mode + โหมดทดลอง + + + Enable Dynamic Experimental Control + + + + Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. + + + + Enable Dynamic Personality + + + + Enable this to allow sunnypilot to dynamically adjust following distance and reaction based on your "Driving Personality" setting. Instead of predefined settings for each personality, every personality now adapts dynamically according to your speed and the distance to the lead car. + + + + Disengage on Accelerator Pedal + ยกเลิกระบบช่วยขับเมื่อเหยียบคันเร่ง + + + When enabled, pressing the accelerator pedal will disengage openpilot. + เมื่อเปิดใช้งาน การกดแป้นคันเร่งจะเป็นการยกเลิกระบบช่วยขับโดย openpilot + + + Enable Lane Departure Warnings + เปิดใช้งานการเตือนการออกนอกเลน + + + Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). + รับการแจ้งเตือนให้เลี้ยวกลับเข้าเลนเมื่อรถของคุณตรวจพบการข้ามช่องจราจรโดยไม่เปิดสัญญาณไฟเลี้ยวในขณะขับขี่ที่ความเร็วเกิน 31 ไมล์ต่อชั่วโมง (50 กม./ชม) + + + Always-On Driver Monitoring + + + + Enable driver monitoring even when sunnypilot is not engaged. + + + + Record and Upload Driver Camera + บันทึกและอัปโหลดภาพจากกล้องคนขับ + + + Upload data from the driver facing camera and help improve the driver monitoring algorithm. + อัปโหลดข้อมูลจากกล้องที่หันหน้าไปทางคนขับ และช่วยปรับปรุงอัลกอริธึมการตรวจสอบผู้ขับขี่ + + + Disable Onroad Uploads + + + + Disable uploads completely when onroad. Necessary to avoid high data usage when connected to Wi-Fi hotspot. Turn on this feature if you are looking to utilize map-based features, such as Speed Limit Control (SLC) and Map-based Turn Speed Control (MTSC). + + + + Use Metric System + ใช้ระบบเมตริก + + + Display speed in km/h instead of mph. + แสดงความเร็วเป็น กม./ชม. แทน ไมล์/ชั่วโมง + + + Show ETA in 24h Format + แสดงเวลา ETA ในรูปแบบ 24 ชั่วโมง + + + Use 24h format instead of am/pm + ใช้รูปแบบเวลา 24 ชั่วโมง แทน am/pm + + + Show Map on Left Side of UI + แสดงแผนที่ที่ด้านซ้ายของหน้าจอ + + + Show map on left side when in split screen view. + แสดงแผนที่ด้านซ้ายของหน้าจอเมื่ออยู่ในโหมดแบ่งหน้าจอ + + + Aggressive + ดุดัน + + + Moderate + + + + Standard + มาตรฐาน + + + Relaxed + ผ่อนคลาย + + + Driving Personality + บุคลิกการขับขี่ + + + Standard is recommended. In moderate/aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + + + + Sport + + + + Normal + + + + Eco + + + + Stock + + + + Acceleration Personality + + + + Normal is recommended. In sport mode, sunnypilot will provide aggressive acceleration for a dynamic driving experience. In eco mode, sunnypilot will apply smoother and more relaxed acceleration. On supported cars, you can cycle through these acceleration personality within Onroad Settings on the driving screen. + + + + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + โดยปกติ openpilot จะขับใน<b>โหมดชิล</b> เปิดโหมดทดลองเพื่อใช้<b>ความสามารถในขั้นพัฒนา</b> ซึ่งยังไม่พร้อมสำหรับโหมดชิล ความสามารถในขั้นพัฒนามีดังนี้: + + + End-to-End Longitudinal Control + ควบคุมเร่ง/เบรคแบบ End-to-End + + + Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + + + + New Driving Visualization + การแสดงภาพการขับขี่แบบใหม่ + + + The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. + การแสดงภาพการขับขี่จะเปลี่ยนไปใช้กล้องมุมกว้างที่หันหน้าไปทางถนนเมื่ออยู่ในความเร็วต่ำ เพื่อแสดงภาพการเลี้ยวที่ดีขึ้น โลโก้โหมดการทดลองจะแสดงที่มุมบนขวาด้วย + + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + ขณะนี้โหมดทดลองไม่สามารถใช้งานได้ในรถคันนี้ เนื่องจากเปิดใช้ระบบควบคุมการเร่ง/เบรคของรถที่ติดตั้งจากโรงงานอยู่ + + + openpilot longitudinal control may come in a future update. + ระบบควบคุมการเร่ง/เบรคโดย openpilot อาจมาในการอัปเดตในอนาคต + + + An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. + + + + + TorqueFriction + + FRICTION + + + + Adjust Friction for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueMaxLatAccel + + LAT_ACCEL_FACTOR + + + + Adjust Max Lateral Acceleration for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + Updater @@ -1202,6 +3124,168 @@ This may take up to a minute. การอัปเดตล้มเหลว + + VehiclePanel + + Updating this setting takes effect when the car is powered off. + + + + Select your car + + + + + VisualsPanel + + Display Braking Status + + + + Enable this will turn the current speed value to red while the brake is used. + + + + Display Stand Still Timer + + + + Enable this will display time spent at a stop (i.e., at a stop lights, stop signs, traffic congestions). + + + + Display DM Camera in Reverse Gear + + + + Show Driver Monitoring camera while the car is in reverse gear. + + + + OSM: Show debug UI elements + + + + OSM: Show UI elements that aid debugging. + + + + Display Feature Status + + + + Display the statuses of certain features on the driving screen. + + + + Enable Onroad Settings + + + + Display the Onroad Settings button on the driving screen to adjust feature options on the driving screen, without navigating into the settings menu. + + + + Speedometer: Display True Speed + + + + Display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Display End-to-end Longitudinal Status (Beta) + + + + Enable this will display an icon that appears when the End-to-end model decides to start or stop. + + + + Navigation: Display in Full Screen + + + + Enable this will display the built-in navigation in full screen.<br>To switch back to driving view, <font color='yellow'>tap on the border edge</font>. + + + + Map: Display 3D Buildings + + + + Parse and display 3D buildings on map. Thanks to jakethesnake420 for this implementation. + + + + Off + + + + 5 Metrics + + + + 10 Metrics + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + + + Distance + + + + Speed + + + + Display Metrics Below Chevron + + + + Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + + + RAM + + + + CPU + + + + GPU + + + + Max + + + + Display Temperature on Sidebar + + + + Time + + + + All + + + WiFiPromptWidget @@ -1248,4 +3332,27 @@ This may take up to a minute. เลิกใช้ + + WifiUISP + + Scanning for networks... + กำลังสแกนหาเครือข่าย... + + + CONNECTING... + กำลังเชื่อมต่อ... + + + FORGET + เลิกใช้ + + + Forget Wi-Fi Network "%1"? + เลิกใช้เครือข่าย Wi-Fi "%1"? + + + Forget + เลิกใช้ + + diff --git a/selfdrive/ui/translations/main_tr.ts b/selfdrive/ui/translations/main_tr.ts index 48615f1699..a8c3992fd2 100644 --- a/selfdrive/ui/translations/main_tr.ts +++ b/selfdrive/ui/translations/main_tr.ts @@ -87,6 +87,89 @@ için "%1" + + AdvancedNetworkingSP + + Back + + + + Enable Tethering + Kişisel erişim noktasını aç + + + Retain hotspot/tethering state + + + + Enabling this toggle will retain the hotspot/tethering toggle state across reboots. + + + + Tethering Password + Kişisel erişim noktasının parolası + + + EDIT + DÜZENLE + + + Enter new tethering password + Erişim noktasına yeni bir sonraki başlatılışında çekilir. parola belirleyin. + + + IP Address + IP Adresi + + + Enable Roaming + Hücresel veri aç + + + APN Setting + APN Ayarları + + + Enter APN + APN Gir + + + leave blank for automatic configuration + otomatik yapılandırma için boş bırakın + + + Cellular Metered + + + + Prevent large data uploads when on a metered connection + + + + Hidden Network + + + + CONNECT + BAĞLANTI + + + Enter SSID + APN Gir + + + Enter password + Parolayı girin + + + for "%1" + için "%1" + + + Ngrok Service + + + AnnotatedCameraWidget @@ -101,6 +184,29 @@ MAX MAX + + SPEED + HIZ + + + LIMIT + LİMİT + + + + AnnotatedCameraWidgetSP + + km/h + km/h + + + mph + mph + + + MAX + MAX + SPEED HIZ @@ -110,6 +216,91 @@ LİMİT + + AutoLaneChangeTimer + + Auto Lane Change by Blinker + + + + Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. +Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. + + + + s + + + + Off + + + + Nudge + + + + Nudgeless + + + + + BackupSettings + + Settings backed up for sunnylink Device ID: + + + + Settings updated successfully, but no additional data was returned by the server. + + + + OOPS! We made a booboo. + + + + Please try again later. + + + + Settings restored. Confirm to restart the interface. + + + + No settings found to restore. + + + + + BrightnessControl + + Brightness + + + + Manually adjusts the global brightness of the screen. + + + + Auto + + + + + CameraOffset + + Camera Offset - Laneful Only + + + + Hack to trick vehicle to be left or right biased in its lane. Decreasing the value will make the car keep more left, increasing will make it keep more right. Changes take effect immediately. Default: +4 cm + + + + cm + + + ConfirmationDialog @@ -121,11 +312,18 @@ Vazgeç + + CustomOffsetsSettings + + Back + + + DeclinePage You must accept the Terms and Conditions in order to use openpilot. - Openpilotu kullanmak için Kullanıcı Koşullarını kabul etmelisiniz. + Openpilotu kullanmak için Kullanıcı Koşullarını kabul etmelisiniz. Back @@ -135,6 +333,10 @@ Decline, uninstall %1 Reddet, Kurulumu kaldır. %1 + + You must accept the Terms and Conditions in order to use sunnypilot. + + DestinationWidget @@ -247,7 +449,7 @@ openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required. - openpilot, cihazın 4° sola veya 5° yukarı yada 9° aşağı bakıcak şekilde monte edilmesi gerekmektedir. openpilot sürekli kendisini kalibre edilmektedir ve nadiren sıfırlama gerebilir. + openpilot, cihazın 4° sola veya 5° yukarı yada 9° aşağı bakıcak şekilde monte edilmesi gerekmektedir. openpilot sürekli kendisini kalibre edilmektedir ve nadiren sıfırlama gerebilir. Your device is pointed %1° %2 and %3° %4. @@ -305,6 +507,155 @@ PAIR + + sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. sunnypilot is continuously calibrating, resetting is rarely required. + + + + + DevicePanelSP + + TOGGLE + + + + Enable or disable PIN requirement for Fleet Manager access. + + + + Are you sure you want to turn off PIN requirement? + + + + Turn Off + + + + Error Troubleshoot + + + + VIEW + BAK + + + Display error from the tmux session when an error has occurred from a system process. + + + + Reset Access Tokens for Map Services + + + + RESET + SIFIRLA + + + Reset self-service access tokens for Mapbox, Amap, and Google Maps. + + + + Are you sure you want to reset access tokens for all map services? + + + + Reset + + + + Reset sunnypilot Settings + + + + Are you sure you want to reset all sunnypilot settings? + + + + Toggle Onroad/Offroad + + + + OFF + + + + Are you sure you want to unforce offroad? + + + + Unforce + + + + Are you sure you want to force offroad? + + + + Force + + + + Disengage to Force Offroad + + + + Unforce Offroad + + + + Force Offroad + + + + Fleet Manager PIN: + + + + + DisplayPanel + + Driving Screen Off: Non-Critical Events + + + + When <b>Driving Screen Off Timer</b> is not set to <b>"Always On"</b>: + + + + Enabled: Wake the brightness of the screen to display all events. + + + + Disabled: Wake the brightness of the screen to display critical events. + + + + + DriveStats + + Drives + + + + Hours + + + + ALL TIME + + + + PAST WEEK + + + + KM + + + + Miles + + DriverViewWindow @@ -344,6 +695,79 @@ Yükleniyor... + + LaneChangeSettings + + Back + + + + Pause Lateral Below Speed with Blinker + + + + Enable this toggle to pause lateral actuation with blinker when traveling below the desired speed selected below. + + + + Auto Lane Change: Delay with Blind Spot + + + + Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. + + + + Block Lane Change: Road Edge Detection + + + + Enable this toggle to block lane change when road edge is detected on the stalk actuated side. + + + + + MadsSettings + + Enable ACC+MADS with RES+/SET- + + + + Engage both M.A.D.S. and ACC with a single press of RES+ or SET- button. + + + + Note: Once M.A.D.S. is engaged via this mode, it will remain engaged until it is manually disabled via the M.A.D.S. button or car shut off. + + + + Toggle M.A.D.S. with Cruise Main + + + + Allows M.A.D.S. engagement/disengagement with "Cruise Main" cruise control button from the steering wheel. + + + + Remain Active + + + + Pause Steering + + + + Steering Mode After Braking + + + + Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. + +Remain Active: ALC will remain active even after the brake pedal is pressed. +Pause Steering: ALC will be paused after the brake pedal is manually pressed. + + + MapETA @@ -385,6 +809,63 @@ + + MapWindowSP + + Map Loading + Harita yükleniyor + + + Waiting for GPS + GPS verisi bekleniyor... + + + Waiting for route + + + + + MaxTimeOffroad + + Max Time Offroad + + + + Device is automatically turned off after a set time when the engine is turned off (off-road) after driving (on-road). + + + + s + + + + m + m + + + hr + saat + + + Always On + + + + Immediate + + + + + MonitoringPanel + + Enable Hands on Wheel Monitoring + + + + Monitor and alert when driver is not keeping the hands on the steering wheel. + + + MultiOptionDialog @@ -415,6 +896,33 @@ Yalnış parola + + NetworkingSP + + Scan + + + + Scanning... + + + + Advanced + Gelişmiş Seçenekler + + + Enter password + Parolayı girin + + + for "%1" + için "%1" + + + Wrong password + Yalnış parola + + OffroadAlert @@ -466,6 +974,16 @@ openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. + + OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. + +%1 + + + + sunnypilot is now in Forced Offroad mode. sunnypilot won't start until Forced Offroad mode is disabled. Go to "Settings" -> "Device" -> "Unforce Offroad" to exit Force Offroad mode. + + OffroadHome @@ -505,6 +1023,186 @@ + + OnroadScreenOff + + Driving Screen Off Timer + + + + Turn off the device screen or reduce brightness to protect the screen after driving starts. It automatically brightens or turns on when a touch or event occurs. + + + + s + + + + min + dk + + + Always On + + + + + OnroadScreenOffBrightness + + Driving Screen Off Brightness (%) + + + + When using the Driving Screen Off feature, the brightness is reduced according to the automatic brightness ratio. + + + + Dark + + + + + OnroadSettings + + ONROAD OPTIONS + + + + <b>ONROAD SETTINGS | SUNNYPILOT</b> + + + + + OsmPanel + + Mapd Version + + + + Offline Maps ETA + + + + Time Elapsed + + + + Downloaded Maps + + + + DELETE + + + + This will delete ALL downloaded maps + +Are you sure you want to delete all the maps? + + + + Yes, delete all the maps. + + + + Database Update + + + + CHECK + KONTROL ET + + + Country + + + + SELECT + + + + Fetching Country list... + + + + State + + + + Fetching State list... + + + + All + + + + REFRESH + + + + UPDATE + GÜNCELLE + + + Download starting... + + + + Error: Invalid download. Retry. + + + + Download complete! + + + + + +Warning: You are on a metered connection! + + + + This will start the download process and it might take a while to complete. + + + + Continue on Metered + + + + Start Download + + + + m + + + + s + + + + Calculating... + + + + Downloaded + + + + Calculating ETA... + + + + Ready + + + + Time remaining: + + + PairingPopup @@ -535,6 +1233,51 @@ + + ParamControlSP + + Enable + + + + Cancel + + + + + PathOffset + + Path Offset + + + + Hack to trick the model path to be left or right biased of the lane. Decreasing the value will shift the model more left, increasing will shift the model more right. Changes take effect immediately. + + + + cm + + + + + PauseLateralSpeed + + Pause lateral actuation with blinker when traveling below the desired speed selected. Default is 20 MPH or 32 km/h. + + + + Default + + + + km/h + km/h + + + mph + mph + + PrimeAdWidget @@ -589,7 +1332,7 @@ openpilot - openpilot + openpilot %n minute(s) ago @@ -629,6 +1372,30 @@ now + + sunnypilot + + + + Update downloaded. Ready to reboot. + + + + Update: Check and Download Update + + + + Reboot: Reboot Device + + + + Update + + + + Updating... + + Reset @@ -670,6 +1437,131 @@ This may take up to a minute. + + SPVehiclesTogglesPanel + + Hyundai/Kia/Genesis + + + + HKG CAN: Smoother Stopping Performance (Beta) + + + + Smoother stopping behind a stopped car or desired stopping event. This is only applicable to HKG CAN platforms using openpilot longitudinal control. + + + + Subaru + + + + Manual Parking Brake: Stop and Go (Beta) + + + + Experimental feature to enable stop and go for Subaru Global models with manual handbrake. Models with electric parking brake should keep this disabled. Thanks to martinl for this implementation! + + + + Toyota/Lexus + + + + Enable Stock Toyota Longitudinal Control + + + + sunnypilot will <b>not</b> take over control of gas and brakes. Stock Toyota longitudinal control will be used. + + + + Allow M.A.D.S. toggling w/ LKAS Button (Beta) + + + + Allows M.A.D.S. engagement/disengagement with "LKAS" button from the steering wheel. + + + + Note: Enabling this toggle may have unexpected behavior with steering control. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Toyota TSS2 Longitudinal: Custom Tuning + + + + Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + + + Enable Enhanced Blind Spot Monitor + + + + Enable Toyota Stop and Go Hack + + + + sunnypilot will allow some Toyota/Lexus cars to auto resume during stop and go traffic. This feature is only applicable to certain models. Use at your own risk. + + + + Enable Toyota Door Auto Locking + + + + sunnypilot will attempt to lock the doors when drive above 10 km/h (6.2 mph). +Reboot Required. + + + + Enable Toyota Door Auto Unlocking + + + + sunnypilot will attempt to unlock the doors when shift to gear P. +Reboot Required. + + + + Volkswagen + + + + Enable CC Only support + + + + sunnypilot supports Volkswagen MQB CC only platforms with this toggle enabled. Only enable this toggle if your car does not have ACC from the factory. + + + + Start the car to check car compatibility + + + + This platform is already supported, therefore no need to enable this toggle + + + + This platform is not supported + + + + This platform can be supported + + + + sunnypilot will use debugging CAN messages to receive unfiltered BSM signals, allowing detection of more objects. + + + + Tested on RAV4 TSS1, Lexus LSS1, Toyota TSS1/1.5, and Prius TSS2. + + + SettingsWindow @@ -693,6 +1585,61 @@ This may take up to a minute. Yazılım + + SettingsWindowSP + + × + x + + + Device + Cihaz + + + Network + + + + sunnylink + + + + Toggles + Değiştirme + + + Software + Yazılım + + + sunnypilot + + + + OSM + + + + Monitoring + + + + Visuals + + + + Display + + + + Trips + + + + Vehicle + + + Setup @@ -886,6 +1833,100 @@ This may take up to a minute. 5G + + SidebarSP + + TEMP + SICAKLIK + + + HIGH + YÜKSEK + + + GOOD + İYİ + + + OK + TAMAM + + + DISABLED + + + + OFFLINE + ÇEVRİMDIŞI + + + REGIST... + + + + ONLINE + ÇEVRİMİÇİ + + + ERROR + HATA + + + SUNNYLINK + + + + + SlcSettings + + Auto + + + + User Confirm + + + + Engage Mode + + + + Default + + + + Fixed + + + + Percentage + + + + Limit Offset + + + + Set speed limit slightly higher than actual speed limit for a more natural drive. + + + + This platform defaults to <b>Auto</b> mode. <b>User Confirm</b> mode is not supported on this platform. + + + + Select the desired mode to set the cruising speed to the speed limit: + + + + Auto: Automatic speed adjustment on motorways based on speed limit data. + + + + User Confirm: Inform the driver to change set speed of Adaptive Cruise Control to help the driver stay within the speed limit. + + + SoftwarePanel @@ -961,6 +2002,233 @@ This may take up to a minute. + + SoftwarePanelSP + + Driving Model + + + + SELECT + + + + PENDING + + + + Downloading Driving model + + + + (CACHED) + + + + Driving model + + + + downloaded + + + + Downloading Navigation model + + + + Navigation model + + + + Downloading Metadata model + + + + Metadata model + + + + Downloads have failed, please try swapping the model! + + + + Failed: + + + + Fetching models... + + + + Select a Driving Model + + + + Download has started in the background. + + + + We STRONGLY suggest you to reset calibration. Would you like to do that now? + + + + Reset Calibration + Kalibrasyonu sıfırla + + + Warning: You are on a metered connection! + + + + Continue + Devam et + + + on Metered + + + + + SpeedLimitPolicySettings + + Speed Limit Source Policy + + + + Nav + + + + Only + + + + Map + + + + Car + + + + First + + + + Select the precedence order of sources. Utilized by Speed Limit Control and Speed Limit Warning + + + + Nav Only: Data from Mapbox active navigation only. + + + + Map Only: Data from OpenStreetMap only. + + + + Car Only: Data from the car's built-in sources (if available). + + + + Nav First: Nav -> Map -> Car + + + + Map First: Map -> Nav -> Car + + + + Car First: Car -> Nav -> Map + + + + + SpeedLimitValueOffset + + km/h + km/h + + + mph + mph + + + + SpeedLimitWarningSettings + + Off + + + + Display + + + + Chime + + + + Speed Limit Warning + + + + Warning with speed limit flash + + + + When Speed Limit Warning is enabled, the speed limit sign will alert the driver when the cruising speed is faster than then speed limit plus the offset. + + + + Default + + + + Fixed + + + + Percentage + + + + Warning Offset + + + + Select the desired offset to warn the driver when the vehicle is driving faster than the speed limit. + + + + Off: When the cruising speed is faster than the speed limit plus the offset, there will be no warning. + + + + Display: The speed on the speed limit sign turns red to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + Chime: The speed on the speed limit sign turns red and chimes to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + + SpeedLimitWarningValueOffset + + N/A + N/A + + + km/h + km/h + + + mph + mph + + SshControl @@ -1007,6 +2275,399 @@ This may take up to a minute. SSH aç + + SunnylinkPanel + + Enable sunnylink + + + + Device ID + + + + N/A + N/A + + + This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. + + + + 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 + + + + 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. + + + + Sponsor Status + + + + SPONSOR + + + + Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. + + + + Pair GitHub Account + + + + PAIR + + + + Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. + + + + sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. + + + + Manage Settings + + + + Backup Settings + + + + Are you sure you want to backup sunnypilot settings? + + + + Back Up + + + + Restore Settings + + + + Are you sure you want to restore the last backed up sunnypilot settings? + + + + Restore + + + + THANKS + + + + Not Sponsor + + + + Paired + + + + Not Paired + + + + Backing up... + + + + Restoring... + + + + + SunnylinkSponsorPopup + + Scan the QR code to login to your GitHub account + + + + Follow the prompts to complete the pairing process + + + + Re-enter the "sunnylink" panel to verify sponsorship status + + + + If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot + + + + Scan the QR code to visit sunnyhaibin's GitHub Sponsors page + + + + Choose your sponsorship tier and confirm your support + + + + Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status + + + + Pair your GitHub account + + + + Early Access: Become a sunnypilot Sponsor + + + + + SunnypilotPanel + + Enable M.A.D.S. + + + + Enable the beloved M.A.D.S. feature. Disable toggle to revert back to stock openpilot engagement/disengagement. + + + + Laneless for Curves in "Auto" Mode + + + + While in Auto Lane, switch to Laneless for current/future curves. + + + + Speed Limit Control (SLC) + + + + When you engage ACC, you will be prompted to set the cruising speed to the speed limit of the road adjusted by the Offset and Source Policy specified, or the current driving speed. The maximum cruising speed will always be the MAX set speed. + + + + Enable Vision-based Turn Speed Control (V-TSC) + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Enable Map Data Turn Speed Control (M-TSC) (Beta) + + + + Use curvature information from map data to define speed limits to take turns ahead. + + + + ACC +/-: Long Press Reverse + + + + Change the ACC +/- buttons behavior with cruise speed change in sunnypilot. + + + + Disabled (Stock): Short=1, Long = 5 (imperial) / 10 (metric) + + + + Enabled: Short = 5 (imperial) / 10 (metric), Long=1 + + + + Custom Offsets + + + + Neural Network Lateral Control (NNLC) + + + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Enable Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying FRICTION and LAT_ACCEL_FACTOR below will override the offline values indicated in the YAML files within "selfdrive/torque_data". The values will also be used live when "Override Self-Tune" toggle is enabled. + + + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Quiet Drive 🤫 + + + + sunnypilot will display alerts but only play the most important warning sounds. This feature can be toggled while the car is on. + + + + Green Traffic Light Chime (Beta) + + + + A chime will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. If you are waiting behind another vehicle, the chime will play once the vehicle advances unless ACC is engaged. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Vehicle Departure Alert + + + + Enable this will notify when the leading vehicle drives away. + + + + Customize M.A.D.S. + + + + Customize Lane Change + + + + Customize Offsets + + + + Customize Speed Limit Control + + + + Customize Warning + + + + Customize Source + + + + Laneful + + + + Laneless + + + + Auto + + + + Dynamic Lane Profile + + + + Speed Limit Assist + + + + Real-time and Offline + + + + Offline Only + + + + Dynamic Lane Profile is not available with the current Driving Model + + + + Custom Offsets is not available with the current Driving Model + + + + NNLC is currently not available on this platform. + + + + Match: "Exact" is ideal, but "Fuzzy" is fine too. Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server if there are any issues: + + + + Start the car to check car compatibility + + + + NNLC Not Loaded + + + + NNLC Loaded + + + + Fuzzy + + + + Exact + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server and donate logs to get NNLC loaded for your car: + + + + Match + + + + Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server with feedback, or to provide log data for your car if your car is currently unsupported: + + + + Add custom offsets to Camera and Path in sunnypilot. + + + + Default is Laneless. In Auto mode, sunnnypilot dynamically chooses between Laneline or Laneless model based on lane recognition confidence level on road and certain conditions. + + + TermsPage @@ -1026,15 +2687,30 @@ This may take up to a minute. Kabul et + + TermsPageSP + + Terms & Conditions + Şartlar ve Koşullar + + + Decline + Reddet + + + Scroll to accept + Kabul etmek için kaydırın + + TogglesPanel Enable openpilot - openpilot'u aktifleştir + openpilot'u aktifleştir Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. - Ayarlanabilir hız sabitleyici ve şeritte kalma yardımı için openpilot sistemini kullanın. Bu özelliği kullanırken her zaman dikkatli olmanız gerekiyor. Bu ayarın değiştirilmesi için araç kapatılıp açılması gerekiyor. + Ayarlanabilir hız sabitleyici ve şeritte kalma yardımı için openpilot sistemini kullanın. Bu özelliği kullanırken her zaman dikkatli olmanız gerekiyor. Bu ayarın değiştirilmesi için araç kapatılıp açılması gerekiyor. Enable Lane Departure Warnings @@ -1066,19 +2742,19 @@ This may take up to a minute. Show ETA in 24h Format - Tahmini varış süresini 24 saat formatı şeklinde göster + Tahmini varış süresini 24 saat formatı şeklinde göster Use 24h format instead of am/pm - 24 saat formatını kullan + 24 saat formatını kullan Show Map on Left Side of UI - Haritayı arayüzün sol tarafında göster + Haritayı arayüzün sol tarafında göster Show map on left side when in split screen view. - Bölünmüş ekran görünümündeyken haritayı sol tarafta göster. + Bölünmüş ekran görünümündeyken haritayı sol tarafta göster. openpilot Longitudinal Control (Alpha) @@ -1164,6 +2840,252 @@ This may take up to a minute. Enable driver monitoring even when openpilot is not engaged. + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + + TogglesPanelSP + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + openpilot Longitudinal Control (Alpha) + + + + WARNING: sunnypilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + + + + On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to sunnypilot longitudinal control. Enabling Experimental mode is recommended when enabling sunnypilot longitudinal control alpha. + + + + Custom Stock Longitudinal Control + + + + When enabled, sunnypilot will attempt to control stock longitudinal control with ACC button presses. +This feature must be used along with SLC, and/or V-TSC, and/or M-TSC. + + + + Experimental Mode + + + + Enable Dynamic Experimental Control + + + + Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. + + + + Enable Dynamic Personality + + + + Enable this to allow sunnypilot to dynamically adjust following distance and reaction based on your "Driving Personality" setting. Instead of predefined settings for each personality, every personality now adapts dynamically according to your speed and the distance to the lead car. + + + + Disengage on Accelerator Pedal + + + + When enabled, pressing the accelerator pedal will disengage openpilot. + Aktifleştirilirse eğer gaz pedalına basınca openpilot devre dışı kalır. + + + Enable Lane Departure Warnings + Şerit ihlali uyarı alın + + + Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). + 50 km/s (31 mph) hızın üzerinde sürüş sırasında aracınız dönüş sinyali vermeden algılanan bir sonraki başlatılışında çekilir. şerit çizgisi ihlalinde şeride geri dönmek için uyarılar alın. + + + Always-On Driver Monitoring + + + + Enable driver monitoring even when sunnypilot is not engaged. + + + + Record and Upload Driver Camera + Sürücü kamerasını kayıt et. + + + Upload data from the driver facing camera and help improve the driver monitoring algorithm. + Sürücüye bakan kamera verisini yükleyin ve Cihazın algoritmasını geliştirmemize yardımcı olun. + + + Disable Onroad Uploads + + + + Disable uploads completely when onroad. Necessary to avoid high data usage when connected to Wi-Fi hotspot. Turn on this feature if you are looking to utilize map-based features, such as Speed Limit Control (SLC) and Map-based Turn Speed Control (MTSC). + + + + Use Metric System + Metrik sistemi kullan + + + Display speed in km/h instead of mph. + Hızı mph yerine km/h şeklinde görüntüleyin. + + + Show ETA in 24h Format + Tahmini varış süresini 24 saat formatı şeklinde göster + + + Use 24h format instead of am/pm + 24 saat formatını kullan + + + Show Map on Left Side of UI + Haritayı arayüzün sol tarafında göster + + + Show map on left side when in split screen view. + Bölünmüş ekran görünümündeyken haritayı sol tarafta göster. + + + Aggressive + + + + Moderate + + + + Standard + + + + Relaxed + + + + Driving Personality + + + + Standard is recommended. In moderate/aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + + + + Sport + + + + Normal + + + + Eco + + + + Stock + + + + Acceleration Personality + + + + Normal is recommended. In sport mode, sunnypilot will provide aggressive acceleration for a dynamic driving experience. In eco mode, sunnypilot will apply smoother and more relaxed acceleration. On supported cars, you can cycle through these acceleration personality within Onroad Settings on the driving screen. + + + + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + + + + End-to-End Longitudinal Control + + + + Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + + + + New Driving Visualization + + + + The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. + + + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + + + + openpilot longitudinal control may come in a future update. + + + + An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. + + + + + TorqueFriction + + FRICTION + + + + Adjust Friction for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueMaxLatAccel + + LAT_ACCEL_FACTOR + + + + Adjust Max Lateral Acceleration for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + Updater @@ -1200,6 +3122,168 @@ This may take up to a minute. Güncelleme başarız oldu + + VehiclePanel + + Updating this setting takes effect when the car is powered off. + + + + Select your car + + + + + VisualsPanel + + Display Braking Status + + + + Enable this will turn the current speed value to red while the brake is used. + + + + Display Stand Still Timer + + + + Enable this will display time spent at a stop (i.e., at a stop lights, stop signs, traffic congestions). + + + + Display DM Camera in Reverse Gear + + + + Show Driver Monitoring camera while the car is in reverse gear. + + + + OSM: Show debug UI elements + + + + OSM: Show UI elements that aid debugging. + + + + Display Feature Status + + + + Display the statuses of certain features on the driving screen. + + + + Enable Onroad Settings + + + + Display the Onroad Settings button on the driving screen to adjust feature options on the driving screen, without navigating into the settings menu. + + + + Speedometer: Display True Speed + + + + Display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Display End-to-end Longitudinal Status (Beta) + + + + Enable this will display an icon that appears when the End-to-end model decides to start or stop. + + + + Navigation: Display in Full Screen + + + + Enable this will display the built-in navigation in full screen.<br>To switch back to driving view, <font color='yellow'>tap on the border edge</font>. + + + + Map: Display 3D Buildings + + + + Parse and display 3D buildings on map. Thanks to jakethesnake420 for this implementation. + + + + Off + + + + 5 Metrics + + + + 10 Metrics + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + + + Distance + + + + Speed + + + + Display Metrics Below Chevron + + + + Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + + + RAM + + + + CPU + + + + GPU + + + + Max + + + + Display Temperature on Sidebar + + + + Time + + + + All + + + WiFiPromptWidget @@ -1246,4 +3330,27 @@ This may take up to a minute. + + WifiUISP + + Scanning for networks... + Ağ aranıyor... + + + CONNECTING... + BAĞLANILIYOR... + + + FORGET + UNUT + + + Forget Wi-Fi Network "%1"? + Wi-Fi ağını unut "%1"? + + + Forget + + + diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 32119ee10f..fddf413a50 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -87,6 +87,89 @@ 网络名称:"%1" + + AdvancedNetworkingSP + + Back + 返回 + + + Enable Tethering + 启用WiFi热点 + + + Retain hotspot/tethering state + + + + Enabling this toggle will retain the hotspot/tethering toggle state across reboots. + + + + Tethering Password + WiFi热点密码 + + + EDIT + 编辑 + + + Enter new tethering password + 输入新的WiFi热点密码 + + + IP Address + IP地址 + + + Enable Roaming + 启用数据漫游 + + + APN Setting + APN设置 + + + Enter APN + 输入APN + + + leave blank for automatic configuration + 留空以自动配置 + + + Cellular Metered + 按流量计费的手机移动网络 + + + Prevent large data uploads when on a metered connection + 当使用按流量计费的连接时,避免上传大流量数据 + + + Hidden Network + 隐藏的网络 + + + CONNECT + + + + Enter SSID + 输入 SSID + + + Enter password + 输入密码 + + + for "%1" + 网络名称:"%1" + + + Ngrok Service + + + AnnotatedCameraWidget @@ -103,11 +186,119 @@ SPEED - SPEED + SPEED LIMIT - LIMIT + LIMIT + + + + AnnotatedCameraWidgetSP + + km/h + km/h + + + mph + mph + + + MAX + 最高定速 + + + SPEED + SPEED + + + LIMIT + LIMIT + + + + AutoLaneChangeTimer + + Auto Lane Change by Blinker + + + + Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. +Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. + + + + s + + + + Off + + + + Nudge + + + + Nudgeless + + + + + BackupSettings + + Settings backed up for sunnylink Device ID: + + + + Settings updated successfully, but no additional data was returned by the server. + + + + OOPS! We made a booboo. + + + + Please try again later. + + + + Settings restored. Confirm to restart the interface. + + + + No settings found to restore. + + + + + BrightnessControl + + Brightness + + + + Manually adjusts the global brightness of the screen. + + + + Auto + + + + + CameraOffset + + Camera Offset - Laneful Only + + + + Hack to trick vehicle to be left or right biased in its lane. Decreasing the value will make the car keep more left, increasing will make it keep more right. Changes take effect immediately. Default: +4 cm + + + + cm + @@ -121,11 +312,18 @@ 取消 + + CustomOffsetsSettings + + Back + 返回 + + DeclinePage You must accept the Terms and Conditions in order to use openpilot. - 您必须接受条款和条件以使用openpilot。 + 您必须接受条款和条件以使用openpilot。 Back @@ -135,6 +333,10 @@ Decline, uninstall %1 拒绝并卸载%1 + + You must accept the Terms and Conditions in order to use sunnypilot. + + DestinationWidget @@ -247,7 +449,7 @@ openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required. - openpilot要求设备安装的偏航角在左4°和右4°之间,俯仰角在上5°和下9°之间。一般来说,openpilot会持续更新校准,很少需要重置。 + openpilot要求设备安装的偏航角在左4°和右4°之间,俯仰角在上5°和下9°之间。一般来说,openpilot会持续更新校准,很少需要重置。 Your device is pointed %1° %2 and %3° %4. @@ -305,6 +507,155 @@ PAIR 配对 + + sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. sunnypilot is continuously calibrating, resetting is rarely required. + + + + + DevicePanelSP + + TOGGLE + + + + Enable or disable PIN requirement for Fleet Manager access. + + + + Are you sure you want to turn off PIN requirement? + + + + Turn Off + + + + Error Troubleshoot + + + + VIEW + 查看 + + + Display error from the tmux session when an error has occurred from a system process. + + + + Reset Access Tokens for Map Services + + + + RESET + 重置 + + + Reset self-service access tokens for Mapbox, Amap, and Google Maps. + + + + Are you sure you want to reset access tokens for all map services? + + + + Reset + 重置 + + + Reset sunnypilot Settings + + + + Are you sure you want to reset all sunnypilot settings? + + + + Toggle Onroad/Offroad + + + + OFF + + + + Are you sure you want to unforce offroad? + + + + Unforce + + + + Are you sure you want to force offroad? + + + + Force + + + + Disengage to Force Offroad + + + + Unforce Offroad + + + + Force Offroad + + + + Fleet Manager PIN: + + + + + DisplayPanel + + Driving Screen Off: Non-Critical Events + + + + When <b>Driving Screen Off Timer</b> is not set to <b>"Always On"</b>: + + + + Enabled: Wake the brightness of the screen to display all events. + + + + Disabled: Wake the brightness of the screen to display critical events. + + + + + DriveStats + + Drives + + + + Hours + + + + ALL TIME + + + + PAST WEEK + + + + KM + + + + Miles + + DriverViewWindow @@ -344,6 +695,79 @@ 正在安装…… + + LaneChangeSettings + + Back + 返回 + + + Pause Lateral Below Speed with Blinker + + + + Enable this toggle to pause lateral actuation with blinker when traveling below the desired speed selected below. + + + + Auto Lane Change: Delay with Blind Spot + + + + Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. + + + + Block Lane Change: Road Edge Detection + + + + Enable this toggle to block lane change when road edge is detected on the stalk actuated side. + + + + + MadsSettings + + Enable ACC+MADS with RES+/SET- + + + + Engage both M.A.D.S. and ACC with a single press of RES+ or SET- button. + + + + Note: Once M.A.D.S. is engaged via this mode, it will remain engaged until it is manually disabled via the M.A.D.S. button or car shut off. + + + + Toggle M.A.D.S. with Cruise Main + + + + Allows M.A.D.S. engagement/disengagement with "Cruise Main" cruise control button from the steering wheel. + + + + Remain Active + + + + Pause Steering + + + + Steering Mode After Braking + + + + Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. + +Remain Active: ALC will remain active even after the brake pedal is pressed. +Pause Steering: ALC will be paused after the brake pedal is manually pressed. + + + MapETA @@ -385,6 +809,63 @@ 等待路线 + + MapWindowSP + + Map Loading + 地图加载中 + + + Waiting for GPS + 等待 GPS + + + Waiting for route + 等待路线 + + + + MaxTimeOffroad + + Max Time Offroad + + + + Device is automatically turned off after a set time when the engine is turned off (off-road) after driving (on-road). + + + + s + + + + m + m + + + hr + 小时 + + + Always On + + + + Immediate + + + + + MonitoringPanel + + Enable Hands on Wheel Monitoring + + + + Monitor and alert when driver is not keeping the hands on the steering wheel. + + + MultiOptionDialog @@ -415,6 +896,33 @@ 密码错误 + + NetworkingSP + + Scan + + + + Scanning... + + + + Advanced + 高级 + + + Enter password + 输入密码 + + + for "%1" + 网络名称:"%1" + + + Wrong password + 密码错误 + + OffroadAlert @@ -467,6 +975,16 @@ Device temperature too high. System cooling down before starting. Current internal component temperature: %1 设备温度过高。系统正在冷却中,等冷却完毕后才会启动。目前内部组件温度:%1 + + OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. + +%1 + + + + sunnypilot is now in Forced Offroad mode. sunnypilot won't start until Forced Offroad mode is disabled. Go to "Settings" -> "Device" -> "Unforce Offroad" to exit Force Offroad mode. + + OffroadHome @@ -506,6 +1024,186 @@ 重启设备 + + OnroadScreenOff + + Driving Screen Off Timer + + + + Turn off the device screen or reduce brightness to protect the screen after driving starts. It automatically brightens or turns on when a touch or event occurs. + + + + s + + + + min + 分钟 + + + Always On + + + + + OnroadScreenOffBrightness + + Driving Screen Off Brightness (%) + + + + When using the Driving Screen Off feature, the brightness is reduced according to the automatic brightness ratio. + + + + Dark + + + + + OnroadSettings + + ONROAD OPTIONS + + + + <b>ONROAD SETTINGS | SUNNYPILOT</b> + + + + + OsmPanel + + Mapd Version + + + + Offline Maps ETA + + + + Time Elapsed + + + + Downloaded Maps + + + + DELETE + + + + This will delete ALL downloaded maps + +Are you sure you want to delete all the maps? + + + + Yes, delete all the maps. + + + + Database Update + + + + CHECK + 查看 + + + Country + + + + SELECT + 选择 + + + Fetching Country list... + + + + State + + + + Fetching State list... + + + + All + + + + REFRESH + + + + UPDATE + 更新 + + + Download starting... + + + + Error: Invalid download. Retry. + + + + Download complete! + + + + + +Warning: You are on a metered connection! + + + + This will start the download process and it might take a while to complete. + + + + Continue on Metered + + + + Start Download + + + + m + + + + s + + + + Calculating... + + + + Downloaded + + + + Calculating ETA... + + + + Ready + + + + Time remaining: + + + PairingPopup @@ -536,6 +1234,51 @@ 启用 + + ParamControlSP + + Enable + 启用 + + + Cancel + 取消 + + + + PathOffset + + Path Offset + + + + Hack to trick the model path to be left or right biased of the lane. Decreasing the value will shift the model more left, increasing will shift the model more right. Changes take effect immediately. + + + + cm + + + + + PauseLateralSpeed + + Pause lateral actuation with blinker when traveling below the desired speed selected. Default is 20 MPH or 32 km/h. + + + + Default + + + + km/h + km/h + + + mph + mph + + PrimeAdWidget @@ -590,7 +1333,7 @@ openpilot - openpilot + openpilot %n minute(s) ago @@ -630,6 +1373,30 @@ now 现在 + + sunnypilot + + + + Update downloaded. Ready to reboot. + + + + Update: Check and Download Update + + + + Reboot: Reboot Device + + + + Update + + + + Updating... + + Reset @@ -672,6 +1439,131 @@ This may take up to a minute. 系统重置已触发。按下“确认”以清除所有内容和设置,按下“取消”以继续启动。 + + SPVehiclesTogglesPanel + + Hyundai/Kia/Genesis + + + + HKG CAN: Smoother Stopping Performance (Beta) + + + + Smoother stopping behind a stopped car or desired stopping event. This is only applicable to HKG CAN platforms using openpilot longitudinal control. + + + + Subaru + + + + Manual Parking Brake: Stop and Go (Beta) + + + + Experimental feature to enable stop and go for Subaru Global models with manual handbrake. Models with electric parking brake should keep this disabled. Thanks to martinl for this implementation! + + + + Toyota/Lexus + + + + Enable Stock Toyota Longitudinal Control + + + + sunnypilot will <b>not</b> take over control of gas and brakes. Stock Toyota longitudinal control will be used. + + + + Allow M.A.D.S. toggling w/ LKAS Button (Beta) + + + + Allows M.A.D.S. engagement/disengagement with "LKAS" button from the steering wheel. + + + + Note: Enabling this toggle may have unexpected behavior with steering control. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Toyota TSS2 Longitudinal: Custom Tuning + + + + Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + + + Enable Enhanced Blind Spot Monitor + + + + Enable Toyota Stop and Go Hack + + + + sunnypilot will allow some Toyota/Lexus cars to auto resume during stop and go traffic. This feature is only applicable to certain models. Use at your own risk. + + + + Enable Toyota Door Auto Locking + + + + sunnypilot will attempt to lock the doors when drive above 10 km/h (6.2 mph). +Reboot Required. + + + + Enable Toyota Door Auto Unlocking + + + + sunnypilot will attempt to unlock the doors when shift to gear P. +Reboot Required. + + + + Volkswagen + + + + Enable CC Only support + + + + sunnypilot supports Volkswagen MQB CC only platforms with this toggle enabled. Only enable this toggle if your car does not have ACC from the factory. + + + + Start the car to check car compatibility + + + + This platform is already supported, therefore no need to enable this toggle + + + + This platform is not supported + + + + This platform can be supported + + + + sunnypilot will use debugging CAN messages to receive unfiltered BSM signals, allowing detection of more objects. + + + + Tested on RAV4 TSS1, Lexus LSS1, Toyota TSS1/1.5, and Prius TSS2. + + + SettingsWindow @@ -695,6 +1587,61 @@ This may take up to a minute. 软件 + + SettingsWindowSP + + × + × + + + Device + 设备 + + + Network + 网络 + + + sunnylink + + + + Toggles + 设定 + + + Software + 软件 + + + sunnypilot + + + + OSM + + + + Monitoring + + + + Visuals + + + + Display + + + + Trips + + + + Vehicle + + + Setup @@ -888,6 +1835,100 @@ This may take up to a minute. 5G + + SidebarSP + + TEMP + 设备温度 + + + HIGH + 过热 + + + GOOD + 良好 + + + OK + 一般 + + + DISABLED + + + + OFFLINE + 离线 + + + REGIST... + + + + ONLINE + 在线 + + + ERROR + 连接出错 + + + SUNNYLINK + + + + + SlcSettings + + Auto + + + + User Confirm + + + + Engage Mode + + + + Default + + + + Fixed + + + + Percentage + + + + Limit Offset + + + + Set speed limit slightly higher than actual speed limit for a more natural drive. + + + + This platform defaults to <b>Auto</b> mode. <b>User Confirm</b> mode is not supported on this platform. + + + + Select the desired mode to set the cruising speed to the speed limit: + + + + Auto: Automatic speed adjustment on motorways based on speed limit data. + + + + User Confirm: Inform the driver to change set speed of Adaptive Cruise Control to help the driver stay within the speed limit. + + + SoftwarePanel @@ -963,6 +2004,233 @@ This may take up to a minute. 从未更新 + + SoftwarePanelSP + + Driving Model + + + + SELECT + 选择 + + + PENDING + + + + Downloading Driving model + + + + (CACHED) + + + + Driving model + + + + downloaded + + + + Downloading Navigation model + + + + Navigation model + + + + Downloading Metadata model + + + + Metadata model + + + + Downloads have failed, please try swapping the model! + + + + Failed: + + + + Fetching models... + + + + Select a Driving Model + + + + Download has started in the background. + + + + We STRONGLY suggest you to reset calibration. Would you like to do that now? + + + + Reset Calibration + 重置设备校准 + + + Warning: You are on a metered connection! + + + + Continue + 继续 + + + on Metered + + + + + SpeedLimitPolicySettings + + Speed Limit Source Policy + + + + Nav + + + + Only + + + + Map + + + + Car + + + + First + + + + Select the precedence order of sources. Utilized by Speed Limit Control and Speed Limit Warning + + + + Nav Only: Data from Mapbox active navigation only. + + + + Map Only: Data from OpenStreetMap only. + + + + Car Only: Data from the car's built-in sources (if available). + + + + Nav First: Nav -> Map -> Car + + + + Map First: Map -> Nav -> Car + + + + Car First: Car -> Nav -> Map + + + + + SpeedLimitValueOffset + + km/h + km/h + + + mph + mph + + + + SpeedLimitWarningSettings + + Off + + + + Display + + + + Chime + + + + Speed Limit Warning + + + + Warning with speed limit flash + + + + When Speed Limit Warning is enabled, the speed limit sign will alert the driver when the cruising speed is faster than then speed limit plus the offset. + + + + Default + + + + Fixed + + + + Percentage + + + + Warning Offset + + + + Select the desired offset to warn the driver when the vehicle is driving faster than the speed limit. + + + + Off: When the cruising speed is faster than the speed limit plus the offset, there will be no warning. + + + + Display: The speed on the speed limit sign turns red to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + Chime: The speed on the speed limit sign turns red and chimes to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + + SpeedLimitWarningValueOffset + + N/A + N/A + + + km/h + km/h + + + mph + mph + + SshControl @@ -1009,6 +2277,399 @@ This may take up to a minute. 启用SSH + + SunnylinkPanel + + Enable sunnylink + + + + Device ID + + + + N/A + N/A + + + This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. + + + + 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 + + + + 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. + + + + Sponsor Status + + + + SPONSOR + + + + Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. + + + + Pair GitHub Account + + + + PAIR + 配对 + + + Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. + + + + sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. + + + + Manage Settings + + + + Backup Settings + + + + Are you sure you want to backup sunnypilot settings? + + + + Back Up + + + + Restore Settings + + + + Are you sure you want to restore the last backed up sunnypilot settings? + + + + Restore + + + + THANKS + + + + Not Sponsor + + + + Paired + + + + Not Paired + + + + Backing up... + + + + Restoring... + + + + + SunnylinkSponsorPopup + + Scan the QR code to login to your GitHub account + + + + Follow the prompts to complete the pairing process + + + + Re-enter the "sunnylink" panel to verify sponsorship status + + + + If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot + + + + Scan the QR code to visit sunnyhaibin's GitHub Sponsors page + + + + Choose your sponsorship tier and confirm your support + + + + Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status + + + + Pair your GitHub account + + + + Early Access: Become a sunnypilot Sponsor + + + + + SunnypilotPanel + + Enable M.A.D.S. + + + + Enable the beloved M.A.D.S. feature. Disable toggle to revert back to stock openpilot engagement/disengagement. + + + + Laneless for Curves in "Auto" Mode + + + + While in Auto Lane, switch to Laneless for current/future curves. + + + + Speed Limit Control (SLC) + + + + When you engage ACC, you will be prompted to set the cruising speed to the speed limit of the road adjusted by the Offset and Source Policy specified, or the current driving speed. The maximum cruising speed will always be the MAX set speed. + + + + Enable Vision-based Turn Speed Control (V-TSC) + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Enable Map Data Turn Speed Control (M-TSC) (Beta) + + + + Use curvature information from map data to define speed limits to take turns ahead. + + + + ACC +/-: Long Press Reverse + + + + Change the ACC +/- buttons behavior with cruise speed change in sunnypilot. + + + + Disabled (Stock): Short=1, Long = 5 (imperial) / 10 (metric) + + + + Enabled: Short = 5 (imperial) / 10 (metric), Long=1 + + + + Custom Offsets + + + + Neural Network Lateral Control (NNLC) + + + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Enable Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying FRICTION and LAT_ACCEL_FACTOR below will override the offline values indicated in the YAML files within "selfdrive/torque_data". The values will also be used live when "Override Self-Tune" toggle is enabled. + + + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Quiet Drive 🤫 + + + + sunnypilot will display alerts but only play the most important warning sounds. This feature can be toggled while the car is on. + + + + Green Traffic Light Chime (Beta) + + + + A chime will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. If you are waiting behind another vehicle, the chime will play once the vehicle advances unless ACC is engaged. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Vehicle Departure Alert + + + + Enable this will notify when the leading vehicle drives away. + + + + Customize M.A.D.S. + + + + Customize Lane Change + + + + Customize Offsets + + + + Customize Speed Limit Control + + + + Customize Warning + + + + Customize Source + + + + Laneful + + + + Laneless + + + + Auto + + + + Dynamic Lane Profile + + + + Speed Limit Assist + + + + Real-time and Offline + + + + Offline Only + + + + Dynamic Lane Profile is not available with the current Driving Model + + + + Custom Offsets is not available with the current Driving Model + + + + NNLC is currently not available on this platform. + + + + Match: "Exact" is ideal, but "Fuzzy" is fine too. Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server if there are any issues: + + + + Start the car to check car compatibility + + + + NNLC Not Loaded + + + + NNLC Loaded + + + + Fuzzy + + + + Exact + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server and donate logs to get NNLC loaded for your car: + + + + Match + + + + Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server with feedback, or to provide log data for your car if your car is currently unsupported: + + + + Add custom offsets to Camera and Path in sunnypilot. + + + + Default is Laneless. In Auto mode, sunnnypilot dynamically chooses between Laneline or Laneless model based on lane recognition confidence level on road and certain conditions. + + + TermsPage @@ -1028,15 +2689,30 @@ This may take up to a minute. 同意 + + TermsPageSP + + Terms & Conditions + 条款和条件 + + + Decline + 拒绝 + + + Scroll to accept + 滑动以接受 + + TogglesPanel Enable openpilot - 启用openpilot + 启用openpilot Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. - 使用openpilot进行自适应巡航和车道保持辅助。使用此功能时您必须时刻保持注意力。该设置的更改在熄火时生效。 + 使用openpilot进行自适应巡航和车道保持辅助。使用此功能时您必须时刻保持注意力。该设置的更改在熄火时生效。 Enable Lane Departure Warnings @@ -1072,19 +2748,19 @@ This may take up to a minute. Show ETA in 24h Format - 以24小时格式显示预计到达时间 + 以24小时格式显示预计到达时间 Use 24h format instead of am/pm - 使用24小时制代替am/pm + 使用24小时制代替am/pm Show Map on Left Side of UI - 在介面左侧显示地图 + 在介面左侧显示地图 Show map on left side when in split screen view. - 在分屏模式中,将地图置于屏幕左侧。 + 在分屏模式中,将地图置于屏幕左侧。 Experimental Mode @@ -1166,6 +2842,252 @@ This may take up to a minute. Enable driver monitoring even when openpilot is not engaged. 即使在openpilot未激活时也启用驾驶员监控。 + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + + TogglesPanelSP + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + openpilot Longitudinal Control (Alpha) + openpilot纵向控制(Alpha 版) + + + WARNING: sunnypilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + + + + On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to sunnypilot longitudinal control. Enabling Experimental mode is recommended when enabling sunnypilot longitudinal control alpha. + + + + Custom Stock Longitudinal Control + + + + When enabled, sunnypilot will attempt to control stock longitudinal control with ACC button presses. +This feature must be used along with SLC, and/or V-TSC, and/or M-TSC. + + + + Experimental Mode + 测试模式 + + + Enable Dynamic Experimental Control + + + + Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. + + + + Enable Dynamic Personality + + + + Enable this to allow sunnypilot to dynamically adjust following distance and reaction based on your "Driving Personality" setting. Instead of predefined settings for each personality, every personality now adapts dynamically according to your speed and the distance to the lead car. + + + + Disengage on Accelerator Pedal + 踩油门时取消控制 + + + When enabled, pressing the accelerator pedal will disengage openpilot. + 启用后,踩下油门踏板将取消openpilot。 + + + Enable Lane Departure Warnings + 启用车道偏离警告 + + + Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). + 车速超过31mph(50km/h)时,若检测到车辆越过车道线且未打转向灯,系统将发出警告以提醒您返回车道。 + + + Always-On Driver Monitoring + 驾驶员监控常开 + + + Enable driver monitoring even when sunnypilot is not engaged. + + + + Record and Upload Driver Camera + 录制并上传驾驶员摄像头 + + + Upload data from the driver facing camera and help improve the driver monitoring algorithm. + 上传驾驶员摄像头的数据,帮助改进驾驶员监控算法。 + + + Disable Onroad Uploads + + + + Disable uploads completely when onroad. Necessary to avoid high data usage when connected to Wi-Fi hotspot. Turn on this feature if you are looking to utilize map-based features, such as Speed Limit Control (SLC) and Map-based Turn Speed Control (MTSC). + + + + Use Metric System + 使用公制单位 + + + Display speed in km/h instead of mph. + 显示车速时,以km/h代替mph。 + + + Show ETA in 24h Format + 以24小时格式显示预计到达时间 + + + Use 24h format instead of am/pm + 使用24小时制代替am/pm + + + Show Map on Left Side of UI + 在介面左侧显示地图 + + + Show map on left side when in split screen view. + 在分屏模式中,将地图置于屏幕左侧。 + + + Aggressive + 积极 + + + Moderate + + + + Standard + 标准 + + + Relaxed + 舒适 + + + Driving Personality + 驾驶风格 + + + Standard is recommended. In moderate/aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + + + + Sport + + + + Normal + + + + Eco + + + + Stock + + + + Acceleration Personality + + + + Normal is recommended. In sport mode, sunnypilot will provide aggressive acceleration for a dynamic driving experience. In eco mode, sunnypilot will apply smoother and more relaxed acceleration. On supported cars, you can cycle through these acceleration personality within Onroad Settings on the driving screen. + + + + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + openpilot 默认 <b>轻松模式</b>驾驶车辆。试验模式启用一些轻松模式之外的 <b>试验性功能</b>。试验性功能包括: + + + End-to-End Longitudinal Control + 端到端纵向控制 + + + Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + + + + New Driving Visualization + 新驾驶视角 + + + The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. + 在低速时,驾驶可视化将转换为道路朝向的广角摄像头,以更好地展示某些转弯。测试模式标志也将显示在右上角。 + + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + 由于此车辆使用自带的ACC纵向控制,当前无法使用试验模式。 + + + openpilot longitudinal control may come in a future update. + openpilot纵向控制可能会在未来的更新中提供。 + + + An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. + + + + + TorqueFriction + + FRICTION + + + + Adjust Friction for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueMaxLatAccel + + LAT_ACCEL_FACTOR + + + + Adjust Max Lateral Acceleration for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + Updater @@ -1202,6 +3124,168 @@ This may take up to a minute. 更新失败 + + VehiclePanel + + Updating this setting takes effect when the car is powered off. + + + + Select your car + + + + + VisualsPanel + + Display Braking Status + + + + Enable this will turn the current speed value to red while the brake is used. + + + + Display Stand Still Timer + + + + Enable this will display time spent at a stop (i.e., at a stop lights, stop signs, traffic congestions). + + + + Display DM Camera in Reverse Gear + + + + Show Driver Monitoring camera while the car is in reverse gear. + + + + OSM: Show debug UI elements + + + + OSM: Show UI elements that aid debugging. + + + + Display Feature Status + + + + Display the statuses of certain features on the driving screen. + + + + Enable Onroad Settings + + + + Display the Onroad Settings button on the driving screen to adjust feature options on the driving screen, without navigating into the settings menu. + + + + Speedometer: Display True Speed + + + + Display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Display End-to-end Longitudinal Status (Beta) + + + + Enable this will display an icon that appears when the End-to-end model decides to start or stop. + + + + Navigation: Display in Full Screen + + + + Enable this will display the built-in navigation in full screen.<br>To switch back to driving view, <font color='yellow'>tap on the border edge</font>. + + + + Map: Display 3D Buildings + + + + Parse and display 3D buildings on map. Thanks to jakethesnake420 for this implementation. + + + + Off + + + + 5 Metrics + + + + 10 Metrics + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + + + Distance + + + + Speed + + + + Display Metrics Below Chevron + + + + Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + + + RAM + + + + CPU + + + + GPU + + + + Max + + + + Display Temperature on Sidebar + + + + Time + + + + All + + + WiFiPromptWidget @@ -1248,4 +3332,27 @@ This may take up to a minute. 忽略 + + WifiUISP + + Scanning for networks... + 正在扫描网络…… + + + CONNECTING... + 正在连接…… + + + FORGET + 忽略 + + + Forget Wi-Fi Network "%1"? + 忽略WiFi网络 "%1"? + + + Forget + 忽略 + + diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 9d1c16db9f..684447b113 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -87,6 +87,89 @@ 給 "%1" + + AdvancedNetworkingSP + + Back + 回上頁 + + + Enable Tethering + 啟用網路分享 + + + Retain hotspot/tethering state + + + + Enabling this toggle will retain the hotspot/tethering toggle state across reboots. + + + + Tethering Password + 網路分享密碼 + + + EDIT + 編輯 + + + Enter new tethering password + 輸入新的網路分享密碼 + + + IP Address + IP 地址 + + + Enable Roaming + 啟用漫遊 + + + APN Setting + APN 設置 + + + Enter APN + 輸入 APN + + + leave blank for automatic configuration + 留空白將自動配置 + + + Cellular Metered + 行動網路 + + + Prevent large data uploads when on a metered connection + 防止使用行動網路上傳大量的數據 + + + Hidden Network + 隱藏的網路 + + + CONNECT + + + + Enter SSID + 輸入 SSID + + + Enter password + 輸入密碼 + + + for "%1" + 給 "%1" + + + Ngrok Service + + + AnnotatedCameraWidget @@ -103,11 +186,119 @@ SPEED - 速度 + 速度 LIMIT - 速限 + 速限 + + + + AnnotatedCameraWidgetSP + + km/h + km/h + + + mph + mph + + + MAX + 最高 + + + SPEED + 速度 + + + LIMIT + 速限 + + + + AutoLaneChangeTimer + + Auto Lane Change by Blinker + + + + Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. +Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. + + + + s + + + + Off + + + + Nudge + + + + Nudgeless + + + + + BackupSettings + + Settings backed up for sunnylink Device ID: + + + + Settings updated successfully, but no additional data was returned by the server. + + + + OOPS! We made a booboo. + + + + Please try again later. + + + + Settings restored. Confirm to restart the interface. + + + + No settings found to restore. + + + + + BrightnessControl + + Brightness + + + + Manually adjusts the global brightness of the screen. + + + + Auto + + + + + CameraOffset + + Camera Offset - Laneful Only + + + + Hack to trick vehicle to be left or right biased in its lane. Decreasing the value will make the car keep more left, increasing will make it keep more right. Changes take effect immediately. Default: +4 cm + + + + cm + @@ -121,11 +312,18 @@ 取消 + + CustomOffsetsSettings + + Back + 回上頁 + + DeclinePage You must accept the Terms and Conditions in order to use openpilot. - 您必須先接受條款和條件才能使用 openpilot。 + 您必須先接受條款和條件才能使用 openpilot。 Back @@ -135,6 +333,10 @@ Decline, uninstall %1 拒絕並解除安裝 %1 + + You must accept the Terms and Conditions in order to use sunnypilot. + + DestinationWidget @@ -247,7 +449,7 @@ openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required. - openpilot 需要將裝置固定在左右偏差 4° 以內,朝上偏差 5° 以內或朝下偏差 9° 以內。鏡頭在後台會持續自動校準,很少有需要重置的情況。 + openpilot 需要將裝置固定在左右偏差 4° 以內,朝上偏差 5° 以內或朝下偏差 9° 以內。鏡頭在後台會持續自動校準,很少有需要重置的情況。 Your device is pointed %1° %2 and %3° %4. @@ -305,6 +507,155 @@ PAIR 配對 + + sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. sunnypilot is continuously calibrating, resetting is rarely required. + + + + + DevicePanelSP + + TOGGLE + + + + Enable or disable PIN requirement for Fleet Manager access. + + + + Are you sure you want to turn off PIN requirement? + + + + Turn Off + + + + Error Troubleshoot + + + + VIEW + 觀看 + + + Display error from the tmux session when an error has occurred from a system process. + + + + Reset Access Tokens for Map Services + + + + RESET + 重設 + + + Reset self-service access tokens for Mapbox, Amap, and Google Maps. + + + + Are you sure you want to reset access tokens for all map services? + + + + Reset + 重設 + + + Reset sunnypilot Settings + + + + Are you sure you want to reset all sunnypilot settings? + + + + Toggle Onroad/Offroad + + + + OFF + + + + Are you sure you want to unforce offroad? + + + + Unforce + + + + Are you sure you want to force offroad? + + + + Force + + + + Disengage to Force Offroad + + + + Unforce Offroad + + + + Force Offroad + + + + Fleet Manager PIN: + + + + + DisplayPanel + + Driving Screen Off: Non-Critical Events + + + + When <b>Driving Screen Off Timer</b> is not set to <b>"Always On"</b>: + + + + Enabled: Wake the brightness of the screen to display all events. + + + + Disabled: Wake the brightness of the screen to display critical events. + + + + + DriveStats + + Drives + + + + Hours + + + + ALL TIME + + + + PAST WEEK + + + + KM + + + + Miles + + DriverViewWindow @@ -344,6 +695,79 @@ 安裝中… + + LaneChangeSettings + + Back + 回上頁 + + + Pause Lateral Below Speed with Blinker + + + + Enable this toggle to pause lateral actuation with blinker when traveling below the desired speed selected below. + + + + Auto Lane Change: Delay with Blind Spot + + + + Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. + + + + Block Lane Change: Road Edge Detection + + + + Enable this toggle to block lane change when road edge is detected on the stalk actuated side. + + + + + MadsSettings + + Enable ACC+MADS with RES+/SET- + + + + Engage both M.A.D.S. and ACC with a single press of RES+ or SET- button. + + + + Note: Once M.A.D.S. is engaged via this mode, it will remain engaged until it is manually disabled via the M.A.D.S. button or car shut off. + + + + Toggle M.A.D.S. with Cruise Main + + + + Allows M.A.D.S. engagement/disengagement with "Cruise Main" cruise control button from the steering wheel. + + + + Remain Active + + + + Pause Steering + + + + Steering Mode After Braking + + + + Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. + +Remain Active: ALC will remain active even after the brake pedal is pressed. +Pause Steering: ALC will be paused after the brake pedal is manually pressed. + + + MapETA @@ -385,6 +809,63 @@ 等待路線 + + MapWindowSP + + Map Loading + 地圖載入中 + + + Waiting for GPS + 等待 GPS + + + Waiting for route + 等待路線 + + + + MaxTimeOffroad + + Max Time Offroad + + + + Device is automatically turned off after a set time when the engine is turned off (off-road) after driving (on-road). + + + + s + + + + m + m + + + hr + 小時 + + + Always On + + + + Immediate + + + + + MonitoringPanel + + Enable Hands on Wheel Monitoring + + + + Monitor and alert when driver is not keeping the hands on the steering wheel. + + + MultiOptionDialog @@ -415,6 +896,33 @@ 密碼錯誤 + + NetworkingSP + + Scan + + + + Scanning... + + + + Advanced + 進階 + + + Enter password + 輸入密碼 + + + for "%1" + 給 "%1" + + + Wrong password + 密碼錯誤 + + OffroadAlert @@ -467,6 +975,16 @@ Device temperature too high. System cooling down before starting. Current internal component temperature: %1 裝置溫度過高。系統正在冷卻中,等冷卻完畢後才會啟動。目前內部組件溫度:%1 + + OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. + +%1 + + + + sunnypilot is now in Forced Offroad mode. sunnypilot won't start until Forced Offroad mode is disabled. Go to "Settings" -> "Device" -> "Unforce Offroad" to exit Force Offroad mode. + + OffroadHome @@ -506,6 +1024,186 @@ 請重新啟裝置 + + OnroadScreenOff + + Driving Screen Off Timer + + + + Turn off the device screen or reduce brightness to protect the screen after driving starts. It automatically brightens or turns on when a touch or event occurs. + + + + s + + + + min + 分鐘 + + + Always On + + + + + OnroadScreenOffBrightness + + Driving Screen Off Brightness (%) + + + + When using the Driving Screen Off feature, the brightness is reduced according to the automatic brightness ratio. + + + + Dark + + + + + OnroadSettings + + ONROAD OPTIONS + + + + <b>ONROAD SETTINGS | SUNNYPILOT</b> + + + + + OsmPanel + + Mapd Version + + + + Offline Maps ETA + + + + Time Elapsed + + + + Downloaded Maps + + + + DELETE + + + + This will delete ALL downloaded maps + +Are you sure you want to delete all the maps? + + + + Yes, delete all the maps. + + + + Database Update + + + + CHECK + 檢查 + + + Country + + + + SELECT + 選取 + + + Fetching Country list... + + + + State + + + + Fetching State list... + + + + All + + + + REFRESH + + + + UPDATE + 更新 + + + Download starting... + + + + Error: Invalid download. Retry. + + + + Download complete! + + + + + +Warning: You are on a metered connection! + + + + This will start the download process and it might take a while to complete. + + + + Continue on Metered + + + + Start Download + + + + m + + + + s + + + + Calculating... + + + + Downloaded + + + + Calculating ETA... + + + + Ready + + + + Time remaining: + + + PairingPopup @@ -536,6 +1234,51 @@ 啟用 + + ParamControlSP + + Enable + 啟用 + + + Cancel + 取消 + + + + PathOffset + + Path Offset + + + + Hack to trick the model path to be left or right biased of the lane. Decreasing the value will shift the model more left, increasing will shift the model more right. Changes take effect immediately. + + + + cm + + + + + PauseLateralSpeed + + Pause lateral actuation with blinker when traveling below the desired speed selected. Default is 20 MPH or 32 km/h. + + + + Default + + + + km/h + km/h + + + mph + mph + + PrimeAdWidget @@ -590,7 +1333,7 @@ openpilot - openpilot + openpilot %n minute(s) ago @@ -630,6 +1373,30 @@ now 現在 + + sunnypilot + + + + Update downloaded. Ready to reboot. + + + + Update: Check and Download Update + + + + Reboot: Reboot Device + + + + Update + + + + Updating... + + Reset @@ -672,6 +1439,131 @@ This may take up to a minute. 系統重設已啟動。按下「確認」以清除所有內容和設定,或按下「取消」以繼續開機。 + + SPVehiclesTogglesPanel + + Hyundai/Kia/Genesis + + + + HKG CAN: Smoother Stopping Performance (Beta) + + + + Smoother stopping behind a stopped car or desired stopping event. This is only applicable to HKG CAN platforms using openpilot longitudinal control. + + + + Subaru + + + + Manual Parking Brake: Stop and Go (Beta) + + + + Experimental feature to enable stop and go for Subaru Global models with manual handbrake. Models with electric parking brake should keep this disabled. Thanks to martinl for this implementation! + + + + Toyota/Lexus + + + + Enable Stock Toyota Longitudinal Control + + + + sunnypilot will <b>not</b> take over control of gas and brakes. Stock Toyota longitudinal control will be used. + + + + Allow M.A.D.S. toggling w/ LKAS Button (Beta) + + + + Allows M.A.D.S. engagement/disengagement with "LKAS" button from the steering wheel. + + + + Note: Enabling this toggle may have unexpected behavior with steering control. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Toyota TSS2 Longitudinal: Custom Tuning + + + + Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + + + Enable Enhanced Blind Spot Monitor + + + + Enable Toyota Stop and Go Hack + + + + sunnypilot will allow some Toyota/Lexus cars to auto resume during stop and go traffic. This feature is only applicable to certain models. Use at your own risk. + + + + Enable Toyota Door Auto Locking + + + + sunnypilot will attempt to lock the doors when drive above 10 km/h (6.2 mph). +Reboot Required. + + + + Enable Toyota Door Auto Unlocking + + + + sunnypilot will attempt to unlock the doors when shift to gear P. +Reboot Required. + + + + Volkswagen + + + + Enable CC Only support + + + + sunnypilot supports Volkswagen MQB CC only platforms with this toggle enabled. Only enable this toggle if your car does not have ACC from the factory. + + + + Start the car to check car compatibility + + + + This platform is already supported, therefore no need to enable this toggle + + + + This platform is not supported + + + + This platform can be supported + + + + sunnypilot will use debugging CAN messages to receive unfiltered BSM signals, allowing detection of more objects. + + + + Tested on RAV4 TSS1, Lexus LSS1, Toyota TSS1/1.5, and Prius TSS2. + + + SettingsWindow @@ -695,6 +1587,61 @@ This may take up to a minute. 軟體 + + SettingsWindowSP + + × + × + + + Device + 裝置 + + + Network + 網路 + + + sunnylink + + + + Toggles + 設定 + + + Software + 軟體 + + + sunnypilot + + + + OSM + + + + Monitoring + + + + Visuals + + + + Display + + + + Trips + + + + Vehicle + + + Setup @@ -888,6 +1835,100 @@ This may take up to a minute. 5G + + SidebarSP + + TEMP + 溫度 + + + HIGH + 偏高 + + + GOOD + 正常 + + + OK + 一般 + + + DISABLED + + + + OFFLINE + 已離線 + + + REGIST... + + + + ONLINE + 已連線 + + + ERROR + 錯誤 + + + SUNNYLINK + + + + + SlcSettings + + Auto + + + + User Confirm + + + + Engage Mode + + + + Default + + + + Fixed + + + + Percentage + + + + Limit Offset + + + + Set speed limit slightly higher than actual speed limit for a more natural drive. + + + + This platform defaults to <b>Auto</b> mode. <b>User Confirm</b> mode is not supported on this platform. + + + + Select the desired mode to set the cruising speed to the speed limit: + + + + Auto: Automatic speed adjustment on motorways based on speed limit data. + + + + User Confirm: Inform the driver to change set speed of Adaptive Cruise Control to help the driver stay within the speed limit. + + + SoftwarePanel @@ -963,6 +2004,233 @@ This may take up to a minute. 從未更新 + + SoftwarePanelSP + + Driving Model + + + + SELECT + 選取 + + + PENDING + + + + Downloading Driving model + + + + (CACHED) + + + + Driving model + + + + downloaded + + + + Downloading Navigation model + + + + Navigation model + + + + Downloading Metadata model + + + + Metadata model + + + + Downloads have failed, please try swapping the model! + + + + Failed: + + + + Fetching models... + + + + Select a Driving Model + + + + Download has started in the background. + + + + We STRONGLY suggest you to reset calibration. Would you like to do that now? + + + + Reset Calibration + 重設校準 + + + Warning: You are on a metered connection! + + + + Continue + 繼續 + + + on Metered + + + + + SpeedLimitPolicySettings + + Speed Limit Source Policy + + + + Nav + + + + Only + + + + Map + + + + Car + + + + First + + + + Select the precedence order of sources. Utilized by Speed Limit Control and Speed Limit Warning + + + + Nav Only: Data from Mapbox active navigation only. + + + + Map Only: Data from OpenStreetMap only. + + + + Car Only: Data from the car's built-in sources (if available). + + + + Nav First: Nav -> Map -> Car + + + + Map First: Map -> Nav -> Car + + + + Car First: Car -> Nav -> Map + + + + + SpeedLimitValueOffset + + km/h + km/h + + + mph + mph + + + + SpeedLimitWarningSettings + + Off + + + + Display + + + + Chime + + + + Speed Limit Warning + + + + Warning with speed limit flash + + + + When Speed Limit Warning is enabled, the speed limit sign will alert the driver when the cruising speed is faster than then speed limit plus the offset. + + + + Default + + + + Fixed + + + + Percentage + + + + Warning Offset + + + + Select the desired offset to warn the driver when the vehicle is driving faster than the speed limit. + + + + Off: When the cruising speed is faster than the speed limit plus the offset, there will be no warning. + + + + Display: The speed on the speed limit sign turns red to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + Chime: The speed on the speed limit sign turns red and chimes to alert the driver when the cruising speed is faster than the speed limit plus the offset. + + + + + SpeedLimitWarningValueOffset + + N/A + 無法使用 + + + km/h + km/h + + + mph + mph + + SshControl @@ -1009,6 +2277,399 @@ This may take up to a minute. 啟用 SSH 服務 + + SunnylinkPanel + + Enable sunnylink + + + + Device ID + + + + N/A + 無法使用 + + + This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. + + + + 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 + + + + 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. + + + + Sponsor Status + + + + SPONSOR + + + + Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. + + + + Pair GitHub Account + + + + PAIR + 配對 + + + Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. + + + + sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. + + + + Manage Settings + + + + Backup Settings + + + + Are you sure you want to backup sunnypilot settings? + + + + Back Up + + + + Restore Settings + + + + Are you sure you want to restore the last backed up sunnypilot settings? + + + + Restore + + + + THANKS + + + + Not Sponsor + + + + Paired + + + + Not Paired + + + + Backing up... + + + + Restoring... + + + + + SunnylinkSponsorPopup + + Scan the QR code to login to your GitHub account + + + + Follow the prompts to complete the pairing process + + + + Re-enter the "sunnylink" panel to verify sponsorship status + + + + If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot + + + + Scan the QR code to visit sunnyhaibin's GitHub Sponsors page + + + + Choose your sponsorship tier and confirm your support + + + + Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status + + + + Pair your GitHub account + + + + Early Access: Become a sunnypilot Sponsor + + + + + SunnypilotPanel + + Enable M.A.D.S. + + + + Enable the beloved M.A.D.S. feature. Disable toggle to revert back to stock openpilot engagement/disengagement. + + + + Laneless for Curves in "Auto" Mode + + + + While in Auto Lane, switch to Laneless for current/future curves. + + + + Speed Limit Control (SLC) + + + + When you engage ACC, you will be prompted to set the cruising speed to the speed limit of the road adjusted by the Offset and Source Policy specified, or the current driving speed. The maximum cruising speed will always be the MAX set speed. + + + + Enable Vision-based Turn Speed Control (V-TSC) + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Enable Map Data Turn Speed Control (M-TSC) (Beta) + + + + Use curvature information from map data to define speed limits to take turns ahead. + + + + ACC +/-: Long Press Reverse + + + + Change the ACC +/- buttons behavior with cruise speed change in sunnypilot. + + + + Disabled (Stock): Short=1, Long = 5 (imperial) / 10 (metric) + + + + Enabled: Short = 5 (imperial) / 10 (metric), Long=1 + + + + Custom Offsets + + + + Neural Network Lateral Control (NNLC) + + + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Enable Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying FRICTION and LAT_ACCEL_FACTOR below will override the offline values indicated in the YAML files within "selfdrive/torque_data". The values will also be used live when "Override Self-Tune" toggle is enabled. + + + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Quiet Drive 🤫 + + + + sunnypilot will display alerts but only play the most important warning sounds. This feature can be toggled while the car is on. + + + + Green Traffic Light Chime (Beta) + + + + A chime will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. If you are waiting behind another vehicle, the chime will play once the vehicle advances unless ACC is engaged. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Vehicle Departure Alert + + + + Enable this will notify when the leading vehicle drives away. + + + + Customize M.A.D.S. + + + + Customize Lane Change + + + + Customize Offsets + + + + Customize Speed Limit Control + + + + Customize Warning + + + + Customize Source + + + + Laneful + + + + Laneless + + + + Auto + + + + Dynamic Lane Profile + + + + Speed Limit Assist + + + + Real-time and Offline + + + + Offline Only + + + + Dynamic Lane Profile is not available with the current Driving Model + + + + Custom Offsets is not available with the current Driving Model + + + + NNLC is currently not available on this platform. + + + + Match: "Exact" is ideal, but "Fuzzy" is fine too. Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server if there are any issues: + + + + Start the car to check car compatibility + + + + NNLC Not Loaded + + + + NNLC Loaded + + + + Fuzzy + + + + Exact + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server and donate logs to get NNLC loaded for your car: + + + + Match + + + + Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. + + + + Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server with feedback, or to provide log data for your car if your car is currently unsupported: + + + + Add custom offsets to Camera and Path in sunnypilot. + + + + Default is Laneless. In Auto mode, sunnnypilot dynamically chooses between Laneline or Laneless model based on lane recognition confidence level on road and certain conditions. + + + TermsPage @@ -1028,15 +2689,30 @@ This may take up to a minute. 接受 + + TermsPageSP + + Terms & Conditions + 條款和條件 + + + Decline + 拒絕 + + + Scroll to accept + 滑動至頁尾接受條款 + + TogglesPanel Enable openpilot - 啟用 openpilot + 啟用 openpilot Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. - 使用 openpilot 的主動式巡航和車道保持功能,開啟後您需要持續集中注意力,設定變更在重新啟動車輛後生效。 + 使用 openpilot 的主動式巡航和車道保持功能,開啟後您需要持續集中注意力,設定變更在重新啟動車輛後生效。 Enable Lane Departure Warnings @@ -1072,19 +2748,19 @@ This may take up to a minute. Show ETA in 24h Format - 預計到達時間單位改用 24 小時制 + 預計到達時間單位改用 24 小時制 Use 24h format instead of am/pm - 使用 24 小時制。(預設值為 12 小時制) + 使用 24 小時制。(預設值為 12 小時制) Show Map on Left Side of UI - 將地圖顯示在畫面的左側 + 將地圖顯示在畫面的左側 Show map on left side when in split screen view. - 進入分割畫面後,地圖將會顯示在畫面的左側。 + 進入分割畫面後,地圖將會顯示在畫面的左側。 Experimental Mode @@ -1166,6 +2842,252 @@ This may take up to a minute. Enable driver monitoring even when openpilot is not engaged. 即使在openpilot未激活時也啟用駕駛監控。 + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + + TogglesPanelSP + + Enable sunnypilot + + + + Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + + + + openpilot Longitudinal Control (Alpha) + openpilot 縱向控制 (Alpha 版) + + + WARNING: sunnypilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + + + + On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to sunnypilot longitudinal control. Enabling Experimental mode is recommended when enabling sunnypilot longitudinal control alpha. + + + + Custom Stock Longitudinal Control + + + + When enabled, sunnypilot will attempt to control stock longitudinal control with ACC button presses. +This feature must be used along with SLC, and/or V-TSC, and/or M-TSC. + + + + Experimental Mode + 實驗模式 + + + Enable Dynamic Experimental Control + + + + Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. + + + + Enable Dynamic Personality + + + + Enable this to allow sunnypilot to dynamically adjust following distance and reaction based on your "Driving Personality" setting. Instead of predefined settings for each personality, every personality now adapts dynamically according to your speed and the distance to the lead car. + + + + Disengage on Accelerator Pedal + 油門取消控車 + + + When enabled, pressing the accelerator pedal will disengage openpilot. + 啟用後,踩踏油門將會取消 openpilot 控制。 + + + Enable Lane Departure Warnings + 啟用車道偏離警告 + + + Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). + 車速在時速 50 公里 (31 英里) 以上且未打方向燈的情況下,如果偵測到車輛駛出目前車道線時,發出車道偏離警告。 + + + Always-On Driver Monitoring + 駕駛監控常開 + + + Enable driver monitoring even when sunnypilot is not engaged. + + + + Record and Upload Driver Camera + 記錄並上傳駕駛監控影像 + + + Upload data from the driver facing camera and help improve the driver monitoring algorithm. + 上傳駕駛監控的錄影來協助我們提升駕駛監控的準確率。 + + + Disable Onroad Uploads + + + + Disable uploads completely when onroad. Necessary to avoid high data usage when connected to Wi-Fi hotspot. Turn on this feature if you are looking to utilize map-based features, such as Speed Limit Control (SLC) and Map-based Turn Speed Control (MTSC). + + + + Use Metric System + 使用公制單位 + + + Display speed in km/h instead of mph. + 啟用後,速度單位顯示將從 mp/h 改為 km/h。 + + + Show ETA in 24h Format + 預計到達時間單位改用 24 小時制 + + + Use 24h format instead of am/pm + 使用 24 小時制。(預設值為 12 小時制) + + + Show Map on Left Side of UI + 將地圖顯示在畫面的左側 + + + Show map on left side when in split screen view. + 進入分割畫面後,地圖將會顯示在畫面的左側。 + + + Aggressive + 積極 + + + Moderate + + + + Standard + 標準 + + + Relaxed + 舒適 + + + Driving Personality + 駕駛風格 + + + Standard is recommended. In moderate/aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + + + + Sport + + + + Normal + + + + Eco + + + + Stock + + + + Acceleration Personality + + + + Normal is recommended. In sport mode, sunnypilot will provide aggressive acceleration for a dynamic driving experience. In eco mode, sunnypilot will apply smoother and more relaxed acceleration. On supported cars, you can cycle through these acceleration personality within Onroad Settings on the driving screen. + + + + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + openpilot 預設以 <b>輕鬆模式</b> 駕駛。 實驗模式啟用了尚未準備好進入輕鬆模式的 <b>alpha 級功能</b>。實驗功能如下: + + + End-to-End Longitudinal Control + 端到端縱向控制 + + + Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + + + + New Driving Visualization + 新的駕駛視覺介面 + + + The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. + 在低速時,駕駛可視化將切換至道路朝向的廣角攝影機,以更好地顯示某些彎道。在右上角還會顯示「實驗模式」的標誌。 + + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + 因車輛使用內建ACC系統,無法在本車輛上啟動實驗模式。 + + + openpilot longitudinal control may come in a future update. + openpilot 縱向控制可能會在未來的更新中提供。 + + + An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. + + + + + TorqueFriction + + FRICTION + + + + Adjust Friction for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueMaxLatAccel + + LAT_ACCEL_FACTOR + + + + Adjust Max Lateral Acceleration for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart. + + + + Real-time and Offline + + + + Offline Only + + Updater @@ -1202,6 +3124,168 @@ This may take up to a minute. 更新失敗 + + VehiclePanel + + Updating this setting takes effect when the car is powered off. + + + + Select your car + + + + + VisualsPanel + + Display Braking Status + + + + Enable this will turn the current speed value to red while the brake is used. + + + + Display Stand Still Timer + + + + Enable this will display time spent at a stop (i.e., at a stop lights, stop signs, traffic congestions). + + + + Display DM Camera in Reverse Gear + + + + Show Driver Monitoring camera while the car is in reverse gear. + + + + OSM: Show debug UI elements + + + + OSM: Show UI elements that aid debugging. + + + + Display Feature Status + + + + Display the statuses of certain features on the driving screen. + + + + Enable Onroad Settings + + + + Display the Onroad Settings button on the driving screen to adjust feature options on the driving screen, without navigating into the settings menu. + + + + Speedometer: Display True Speed + + + + Display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Display End-to-end Longitudinal Status (Beta) + + + + Enable this will display an icon that appears when the End-to-end model decides to start or stop. + + + + Navigation: Display in Full Screen + + + + Enable this will display the built-in navigation in full screen.<br>To switch back to driving view, <font color='yellow'>tap on the border edge</font>. + + + + Map: Display 3D Buildings + + + + Parse and display 3D buildings on map. Thanks to jakethesnake420 for this implementation. + + + + Off + + + + 5 Metrics + + + + 10 Metrics + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + + + Distance + + + + Speed + + + + Display Metrics Below Chevron + + + + Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + + + RAM + + + + CPU + + + + GPU + + + + Max + + + + Display Temperature on Sidebar + + + + Time + + + + All + + + WiFiPromptWidget @@ -1248,4 +3332,27 @@ This may take up to a minute. 清除 + + WifiUISP + + Scanning for networks... + 掃描無線網路中... + + + CONNECTING... + 連線中... + + + FORGET + 清除 + + + Forget Wi-Fi Network "%1"? + 清除 Wi-Fi 網路 "%1"? + + + Forget + 清除 + + diff --git a/system/manager/manager.py b/system/manager/manager.py index 032fc0a667..0f34a5e57f 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -99,7 +99,6 @@ def manager_init() -> None: ("TorqueDeadzoneDeg", "0"), ("TorqueFriction", "1"), ("TorqueMaxLatAccel", "250"), - ("ToyotaAutoHold", "0"), ("ToyotaAutoLockBySpeed", "0"), ("ToyotaAutoUnlockByShifter", "0"), ("ToyotaEnhancedBsm", "0"), From 447f76d9cf7fac394b932c2b6446bf5cf1d054ef Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Mon, 29 Jul 2024 10:16:46 +0000 Subject: [PATCH 146/229] ui: Split sunnypilot into its own classes --- SConstruct | 53 +- selfdrive/navd/main.cc | 4 + selfdrive/navd/map_renderer.cc | 4 + selfdrive/ui/SConscript | 19 +- selfdrive/ui/main.cc | 7 +- selfdrive/ui/qt/api.cc | 162 +- selfdrive/ui/qt/api.h | 18 +- selfdrive/ui/qt/body.h | 4 + selfdrive/ui/qt/home.cc | 172 +- selfdrive/ui/qt/home.h | 43 +- selfdrive/ui/qt/maps/map.cc | 71 +- selfdrive/ui/qt/maps/map.h | 17 +- selfdrive/ui/qt/maps/map_eta.cc | 7 +- selfdrive/ui/qt/maps/map_helpers.cc | 4 + selfdrive/ui/qt/maps/map_helpers.h | 3 +- selfdrive/ui/qt/maps/map_instructions.cc | 7 +- selfdrive/ui/qt/maps/map_panel.cc | 8 +- selfdrive/ui/qt/maps/map_settings.h | 4 + selfdrive/ui/qt/network/networking.cc | 65 +- selfdrive/ui/qt/network/networking.h | 11 +- .../qt/network/sunnylink/models/user_model.h | 33 - .../sunnylink/services/base_device_service.cc | 48 - .../sunnylink/services/base_device_service.h | 29 - .../sunnylink/services/role_service.cc | 29 - .../network/sunnylink/services/role_service.h | 26 - .../sunnylink/services/user_service.cc | 31 - .../network/sunnylink/services/user_service.h | 26 - .../qt/network/sunnylink/sunnylink_client.cc | 7 - .../qt/network/sunnylink/sunnylink_client.h | 18 - selfdrive/ui/qt/network/wifi_manager.cc | 4 + selfdrive/ui/qt/offroad/experimental_mode.cc | 7 +- selfdrive/ui/qt/offroad/onboarding.cc | 20 +- selfdrive/ui/qt/offroad/onboarding.h | 17 +- selfdrive/ui/qt/offroad/settings.cc | 362 +--- selfdrive/ui/qt/offroad/settings.h | 53 +- selfdrive/ui/qt/offroad/software_settings.cc | 17 +- .../sunnypilot/custom_offsets_settings.h | 45 - .../qt/offroad/sunnypilot/display_settings.h | 69 - .../ui/qt/offroad/sunnypilot/json_fetcher.h | 35 - .../offroad/sunnypilot/lane_change_settings.h | 57 - .../ui/qt/offroad/sunnypilot/mads_settings.h | 25 - .../offroad/sunnypilot/monitoring_settings.cc | 30 - .../offroad/sunnypilot/monitoring_settings.h | 17 - .../sunnypilot/speed_limit_policy_settings.cc | 51 - .../offroad/sunnypilot/sunnypilot_settings.h | 84 - .../qt/offroad/sunnypilot/trips_settings.cc | 29 - .../ui/qt/offroad/sunnypilot/trips_settings.h | 17 - .../qt/offroad/sunnypilot/vehicle_settings.h | 59 - .../qt/offroad/sunnypilot/visuals_settings.h | 19 - selfdrive/ui/qt/offroad/sunnypilot_main.h | 11 - selfdrive/ui/qt/offroad_home.cc | 152 ++ selfdrive/ui/qt/offroad_home.h | 55 + selfdrive/ui/qt/onroad/annotated_camera.cc | 1403 +-------------- selfdrive/ui/qt/onroad/annotated_camera.h | 176 +- selfdrive/ui/qt/onroad/buttons.cc | 60 +- selfdrive/ui/qt/onroad/buttons.h | 37 +- selfdrive/ui/qt/onroad/onroad_home.cc | 111 +- selfdrive/ui/qt/onroad/onroad_home.h | 46 +- selfdrive/ui/qt/onroad_settings_panel.cc | 26 - selfdrive/ui/qt/onroad_settings_panel.h | 23 - selfdrive/ui/qt/request_repeater.cc | 34 +- selfdrive/ui/qt/request_repeater.h | 23 +- selfdrive/ui/qt/sidebar.cc | 89 +- selfdrive/ui/qt/sidebar.h | 16 +- selfdrive/ui/qt/text.cc | 72 - selfdrive/ui/qt/util.cc | 116 +- selfdrive/ui/qt/util.h | 15 +- selfdrive/ui/qt/widgets/cameraview.h | 4 + selfdrive/ui/qt/widgets/controls.cc | 70 +- selfdrive/ui/qt/widgets/controls.h | 337 +--- selfdrive/ui/qt/widgets/scrollview.cc | 8 - selfdrive/ui/qt/widgets/scrollview.h | 7 - selfdrive/ui/qt/widgets/ssh_keys.h | 6 + .../ui/qt/widgets/sunnypilot/drive_stats.h | 25 - selfdrive/ui/qt/widgets/toggle.cc | 4 +- selfdrive/ui/qt/widgets/toggle.h | 3 +- selfdrive/ui/qt/widgets/wifi.h | 4 + selfdrive/ui/qt/window.cc | 13 +- selfdrive/ui/qt/window.h | 13 +- selfdrive/ui/sunnypilot/SConscript | 75 +- selfdrive/ui/sunnypilot/qt/api.cc | 212 +++ selfdrive/ui/sunnypilot/qt/api.h | 55 + .../ui/sunnypilot/qt/common/json_fetcher.h | 60 + selfdrive/ui/sunnypilot/qt/home.cc | 80 + selfdrive/ui/sunnypilot/qt/home.h | 59 + selfdrive/ui/sunnypilot/qt/maps/map.cc | 293 ++++ selfdrive/ui/sunnypilot/qt/maps/map.h | 53 + selfdrive/ui/sunnypilot/qt/maps/map_helpers.h | 38 + .../ui/sunnypilot/qt/network/networking.cc | 448 +++++ .../ui/sunnypilot/qt/network/networking.h | 128 ++ .../qt/network/sunnylink/models/role_model.h | 31 +- .../sunnylink/models/sponsor_role_model.h | 33 +- .../qt/network/sunnylink/models/user_model.h | 56 + .../sunnylink/services/base_device_service.cc | 76 + .../sunnylink/services/base_device_service.h | 50 + .../sunnylink/services/role_service.cc | 55 + .../network/sunnylink/services/role_service.h | 51 + .../sunnylink/services/user_service.cc | 57 + .../network/sunnylink/services/user_service.h | 51 + .../qt/network/sunnylink/sunnylink_client.cc | 33 + .../qt/network/sunnylink/sunnylink_client.h | 41 + .../qt/offroad/settings/device_panel.cc | 189 ++ .../qt/offroad/settings/device_panel.h | 52 + .../qt/offroad/settings}/display_settings.cc | 53 +- .../qt/offroad/settings/display_settings.h | 98 ++ .../offroad/settings/monitoring_settings.cc | 58 + .../qt/offroad/settings/monitoring_settings.h | 46 + .../qt/offroad/settings/onboarding.cc | 123 ++ .../qt/offroad/settings/onboarding.h | 57 + .../offroad/settings/osm}/locations_fetcher.h | 35 +- .../offroad/settings/osm}/models_fetcher.cc | 31 +- .../qt/offroad/settings/osm}/models_fetcher.h | 36 +- .../qt/offroad/settings}/osm_settings.cc | 79 +- .../qt/offroad/settings}/osm_settings.h | 68 +- .../qt/offroad/settings/settings.cc | 446 +++++ .../sunnypilot/qt/offroad/settings/settings.h | 66 + .../qt/offroad/settings/software_settings.cc} | 48 +- .../qt/offroad/settings/software_settings.h} | 39 +- .../offroad/settings}/sunnylink_settings.cc | 97 +- .../qt/offroad/settings}/sunnylink_settings.h | 42 +- .../sunnypilot/custom_offsets_settings.cc | 40 +- .../sunnypilot/custom_offsets_settings.h | 74 + .../sunnypilot/lane_change_settings.cc | 53 +- .../sunnypilot/lane_change_settings.h | 86 + .../settings}/sunnypilot/mads_settings.cc | 53 +- .../settings/sunnypilot/mads_settings.h | 54 + .../speed_limit_control_settings.cc | 56 +- .../sunnypilot/speed_limit_control_settings.h | 44 +- .../sunnypilot/speed_limit_policy_settings.cc | 76 + .../sunnypilot/speed_limit_policy_settings.h | 37 +- .../speed_limit_warning_settings.cc | 61 +- .../sunnypilot/speed_limit_warning_settings.h | 46 +- .../offroad/settings}/sunnypilot_settings.cc | 98 +- .../qt/offroad/settings/sunnypilot_settings.h | 115 ++ .../qt/offroad/settings/trips_settings.cc | 55 + .../qt/offroad/settings/trips_settings.h | 47 + .../qt/offroad/settings}/vehicle_settings.cc | 93 +- .../qt/offroad/settings/vehicle_settings.h | 82 + .../qt/offroad/settings}/visuals_settings.cc | 60 +- .../qt/offroad/settings/visuals_settings.h | 48 + selfdrive/ui/sunnypilot/qt/offroad_home.cc | 58 + selfdrive/ui/sunnypilot/qt/offroad_home.h | 45 + .../sunnypilot/qt/onroad/annotated_camera.cc | 1535 +++++++++++++++++ .../sunnypilot/qt/onroad/annotated_camera.h | 230 +++ selfdrive/ui/sunnypilot/qt/onroad/buttons.cc | 96 ++ selfdrive/ui/sunnypilot/qt/onroad/buttons.h | 68 + .../qt/onroad/developer_ui/developer_ui.cc | 224 +++ .../qt/onroad/developer_ui/developer_ui.h | 46 + .../qt/onroad/developer_ui/ui_elements.h | 39 + .../ui/sunnypilot/qt/onroad/onroad_home.cc | 163 ++ .../ui/sunnypilot/qt/onroad/onroad_home.h | 72 + .../qt/onroad}/onroad_settings.cc | 78 +- .../qt/onroad}/onroad_settings.h | 37 +- .../qt/onroad/onroad_settings_panel.cc | 51 + .../qt/onroad/onroad_settings_panel.h | 49 + .../ui/sunnypilot/qt/request_repeater.cc | 62 + selfdrive/ui/sunnypilot/qt/request_repeater.h | 52 + selfdrive/ui/sunnypilot/qt/sidebar.cc | 132 ++ selfdrive/ui/sunnypilot/qt/sidebar.h | 57 + selfdrive/ui/sunnypilot/qt/text.cc | 162 ++ selfdrive/ui/sunnypilot/qt/ui_scene.h | 115 ++ selfdrive/ui/sunnypilot/qt/util.cc | 104 ++ selfdrive/ui/sunnypilot/qt/util.h | 39 + .../ui/sunnypilot/qt/widgets/controls.cc | 247 +++ selfdrive/ui/sunnypilot/qt/widgets/controls.h | 582 +++++++ .../qt/widgets}/drive_stats.cc | 29 +- .../ui/sunnypilot/qt/widgets/drive_stats.h | 51 + .../ui/sunnypilot/qt/widgets/scrollview.cc | 37 + .../ui/sunnypilot/qt/widgets/scrollview.h | 43 + selfdrive/ui/sunnypilot/qt/widgets/toggle.cc | 49 + selfdrive/ui/sunnypilot/qt/widgets/toggle.h | 39 + selfdrive/ui/sunnypilot/qt/window.cc | 44 + selfdrive/ui/sunnypilot/qt/window.h | 45 + selfdrive/ui/sunnypilot/sunnypilot_main.h | 45 + selfdrive/ui/sunnypilot/ui.cc | 348 ++++ selfdrive/ui/sunnypilot/ui.h | 154 ++ selfdrive/ui/translations/main_ar.ts | 16 + selfdrive/ui/translations/main_de.ts | 16 + selfdrive/ui/translations/main_es.ts | 16 + selfdrive/ui/translations/main_fr.ts | 16 + selfdrive/ui/translations/main_ja.ts | 16 + selfdrive/ui/translations/main_ko.ts | 16 + selfdrive/ui/translations/main_pt-BR.ts | 16 + selfdrive/ui/translations/main_th.ts | 16 + selfdrive/ui/translations/main_tr.ts | 16 + selfdrive/ui/translations/main_zh-CHS.ts | 16 + selfdrive/ui/translations/main_zh-CHT.ts | 16 + selfdrive/ui/ui.cc | 210 +-- selfdrive/ui/ui.h | 196 +-- system/manager/process_config.py | 16 +- tools/cabana/detailwidget.h | 5 + 191 files changed, 10742 insertions(+), 4970 deletions(-) delete mode 100644 selfdrive/ui/qt/network/sunnylink/models/user_model.h delete mode 100644 selfdrive/ui/qt/network/sunnylink/services/base_device_service.cc delete mode 100644 selfdrive/ui/qt/network/sunnylink/services/base_device_service.h delete mode 100644 selfdrive/ui/qt/network/sunnylink/services/role_service.cc delete mode 100644 selfdrive/ui/qt/network/sunnylink/services/role_service.h delete mode 100644 selfdrive/ui/qt/network/sunnylink/services/user_service.cc delete mode 100644 selfdrive/ui/qt/network/sunnylink/services/user_service.h delete mode 100644 selfdrive/ui/qt/network/sunnylink/sunnylink_client.cc delete mode 100644 selfdrive/ui/qt/network/sunnylink/sunnylink_client.h delete mode 100644 selfdrive/ui/qt/offroad/sunnypilot/custom_offsets_settings.h delete mode 100644 selfdrive/ui/qt/offroad/sunnypilot/display_settings.h delete mode 100644 selfdrive/ui/qt/offroad/sunnypilot/json_fetcher.h delete mode 100644 selfdrive/ui/qt/offroad/sunnypilot/lane_change_settings.h delete mode 100644 selfdrive/ui/qt/offroad/sunnypilot/mads_settings.h delete mode 100644 selfdrive/ui/qt/offroad/sunnypilot/monitoring_settings.cc delete mode 100644 selfdrive/ui/qt/offroad/sunnypilot/monitoring_settings.h delete mode 100644 selfdrive/ui/qt/offroad/sunnypilot/speed_limit_policy_settings.cc delete mode 100644 selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.h delete mode 100644 selfdrive/ui/qt/offroad/sunnypilot/trips_settings.cc delete mode 100644 selfdrive/ui/qt/offroad/sunnypilot/trips_settings.h delete mode 100644 selfdrive/ui/qt/offroad/sunnypilot/vehicle_settings.h delete mode 100644 selfdrive/ui/qt/offroad/sunnypilot/visuals_settings.h delete mode 100644 selfdrive/ui/qt/offroad/sunnypilot_main.h create mode 100644 selfdrive/ui/qt/offroad_home.cc create mode 100644 selfdrive/ui/qt/offroad_home.h delete mode 100644 selfdrive/ui/qt/onroad_settings_panel.cc delete mode 100644 selfdrive/ui/qt/onroad_settings_panel.h delete mode 100644 selfdrive/ui/qt/widgets/sunnypilot/drive_stats.h create mode 100644 selfdrive/ui/sunnypilot/qt/api.cc create mode 100644 selfdrive/ui/sunnypilot/qt/api.h create mode 100644 selfdrive/ui/sunnypilot/qt/common/json_fetcher.h create mode 100644 selfdrive/ui/sunnypilot/qt/home.cc create mode 100644 selfdrive/ui/sunnypilot/qt/home.h create mode 100644 selfdrive/ui/sunnypilot/qt/maps/map.cc create mode 100644 selfdrive/ui/sunnypilot/qt/maps/map.h create mode 100644 selfdrive/ui/sunnypilot/qt/maps/map_helpers.h create mode 100644 selfdrive/ui/sunnypilot/qt/network/networking.cc create mode 100644 selfdrive/ui/sunnypilot/qt/network/networking.h rename selfdrive/ui/{ => sunnypilot}/qt/network/sunnylink/models/role_model.h (53%) rename selfdrive/ui/{ => sunnypilot}/qt/network/sunnylink/models/sponsor_role_model.h (67%) create mode 100644 selfdrive/ui/sunnypilot/qt/network/sunnylink/models/user_model.h create mode 100644 selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.cc create mode 100644 selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.h create mode 100644 selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.cc create mode 100644 selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.h create mode 100644 selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.cc create mode 100644 selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.h create mode 100644 selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.cc create mode 100644 selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.h create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.cc create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h rename selfdrive/ui/{qt/offroad/sunnypilot => sunnypilot/qt/offroad/settings}/display_settings.cc (71%) create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/display_settings.h create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/monitoring_settings.cc create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/monitoring_settings.h create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/onboarding.cc create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/onboarding.h rename selfdrive/ui/{qt/offroad/sunnypilot => sunnypilot/qt/offroad/settings/osm}/locations_fetcher.h (64%) rename selfdrive/ui/{qt/offroad/sunnypilot => sunnypilot/qt/offroad/settings/osm}/models_fetcher.cc (80%) rename selfdrive/ui/{qt/offroad/sunnypilot => sunnypilot/qt/offroad/settings/osm}/models_fetcher.h (75%) rename selfdrive/ui/{qt/offroad/sunnypilot => sunnypilot/qt/offroad/settings}/osm_settings.cc (76%) rename selfdrive/ui/{qt/offroad/sunnypilot => sunnypilot/qt/offroad/settings}/osm_settings.h (77%) create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/settings.cc create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h rename selfdrive/ui/{qt/offroad/sunnypilot/software_settings_sp.cc => sunnypilot/qt/offroad/settings/software_settings.cc} (86%) rename selfdrive/ui/{qt/offroad/sunnypilot/software_settings_sp.h => sunnypilot/qt/offroad/settings/software_settings.h} (64%) rename selfdrive/ui/{qt/offroad/sunnypilot => sunnypilot/qt/offroad/settings}/sunnylink_settings.cc (85%) rename selfdrive/ui/{qt/offroad/sunnypilot => sunnypilot/qt/offroad/settings}/sunnylink_settings.h (58%) rename selfdrive/ui/{qt/offroad => sunnypilot/qt/offroad/settings}/sunnypilot/custom_offsets_settings.cc (54%) create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/custom_offsets_settings.h rename selfdrive/ui/{qt/offroad => sunnypilot/qt/offroad/settings}/sunnypilot/lane_change_settings.cc (68%) create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/lane_change_settings.h rename selfdrive/ui/{qt/offroad => sunnypilot/qt/offroad/settings}/sunnypilot/mads_settings.cc (52%) create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/mads_settings.h rename selfdrive/ui/{qt/offroad => sunnypilot/qt/offroad/settings}/sunnypilot/speed_limit_control_settings.cc (68%) rename selfdrive/ui/{qt/offroad => sunnypilot/qt/offroad/settings}/sunnypilot/speed_limit_control_settings.h (50%) create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_policy_settings.cc rename selfdrive/ui/{qt/offroad => sunnypilot/qt/offroad/settings}/sunnypilot/speed_limit_policy_settings.h (59%) rename selfdrive/ui/{qt/offroad => sunnypilot/qt/offroad/settings}/sunnypilot/speed_limit_warning_settings.cc (64%) rename selfdrive/ui/{qt/offroad => sunnypilot/qt/offroad/settings}/sunnypilot/speed_limit_warning_settings.h (50%) rename selfdrive/ui/{qt/offroad/sunnypilot => sunnypilot/qt/offroad/settings}/sunnypilot_settings.cc (85%) create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot_settings.h create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/trips_settings.cc create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/trips_settings.h rename selfdrive/ui/{qt/offroad/sunnypilot => sunnypilot/qt/offroad/settings}/vehicle_settings.cc (75%) create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_settings.h rename selfdrive/ui/{qt/offroad/sunnypilot => sunnypilot/qt/offroad/settings}/visuals_settings.cc (68%) create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_settings.h create mode 100644 selfdrive/ui/sunnypilot/qt/offroad_home.cc create mode 100644 selfdrive/ui/sunnypilot/qt/offroad_home.h create mode 100644 selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.cc create mode 100644 selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h create mode 100644 selfdrive/ui/sunnypilot/qt/onroad/buttons.cc create mode 100644 selfdrive/ui/sunnypilot/qt/onroad/buttons.h create mode 100644 selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.cc create mode 100644 selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.h create mode 100644 selfdrive/ui/sunnypilot/qt/onroad/developer_ui/ui_elements.h create mode 100644 selfdrive/ui/sunnypilot/qt/onroad/onroad_home.cc create mode 100644 selfdrive/ui/sunnypilot/qt/onroad/onroad_home.h rename selfdrive/ui/{qt => sunnypilot/qt/onroad}/onroad_settings.cc (86%) rename selfdrive/ui/{qt => sunnypilot/qt/onroad}/onroad_settings.h (51%) create mode 100644 selfdrive/ui/sunnypilot/qt/onroad/onroad_settings_panel.cc create mode 100644 selfdrive/ui/sunnypilot/qt/onroad/onroad_settings_panel.h create mode 100644 selfdrive/ui/sunnypilot/qt/request_repeater.cc create mode 100644 selfdrive/ui/sunnypilot/qt/request_repeater.h create mode 100644 selfdrive/ui/sunnypilot/qt/sidebar.cc create mode 100644 selfdrive/ui/sunnypilot/qt/sidebar.h create mode 100644 selfdrive/ui/sunnypilot/qt/text.cc create mode 100644 selfdrive/ui/sunnypilot/qt/ui_scene.h create mode 100644 selfdrive/ui/sunnypilot/qt/util.cc create mode 100644 selfdrive/ui/sunnypilot/qt/util.h create mode 100644 selfdrive/ui/sunnypilot/qt/widgets/controls.cc create mode 100644 selfdrive/ui/sunnypilot/qt/widgets/controls.h rename selfdrive/ui/{qt/widgets/sunnypilot => sunnypilot/qt/widgets}/drive_stats.cc (73%) create mode 100644 selfdrive/ui/sunnypilot/qt/widgets/drive_stats.h create mode 100644 selfdrive/ui/sunnypilot/qt/widgets/scrollview.cc create mode 100644 selfdrive/ui/sunnypilot/qt/widgets/scrollview.h create mode 100644 selfdrive/ui/sunnypilot/qt/widgets/toggle.cc create mode 100644 selfdrive/ui/sunnypilot/qt/widgets/toggle.h create mode 100644 selfdrive/ui/sunnypilot/qt/window.cc create mode 100644 selfdrive/ui/sunnypilot/qt/window.h create mode 100644 selfdrive/ui/sunnypilot/sunnypilot_main.h create mode 100644 selfdrive/ui/sunnypilot/ui.cc create mode 100644 selfdrive/ui/sunnypilot/ui.h diff --git a/SConstruct b/SConstruct index 13da37c7a8..1ccd76e740 100644 --- a/SConstruct +++ b/SConstruct @@ -7,8 +7,6 @@ import numpy as np import SCons.Errors -from openpilot.common.basedir import BASEDIR - SCons.Warnings.warningAsException(True) # pending upstream fix - https://github.com/SCons/scons/issues/4461 @@ -18,45 +16,6 @@ TICI = os.path.isfile('/TICI') AGNOS = TICI UBUNTU_FOCAL = int(subprocess.check_output('[ -f /etc/os-release ] && . /etc/os-release && [ "$ID" = "ubuntu" ] && [ "$VERSION_ID" = "20.04" ] && echo 1 || echo 0', shell=True, encoding='utf-8').rstrip()) Export('UBUNTU_FOCAL') -_DEBUG = False - -def is_internal_developer(debug=False): - def collect_required_gpg_key_ids(keys_dir): - try: - key_ids = [f.split('.')[0] for f in os.listdir(keys_dir) if f.endswith(".gpg")] - if debug: - print(f"SP: Required GPG key IDs: {key_ids}") - return key_ids - except OSError as e: - if debug: - print(f"SP: Failed to read GPG key IDs from {keys_dir}. Error: {e}") - return [] - - def is_key_available(required_gpg_key_ids): - for key_id in required_gpg_key_ids: - try: - result = subprocess.check_output(['gpg', '--list-keys', key_id], stderr=subprocess.STDOUT) - if key_id in result.decode(): - if debug: - print(f"SP: GPG key {key_id} is available.") - return True - except subprocess.CalledProcessError as e: - if debug: - print(f"SP: Failed to list GPG key {key_id}. Error:", e.output.decode().strip()) - return False - - keys_dir = os.path.join(BASEDIR, ".git-crypt/keys/default/0") - required_gpg_key_ids = collect_required_gpg_key_ids(keys_dir) - - sunnypilot = is_key_available(required_gpg_key_ids) - - if sunnypilot: - print("SP: Confirmed sunnypilot internal developer.") - print("SP: Loading sunnypilot elements ...") - elif debug: - print("SP: None of the required GPG keys are available.") - - return sunnypilot Decider('MD5-timestamp') @@ -113,11 +72,11 @@ AddOption('--minimal', default=os.path.exists(File('#.lfsconfig').abspath), # minimal by default on release branch (where there's no LFS) help='the minimum build to run openpilot. no tests, tools, etc.') -AddOption('--sunnypilot', +AddOption('--stock-ui', action='store_true', - dest='sunnypilot', - default=is_internal_developer(_DEBUG), # check if the current user is a sunnypilot developer - help='build sunnypilot elements and other sunnypilot-specific items that are meant for internal development') + dest='stock_ui', + default=False, + help='Build stock UI instead of sunnypilot UI') ## Architecture name breakdown (arch) ## - larch64: linux tici aarch64 @@ -222,6 +181,10 @@ if arch != "Darwin": cflags += ['-DSWAGLOG="\\"common/swaglog.h\\""'] cxxflags += ['-DSWAGLOG="\\"common/swaglog.h\\""'] +if not GetOption('stock_ui'): + cflags += ["-DSUNNYPILOT"] + cxxflags += ["-DSUNNYPILOT"] + ccflags_option = GetOption('ccflags') if ccflags_option: ccflags += ccflags_option.split(' ') diff --git a/selfdrive/navd/main.cc b/selfdrive/navd/main.cc index 2e7b4d3b60..da188bb26b 100644 --- a/selfdrive/navd/main.cc +++ b/selfdrive/navd/main.cc @@ -6,7 +6,11 @@ #include "common/util.h" #include "selfdrive/ui/qt/util.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/maps/map_helpers.h" +#else #include "selfdrive/ui/qt/maps/map_helpers.h" +#endif #include "selfdrive/navd/map_renderer.h" #include "system/hardware/hw.h" diff --git a/selfdrive/navd/map_renderer.cc b/selfdrive/navd/map_renderer.cc index d52ee162bd..f24e6bb876 100644 --- a/selfdrive/navd/map_renderer.cc +++ b/selfdrive/navd/map_renderer.cc @@ -8,7 +8,11 @@ #include "common/util.h" #include "common/timing.h" #include "common/swaglog.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/maps/map_helpers.h" +#else #include "selfdrive/ui/qt/maps/map_helpers.h" +#endif const float DEFAULT_ZOOM = 13.5; // Don't go below 13 or features will start to disappear const int HEIGHT = 256, WIDTH = 256; diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 3d49b3df14..a825a74ab0 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -18,30 +18,32 @@ if arch == "Darwin": qt_env['CXXFLAGS'] += ["-Wno-deprecated-declarations"] sp_widgets_src = [] +sp_maps_widgets_src = [] sp_qt_src = [] -if GetOption('sunnypilot'): +sp_qt_util = [] +if not GetOption('stock_ui'): SConscript(['sunnypilot/SConscript']) - Import('sp_widgets_src', 'sp_qt_src') + Import('sp_widgets_src', 'sp_maps_widgets_src', 'sp_qt_src', "sp_qt_util") -qt_util = qt_env.Library("qt_util", ["#selfdrive/ui/qt/api.cc", "#selfdrive/ui/qt/util.cc"], LIBS=base_libs) +qt_util = qt_env.Library("qt_util", ["#selfdrive/ui/qt/api.cc", "#selfdrive/ui/qt/util.cc"] + sp_qt_util, LIBS=base_libs) widgets_src = ["ui.cc", "qt/widgets/input.cc", "qt/widgets/wifi.cc", "qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc", "qt/widgets/offroad_alerts.cc", "qt/widgets/prime.cc", "qt/widgets/keyboard.cc", "qt/widgets/scrollview.cc", "qt/widgets/cameraview.cc", "#third_party/qrcode/QrCode.cc", "qt/request_repeater.cc", "qt/qt_window.cc", "qt/network/networking.cc", "qt/network/wifi_manager.cc"] + sp_widgets_src -qt_env['CPPDEFINES'] = ["SUNNYPILOT"] if GetOption('sunnypilot') else [] +qt_env['CPPDEFINES'] = [] if maps: base_libs += ['QMapLibre'] widgets_src += ["qt/maps/map_helpers.cc", "qt/maps/map_settings.cc", "qt/maps/map.cc", "qt/maps/map_panel.cc", - "qt/maps/map_eta.cc", "qt/maps/map_instructions.cc"] + "qt/maps/map_eta.cc", "qt/maps/map_instructions.cc"] + sp_maps_widgets_src qt_env['CPPDEFINES'] += ["ENABLE_MAPS"] widgets = qt_env.Library("qt_widgets", widgets_src, LIBS=base_libs) Export('widgets') qt_libs = [widgets, qt_util] + base_libs -qt_src = ["main.cc", "qt/sidebar.cc", "qt/body.cc", +qt_src = ["main.cc", "qt/sidebar.cc", "qt/body.cc", "qt/offroad_home.cc", "qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc", "qt/offroad/software_settings.cc", "qt/offroad/onboarding.cc", "qt/offroad/driverview.cc", "qt/offroad/experimental_mode.cc", @@ -79,14 +81,15 @@ asset_obj = qt_env.Object("assets", assets) qt_env.SharedLibrary("qt/python_helpers", ["qt/qt_window.cc"], LIBS=qt_libs) # spinner and text window -qt_env.Program("_text", ["qt/text.cc"], LIBS=qt_libs) +text_cc_path = "qt/text.cc" if GetOption('stock_ui') else "sunnypilot/qt/text.cc" +qt_env.Program("_text", [text_cc_path], LIBS=qt_libs) qt_env.Program("_spinner", ["qt/spinner.cc"], LIBS=qt_libs) # build main UI qt_env.Program("ui", qt_src + [asset_obj], LIBS=qt_libs) if GetOption('extras'): qt_src.remove("main.cc") # replaced by test_runner - #qt_env.Program('tests/test_translations', [asset_obj, 'tests/test_runner.cc', 'tests/test_translations.cc'] + qt_src, LIBS=qt_libs) + qt_env.Program('tests/test_translations', [asset_obj, 'tests/test_runner.cc', 'tests/test_translations.cc'] + qt_src, LIBS=qt_libs) qt_env.Program('tests/ui_snapshot', [asset_obj, "tests/ui_snapshot.cc"] + qt_src, LIBS=qt_libs) diff --git a/selfdrive/ui/main.cc b/selfdrive/ui/main.cc index 4903a3db3d..baf09c79f1 100644 --- a/selfdrive/ui/main.cc +++ b/selfdrive/ui/main.cc @@ -6,7 +6,13 @@ #include "system/hardware/hw.h" #include "selfdrive/ui/qt/qt_window.h" #include "selfdrive/ui/qt/util.h" + +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/window.h" +#define MainWindow MainWindowSP +#else #include "selfdrive/ui/qt/window.h" +#endif int main(int argc, char *argv[]) { setpriority(PRIO_PROCESS, 0, -20); @@ -22,7 +28,6 @@ int main(int argc, char *argv[]) { QApplication a(argc, argv); a.installTranslator(&translator); - MainWindow w; setMainWindow(&w); a.installEventFilter(&w); diff --git a/selfdrive/ui/qt/api.cc b/selfdrive/ui/qt/api.cc index f3314221b8..80019f406e 100644 --- a/selfdrive/ui/qt/api.cc +++ b/selfdrive/ui/qt/api.cc @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -10,12 +9,10 @@ #include #include #include -#include #include #include -#include "common/swaglog.h" #include "common/util.h" #include "system/hardware/hw.h" #include "selfdrive/ui/qt/util.h" @@ -48,130 +45,11 @@ QByteArray rsa_sign(const QByteArray &data) { return sig; } -void derive_aes_key_iv_from_rsa(EVP_PKEY *rsa_key, unsigned char *aes_key, unsigned char *aes_iv) { - unsigned char hash[SHA256_DIGEST_LENGTH]; - size_t pub_len; - unsigned char *pub_key; - - // Convert RSA key to public key in DER format for simplicity - pub_len = i2d_PublicKey(rsa_key, NULL); - pub_key = (unsigned char *)malloc(pub_len); - unsigned char *tmp = pub_key; - i2d_PublicKey(rsa_key, &tmp); - - // Hash the public key to derive bytes for AES key and IV - SHA256(pub_key, pub_len, hash); - - // Assuming AES-256-CBC, we need 32 bytes for the key and 16 for the IV - memcpy(aes_key, hash, 32); // First 32 bytes for AES key - memcpy(aes_iv, hash + 32 - 16, 16); // Last 16 bytes for AES IV - - free(pub_key); -} - -EVP_PKEY *load_public_key(const char *file) { - EVP_PKEY *key = NULL; - FILE *fp = fopen(file, "r"); - if (fp) { - key = PEM_read_PUBKEY(fp, NULL, NULL, NULL); - fclose(fp); - } - return key; -} - -EVP_PKEY *load_private_key(const char *file) { - EVP_PKEY *key = NULL; - FILE *fp = fopen(file, "r"); - if (fp) { - key = PEM_read_PrivateKey(fp, NULL, NULL, NULL); - fclose(fp); - } - return key; -} - -QByteArray rsa_encrypt(const QByteArray &data) { - EVP_PKEY *rsa_key = load_public_key(Path::rsa_pub_file().c_str()); // Load your RSA key - unsigned char aes_key[32], aes_iv[16]; - derive_aes_key_iv_from_rsa(rsa_key, aes_key, aes_iv); - - EVP_CIPHER_CTX *ctx; - if (!(ctx = EVP_CIPHER_CTX_new())) { - // Handle error: Allocate memory failed - return {}; - } - - if (EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, aes_key, aes_iv) != 1) { - qDebug() << "Failed to initialize encryption"; - EVP_CIPHER_CTX_free(ctx); - return {}; - } - - int ciphertext_len; - int len = data.size(); - unsigned char out[len + AES_BLOCK_SIZE]; - auto *in = (unsigned char*) data.constData(); - if (EVP_EncryptUpdate(ctx, out, &ciphertext_len, in, len) != 1) { - qDebug() << "Failed to update encryption"; - EVP_CIPHER_CTX_free(ctx); - return {}; - } - - if (EVP_EncryptFinal_ex(ctx, out + ciphertext_len, &len) != 1) { - // Handle error: Encryption finalize failed - qDebug() << "Failed to finalize encryption"; - EVP_CIPHER_CTX_free(ctx); - return {}; - } - - //qDebug() << "Encrypted data length: %d", ciphertext_len + len; // Print the length of encrypted data - EVP_CIPHER_CTX_free(ctx); - return {reinterpret_cast(out), ciphertext_len + len}; -} - -QByteArray rsa_decrypt(const QByteArray &data) { - EVP_PKEY *rsa_key = load_public_key(Path::rsa_pub_file().c_str()); // Load your RSA key - unsigned char aes_key[32], aes_iv[16]; - derive_aes_key_iv_from_rsa(rsa_key, aes_key, aes_iv); - - EVP_CIPHER_CTX *ctx; - if (!(ctx = EVP_CIPHER_CTX_new())) { - qDebug() << "Failed to allocate memory for EVP_CIPHER_CTX"; - return {}; - } - - if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, aes_key, aes_iv) != 1) { - qDebug() << "Failed to initialize EVP"; - EVP_CIPHER_CTX_free(ctx); - return {}; - } - - int len = data.size(); - unsigned char out[len + AES_BLOCK_SIZE]; - auto *in = (unsigned char*) data.constData(); - if (EVP_DecryptUpdate(ctx, out, &len, in, len) != 1) { - qDebug() << "Failed to update decryption"; - EVP_CIPHER_CTX_free(ctx); - return {}; - } - - int final_len; - if (EVP_DecryptFinal_ex(ctx, out + len, &final_len) != 1) { - qDebug() << "Failed to finalize decryption"; - EVP_CIPHER_CTX_free(ctx); - return {}; - } - EVP_CIPHER_CTX_free(ctx); - - //qDebug() << "Decrypted data length: %d", len + final_len; // Print the length of decrypted data - return {reinterpret_cast(out), len + final_len}; -} - -QString create_jwt(const QJsonObject &payloads, int expiry, bool sunnylink) { +QString create_jwt(const QJsonObject &payloads, int expiry) { QJsonObject header = {{"alg", "RS256"}}; auto t = QDateTime::currentSecsSinceEpoch(); - auto dongle_id = sunnylink ? getSunnylinkDongleId() : getDongleId(); - QJsonObject payload = {{"identity", dongle_id.value_or("")}, {"nbf", t}, {"iat", t}, {"exp", t + expiry}}; + QJsonObject payload = {{"identity", getDongleId().value_or("")}, {"nbf", t}, {"iat", t}, {"exp", t + expiry}}; for (auto it = payloads.begin(); it != payloads.end(); ++it) { payload.insert(it.key(), it.value()); } @@ -186,7 +64,7 @@ QString create_jwt(const QJsonObject &payloads, int expiry, bool sunnylink) { } // namespace CommaApi -HttpRequest::HttpRequest(QObject *parent, bool create_jwt, int timeout, const bool sunnylink) : create_jwt(create_jwt), sunnylink(sunnylink), QObject(parent) { +HttpRequest::HttpRequest(QObject *parent, bool create_jwt, int timeout) : create_jwt(create_jwt), QObject(parent) { networkTimer = new QTimer(this); networkTimer->setSingleShot(true); networkTimer->setInterval(timeout); @@ -201,40 +79,38 @@ bool HttpRequest::timeout() const { return reply && reply->error() == QNetworkReply::OperationCanceledError; } -void HttpRequest::sendRequest(const QString &requestURL, const HttpRequest::Method method, const QByteArray &payload) { - LOGD("Requesting %s", qPrintable(requestURL)); - if (active()) { - qDebug() << "HttpRequest is active"; - return; - } +QNetworkRequest HttpRequest::prepareRequest(const QString &requestURL) +{ + QNetworkRequest request; QString token; if (create_jwt) { - token = CommaApi::create_jwt({}, 3600, sunnylink); + token = GetJwtToken(); } else { QString token_json = QString::fromStdString(util::read_file(util::getenv("HOME") + "/.comma/auth.json")); QJsonDocument json_d = QJsonDocument::fromJson(token_json.toUtf8()); token = json_d["access_token"].toString(); } - QNetworkRequest request; request.setUrl(QUrl(requestURL)); - request.setRawHeader("User-Agent", getUserAgent(sunnylink).toUtf8()); - if (!payload.isEmpty()) { - request.setRawHeader("Content-Type", "application/json"); - } + request.setRawHeader("User-Agent", GetUserAgent().toUtf8()); if (!token.isEmpty()) { request.setRawHeader(QByteArray("Authorization"), ("JWT " + token).toUtf8()); } + return request; +} - if (method == HttpRequest::Method::GET) { +void HttpRequest::sendRequest(const QString &requestURL, const Method method) { + if (active()) { + qDebug() << "HttpRequest is active"; + return; + } + + QNetworkRequest request = prepareRequest(requestURL); + if (method == Method::GET) { reply = nam()->get(request); - } else if (method == HttpRequest::Method::DELETE) { + } else if (method == Method::DELETE) { reply = nam()->deleteResource(request); - } else if (method == HttpRequest::Method::POST) { - reply = nam()->post(request, payload); - } else if (method == HttpRequest::Method::PUT) { - reply = nam()->put(request, payload); } networkTimer->start(); diff --git a/selfdrive/ui/qt/api.h b/selfdrive/ui/qt/api.h index bbebc502e5..f0e21f56a8 100644 --- a/selfdrive/ui/qt/api.h +++ b/selfdrive/ui/qt/api.h @@ -6,14 +6,13 @@ #include #include "common/util.h" +#include "selfdrive/ui/qt/util.h" namespace CommaApi { const QString BASE_URL = util::getenv("API_HOST", "https://api.commadotai.com").c_str(); QByteArray rsa_sign(const QByteArray &data); -QByteArray rsa_encrypt(const QByteArray &data); -QByteArray rsa_decrypt(const QByteArray &data); -QString create_jwt(const QJsonObject &payloads = {}, int expiry = 3600, bool sunnylink = false); +QString create_jwt(const QJsonObject &payloads = {}, int expiry = 3600); } // namespace CommaApi @@ -27,8 +26,9 @@ class HttpRequest : public QObject { public: enum class Method {GET, DELETE, POST, PUT}; - explicit HttpRequest(QObject* parent, bool create_jwt = true, int timeout = 20000, const bool sunnylink = false); - void sendRequest(const QString &requestURL, const Method method = Method::GET, const QByteArray &payload = {}); + explicit HttpRequest(QObject* parent, bool create_jwt = true, int timeout = 20000); + virtual void sendRequest(const QString &requestURL, Method method); + void sendRequest(const QString &requestURL) { sendRequest(requestURL, Method::GET);} bool active() const; bool timeout() const; @@ -37,14 +37,14 @@ signals: protected: QNetworkReply *reply = nullptr; - -private: static QNetworkAccessManager *nam(); QTimer *networkTimer = nullptr; bool create_jwt; - bool sunnylink; + virtual QNetworkRequest prepareRequest(const QString& requestURL); + virtual QString GetJwtToken() const { return CommaApi::create_jwt(); } + virtual QString GetUserAgent() const { return getUserAgent(); } -private slots: +protected slots: void requestTimeout(); void requestFinished(); }; diff --git a/selfdrive/ui/qt/body.h b/selfdrive/ui/qt/body.h index 567a54d49b..ac3cd2ce1c 100644 --- a/selfdrive/ui/qt/body.h +++ b/selfdrive/ui/qt/body.h @@ -5,7 +5,11 @@ #include #include "common/util.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/ui.h" +#else #include "selfdrive/ui/ui.h" +#endif class RecordButton : public QPushButton { Q_OBJECT diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index 48de10a79c..68ab992095 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -9,10 +9,6 @@ #include "selfdrive/ui/qt/util.h" #include "selfdrive/ui/qt/widgets/prime.h" -#ifdef ENABLE_MAPS -#include "selfdrive/ui/qt/maps/map_settings.h" -#endif - // HomeWindow: the container for the offroad and onroad UIs HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) { @@ -32,8 +28,6 @@ HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) { slayout->addWidget(home); onroad = new OnroadWindow(this); - QObject::connect(onroad, &OnroadWindow::mapPanelRequested, this, [=] { sidebar->hide(); }); - QObject::connect(onroad, &OnroadWindow::onroadSettingsPanelRequested, this, [=] { sidebar->hide(); }); slayout->addWidget(onroad); body = new BodyWindow(this); @@ -54,10 +48,6 @@ void HomeWindow::showSidebar(bool show) { sidebar->setVisible(show); } -void HomeWindow::showMapPanel(bool show) { - onroad->showMapPanel(show); -} - void HomeWindow::updateState(const UIState &s) { const SubMaster &sm = *(s.sm); @@ -66,9 +56,6 @@ void HomeWindow::updateState(const UIState &s) { body->setEnabled(true); slayout->setCurrentWidget(body); } - - uiState()->scene.map_visible = onroad->isMapVisible(); - uiState()->scene.onroad_settings_visible = onroad->isOnroadSettingsVisible(); } void HomeWindow::offroadTransition(bool offroad) { @@ -92,23 +79,9 @@ void HomeWindow::showDriverView(bool show) { } void HomeWindow::mousePressEvent(QMouseEvent* e) { - if (uiState()->scene.started) { - if (uiState()->scene.onroadScreenOff != -2) { - uiState()->scene.touched2 = true; - QTimer::singleShot(500, []() { uiState()->scene.touched2 = false; }); - } - if (uiState()->scene.button_auto_hide) { - uiState()->scene.touch_to_wake = true; - uiState()->scene.sleep_btn_fading_in = true; - QTimer::singleShot(500, []() { uiState()->scene.touch_to_wake = false; }); - } - } - // Handle sidebar collapsing if ((onroad->isVisible() || body->isVisible()) && (!sidebar->isVisible() || e->x() > sidebar->width())) { - if (onroad->wakeScreenTimeout()) { - sidebar->setVisible(!sidebar->isVisible() && !onroad->isMapVisible()); - } + sidebar->setVisible(!sidebar->isVisible()); } } @@ -124,146 +97,3 @@ void HomeWindow::mouseDoubleClickEvent(QMouseEvent* e) { showSidebar(false); } } - -// OffroadHome: the offroad home page - -OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { - QVBoxLayout* main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(40, 40, 40, 40); - - // top header - QHBoxLayout* header_layout = new QHBoxLayout(); - header_layout->setContentsMargins(0, 0, 0, 0); - header_layout->setSpacing(16); - - update_notif = new QPushButton(tr("UPDATE")); - update_notif->setVisible(false); - update_notif->setStyleSheet("background-color: #364DEF;"); - QObject::connect(update_notif, &QPushButton::clicked, [=]() { center_layout->setCurrentIndex(1); }); - header_layout->addWidget(update_notif, 0, Qt::AlignHCenter | Qt::AlignLeft); - - alert_notif = new QPushButton(); - alert_notif->setVisible(false); - alert_notif->setStyleSheet("background-color: #E22C2C;"); - QObject::connect(alert_notif, &QPushButton::clicked, [=] { center_layout->setCurrentIndex(2); }); - header_layout->addWidget(alert_notif, 0, Qt::AlignHCenter | Qt::AlignLeft); - - version = new ElidedLabel(); - header_layout->addWidget(version, 0, Qt::AlignHCenter | Qt::AlignRight); - - main_layout->addLayout(header_layout); - - // main content - main_layout->addSpacing(25); - center_layout = new QStackedLayout(); - - QWidget *home_widget = new QWidget(this); - { - QHBoxLayout *home_layout = new QHBoxLayout(home_widget); - home_layout->setContentsMargins(0, 0, 0, 0); - home_layout->setSpacing(30); - - // left: MapSettings/PrimeAdWidget - QStackedWidget *left_widget = new QStackedWidget(this); -#ifdef ENABLE_MAPS - left_widget->addWidget(new MapSettings); -#else - left_widget->addWidget(new QWidget); -#endif - custom_mapbox = QString::fromStdString(params.get("CustomMapboxTokenSk")) != ""; - if (!custom_mapbox) { - left_widget->addWidget(new PrimeAdWidget); - } - left_widget->setStyleSheet("border-radius: 10px;"); - - left_widget->setCurrentIndex((uiState()->hasPrime() || custom_mapbox) ? 0 : 1); - connect(uiState(), &UIState::primeChanged, [=](bool prime) { - left_widget->setCurrentIndex((prime || custom_mapbox) ? 0 : 1); - }); - - home_layout->addWidget(left_widget, 1); - - // right: ExperimentalModeButton, SetupWidget - QWidget* right_widget = new QWidget(this); - QVBoxLayout* right_column = new QVBoxLayout(right_widget); - right_column->setContentsMargins(0, 0, 0, 0); - right_widget->setFixedWidth(750); - right_column->setSpacing(30); - - ExperimentalModeButton *experimental_mode = new ExperimentalModeButton(this); - QObject::connect(experimental_mode, &ExperimentalModeButton::openSettings, this, &OffroadHome::openSettings); - right_column->addWidget(experimental_mode, 1); - - SetupWidget *setup_widget = new SetupWidget; - QObject::connect(setup_widget, &SetupWidget::openSettings, this, &OffroadHome::openSettings); - right_column->addWidget(setup_widget, 1); - - home_layout->addWidget(right_widget, 1); - } - center_layout->addWidget(home_widget); - - // add update & alerts widgets - update_widget = new UpdateAlert(); - QObject::connect(update_widget, &UpdateAlert::dismiss, [=]() { center_layout->setCurrentIndex(0); }); - center_layout->addWidget(update_widget); - alerts_widget = new OffroadAlert(); - QObject::connect(alerts_widget, &OffroadAlert::dismiss, [=]() { center_layout->setCurrentIndex(0); }); - center_layout->addWidget(alerts_widget); - - main_layout->addLayout(center_layout, 1); - - // set up refresh timer - timer = new QTimer(this); - timer->callOnTimeout(this, &OffroadHome::refresh); - - setStyleSheet(R"( - * { - color: white; - } - OffroadHome { - background-color: black; - } - OffroadHome > QPushButton { - padding: 15px 30px; - border-radius: 5px; - font-size: 40px; - font-weight: 500; - } - OffroadHome > QLabel { - font-size: 55px; - } - )"); -} - -void OffroadHome::showEvent(QShowEvent *event) { - refresh(); - timer->start(10 * 1000); -} - -void OffroadHome::hideEvent(QHideEvent *event) { - timer->stop(); -} - -void OffroadHome::refresh() { - version->setText(getBrand() + " " + QString::fromStdString(params.get("UpdaterCurrentDescription"))); - - bool updateAvailable = update_widget->refresh(); - int alerts = alerts_widget->refresh(); - - // pop-up new notification - int idx = center_layout->currentIndex(); - if (!updateAvailable && !alerts) { - idx = 0; - } else if (updateAvailable && (!update_notif->isVisible() || (!alerts && idx == 2))) { - idx = 1; - } else if (alerts && (!alert_notif->isVisible() || (!updateAvailable && idx == 1))) { - idx = 2; - } - center_layout->setCurrentIndex(idx); - - update_notif->setVisible(updateAvailable); - alert_notif->setVisible(alerts); - if (alerts) { - alert_notif->setText(QString::number(alerts) + (alerts > 1 ? tr(" ALERTS") : tr(" ALERT"))); - } -} diff --git a/selfdrive/ui/qt/home.h b/selfdrive/ui/qt/home.h index 7e0267a8a9..e903dad47d 100644 --- a/selfdrive/ui/qt/home.h +++ b/selfdrive/ui/qt/home.h @@ -12,35 +12,20 @@ #include "selfdrive/ui/qt/body.h" #include "selfdrive/ui/qt/onroad/onroad_home.h" #include "selfdrive/ui/qt/sidebar.h" -#include "selfdrive/ui/qt/widgets/controls.h" #include "selfdrive/ui/qt/widgets/offroad_alerts.h" #include "selfdrive/ui/ui.h" -class OffroadHome : public QFrame { - Q_OBJECT - -public: - explicit OffroadHome(QWidget* parent = 0); - -signals: - void openSettings(int index = 0, const QString ¶m = ""); - -private: - void showEvent(QShowEvent *event) override; - void hideEvent(QHideEvent *event) override; - void refresh(); - - Params params; - - QTimer* timer; - ElidedLabel* version; - QStackedLayout* center_layout; - UpdateAlert *update_widget; - OffroadAlert* alerts_widget; - QPushButton* alert_notif; - QPushButton* update_notif; - bool custom_mapbox; -}; +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#include "selfdrive/ui/sunnypilot/qt/offroad_home.h" +#include "selfdrive/ui/sunnypilot/qt/onroad/onroad_home.h" +#define OnroadWindow OnroadWindowSP +#define OffroadHome OffroadHomeSP +#else +#include "selfdrive/ui/qt/widgets/controls.h" +#include "selfdrive/ui/qt/onroad/onroad_home.h" +#include "selfdrive/ui/qt/offroad_home.h" +#endif class HomeWindow : public QWidget { Q_OBJECT @@ -56,13 +41,11 @@ public slots: void offroadTransition(bool offroad); void showDriverView(bool show); void showSidebar(bool show); - void showMapPanel(bool show); protected: void mousePressEvent(QMouseEvent* e) override; void mouseDoubleClickEvent(QMouseEvent* e) override; -private: Sidebar *sidebar; OffroadHome *home; OnroadWindow *onroad; @@ -70,6 +53,6 @@ private: DriverViewWindow *driver_view; QStackedLayout *slayout; -private slots: - void updateState(const UIState &s); +protected slots: + virtual void updateState(const UIState &s); }; diff --git a/selfdrive/ui/qt/maps/map.cc b/selfdrive/ui/qt/maps/map.cc index b5b731ef66..80cd82277e 100644 --- a/selfdrive/ui/qt/maps/map.cc +++ b/selfdrive/ui/qt/maps/map.cc @@ -6,9 +6,14 @@ #include #include "common/swaglog.h" -#include "selfdrive/ui/qt/maps/map_helpers.h" #include "selfdrive/ui/qt/util.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/maps/map_helpers.h" +#else +#include "selfdrive/ui/qt/maps/map_helpers.h" #include "selfdrive/ui/ui.h" +#endif const int INTERACTION_TIMEOUT = 100; @@ -54,6 +59,7 @@ MapWindow::~MapWindow() { } void MapWindow::initLayers() { + RETURN_IF_SUNNYPILOT // This doesn't work from initializeGL if (!m_map->layerExists("modelPathLayer")) { qDebug() << "Initializing modelPathLayer"; @@ -75,7 +81,7 @@ void MapWindow::initLayers() { QVariantMap transition; transition["duration"] = 400; // ms - m_map->setPaintProperty("navLayer", "line-color", getNavPathColor(uiState()->scene.navigate_on_openpilot_deprecated)); + m_map->setPaintProperty("navLayer", "line-color", QColor("#31a1ee")); m_map->setPaintProperty("navLayer", "line-color-transition", transition); m_map->setPaintProperty("navLayer", "line-width", 7.5); m_map->setLayoutProperty("navLayer", "line-cap", "round"); @@ -110,52 +116,10 @@ void MapWindow::initLayers() { // TODO: remove, symbol-sort-key does not seem to matter outside of each layer m_map->setLayoutProperty("carPosLayer", "symbol-sort-key", 0); } - if ((!m_map->layerExists("buildingsLayer")) && uiState()->scene.map_3d_buildings) { // Could put this behind the cellular metered toggle in case it increases data usage - qDebug() << "Initializing buildingsLayer"; - QVariantMap buildings; - buildings["id"] = "buildingsLayer"; - buildings["source"] = "composite"; - buildings["source-layer"] = "building"; - buildings["type"] = "fill-extrusion"; - buildings["minzoom"] = 15; - m_map->addLayer("buildingsLayer", buildings); - m_map->setFilter("buildingsLayer", QVariantList({"==", "extrude", "true"})); - - QVariantList fillExtrusionHeight = { // scale buildings as you zoom in - "interpolate", - QVariantList{"linear"}, - QVariantList{"zoom"}, - 15, 0, - 15.05, QVariantList{"get", "height"} - }; - - QVariantList fillExtrusionBase = { - "interpolate", - QVariantList{"linear"}, - QVariantList{"zoom"}, - 15, 0, - 15.05, QVariantList{"get", "min_height"} - }; - - QVariantList fillExtrusionOpacity = { - "interpolate", - QVariantList{"linear"}, - QVariantList{"zoom"}, - 15, 0, // transparent at zoom level 15 - 15.5, .6, // fade in - 17, .6, // begin fading out - 20, 0 // fade out when zoomed in - }; - - m_map->setPaintProperty("buildingsLayer", "fill-extrusion-color", QColor("grey")); - m_map->setPaintProperty("buildingsLayer", "fill-extrusion-opacity", fillExtrusionOpacity); - m_map->setPaintProperty("buildingsLayer", "fill-extrusion-height", fillExtrusionHeight); - m_map->setPaintProperty("buildingsLayer", "fill-extrusion-base", fillExtrusionBase); - m_map->setLayoutProperty("buildingsLayer", "visibility", "visible"); - } } void MapWindow::updateState(const UIState &s) { + RETURN_IF_SUNNYPILOT if (!uiState()->scene.started) { return; } @@ -170,22 +134,6 @@ void MapWindow::updateState(const UIState &s) { } prev_time_valid = sm.valid("clocks"); - if (sm.updated("modelV2")) { - // set path color on change, and show map on rising edge of navigate on openpilot - auto car_control = sm["carControl"].getCarControl(); - bool nav_enabled = sm["modelV2"].getModelV2().getNavEnabledDEPRECATED() && - (sm["controlsState"].getControlsState().getEnabled() || car_control.getLatActive() || car_control.getLongActive()); - if (nav_enabled != uiState()->scene.navigate_on_openpilot_deprecated) { - if (loaded_once) { - m_map->setPaintProperty("navLayer", "line-color", getNavPathColor(nav_enabled)); - } - if (nav_enabled) { - emit requestVisible(true); - } - } - uiState()->scene.navigate_on_openpilot_deprecated = nav_enabled; - } - if (sm.updated("liveLocationKalman")) { auto locationd_location = sm["liveLocationKalman"].getLiveLocationKalman(); auto locationd_pos = locationd_location.getPositionGeodetic(); @@ -425,7 +373,6 @@ void MapWindow::pinchTriggered(QPinchGesture *gesture) { void MapWindow::offroadTransition(bool offroad) { if (offroad) { clearRoute(); - uiState()->scene.navigate_on_openpilot_deprecated = false; routing_problem = false; } else { auto dest = coordinate_from_param("NavDestination"); diff --git a/selfdrive/ui/qt/maps/map.h b/selfdrive/ui/qt/maps/map.h index 62871e79d2..00e8b6f78f 100644 --- a/selfdrive/ui/qt/maps/map.h +++ b/selfdrive/ui/qt/maps/map.h @@ -20,7 +20,11 @@ #include "cereal/messaging/messaging.h" #include "common/params.h" #include "common/util.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/ui.h" +#else #include "selfdrive/ui/ui.h" +#endif #include "selfdrive/ui/qt/maps/map_eta.h" #include "selfdrive/ui/qt/maps/map_instructions.h" @@ -32,15 +36,17 @@ public: ~MapWindow(); private: - void initializeGL() final; void paintGL() final; void resizeGL(int w, int h) override; +protected: + void initializeGL() final; QMapLibre::Settings m_settings; QScopedPointer m_map; void initLayers(); +protected: void mousePressEvent(QMouseEvent *ev) final; void mouseDoubleClickEvent(QMouseEvent *ev) final; void mouseMoveEvent(QMouseEvent *ev) final; @@ -50,9 +56,11 @@ private: void pinchTriggered(QPinchGesture *gesture); void setError(const QString &err_str); +protected: bool loaded_once = false; bool prev_time_valid = true; +protected: // Panning QPointF m_lastPos; int interaction_counter = 0; @@ -70,16 +78,11 @@ private: MapInstructions* map_instructions; MapETA* map_eta; - // Blue with normal nav, green when nav is input into the model - QColor getNavPathColor(bool nav_enabled) { - return nav_enabled ? QColor("#31ee73") : QColor("#31a1ee"); - } - void clearRoute(); void updateDestinationMarker(); uint64_t route_rcv_frame = 0; -private slots: +public slots: void updateState(const UIState &s); public slots: diff --git a/selfdrive/ui/qt/maps/map_eta.cc b/selfdrive/ui/qt/maps/map_eta.cc index 0eb77e36ce..e153884576 100644 --- a/selfdrive/ui/qt/maps/map_eta.cc +++ b/selfdrive/ui/qt/maps/map_eta.cc @@ -3,8 +3,13 @@ #include #include -#include "selfdrive/ui/qt/maps/map_helpers.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/maps/map_helpers.h" +#else #include "selfdrive/ui/ui.h" +#include "selfdrive/ui/qt/maps/map_helpers.h" +#endif const float MANEUVER_TRANSITION_THRESHOLD = 10; diff --git a/selfdrive/ui/qt/maps/map_helpers.cc b/selfdrive/ui/qt/maps/map_helpers.cc index 50e1401164..6b7b05e786 100644 --- a/selfdrive/ui/qt/maps/map_helpers.cc +++ b/selfdrive/ui/qt/maps/map_helpers.cc @@ -1,4 +1,8 @@ +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/maps/map_helpers.h" +#else #include "selfdrive/ui/qt/maps/map_helpers.h" +#endif #include #include diff --git a/selfdrive/ui/qt/maps/map_helpers.h b/selfdrive/ui/qt/maps/map_helpers.h index b9cb1f9469..0f4be674f0 100644 --- a/selfdrive/ui/qt/maps/map_helpers.h +++ b/selfdrive/ui/qt/maps/map_helpers.h @@ -12,9 +12,8 @@ #include "common/transformations/coordinates.hpp" #include "common/transformations/orientation.hpp" #include "cereal/messaging/messaging.h" -#include "common/params.h" -const QString MAPBOX_TOKEN = QString::fromStdString(Params().get("CustomMapboxTokenSk")) != "" ? QString::fromStdString(Params().get("CustomMapboxTokenSk")) : util::getenv("MAPBOX_TOKEN").c_str(); +const QString MAPBOX_TOKEN = util::getenv("MAPBOX_TOKEN").c_str(); const QString MAPS_HOST = util::getenv("MAPS_HOST", MAPBOX_TOKEN.isEmpty() ? "https://maps.comma.ai" : "https://api.mapbox.com").c_str(); const QString MAPS_CACHE_PATH = "/data/mbgl-cache-navd.db"; diff --git a/selfdrive/ui/qt/maps/map_instructions.cc b/selfdrive/ui/qt/maps/map_instructions.cc index ba8cb356bd..b631548fe7 100644 --- a/selfdrive/ui/qt/maps/map_instructions.cc +++ b/selfdrive/ui/qt/maps/map_instructions.cc @@ -3,8 +3,13 @@ #include #include -#include "selfdrive/ui/qt/maps/map_helpers.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/maps/map_helpers.h" +#else #include "selfdrive/ui/ui.h" +#include "selfdrive/ui/qt/maps/map_helpers.h" +#endif const QString ICON_SUFFIX = ".png"; diff --git a/selfdrive/ui/qt/maps/map_panel.cc b/selfdrive/ui/qt/maps/map_panel.cc index c4cc20e21d..cd448483ff 100644 --- a/selfdrive/ui/qt/maps/map_panel.cc +++ b/selfdrive/ui/qt/maps/map_panel.cc @@ -3,10 +3,16 @@ #include #include -#include "selfdrive/ui/qt/maps/map.h" #include "selfdrive/ui/qt/maps/map_settings.h" #include "selfdrive/ui/qt/util.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/maps/map.h" +#define MapWindow MapWindowSP +#else #include "selfdrive/ui/ui.h" +#include "selfdrive/ui/qt/maps/map.h" +#endif MapPanel::MapPanel(const QMapLibre::Settings &mapboxSettings, QWidget *parent) : QFrame(parent) { content_stack = new QStackedLayout(this); diff --git a/selfdrive/ui/qt/maps/map_settings.h b/selfdrive/ui/qt/maps/map_settings.h index 0e151df4ad..40b0d35a6a 100644 --- a/selfdrive/ui/qt/maps/map_settings.h +++ b/selfdrive/ui/qt/maps/map_settings.h @@ -13,7 +13,11 @@ #include "common/params.h" #include "selfdrive/ui/qt/util.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#else #include "selfdrive/ui/qt/widgets/controls.h" +#endif const QString NAV_TYPE_FAVORITE = "favorite"; const QString NAV_TYPE_RECENT = "recent"; diff --git a/selfdrive/ui/qt/network/networking.cc b/selfdrive/ui/qt/network/networking.cc index 484536acf2..4f3d333ffd 100644 --- a/selfdrive/ui/qt/network/networking.cc +++ b/selfdrive/ui/qt/network/networking.cc @@ -6,11 +6,16 @@ #include #include +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/ui.h" +#else #include "selfdrive/ui/ui.h" +#endif #include "selfdrive/ui/qt/qt_window.h" #include "selfdrive/ui/qt/util.h" #include "selfdrive/ui/qt/widgets/controls.h" #include "selfdrive/ui/qt/widgets/scrollview.h" +#include "selfdrive/ui/qt/home.h" static const int ICON_WIDTH = 49; @@ -26,29 +31,17 @@ Networking::Networking(QWidget* parent, bool show_advanced) : QFrame(parent) { wifiScreen = new QWidget(this); QVBoxLayout* vlayout = new QVBoxLayout(wifiScreen); vlayout->setContentsMargins(20, 20, 20, 20); - QHBoxLayout* hlayout = new QHBoxLayout(); - QPushButton* scanButton = new QPushButton(tr("Scan")); - scanButton->setObjectName("scan_btn"); - scanButton->setFixedSize(400, 100); - connect(wifi, &WifiManager::refreshSignal, this, [=]() { scanButton->setText(tr("Scan")); scanButton->setEnabled(true); }); - connect(scanButton, &QPushButton::clicked, [=]() { scanButton->setText(tr("Scanning...")); scanButton->setEnabled(false); wifi->requestScan(); }); - - hlayout->addWidget(scanButton); - hlayout->addStretch(1); // Pushes the button all the way to the left - if (show_advanced) { - hlayout->setSpacing(10); - QPushButton* advancedSettings = new QPushButton(tr("Advanced")); advancedSettings->setObjectName("advanced_btn"); + advancedSettings->setStyleSheet("margin-right: 30px;"); advancedSettings->setFixedSize(400, 100); connect(advancedSettings, &QPushButton::clicked, [=]() { main_layout->setCurrentWidget(an); }); - hlayout->addWidget(advancedSettings); + vlayout->addSpacing(10); + vlayout->addWidget(advancedSettings, 0, Qt::AlignRight); + vlayout->addSpacing(10); } - vlayout->addLayout(hlayout); - vlayout->addSpacing(10); - wifiWidget = new WifiUI(this, wifi); wifiWidget->setObjectName("wifiWidget"); connect(wifiWidget, &WifiUI::connectToNetwork, this, &Networking::connectToNetwork); @@ -69,7 +62,7 @@ Networking::Networking(QWidget* parent, bool show_advanced) : QFrame(parent) { setPalette(pal); setStyleSheet(R"( - #wifiWidget > QPushButton, #back_btn, #advanced_btn, #scan_btn{ + #wifiWidget > QPushButton, #back_btn, #advanced_btn { font-size: 50px; margin: 0px; padding: 15px; @@ -78,7 +71,7 @@ Networking::Networking(QWidget* parent, bool show_advanced) : QFrame(parent) { color: #dddddd; background-color: #393939; } - #back_btn:pressed, #advanced_btn:pressed, #scan_btn:pressed { + #back_btn:pressed, #advanced_btn:pressed { background-color: #4a4a4a; } )"); @@ -139,23 +132,10 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid ListWidget *list = new ListWidget(this); // Enable tethering layout - const bool set_hotspot_on_boot = params.getBool("HotspotOnBoot") && params.getBool("HotspotOnBootConfirmed"); - tetheringToggle = new ToggleControl(tr("Enable Tethering"), "", "", wifi->isTetheringEnabled() || set_hotspot_on_boot); + tetheringToggle = new ToggleControl(tr("Enable Tethering"), "", "", wifi->isTetheringEnabled()); list->addItem(tetheringToggle); QObject::connect(tetheringToggle, &ToggleControl::toggleFlipped, this, &AdvancedNetworking::toggleTethering); - hotspotOnBootToggle = new ToggleControl( - tr("Retain hotspot/tethering state"), - tr("Enabling this toggle will retain the hotspot/tethering toggle state across reboots."), - "", - params.getBool("HotspotOnBoot") - ); - hotspotOnBootToggle->setEnabled(wifi->isTetheringEnabled() || set_hotspot_on_boot); - QObject::connect(hotspotOnBootToggle, &ToggleControl::toggleFlipped, [=](bool state) { - params.putBool("HotspotOnBoot", state); - }); - list->addItem(hotspotOnBootToggle); - // Change tethering password ButtonControl *editPasswordButton = new ButtonControl(tr("Tethering Password"), tr("EDIT")); connect(editPasswordButton, &ButtonControl::clicked, [=]() { @@ -226,19 +206,6 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid }); list->addItem(hiddenNetworkButton); - // Ngrok - QProcess process; - process.start("sudo service ngrok status | grep running"); - process.waitForFinished(); - QString output = QString(process.readAllStandardOutput()); - bool ngrokRunning = !output.isEmpty(); - ToggleControl *ngrokToggle = new ToggleControl(tr("Ngrok Service"), "", "", ngrokRunning); - connect(ngrokToggle, &ToggleControl::toggleFlipped, [=](bool state) { - if (state) std::system("sudo ngrok service start"); - else std::system("sudo ngrok service stop"); - }); - list->addItem(ngrokToggle); - // Set initial config wifi->updateGsmSettings(roamingEnabled, QString::fromStdString(params.get("GsmApn")), metered); @@ -260,14 +227,8 @@ void AdvancedNetworking::refresh() { } void AdvancedNetworking::toggleTethering(bool enabled) { - params.putBool("HotspotOnBootConfirmed", enabled); wifi->setTetheringEnabled(enabled); tetheringToggle->setEnabled(false); - - hotspotOnBootToggle->setEnabled(enabled); - if (!enabled) { - params.remove("HotspotOnBoot"); - } } // WifiUI functions @@ -419,4 +380,4 @@ void WifiItem::setItem(const Network &n, const QPixmap &status_icon, bool show_f iconLabel->setPixmap(status_icon); strengthLabel->setPixmap(strength_icon); -} +} \ No newline at end of file diff --git a/selfdrive/ui/qt/network/networking.h b/selfdrive/ui/qt/network/networking.h index 7444e9c28d..5831d66dc9 100644 --- a/selfdrive/ui/qt/network/networking.h +++ b/selfdrive/ui/qt/network/networking.h @@ -6,6 +6,13 @@ #include "selfdrive/ui/qt/widgets/input.h" #include "selfdrive/ui/qt/widgets/ssh_keys.h" #include "selfdrive/ui/qt/widgets/toggle.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#define LabelControl LabelControlSP +#define ElidedLabel ElidedLabelSP +#else +#include "selfdrive/ui/qt/widgets/controls.h" +#endif class WifiItem : public QWidget { Q_OBJECT @@ -67,8 +74,6 @@ private: WifiManager* wifi = nullptr; Params params; - ToggleControl* hotspotOnBootToggle; - signals: void backPress(); void requestWifiScreen(); @@ -100,4 +105,4 @@ public slots: private slots: void connectToNetwork(const Network n); void wrongPassword(const QString &ssid); -}; +}; \ No newline at end of file diff --git a/selfdrive/ui/qt/network/sunnylink/models/user_model.h b/selfdrive/ui/qt/network/sunnylink/models/user_model.h deleted file mode 100644 index 72baa3983d..0000000000 --- a/selfdrive/ui/qt/network/sunnylink/models/user_model.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef USER_MODEL_H -#define USER_MODEL_H - -#include - -class UserModel { -public: - QString device_id; - QString user_id; - qint64 created_at; - qint64 updated_at; - QString token_hash; - - explicit UserModel(const QJsonObject &json) { - device_id = json["device_id"].toString(); - user_id = json["user_id"].toString(); - created_at = json["created_at"].toInt(); - updated_at = json["updated_at"].toInt(); - token_hash = json["token_hash"].toString(); - } - - [[nodiscard]] QJsonObject toJson() const { - QJsonObject json; - json["device_id"] = device_id; - json["user_id"] = user_id; - json["created_at"] = created_at; - json["updated_at"] = updated_at; - json["token_hash"] = token_hash; - return json; - } -}; - -#endif diff --git a/selfdrive/ui/qt/network/sunnylink/services/base_device_service.cc b/selfdrive/ui/qt/network/sunnylink/services/base_device_service.cc deleted file mode 100644 index 2f2561a49a..0000000000 --- a/selfdrive/ui/qt/network/sunnylink/services/base_device_service.cc +++ /dev/null @@ -1,48 +0,0 @@ -#include "base_device_service.h" - -#include "common/swaglog.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.h" - -BaseDeviceService::BaseDeviceService(QObject* parent) : QObject(parent), initial_request(nullptr), repeater(nullptr) { - param_watcher = new ParamWatcher(this); - connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) { - paramsRefresh(); - }); - param_watcher->addParam("SunnylinkEnabled"); -} - -void BaseDeviceService::paramsRefresh() { -} - -void BaseDeviceService::loadDeviceData(const QString &url, bool poll) { - if (!is_sunnylink_enabled()) { - LOGW("Sunnylink is not enabled, refusing to load data."); - return; - } - - auto sl_dongle_id = getSunnylinkDongleId(); - if (!sl_dongle_id.has_value()) - return; - - QString fullUrl = SUNNYLINK_BASE_URL + "/device/" + *sl_dongle_id + url; - if (poll && !isCurrentyPolling()) { - LOGD("Polling %s", qPrintable(fullUrl)); - LOGD("Cache key: SunnylinkCache_%s", qPrintable(QString(getCacheKey()))); - repeater = new RequestRepeater(this, fullUrl, "SunnylinkCache_" + getCacheKey(), 60, false, true); - connect(repeater, &RequestRepeater::requestDone, this, &BaseDeviceService::handleResponse); - } else if(isCurrentyPolling()){ - repeater->ForceUpdate(); - } else { - LOGD("Sending one-time %s", qPrintable(fullUrl)); - initial_request = new HttpRequest(this, true, 10000, true); - connect(initial_request, &HttpRequest::requestDone, this, &BaseDeviceService::handleResponse); - } -} - -void BaseDeviceService::stopPolling() { - if (repeater != nullptr) { - repeater->deleteLater(); - repeater = nullptr; - } -} diff --git a/selfdrive/ui/qt/network/sunnylink/services/base_device_service.h b/selfdrive/ui/qt/network/sunnylink/services/base_device_service.h deleted file mode 100644 index cd7aa9d9b9..0000000000 --- a/selfdrive/ui/qt/network/sunnylink/services/base_device_service.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef BASESERVICE_H -#define BASESERVICE_H - - -#include "selfdrive/ui/qt/api.h" -#include "selfdrive/ui/qt/request_repeater.h" -#include "selfdrive/ui/qt/util.h" - -class BaseDeviceService : public QObject { - Q_OBJECT - -protected: - void paramsRefresh(); - void loadDeviceData(const QString &url, bool poll = false); - virtual void handleResponse(const QString &response, bool success) = 0; - - static bool is_sunnylink_enabled() { return Params().getBool("SunnylinkEnabled");}; - ParamWatcher* param_watcher; - HttpRequest* initial_request = nullptr; - RequestRepeater* repeater = nullptr; - -public: - explicit BaseDeviceService(QObject* parent = nullptr); - virtual QString getCacheKey() const = 0; - bool isCurrentyPolling() {return repeater != nullptr;} - void stopPolling(); -}; - -#endif diff --git a/selfdrive/ui/qt/network/sunnylink/services/role_service.cc b/selfdrive/ui/qt/network/sunnylink/services/role_service.cc deleted file mode 100644 index 8bd0904421..0000000000 --- a/selfdrive/ui/qt/network/sunnylink/services/role_service.cc +++ /dev/null @@ -1,29 +0,0 @@ -#include "selfdrive/ui/qt/network/sunnylink/services/role_service.h" - -#include -#include - -RoleService::RoleService(QObject* parent) : BaseDeviceService(parent) {} - -void RoleService::load() { - loadDeviceData(url); -} - -void RoleService::startPolling() { - loadDeviceData(url, true); -} - -void RoleService::handleResponse(const QString &response, bool success) { - if (!success) return; - - QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); - QJsonArray jsonArray = doc.array(); - - std::vector roles; - for (const auto &value : jsonArray) { - roles.emplace_back(value.toObject()); - } - - emit rolesReady(roles); - uiState()->setSunnylinkRoles(roles); -} diff --git a/selfdrive/ui/qt/network/sunnylink/services/role_service.h b/selfdrive/ui/qt/network/sunnylink/services/role_service.h deleted file mode 100644 index bc40342982..0000000000 --- a/selfdrive/ui/qt/network/sunnylink/services/role_service.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef ROLESERVICE_H -#define ROLESERVICE_H - -#include "selfdrive/ui/qt/network/sunnylink/services/base_device_service.h" -#include "selfdrive/ui/qt/network/sunnylink/models/role_model.h" - -class RoleService : public BaseDeviceService { - Q_OBJECT - -public: - explicit RoleService(QObject* parent = nullptr); - void load(); - void startPolling(); - [[nodiscard]] QString getCacheKey() const final { return "Roles"; }; - -signals: - void rolesReady(const std::vector &roles); - -protected: - void handleResponse(const QString&response, bool success) override; - -private: - QString url = "/roles"; -}; - -#endif diff --git a/selfdrive/ui/qt/network/sunnylink/services/user_service.cc b/selfdrive/ui/qt/network/sunnylink/services/user_service.cc deleted file mode 100644 index 2d52421d69..0000000000 --- a/selfdrive/ui/qt/network/sunnylink/services/user_service.cc +++ /dev/null @@ -1,31 +0,0 @@ -#include "selfdrive/ui/qt/network/sunnylink/services/user_service.h" - -#include -#include - -UserService::UserService(QObject* parent) : BaseDeviceService(parent) { - url = "/users"; -} - -void UserService::load() { - loadDeviceData(url); -} - -void UserService::startPolling() { - loadDeviceData(url, true); -} - -void UserService::handleResponse(const QString &response, bool success) { - if (!success) return; - - QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); - QJsonArray jsonArray = doc.array(); - - std::vector users; - for (const auto &value : jsonArray) { - users.emplace_back(value.toObject()); - } - - emit usersReady(users); - uiState()->setSunnylinkDeviceUsers(users); -} diff --git a/selfdrive/ui/qt/network/sunnylink/services/user_service.h b/selfdrive/ui/qt/network/sunnylink/services/user_service.h deleted file mode 100644 index e4af93fa29..0000000000 --- a/selfdrive/ui/qt/network/sunnylink/services/user_service.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef USERSERVICE_H -#define USERSERVICE_H - -#include "selfdrive/ui/qt/network/sunnylink/services/base_device_service.h" -#include "selfdrive/ui/qt/network/sunnylink/models/user_model.h" - -class UserService : public BaseDeviceService { - Q_OBJECT - -public: - explicit UserService(QObject* parent = nullptr); - void load(); - void startPolling(); - [[nodiscard]] QString getCacheKey() const final { return "Users"; }; - -signals: - void usersReady(const std::vector&users); - -protected: - void handleResponse(const QString&response, bool success) override; - -private: - QString url = "/users"; -}; - -#endif diff --git a/selfdrive/ui/qt/network/sunnylink/sunnylink_client.cc b/selfdrive/ui/qt/network/sunnylink/sunnylink_client.cc deleted file mode 100644 index 2d1613c0eb..0000000000 --- a/selfdrive/ui/qt/network/sunnylink/sunnylink_client.cc +++ /dev/null @@ -1,7 +0,0 @@ -#include "selfdrive/ui/qt/network/sunnylink/sunnylink_client.h" -#include "selfdrive/ui/qt/network/sunnylink/services/user_service.h" - -SunnylinkClient::SunnylinkClient(QObject* parent) : QObject(parent) { - role_service = new RoleService(parent); - user_service = new UserService(parent); -} diff --git a/selfdrive/ui/qt/network/sunnylink/sunnylink_client.h b/selfdrive/ui/qt/network/sunnylink/sunnylink_client.h deleted file mode 100644 index 872d80ccf7..0000000000 --- a/selfdrive/ui/qt/network/sunnylink/sunnylink_client.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef SUNNYLINK_CLIENT_H -#define SUNNYLINK_CLIENT_H - -#include - -#include "selfdrive/ui/qt/network/sunnylink/services/role_service.h" -#include "selfdrive/ui/qt/network/sunnylink/services/user_service.h" - -class SunnylinkClient : public QObject { - Q_OBJECT - -public: - explicit SunnylinkClient(QObject* parent); - RoleService* role_service; - UserService* user_service; -}; - -#endif diff --git a/selfdrive/ui/qt/network/wifi_manager.cc b/selfdrive/ui/qt/network/wifi_manager.cc index 717da47096..b12207fab5 100644 --- a/selfdrive/ui/qt/network/wifi_manager.cc +++ b/selfdrive/ui/qt/network/wifi_manager.cc @@ -2,7 +2,11 @@ #include +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/ui.h" +#else #include "selfdrive/ui/ui.h" +#endif #include "selfdrive/ui/qt/widgets/prime.h" #include "common/params.h" diff --git a/selfdrive/ui/qt/offroad/experimental_mode.cc b/selfdrive/ui/qt/offroad/experimental_mode.cc index b2c6f3323a..88fadd439b 100644 --- a/selfdrive/ui/qt/offroad/experimental_mode.cc +++ b/selfdrive/ui/qt/offroad/experimental_mode.cc @@ -7,13 +7,18 @@ #include #include "selfdrive/ui/ui.h" +#ifdef SUNNYPILOT +#define TOGGLES_PANEL_INDEX 3 +#else +#define TOGGLES_PANEL_INDEX 2 +#endif ExperimentalModeButton::ExperimentalModeButton(QWidget *parent) : QPushButton(parent) { chill_pixmap = QPixmap("../assets/img_couch.svg").scaledToWidth(img_width, Qt::SmoothTransformation); experimental_pixmap = QPixmap("../assets/img_experimental_grey.svg").scaledToWidth(img_width, Qt::SmoothTransformation); // go to toggles and expand experimental mode description - connect(this, &QPushButton::clicked, [=]() { emit openSettings(3, "ExperimentalMode"); }); + connect(this, &QPushButton::clicked, [=]() { emit openSettings(TOGGLES_PANEL_INDEX, "ExperimentalMode"); }); setFixedHeight(125); QHBoxLayout *main_layout = new QHBoxLayout; diff --git a/selfdrive/ui/qt/offroad/onboarding.cc b/selfdrive/ui/qt/offroad/onboarding.cc index 014e9a6f05..8bf92aa06b 100644 --- a/selfdrive/ui/qt/offroad/onboarding.cc +++ b/selfdrive/ui/qt/offroad/onboarding.cc @@ -106,8 +106,7 @@ void TermsPage::showEvent(QShowEvent *event) { text->setAttribute(Qt::WA_AlwaysStackOnTop); text->setClearColor(QColor("#1B1B1B")); - std::string tc_text = sunnypilot_tc ? "../assets/offroad/sp_tc.html" : "../assets/offroad/tc.html"; - QString text_view = util::read_file(tc_text).c_str(); + QString text_view = util::read_file("../assets/offroad/tc.html").c_str(); text->rootContext()->setContextProperty("text_view", text_view); text->setSource(QUrl::fromLocalFile("qt/offroad/text_view.qml")); @@ -186,8 +185,6 @@ void OnboardingWindow::updateActiveScreen() { setCurrentIndex(0); } else if (!training_done) { setCurrentIndex(1); - } else if (!accepted_terms_sp) { - setCurrentIndex(3); } else { emit onboardingDone(); } @@ -195,13 +192,11 @@ void OnboardingWindow::updateActiveScreen() { OnboardingWindow::OnboardingWindow(QWidget *parent) : QStackedWidget(parent) { std::string current_terms_version = params.get("TermsVersion"); - std::string current_terms_version_sp = params.get("TermsVersionSunnypilot"); std::string current_training_version = params.get("TrainingVersion"); accepted_terms = params.get("HasAcceptedTerms") == current_terms_version; - accepted_terms_sp = params.get("HasAcceptedTermsSP") == current_terms_version_sp; training_done = params.get("CompletedTrainingVersion") == current_training_version; - TermsPage* terms = new TermsPage(false, this); + TermsPage* terms = new TermsPage(this); addWidget(terms); connect(terms, &TermsPage::acceptedTerms, [=]() { params.put("HasAcceptedTerms", current_terms_version); @@ -222,15 +217,6 @@ OnboardingWindow::OnboardingWindow(QWidget *parent) : QStackedWidget(parent) { addWidget(declinePage); connect(declinePage, &DeclinePage::getBack, [=]() { updateActiveScreen(); }); - TermsPage* terms_sp = new TermsPage(true, this); - addWidget(terms_sp); // index = 3 - connect(terms_sp, &TermsPage::acceptedTerms, [=]() { - params.put("HasAcceptedTermsSP", current_terms_version_sp); - accepted_terms_sp = true; - updateActiveScreen(); - }); - connect(terms_sp, &TermsPage::declinedTerms, [=]() { setCurrentIndex(2); }); - setStyleSheet(R"( * { color: white; @@ -245,4 +231,4 @@ OnboardingWindow::OnboardingWindow(QWidget *parent) : QStackedWidget(parent) { } )"); updateActiveScreen(); -} +} \ No newline at end of file diff --git a/selfdrive/ui/qt/offroad/onboarding.h b/selfdrive/ui/qt/offroad/onboarding.h index 008d86032c..098b0823a7 100644 --- a/selfdrive/ui/qt/offroad/onboarding.h +++ b/selfdrive/ui/qt/offroad/onboarding.h @@ -63,16 +63,17 @@ class TermsPage : public QFrame { Q_OBJECT public: - explicit TermsPage(bool sunnypilot = false, QWidget *parent = 0) : QFrame(parent), sunnypilot_tc(sunnypilot) {} + explicit TermsPage(QWidget *parent = 0) : QFrame(parent) {} public slots: void enableAccept(); +protected: + QPushButton *accept_btn; + private: void showEvent(QShowEvent *event) override; - QPushButton *accept_btn; - bool sunnypilot_tc = false; signals: void acceptedTerms(); @@ -98,14 +99,14 @@ class OnboardingWindow : public QStackedWidget { public: explicit OnboardingWindow(QWidget *parent = 0); inline void showTrainingGuide() { setCurrentIndex(1); } - inline bool completed() const { return accepted_terms && accepted_terms_sp && training_done; } + virtual inline bool completed() const { return accepted_terms && training_done; } -private: - void updateActiveScreen(); +protected: + virtual void updateActiveScreen(); Params params; - bool accepted_terms = false, accepted_terms_sp = false, training_done = false; + bool accepted_terms = false, training_done = false; signals: void onboardingDone(); -}; +}; \ No newline at end of file diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index f9f852a3b4..040b074784 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -5,28 +5,29 @@ #include #include -#include -#include -#include #include "common/watchdog.h" #include "common/util.h" #include "selfdrive/ui/qt/network/networking.h" #include "selfdrive/ui/qt/offroad/settings.h" -#include "selfdrive/ui/qt/offroad/sunnypilot_main.h" #include "selfdrive/ui/qt/qt_window.h" #include "selfdrive/ui/qt/widgets/prime.h" #include "selfdrive/ui/qt/widgets/scrollview.h" #include "selfdrive/ui/qt/widgets/ssh_keys.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/sunnypilot_main.h" +#endif TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { + RETURN_IF_SUNNYPILOT + // param, title, desc, icon std::vector> toggle_defs{ { "OpenpilotEnabledToggle", tr("Enable sunnypilot"), tr("Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off."), - "../assets/offroad/icon_blank.png", + "../assets/offroad/icon_openpilot.png", }, { "ExperimentalLongitudinalEnabled", @@ -35,105 +36,54 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { .arg(tr("WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).")) .arg(tr("On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. " "Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.")), - "../assets/offroad/icon_blank.png", - }, - { - "CustomStockLong", - tr("Custom Stock Longitudinal Control"), - tr("When enabled, sunnypilot will attempt to control stock longitudinal control with ACC button presses.\nThis feature must be used along with SLC, and/or V-TSC, and/or M-TSC."), - "../assets/offroad/icon_blank.png", + "../assets/offroad/icon_speed_limit.png", }, { "ExperimentalMode", tr("Experimental Mode"), "", - "../assets/offroad/icon_blank.png", - }, - { - "DynamicExperimentalControl", - tr("Enable Dynamic Experimental Control"), - tr("Enable toggle to allow the model to determine when to use openpilot ACC or openpilot End to End Longitudinal."), - "../assets/offroad/icon_blank.png", - }, - { - "DynamicPersonality", - tr("Enable Dynamic Personality"), - tr("Enable this to allow sunnypilot to dynamically adjust following distance and reaction based on your \"Driving Personality\" setting. " - "Instead of predefined settings for each personality, every personality now adapts dynamically according to your speed and the distance to the lead car."), - "../assets/offroad/icon_blank.png", + "../assets/img_experimental_white.svg", }, { "DisengageOnAccelerator", tr("Disengage on Accelerator Pedal"), tr("When enabled, pressing the accelerator pedal will disengage openpilot."), - "../assets/offroad/icon_blank.png", + "../assets/offroad/icon_disengage_on_accelerator.svg", }, { "IsLdwEnabled", tr("Enable Lane Departure Warnings"), tr("Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h)."), - "../assets/offroad/icon_blank.png", + "../assets/offroad/icon_warning.png", }, { "AlwaysOnDM", tr("Always-On Driver Monitoring"), tr("Enable driver monitoring even when openpilot is not engaged."), - "../assets/offroad/icon_blank.png", + "../assets/offroad/icon_monitoring.png", }, { "RecordFront", tr("Record and Upload Driver Camera"), tr("Upload data from the driver facing camera and help improve the driver monitoring algorithm."), - "../assets/offroad/icon_blank.png", - }, - { - "DisableOnroadUploads", - tr("Disable Onroad Uploads"), - tr("Disable uploads completely when onroad. Necessary to avoid high data usage when connected to Wi-Fi hotspot. Turn on this feature if you are looking to utilize map-based features, such as Speed Limit Control (SLC) and Map-based Turn Speed Control (MTSC)."), - "../assets/offroad/icon_blank.png", + "../assets/offroad/icon_monitoring.png", }, { "IsMetric", tr("Use Metric System"), tr("Display speed in km/h instead of mph."), - "../assets/offroad/icon_blank.png", + "../assets/offroad/icon_metric.png", }, -#ifdef ENABLE_MAPS - { - "NavSettingTime24h", - tr("Show ETA in 24h Format"), - tr("Use 24h format instead of am/pm"), - "../assets/offroad/icon_blank.png", - }, - { - "NavSettingLeftSide", - tr("Show Map on Left Side of UI"), - tr("Show map on left side when in split screen view."), - "../assets/offroad/icon_blank.png", - }, -#endif }; - std::vector longi_button_texts{tr("Aggressive"), tr("Moderate"), tr("Standard"), tr("Relaxed")}; + std::vector longi_button_texts{tr("Aggressive"), tr("Standard"), tr("Relaxed")}; long_personality_setting = new ButtonParamControl("LongitudinalPersonality", tr("Driving Personality"), - tr("Standard is recommended. In moderate/aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. " + tr("Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. " "In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with " "your steering wheel distance button."), - "../assets/offroad/icon_blank.png", - longi_button_texts, - 380); - long_personality_setting->showDescription(); - - // accel controller - std::vector accel_personality_texts{tr("Sport"), tr("Normal"), tr("Eco"), tr("Stock")}; - accel_personality_setting = new ButtonParamControl("AccelPersonality", tr("Acceleration Personality"), - tr("Normal is recommended. In sport mode, sunnypilot will provide aggressive acceleration for a dynamic driving experience. " - "In eco mode, sunnypilot will apply smoother and more relaxed acceleration. On supported cars, you can cycle through these " - "acceleration personality within Onroad Settings on the driving screen."), - "../assets/offroad/icon_blank.png", - accel_personality_texts); - accel_personality_setting->showDescription(); + "../assets/offroad/icon_speed_limit.png", + longi_button_texts); // set up uiState update for personality setting QObject::connect(uiState(), &UIState::uiUpdate, this, &TogglesPanel::updateState); @@ -150,28 +100,17 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { // insert longitudinal personality after NDOG toggle if (param == "DisengageOnAccelerator") { addItem(long_personality_setting); - addItem(accel_personality_setting); } } // Toggles with confirmation dialogs - //toggles["ExperimentalMode"]->setActiveIcon("../assets/img_experimental.svg"); + toggles["ExperimentalMode"]->setActiveIcon("../assets/img_experimental.svg"); toggles["ExperimentalMode"]->setConfirmation(true, true); toggles["ExperimentalLongitudinalEnabled"]->setConfirmation(true, false); - toggles["CustomStockLong"]->setConfirmation(true, false); connect(toggles["ExperimentalLongitudinalEnabled"], &ToggleControl::toggleFlipped, [=]() { updateToggles(); }); - connect(toggles["CustomStockLong"], &ToggleControl::toggleFlipped, [=]() { - updateToggles(); - }); - - param_watcher = new ParamWatcher(this); - - QObject::connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) { - updateToggles(); - }); } void TogglesPanel::updateState(const UIState &s) { @@ -184,14 +123,6 @@ void TogglesPanel::updateState(const UIState &s) { } uiState()->scene.personality = personality; } - - if (sm.updated("controlsStateSP")) { - auto accel_personality = sm["controlsStateSP"].getControlsStateSP().getAccelPersonality(); - if (accel_personality != s.scene.accel_personality && s.scene.started && isVisible()) { - accel_personality_setting->setCheckedButton(static_cast(accel_personality)); - } - uiState()->scene.accel_personality = accel_personality; - } } void TogglesPanel::expandToggleDescription(const QString ¶m) { @@ -203,15 +134,8 @@ void TogglesPanel::showEvent(QShowEvent *event) { } void TogglesPanel::updateToggles() { - param_watcher->addParam("LongitudinalPersonality"); - - if (!isVisible()) return; - auto experimental_mode_toggle = toggles["ExperimentalMode"]; auto op_long_toggle = toggles["ExperimentalLongitudinalEnabled"]; - auto custom_stock_long_toggle = toggles["CustomStockLong"]; - auto dec_toggle = toggles["DynamicExperimentalControl"]; - auto dynamic_personality_toggle = toggles["DynamicPersonality"]; const QString e2e_description = QString("%1
" "

%2


" "%3
" @@ -236,35 +160,15 @@ void TogglesPanel::updateToggles() { params.remove("ExperimentalLongitudinalEnabled"); } op_long_toggle->setVisible(CP.getExperimentalLongitudinalAvailable() && !is_release); - - if (!CP.getCustomStockLongAvailable()) { - params.remove("CustomStockLong"); - } - custom_stock_long_toggle->setVisible(CP.getCustomStockLongAvailable()); - if (hasLongitudinalControl(CP)) { // normal description and toggle experimental_mode_toggle->setEnabled(true); experimental_mode_toggle->setDescription(e2e_description); long_personality_setting->setEnabled(true); - accel_personality_setting->setEnabled(true); - op_long_toggle->setEnabled(true); - custom_stock_long_toggle->setEnabled(false); - params.remove("CustomStockLong"); - dec_toggle->setEnabled(true); - dynamic_personality_toggle->setEnabled(true); - } else if (custom_stock_long_toggle->isToggled()) { - op_long_toggle->setEnabled(false); - experimental_mode_toggle->setEnabled(false); - long_personality_setting->setEnabled(false); - accel_personality_setting->setEnabled(false); - params.remove("ExperimentalLongitudinalEnabled"); - params.remove("ExperimentalMode"); } else { // no long for now experimental_mode_toggle->setEnabled(false); long_personality_setting->setEnabled(false); - accel_personality_setting->setEnabled(false); params.remove("ExperimentalMode"); const QString unavailable = tr("Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control."); @@ -279,26 +183,12 @@ void TogglesPanel::updateToggles() { } } experimental_mode_toggle->setDescription("" + long_desc + "

" + e2e_description); - - op_long_toggle->setEnabled(CP.getExperimentalLongitudinalAvailable() && !is_release); - custom_stock_long_toggle->setEnabled(CP.getCustomStockLongAvailable()); - dec_toggle->setEnabled(false); - dynamic_personality_toggle->setEnabled(false); - params.remove("DynamicExperimentalControl"); - params.remove("DynamicPersonality"); } experimental_mode_toggle->refresh(); - op_long_toggle->refresh(); - custom_stock_long_toggle->refresh(); - dec_toggle->refresh(); - dynamic_personality_toggle->refresh(); } else { experimental_mode_toggle->setDescription(e2e_description); op_long_toggle->setVisible(false); - custom_stock_long_toggle->setVisible(false); - dec_toggle->setVisible(false); - dynamic_personality_toggle->setVisible(false); } } @@ -307,44 +197,6 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) { addItem(new LabelControl(tr("Dongle ID"), getDongleId().value_or(tr("N/A")))); addItem(new LabelControl(tr("Serial"), params.get("HardwareSerial").c_str())); - fleetManagerPin = new ButtonControl( - pin_title + pin, tr("TOGGLE"), - tr("Enable or disable PIN requirement for Fleet Manager access.")); - connect(fleetManagerPin, &ButtonControl::clicked, [=]() { - if (params.getBool("FleetManagerPin")) { - if (ConfirmationDialog::confirm(tr("Are you sure you want to turn off PIN requirement?"), tr("Turn Off"), this)) { - params.remove("FleetManagerPin"); - refreshPin(); - } - } else { - params.putBool("FleetManagerPin", true); - refreshPin(); - } - }); - addItem(fleetManagerPin); - - fs_watch = new QFileSystemWatcher(this); - connect(fs_watch, &QFileSystemWatcher::fileChanged, this, &DevicePanel::onPinFileChanged); - - QString pin_path = "/data/otp/otp.conf"; - QString pin_require = "/data/params/d/FleetManagerPin"; - fs_watch->addPath(pin_path); - fs_watch->addPath(pin_require); - refreshPin(); - - // Error Troubleshoot - auto errorBtn = new ButtonControl( - tr("Error Troubleshoot"), tr("VIEW"), - tr("Display error from the tmux session when an error has occurred from a system process.")); - QFileInfo file("/data/community/crashes/error.txt"); - QDateTime modifiedTime = file.lastModified(); - QString modified_time = modifiedTime.toString("yyyy-MM-dd hh:mm:ss "); - connect(errorBtn, &ButtonControl::clicked, [=]() { - const std::string txt = util::read_file("/data/community/crashes/error.txt"); - ConfirmationDialog::rich(modified_time + QString::fromStdString(txt), this); - }); - addItem(errorBtn); - pair_device = new ButtonControl(tr("Pair Device"), tr("PAIR"), tr("Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer.")); connect(pair_device, &ButtonControl::clicked, [=]() { @@ -370,33 +222,7 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) { }); addItem(resetCalibBtn); - auto resetMapboxTokenBtn = new ButtonControl(tr("Reset Access Tokens for Map Services"), tr("RESET"), tr("Reset self-service access tokens for Mapbox, Amap, and Google Maps.")); - connect(resetMapboxTokenBtn, &ButtonControl::clicked, [=]() { - if (ConfirmationDialog::confirm(tr("Are you sure you want to reset access tokens for all map services?"), tr("Reset"), this)) { - std::vector tokens = { - "CustomMapboxTokenPk", - "CustomMapboxTokenSk", - "AmapKey1", - "AmapKey2", - "GmapKey" - }; - for (const auto& token : tokens) { - params.remove(token); - } - } - }); - addItem(resetMapboxTokenBtn); - - auto resetParamsBtn = new ButtonControl(tr("Reset sunnypilot Settings"), tr("RESET"), ""); - connect(resetParamsBtn, &ButtonControl::clicked, [=]() { - if (ConfirmationDialog::confirm(tr("Are you sure you want to reset all sunnypilot settings?"), tr("Reset"), this)) { - std::system("sudo rm -rf /data/params/d/*"); - Hardware::reboot(); - } - }); - addItem(resetParamsBtn); - - auto retrainingBtn = new ButtonControl(tr("Review Training Guide"), tr("REVIEW"), tr("Review the rules, features, and limitations of sunnypilot")); + auto retrainingBtn = new ButtonControl(tr("Review Training Guide"), tr("REVIEW"), tr("Review the rules, features, and limitations of openpilot")); connect(retrainingBtn, &ButtonControl::clicked, [=]() { if (ConfirmationDialog::confirm(tr("Are you sure you want to review the training guide?"), tr("Review"), this)) { emit reviewTrainingGuide(); @@ -429,16 +255,19 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) { QObject::connect(uiState(), &UIState::primeTypeChanged, [this] (PrimeType type) { pair_device->setVisible(type == PrimeType::UNPAIRED); }); + +#ifndef SUNNYPILOT QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { for (auto btn : findChildren()) { - if ((btn != pair_device) && (btn != errorBtn)) { + if (btn != pair_device) { btn->setEnabled(offroad); } } }); +#endif // power buttons - QHBoxLayout *power_layout = new QHBoxLayout(); + power_layout = new QHBoxLayout(); power_layout->setSpacing(30); QPushButton *reboot_btn = new QPushButton(tr("Reboot")); @@ -455,46 +284,14 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) { connect(uiState(), &UIState::offroadTransition, poweroff_btn, &QPushButton::setVisible); } - offroad_btn = new QPushButton(tr("Toggle Onroad/Offroad")); - offroad_btn->setObjectName("offroad_btn"); - QObject::connect(offroad_btn, &QPushButton::clicked, this, &DevicePanel::forceoffroad); - - QVBoxLayout *buttons_layout = new QVBoxLayout(); - buttons_layout->setSpacing(24); - buttons_layout->addLayout(power_layout); - buttons_layout->addWidget(offroad_btn); - setStyleSheet(R"( #reboot_btn { height: 120px; border-radius: 15px; background-color: #393939; } #reboot_btn:pressed { background-color: #4a4a4a; } #poweroff_btn { height: 120px; border-radius: 15px; background-color: #E22C2C; } #poweroff_btn:pressed { background-color: #FF2424; } )"); - addItem(buttons_layout); - - updateLabels(); -} - -void DevicePanel::onPinFileChanged(const QString &file_path) { - if (file_path == "/data/params/d/FleetManagerPin") { - refreshPin(); - } else if (file_path == "/data/otp/otp.conf") { - refreshPin(); - } -} - -void DevicePanel::refreshPin() { - QFile f("/data/otp/otp.conf"); - QFile require("/data/params/d/FleetManagerPin"); - if (!require.exists()) { - setSpacing(50); - fleetManagerPin->setTitle(pin_title + tr("OFF")); - } else if (f.open(QIODevice::ReadOnly | QIODevice::Text)) { - pin = f.readAll(); - f.close(); - setSpacing(50); - fleetManagerPin->setTitle(pin_title + pin); - } + RETURN_IF_SUNNYPILOT + addItem(power_layout); } void DevicePanel::updateCalibDescription() { @@ -547,51 +344,9 @@ void DevicePanel::poweroff() { } } -void DevicePanel::forceoffroad() { - if (!uiState()->engaged()) { - if (params.getBool("ForceOffroad")) { - if (ConfirmationDialog::confirm(tr("Are you sure you want to unforce offroad?"), tr("Unforce"), this)) { - // Check engaged again in case it changed while the dialog was open - if (!uiState()->engaged()) { - params.remove("ForceOffroad"); - } - } - } else { - if (ConfirmationDialog::confirm(tr("Are you sure you want to force offroad?"), tr("Force"), this)) { - // Check engaged again in case it changed while the dialog was open - if (!uiState()->engaged()) { - params.putBool("ForceOffroad", true); - } - } - } - } else { - ConfirmationDialog::alert(tr("Disengage to Force Offroad"), this); - } - - updateLabels(); -} - void DevicePanel::showEvent(QShowEvent *event) { pair_device->setVisible(uiState()->primeType() == PrimeType::UNPAIRED); ListWidget::showEvent(event); - updateLabels(); -} - -void DevicePanel::updateLabels() { - if (!isVisible()) { - return; - } - - bool force_offroad_param = params.getBool("ForceOffroad"); - QString offroad_btn_style = force_offroad_param ? "#393939" : "#E22C2C"; - QString offroad_btn_pressed_style = force_offroad_param ? "#4a4a4a" : "#FF2424"; - QString btn_common_style = QString("QPushButton { height: 120px; border-radius: 15px; background-color: %1; }" - "QPushButton:pressed { background-color: %2; }") - .arg(offroad_btn_style, - offroad_btn_pressed_style); - - offroad_btn->setText(force_offroad_param ? tr("Unforce Offroad") : tr("Force Offroad")); - offroad_btn->setStyleSheet(btn_common_style + offroad_btn_style + offroad_btn_pressed_style); } void SettingsWindow::showEvent(QShowEvent *event) { @@ -607,23 +362,20 @@ void SettingsWindow::setCurrentPanel(int index, const QString ¶m) { } SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { + RETURN_IF_SUNNYPILOT // setup two main layouts sidebar_widget = new QWidget; QVBoxLayout *sidebar_layout = new QVBoxLayout(sidebar_widget); panel_widget = new QStackedWidget(); - // setup layout for close button - QVBoxLayout *close_btn_layout = new QVBoxLayout; - close_btn_layout->setContentsMargins(0, 0, 0, 20); - // close button QPushButton *close_btn = new QPushButton(tr("×")); close_btn->setStyleSheet(R"( QPushButton { font-size: 140px; padding-bottom: 20px; - border-radius: 76px; + border-radius: 100px; background-color: #292929; font-weight: 400; } @@ -631,16 +383,11 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { background-color: #3B3B3B; } )"); - close_btn->setFixedSize(152, 152); - close_btn_layout->addWidget(close_btn, 0, Qt::AlignLeft); + close_btn->setFixedSize(200, 200); + sidebar_layout->addSpacing(45); + sidebar_layout->addWidget(close_btn, 0, Qt::AlignCenter); QObject::connect(close_btn, &QPushButton::clicked, this, &SettingsWindow::closeSettings); - // setup buttons widget - QWidget *buttons_widget = new QWidget; - QVBoxLayout *buttons_layout = new QVBoxLayout(buttons_widget); - buttons_layout->setMargin(0); - buttons_layout->addSpacing(10); - // setup panels DevicePanel *device = new DevicePanel(this); QObject::connect(device, &DevicePanel::reviewTrainingGuide, this, &SettingsWindow::reviewTrainingGuide); @@ -649,43 +396,27 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { TogglesPanel *toggles = new TogglesPanel(this); QObject::connect(this, &SettingsWindow::expandToggleDescription, toggles, &TogglesPanel::expandToggleDescription); - QList panels = { - PanelInfo(" " + tr("Device"), device, "../assets/navigation/icon_home.svg"), - PanelInfo(" " + tr("Network"), new Networking(this), "../assets/offroad/icon_network.png"), - PanelInfo(" " + tr("sunnylink"), new SunnylinkPanel(this), "../assets/offroad/icon_wifi_strength_full.svg"), - PanelInfo(" " + tr("Toggles"), toggles, "../assets/offroad/icon_toggle.png"), - PanelInfo(" " + tr("Software"), new SoftwarePanelSP(this), "../assets/offroad/icon_software.png"), - PanelInfo(" " + tr("sunnypilot"), new SunnypilotPanel(this), "../assets/offroad/icon_openpilot.png"), - PanelInfo(" " + tr("OSM"), new OsmPanel(this), "../assets/offroad/icon_map.png"), - PanelInfo(" " + tr("Monitoring"), new MonitoringPanel(this), "../assets/offroad/icon_monitoring.png"), - PanelInfo(" " + tr("Visuals"), new VisualsPanel(this), "../assets/offroad/icon_visuals.png"), - PanelInfo(" " + tr("Display"), new DisplayPanel(this), "../assets/offroad/icon_display.png"), - PanelInfo(" " + tr("Trips"), new TripsPanel(this), "../assets/offroad/icon_trips.png"), - PanelInfo(" " + tr("Vehicle"), new VehiclePanel(this), "../assets/offroad/icon_vehicle.png"), + QList> panels = { + {tr("Device"), device}, + {tr("Network"), new Networking(this)}, + {tr("Toggles"), toggles}, + {tr("Software"), new SoftwarePanel(this)}, }; nav_btns = new QButtonGroup(this); - for (auto &[name, panel, icon] : panels) { + for (auto &[name, panel] : panels) { QPushButton *btn = new QPushButton(name); btn->setCheckable(true); btn->setChecked(nav_btns->buttons().size() == 0); - btn->setIcon(QIcon(QPixmap(icon))); - btn->setIconSize(QSize(70, 70)); btn->setStyleSheet(R"( QPushButton { - border-radius: 20px; - width: 400px; - height: 98px; - color: #bdbdbd; + color: grey; border: none; background: none; - font-size: 50px; + font-size: 65px; font-weight: 500; - text-align: left; - padding-left: 22px; } QPushButton:checked { - background-color: #696868; color: white; } QPushButton:pressed { @@ -694,9 +425,9 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { )"); btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); nav_btns->addButton(btn); - buttons_layout->addWidget(btn, 0, Qt::AlignLeft | Qt::AlignBottom); + sidebar_layout->addWidget(btn, 0, Qt::AlignRight); - const int lr_margin = (name != (" " + tr("Network")) || (name != (" " + tr("sunnypilot")))) ? 50 : 0; // Network and sunnypilot panel handles its own margins + const int lr_margin = name != tr("Network") ? 50 : 0; // Network panel handles its own margins panel->setContentsMargins(lr_margin, 25, lr_margin, 25); ScrollView *panel_frame = new ScrollView(panel, this); @@ -707,18 +438,11 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { panel_widget->setCurrentWidget(w); }); } - sidebar_layout->setContentsMargins(50, 50, 25, 50); + sidebar_layout->setContentsMargins(50, 50, 100, 50); // main settings layout, sidebar + main panel QHBoxLayout *main_layout = new QHBoxLayout(this); - // add layout for close button - sidebar_layout->addLayout(close_btn_layout); - - // add layout for buttons scrolling - ScrollView *buttons_scrollview = new ScrollView(buttons_widget, this); - sidebar_layout->addWidget(buttons_scrollview); - sidebar_widget->setFixedWidth(500); main_layout->addWidget(sidebar_widget); main_layout->addWidget(panel_widget); @@ -732,7 +456,7 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { background-color: black; } QStackedWidget, ScrollView { - background-color: black; + background-color: #292929; border-radius: 30px; } )"); diff --git a/selfdrive/ui/qt/offroad/settings.h b/selfdrive/ui/qt/offroad/settings.h index 06fbe8bfb9..dcc07aa2f2 100644 --- a/selfdrive/ui/qt/offroad/settings.h +++ b/selfdrive/ui/qt/offroad/settings.h @@ -8,12 +8,23 @@ #include #include #include -#include #include -#include "selfdrive/ui/ui.h" #include "selfdrive/ui/qt/util.h" + +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#define ListWidget ListWidgetSP +#define ParamControl ParamControlSP +#define ButtonControl ButtonControlSP +#define ButtonParamControl ButtonParamControlSP +#define ToggleControl ToggleControlSP +#define LabelControl LabelControlSP +#else +#include "selfdrive/ui/ui.h" #include "selfdrive/ui/qt/widgets/controls.h" +#endif // ********** settings window + top-level panels ********** class SettingsWindow : public QFrame { @@ -32,19 +43,11 @@ signals: void showDriverView(); void expandToggleDescription(const QString ¶m); -private: +protected: QPushButton *sidebar_alert_widget; QWidget *sidebar_widget; QButtonGroup *nav_btns; QStackedWidget *panel_widget; - - struct PanelInfo { - QString name; - QWidget *widget; - QString icon; - - PanelInfo(const QString &name, QWidget *widget, const QString &icon) : name(name), widget(widget), icon(icon) {} - }; }; class DevicePanel : public ListWidget { @@ -57,26 +60,15 @@ signals: void reviewTrainingGuide(); void showDriverView(); -private slots: +protected slots: void poweroff(); void reboot(); void updateCalibDescription(); - void onPinFileChanged(const QString &file_path); - void refreshPin(); - void forceoffroad(); - void updateLabels(); - -private: +protected: Params params; ButtonControl *pair_device; - - ButtonControl *fleetManagerPin; - QString pin_title = tr("Fleet Manager PIN:") + " "; - QString pin = "OFF"; - QFileSystemWatcher *fs_watch; - - QPushButton *offroad_btn; + QHBoxLayout *power_layout; }; class TogglesPanel : public ListWidget { @@ -87,18 +79,16 @@ public: public slots: void expandToggleDescription(const QString ¶m); - void updateToggles(); -private slots: - void updateState(const UIState &s); +protected slots: + virtual void updateState(const UIState &s); -private: +protected: Params params; std::map toggles; ButtonParamControl *long_personality_setting; - ButtonParamControl *accel_personality_setting; - ParamWatcher *param_watcher; + virtual void updateToggles(); }; class SoftwarePanel : public ListWidget { @@ -114,7 +104,6 @@ protected: bool is_onroad = false; QLabel *onroadLbl; - LabelControl *currentModelLbl; LabelControl *versionLbl; ButtonControl *installBtn; ButtonControl *downloadBtn; diff --git a/selfdrive/ui/qt/offroad/software_settings.cc b/selfdrive/ui/qt/offroad/software_settings.cc index 685ca3555d..47b4a22682 100644 --- a/selfdrive/ui/qt/offroad/software_settings.cc +++ b/selfdrive/ui/qt/offroad/software_settings.cc @@ -9,22 +9,27 @@ #include "common/params.h" #include "common/util.h" -#include "common/model.h" #include "selfdrive/ui/ui.h" #include "selfdrive/ui/qt/util.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#else #include "selfdrive/ui/qt/widgets/controls.h" +#endif #include "selfdrive/ui/qt/widgets/input.h" #include "system/hardware/hw.h" +#ifdef SUNNYPILOT +#define ListWidget ListWidgetSP +#define ButtonControl ButtonControlSP +#endif + void SoftwarePanel::checkForUpdates() { std::system("pkill -SIGUSR1 -f system.updated.updated"); } SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) { - currentModelLbl = new LabelControl(tr("Driving Model"), CURRENT_MODEL); - addItem(currentModelLbl); - onroadLbl = new QLabel(tr("Updates are only downloaded while the car is off.")); onroadLbl->setStyleSheet("font-size: 50px; font-weight: 400; text-align: left; padding-top: 30px; padding-bottom: 30px;"); addItem(onroadLbl); @@ -74,7 +79,9 @@ SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) { checkForUpdates(); } }); - addItem(targetBranchBtn); + if (!params.getBool("IsTestedBranch")) { + addItem(targetBranchBtn); + } // uninstall button auto uninstallBtn = new ButtonControl(tr("Uninstall %1").arg(getBrand()), tr("UNINSTALL")); diff --git a/selfdrive/ui/qt/offroad/sunnypilot/custom_offsets_settings.h b/selfdrive/ui/qt/offroad/sunnypilot/custom_offsets_settings.h deleted file mode 100644 index 63a5a817be..0000000000 --- a/selfdrive/ui/qt/offroad/sunnypilot/custom_offsets_settings.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" - -class CameraOffset : public SPOptionControl { - Q_OBJECT - -public: - CameraOffset(); - - void refresh(); - -private: - Params params; -}; - -class PathOffset : public SPOptionControl { - Q_OBJECT - -public: - PathOffset(); - - void refresh(); - -private: - Params params; -}; - -class CustomOffsetsSettings : public QWidget { - Q_OBJECT - -public: - explicit CustomOffsetsSettings(QWidget* parent = nullptr); - -signals: - void backPress(); - -private: - Params params; - std::map toggles; - - CameraOffset *camera_offset; - PathOffset *path_offset; -}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/display_settings.h b/selfdrive/ui/qt/offroad/sunnypilot/display_settings.h deleted file mode 100644 index b8083b53fc..0000000000 --- a/selfdrive/ui/qt/offroad/sunnypilot/display_settings.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include "selfdrive/ui/qt/widgets/controls.h" - -class OnroadScreenOff : public SPOptionControl { - Q_OBJECT - -public: - OnroadScreenOff(); - - void refresh(); - -private: - Params params; -}; - -class OnroadScreenOffBrightness : public SPOptionControl { - Q_OBJECT - -public: - OnroadScreenOffBrightness(); - - void refresh(); - -private: - Params params; -}; - -class MaxTimeOffroad : public SPOptionControl { - Q_OBJECT - -public: - MaxTimeOffroad(); - - void refresh(); - -private: - Params params; -}; - -class BrightnessControl : public SPOptionControl { - Q_OBJECT - -public: - BrightnessControl(); - - void refresh(); - -private: - Params params; -}; - -class DisplayPanel : public ListWidget { - Q_OBJECT - -public: - explicit DisplayPanel(QWidget *parent = nullptr); - void showEvent(QShowEvent *event) override; - -public slots: - void updateToggles(); - -private: - Params params; - std::map toggles; - - OnroadScreenOff *onroad_screen_off; - OnroadScreenOffBrightness *onroad_screen_off_brightness; -}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/json_fetcher.h b/selfdrive/ui/qt/offroad/sunnypilot/json_fetcher.h deleted file mode 100644 index f82041e36e..0000000000 --- a/selfdrive/ui/qt/offroad/sunnypilot/json_fetcher.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once -#include -#include -#include -#include - -class JsonFetcher -{ -public: - static QJsonObject getJsonFromURL(const QString &url) - { - const auto qurl = QUrl(url); - QNetworkAccessManager manager; - const QNetworkRequest request(qurl); - QNetworkReply *reply = manager.get(request); - QEventLoop loop; - - // Send GET request - - QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); - loop.exec(); - - if (reply->error() != QNetworkReply::NoError) { - qWarning() << "Failed to fetch data from URL: " << reply->errorString(); - return QJsonObject(); - } - - const QByteArray responseData = reply->readAll(); - const QJsonDocument doc = QJsonDocument::fromJson(responseData); - QJsonObject json = doc.object(); - - reply->deleteLater(); - return json; - } -}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/lane_change_settings.h b/selfdrive/ui/qt/offroad/sunnypilot/lane_change_settings.h deleted file mode 100644 index dd8e1748bd..0000000000 --- a/selfdrive/ui/qt/offroad/sunnypilot/lane_change_settings.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" - -class AutoLaneChangeTimer : public SPOptionControl { - Q_OBJECT - -public: - AutoLaneChangeTimer(); - - void refresh(); - -signals: - void toggleUpdated(); - -private: - Params params; -}; - -class PauseLateralSpeed : public SPOptionControl { - Q_OBJECT - -public: - PauseLateralSpeed(); - - void refresh(); - - signals: - void ToggleUpdated(); - -private: - Params params; -}; - - -class LaneChangeSettings : public QWidget { - Q_OBJECT - -public: - explicit LaneChangeSettings(QWidget* parent = nullptr); - void showEvent(QShowEvent *event) override; - -signals: - void backPress(); - -public slots: - void updateToggles(); - -private: - Params params; - std::map toggles; - - AutoLaneChangeTimer *auto_lane_change_timer; - PauseLateralSpeed *pause_lateral_speed; -}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/mads_settings.h b/selfdrive/ui/qt/offroad/sunnypilot/mads_settings.h deleted file mode 100644 index 2a949c97a4..0000000000 --- a/selfdrive/ui/qt/offroad/sunnypilot/mads_settings.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" - -class MadsSettings : public QWidget { - Q_OBJECT - -public: - explicit MadsSettings(QWidget* parent = nullptr); - void showEvent(QShowEvent *event) override; - -signals: - void backPress(); - -public slots: - void updateToggles(); - -private: - Params params; - std::map toggles; - - ButtonParamControl *dlob_settings; -}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/monitoring_settings.cc b/selfdrive/ui/qt/offroad/sunnypilot/monitoring_settings.cc deleted file mode 100644 index e2a410f9ff..0000000000 --- a/selfdrive/ui/qt/offroad/sunnypilot/monitoring_settings.cc +++ /dev/null @@ -1,30 +0,0 @@ -#include "selfdrive/ui/qt/offroad/sunnypilot/monitoring_settings.h" - -MonitoringPanel::MonitoringPanel(QWidget *parent) : QFrame(parent) { - main_layout = new QStackedLayout(this); - - ListWidget *list = new ListWidget(this, false); - // param, title, desc, icon - std::vector> toggle_defs{ - { - "HandsOnWheelMonitoring", - tr("Enable Hands on Wheel Monitoring"), - tr("Monitor and alert when driver is not keeping the hands on the steering wheel."), - "../assets/offroad/icon_blank.png", - } - }; - - for (auto &[param, title, desc, icon] : toggle_defs) { - auto toggle = new ParamControl(param, title, desc, icon, this); - - list->addItem(toggle); - toggles[param.toStdString()] = toggle; - } - - monitoringScreen = new QWidget(this); - QVBoxLayout* vlayout = new QVBoxLayout(monitoringScreen); - vlayout->setContentsMargins(50, 20, 50, 20); - - vlayout->addWidget(new ScrollView(list, this), 1); - main_layout->addWidget(monitoringScreen); -} diff --git a/selfdrive/ui/qt/offroad/sunnypilot/monitoring_settings.h b/selfdrive/ui/qt/offroad/sunnypilot/monitoring_settings.h deleted file mode 100644 index 214d2f8ac0..0000000000 --- a/selfdrive/ui/qt/offroad/sunnypilot/monitoring_settings.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" - -class MonitoringPanel : public QFrame { - Q_OBJECT - -public: - explicit MonitoringPanel(QWidget *parent = nullptr); - -private: - QStackedLayout* main_layout = nullptr; - QWidget* monitoringScreen = nullptr; - Params params; - std::map toggles; -}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/speed_limit_policy_settings.cc b/selfdrive/ui/qt/offroad/sunnypilot/speed_limit_policy_settings.cc deleted file mode 100644 index 2de70e9b30..0000000000 --- a/selfdrive/ui/qt/offroad/sunnypilot/speed_limit_policy_settings.cc +++ /dev/null @@ -1,51 +0,0 @@ -#include "selfdrive/ui/qt/offroad/sunnypilot/speed_limit_policy_settings.h" - -SpeedLimitPolicySettings::SpeedLimitPolicySettings(QWidget* parent) : QWidget(parent) { - QVBoxLayout* main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(50, 20, 50, 20); - main_layout->setSpacing(20); - - // Back button - PanelBackButton* back = new PanelBackButton(); - connect(back, &QPushButton::clicked, [=]() { emit backPress(); }); - main_layout->addWidget(back, 0, Qt::AlignLeft); - - ListWidget *list = new ListWidget(this, false); - - speed_limit_policy = new ButtonParamControl( - "SpeedLimitControlPolicy", - tr("Speed Limit Source Policy"), - "", - "../assets/offroad/icon_blank.png", - speed_limit_policy_texts, - 250 - ); - speed_limit_policy->showDescription(); - connect(speed_limit_policy, &ButtonParamControl::buttonToggled, this, &SpeedLimitPolicySettings::updateToggles); - list->addItem(speed_limit_policy); - - param_watcher = new ParamWatcher(this); - - QObject::connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) { - updateToggles(); - }); - - main_layout->addWidget(new ScrollView(list, this)); -} - -void SpeedLimitPolicySettings::showEvent(QShowEvent *event) { - updateToggles(); -} - -void SpeedLimitPolicySettings::updateToggles() { - param_watcher->addParam("SpeedLimitControlPolicy"); - - if (!isVisible()) { - return; - } - - // TODO: SP: use upstream's setCheckedButton - speed_limit_policy->setButton("SpeedLimitControlPolicy"); - - speed_limit_policy->setDescription(speedLimitPolicyDescriptionBuilder("SpeedLimitControlPolicy", speed_limit_policy_descriptions)); -} diff --git a/selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.h b/selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.h deleted file mode 100644 index 8026cf7f1b..0000000000 --- a/selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.h +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -#include "common/model.h" -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/custom_offsets_settings.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/lane_change_settings.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/mads_settings.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/speed_limit_control_settings.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/speed_limit_warning_settings.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/speed_limit_policy_settings.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" - -class TorqueFriction : public SPOptionControl { - Q_OBJECT - -public: - TorqueFriction(); - - void refresh(); - -private: - Params params; -}; - -class TorqueMaxLatAccel : public SPOptionControl { - Q_OBJECT - -public: - TorqueMaxLatAccel(); - - void refresh(); - -private: - Params params; -}; - -class SunnypilotPanel : public QFrame { - Q_OBJECT - -public: - explicit SunnypilotPanel(QWidget *parent = nullptr); - void showEvent(QShowEvent *event) override; - void hideEvent(QHideEvent* event) override; - -public slots: - void updateToggles(); - -private: - QStackedLayout* main_layout = nullptr; - QWidget* sunnypilotScreen = nullptr; - MadsSettings* mads_settings = nullptr; - SubPanelButton *slcSettings = nullptr; - SlcSettings* slc_settings = nullptr; - SubPanelButton *slwSettings = nullptr; - SpeedLimitWarningSettings* slw_settings = nullptr; - SubPanelButton *slpSettings = nullptr; - SpeedLimitPolicySettings* slp_settings = nullptr; - LaneChangeSettings* lane_change_settings = nullptr; - CustomOffsetsSettings* custom_offsets_settings = nullptr; - Params params; - std::map toggles; - ParamWatcher *param_watcher; - - TorqueFriction *friction; - TorqueMaxLatAccel *lat_accel_factor; - ButtonParamControl *dlp_settings; - - ScrollView *scrollView = nullptr; - - const QString nnff_description = QString("%1

" - "%2") - .arg(tr("Formerly known as \"NNFF\", this replaces the lateral \"torque\" controller with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy.")) - .arg(tr("Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server with feedback, or to provide log data for your car if your car is currently unsupported: ") + "#tuning-nnlc"); - - QString nnffDescriptionBuilder(const QString &custom_description) { - QString description = "" + custom_description + "

" + nnff_description; - return description; - } - - const QString custom_offsets_description = QString(tr("Add custom offsets to Camera and Path in sunnypilot.")); - const QString dlp_description = QString(tr("Default is Laneless. In Auto mode, sunnnypilot dynamically chooses between Laneline or Laneless model based on lane recognition confidence level on road and certain conditions.")); -}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/trips_settings.cc b/selfdrive/ui/qt/offroad/sunnypilot/trips_settings.cc deleted file mode 100644 index e21dc675ae..0000000000 --- a/selfdrive/ui/qt/offroad/sunnypilot/trips_settings.cc +++ /dev/null @@ -1,29 +0,0 @@ -#include "selfdrive/ui/qt/offroad/sunnypilot/trips_settings.h" - -TripsPanel::TripsPanel(QWidget* parent) : QFrame(parent) { - QVBoxLayout* main_layout = new QVBoxLayout(this); - main_layout->setMargin(0); - - // main content - main_layout->addSpacing(25); - center_layout = new QStackedLayout(); - - driveStatsWidget = new DriveStats; - driveStatsWidget->setStyleSheet(R"( - QLabel[type="title"] { font-size: 51px; font-weight: 500; } - QLabel[type="number"] { font-size: 78px; font-weight: 500; } - QLabel[type="unit"] { font-size: 51px; font-weight: 300; color: #A0A0A0; } - )"); - center_layout->addWidget(driveStatsWidget); - - main_layout->addLayout(center_layout, 1); - - setStyleSheet(R"( - * { - color: white; - } - TripsPanel > QLabel { - font-size: 55px; - } - )"); -} diff --git a/selfdrive/ui/qt/offroad/sunnypilot/trips_settings.h b/selfdrive/ui/qt/offroad/sunnypilot/trips_settings.h deleted file mode 100644 index dc77acac75..0000000000 --- a/selfdrive/ui/qt/offroad/sunnypilot/trips_settings.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/widgets/sunnypilot/drive_stats.h" - -class TripsPanel : public QFrame { - Q_OBJECT - -public: - explicit TripsPanel(QWidget* parent = 0); - -private: - Params params; - - QStackedLayout* center_layout; - DriveStats *driveStatsWidget; -}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/vehicle_settings.h b/selfdrive/ui/qt/offroad/sunnypilot/vehicle_settings.h deleted file mode 100644 index b210225f49..0000000000 --- a/selfdrive/ui/qt/offroad/sunnypilot/vehicle_settings.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include - -#include "common/watchdog.h" -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" - -class VehiclePanel : public QWidget { - Q_OBJECT - -public: - explicit VehiclePanel(QWidget *parent = nullptr); - void showEvent(QShowEvent *event) override; - -public slots: - void updateToggles(); - -private: - Params params; - - QStackedLayout* main_layout = nullptr; - QWidget* home = nullptr; - - QPushButton* setCarBtn; - QString set; - - QWidget* home_widget; - QString prompt_select = tr("Select your car"); -}; - -class SPVehiclesTogglesPanel : public ListWidget { - Q_OBJECT -public: - explicit SPVehiclesTogglesPanel(VehiclePanel *parent); - void showEvent(QShowEvent *event) override; - -public slots: - void updateToggles(); - -private: - Params params; - bool is_onroad = false; - - ParamControl *stockLongToyota; - ParamControl *toyotaEnhancedBsm; - - const QString toyotaEnhancedBsmDescription = QString("%1

" - "%2") - .arg(tr("sunnypilot will use debugging CAN messages to receive unfiltered BSM signals, allowing detection of more objects.")) - .arg(tr("Tested on RAV4 TSS1, Lexus LSS1, Toyota TSS1/1.5, and Prius TSS2.")); - - QString toyotaEnhancedBsmDesciptionBuilder(const QString &custom_description) { - QString description = "" + custom_description + "

" + toyotaEnhancedBsmDescription; - return description; - } -}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/visuals_settings.h b/selfdrive/ui/qt/offroad/sunnypilot/visuals_settings.h deleted file mode 100644 index 3ea5825f59..0000000000 --- a/selfdrive/ui/qt/offroad/sunnypilot/visuals_settings.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/widgets/controls.h" - -class VisualsPanel : public ListWidget { - Q_OBJECT - -public: - explicit VisualsPanel(QWidget *parent = nullptr); - -private: - Params params; - std::map toggles; - - ButtonParamControl *dev_ui_settings; - ButtonParamControl *chevron_info_settings; - ButtonParamControl *sidebar_temp_setting; -}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot_main.h b/selfdrive/ui/qt/offroad/sunnypilot_main.h deleted file mode 100644 index fe4526db08..0000000000 --- a/selfdrive/ui/qt/offroad/sunnypilot_main.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "selfdrive/ui/qt/offroad/sunnypilot/display_settings.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/vehicle_settings.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/visuals_settings.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/trips_settings.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/monitoring_settings.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/osm_settings.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/software_settings_sp.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.h" diff --git a/selfdrive/ui/qt/offroad_home.cc b/selfdrive/ui/qt/offroad_home.cc new file mode 100644 index 0000000000..e9d54a4efb --- /dev/null +++ b/selfdrive/ui/qt/offroad_home.cc @@ -0,0 +1,152 @@ +#include "selfdrive/ui/qt/offroad_home.h" + +#include +#include + +#include "selfdrive/ui/qt/offroad/experimental_mode.h" +#include "selfdrive/ui/qt/util.h" +#include "selfdrive/ui/qt/widgets/prime.h" + +// OffroadHome: the offroad home page + +OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { + QVBoxLayout* main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(40, 40, 40, 40); + + // top header + QHBoxLayout* header_layout = new QHBoxLayout(); + header_layout->setContentsMargins(0, 0, 0, 0); + header_layout->setSpacing(16); + + update_notif = new QPushButton(tr("UPDATE")); + update_notif->setVisible(false); + update_notif->setStyleSheet("background-color: #364DEF;"); + QObject::connect(update_notif, &QPushButton::clicked, [=]() { center_layout->setCurrentIndex(1); }); + header_layout->addWidget(update_notif, 0, Qt::AlignHCenter | Qt::AlignLeft); + + alert_notif = new QPushButton(); + alert_notif->setVisible(false); + alert_notif->setStyleSheet("background-color: #E22C2C;"); + QObject::connect(alert_notif, &QPushButton::clicked, [=] { center_layout->setCurrentIndex(2); }); + header_layout->addWidget(alert_notif, 0, Qt::AlignHCenter | Qt::AlignLeft); + + version = new ElidedLabel(); + header_layout->addWidget(version, 0, Qt::AlignHCenter | Qt::AlignRight); + + main_layout->addLayout(header_layout); + + // main content + main_layout->addSpacing(25); + center_layout = new QStackedLayout(); + + home_widget = new QWidget(this); + { + home_layout = new QHBoxLayout(home_widget); + home_layout->setContentsMargins(0, 0, 0, 0); + home_layout->setSpacing(30); + + // left: PrimeAdWidget + left_widget = new QStackedWidget(this); + QVBoxLayout *left_prime_layout = new QVBoxLayout(); + QWidget *prime_user = new PrimeUserWidget(); + prime_user->setStyleSheet(R"( + border-radius: 10px; + background-color: #333333; + )"); + left_prime_layout->addWidget(prime_user); + left_prime_layout->addStretch(); + left_widget->addWidget(new LayoutWidget(left_prime_layout)); + left_widget->addWidget(new PrimeAdWidget); + left_widget->setStyleSheet("border-radius: 10px;"); + + left_widget->setCurrentIndex(uiState()->hasPrime() ? 0 : 1); + connect(uiState(), &UIState::primeChanged, [=](bool prime) { + left_widget->setCurrentIndex(prime ? 0 : 1); + }); + + home_layout->addWidget(left_widget, 1); + + // right: ExperimentalModeButton, SetupWidget + QWidget* right_widget = new QWidget(this); + QVBoxLayout* right_column = new QVBoxLayout(right_widget); + right_column->setContentsMargins(0, 0, 0, 0); + right_widget->setFixedWidth(750); + right_column->setSpacing(30); + + ExperimentalModeButton *experimental_mode = new ExperimentalModeButton(this); + QObject::connect(experimental_mode, &ExperimentalModeButton::openSettings, this, &OffroadHome::openSettings); + right_column->addWidget(experimental_mode, 1); + + SetupWidget *setup_widget = new SetupWidget; + QObject::connect(setup_widget, &SetupWidget::openSettings, this, &OffroadHome::openSettings); + right_column->addWidget(setup_widget, 1); + + home_layout->addWidget(right_widget, 1); + } + center_layout->addWidget(home_widget); + + // add update & alerts widgets + update_widget = new UpdateAlert(); + QObject::connect(update_widget, &UpdateAlert::dismiss, [=]() { center_layout->setCurrentIndex(0); }); + center_layout->addWidget(update_widget); + alerts_widget = new OffroadAlert(); + QObject::connect(alerts_widget, &OffroadAlert::dismiss, [=]() { center_layout->setCurrentIndex(0); }); + center_layout->addWidget(alerts_widget); + + main_layout->addLayout(center_layout, 1); + + // set up refresh timer + timer = new QTimer(this); + timer->callOnTimeout(this, &OffroadHome::refresh); + + setStyleSheet(R"( + * { + color: white; + } + OffroadHome { + background-color: black; + } + OffroadHome > QPushButton { + padding: 15px 30px; + border-radius: 5px; + font-size: 40px; + font-weight: 500; + } + OffroadHome > QLabel { + font-size: 55px; + } + )"); +} + +void OffroadHome::showEvent(QShowEvent *event) { + refresh(); + timer->start(10 * 1000); +} + +void OffroadHome::hideEvent(QHideEvent *event) { + timer->stop(); +} + +void OffroadHome::refresh() { + version->setText(getBrand() + " " + QString::fromStdString(params.get("UpdaterCurrentDescription"))); + + bool updateAvailable = update_widget->refresh(); + int alerts = alerts_widget->refresh(); + + // pop-up new notification + int idx = center_layout->currentIndex(); + if (!updateAvailable && !alerts) { + idx = 0; + } else if (updateAvailable && (!update_notif->isVisible() || (!alerts && idx == 2))) { + idx = 1; + } else if (alerts && (!alert_notif->isVisible() || (!updateAvailable && idx == 1))) { + idx = 2; + } + center_layout->setCurrentIndex(idx); + + update_notif->setVisible(updateAvailable); + alert_notif->setVisible(alerts); + if (alerts) { + alert_notif->setText(QString::number(alerts) + (alerts > 1 ? tr(" ALERTS") : tr(" ALERT"))); + } +} diff --git a/selfdrive/ui/qt/offroad_home.h b/selfdrive/ui/qt/offroad_home.h new file mode 100644 index 0000000000..5796c60f52 --- /dev/null +++ b/selfdrive/ui/qt/offroad_home.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include + +#include "common/params.h" +#include "selfdrive/ui/qt/body.h" +#include "selfdrive/ui/qt/onroad/onroad_home.h" +#include "selfdrive/ui/qt/widgets/offroad_alerts.h" + +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#include "selfdrive/ui/sunnypilot/qt/onroad/onroad_home.h" +#include "selfdrive/ui/sunnypilot/qt/sidebar.h" +#define OnroadWindow OnroadWindowSP +#define OffroadHomeImp OffroadHomeSP +#define LayoutWidget LayoutWidgetSP +#define Sidebar SidebarSP +#define ElidedLabel ElidedLabelSP +#else +#include "selfdrive/ui/qt/widgets/controls.h" +#include "selfdrive/ui/qt/onroad/onroad_home.h" +#include "selfdrive/ui/qt/sidebar.h" +#endif + +class OffroadHome : public QFrame { + Q_OBJECT + +public: + void do_work(QWidget*& home_widget); + explicit OffroadHome(QWidget* parent = 0); + +signals: + void openSettings(int index = 0, const QString ¶m = ""); + +protected: + QStackedLayout* center_layout; + QWidget* home_widget; + QHBoxLayout *home_layout; + QStackedWidget *left_widget; + +private: + void showEvent(QShowEvent *event) override; + void hideEvent(QHideEvent *event) override; + void refresh(); + + Params params; + + QTimer* timer; + ElidedLabel* version; + UpdateAlert *update_widget; + OffroadAlert* alerts_widget; + QPushButton* alert_notif; + QPushButton* update_notif; +}; diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc index bb19798e92..b08420a713 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.cc +++ b/selfdrive/ui/qt/onroad/annotated_camera.cc @@ -1,36 +1,17 @@ + #include "selfdrive/ui/qt/onroad/annotated_camera.h" +#include #include #include -#include -#include #include "common/swaglog.h" #include "selfdrive/ui/qt/onroad/buttons.h" #include "selfdrive/ui/qt/util.h" -static std::pair getFeatureStatus(int value, QStringList text_list, QStringList color_list, - bool condition, QString off_text) { - - QString text("Error"); - QColor color("#ffffff"); - - for (int i = 0; i < text_list.size() && i < color_list.size(); ++i) { - if (value == i) { - text = condition ? text_list[i] : off_text; - color = condition ? QColor(color_list[i]) : QColor("#ffffff"); - break; // Exit the loop once a match is found - } - } - - return {text, color}; -} - - // Window that shows camera view and variety of info drawn on top AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraWidget("camerad", type, true, parent) { pm = std::make_unique>({"uiDebug"}); - e2e_state = std::make_unique>({"e2eLongStateSP"}); main_layout = new QVBoxLayout(this); main_layout->setMargin(UI_BORDER_SIZE); @@ -39,68 +20,7 @@ AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* par experimental_btn = new ExperimentalButton(this); main_layout->addWidget(experimental_btn, 0, Qt::AlignTop | Qt::AlignRight); - onroad_settings_btn = new OnroadSettingsButton(this); - - map_settings_btn = new MapSettingsButton(this); - dm_img = loadPixmap("../assets/img_driver_face.png", {img_size + 5, img_size + 5}); - map_img = loadPixmap("../assets/img_world_icon.png", {subsign_img_size, subsign_img_size}); - left_img = loadPixmap("../assets/img_turn_left_icon.png", {subsign_img_size, subsign_img_size}); - right_img = loadPixmap("../assets/img_turn_right_icon.png", {subsign_img_size, subsign_img_size}); - - buttons_layout = new QHBoxLayout(); - buttons_layout->setContentsMargins(0, 0, 10, 20); - main_layout->addLayout(buttons_layout); - updateButtonsLayout(false); -} - -void AnnotatedCameraWidget::mousePressEvent(QMouseEvent* e) { - bool propagate_event = true; - - UIState *s = uiState(); - UIScene &scene = s->scene; - const SubMaster &sm = *(s->sm); - const auto longitudinal_plan_sp = sm["longitudinalPlanSP"].getLongitudinalPlanSP(); - - if (longitudinal_plan_sp.getSpeedLimit() > 0.0 && sl_sign_rect.contains(e->x(), e->y())) { - // If touching the speed limit sign area when visible - scene.last_speed_limit_sign_tap = seconds_since_boot(); - params.putBool("LastSpeedLimitSignTap", true); - scene.speed_limit_control_enabled = !scene.speed_limit_control_enabled; - params.putBool("EnableSlc", scene.speed_limit_control_enabled); - propagate_event = false; - } - - if (propagate_event) { - QWidget::mousePressEvent(e); - } -} - -void AnnotatedCameraWidget::updateButtonsLayout(bool is_rhd) { - QLayoutItem *item; - while ((item = buttons_layout->takeAt(0)) != nullptr) { - delete item; - } - - buttons_layout->setContentsMargins(0, 0, 10, rn_offset != 0 ? rn_offset + 10 : 20); - - if (is_rhd) { - buttons_layout->addSpacing(map_settings_btn->isVisible() ? 30 : 0); - buttons_layout->addWidget(map_settings_btn, 0, Qt::AlignBottom | Qt::AlignLeft); - - buttons_layout->addStretch(1); - - buttons_layout->addWidget(onroad_settings_btn, 0, Qt::AlignBottom | Qt::AlignRight); - buttons_layout->addSpacing(onroad_settings_btn->isVisible() ? 216 : 0); - } else { - buttons_layout->addSpacing(onroad_settings_btn->isVisible() ? 216 : 0); - buttons_layout->addWidget(onroad_settings_btn, 0, Qt::AlignBottom | Qt::AlignLeft); - - buttons_layout->addStretch(1); - - buttons_layout->addWidget(map_settings_btn, 0, Qt::AlignBottom | Qt::AlignRight); - buttons_layout->addSpacing(map_settings_btn->isVisible() ? 30 : 0); // Add spacing to the right - } } void AnnotatedCameraWidget::updateState(const UIState &s) { @@ -108,18 +28,8 @@ void AnnotatedCameraWidget::updateState(const UIState &s) { const SubMaster &sm = *(s.sm); const bool cs_alive = sm.alive("controlsState"); - const bool nav_alive = sm.alive("navInstruction") && sm["navInstruction"].getValid(); const auto cs = sm["controlsState"].getControlsState(); - const auto cs_sp = sm["controlsStateSP"].getControlsStateSP(); const auto car_state = sm["carState"].getCarState(); - const auto nav_instruction = sm["navInstruction"].getNavInstruction(); - const auto car_control = sm["carControl"].getCarControl(); - const auto radar_state = sm["radarState"].getRadarState(); - const auto is_gps_location_external = sm.rcv_frame("gpsLocationExternal") > 1; - const auto gpsLocation = is_gps_location_external ? sm["gpsLocationExternal"].getGpsLocationExternal() : sm["gpsLocation"].getGpsLocation(); - const auto ltp = sm["liveTorqueParameters"].getLiveTorqueParameters(); - const auto lateral_plan_sp = sm["lateralPlanSPDEPRECATED"].getLateralPlanSPDEPRECATED(); - car_params = sm["carParams"].getCarParams(); // Handle older routes where vCruiseCluster is not set float v_cruise = cs.getVCruiseCluster() == 0.0 ? cs.getVCruise() : cs.getVCruiseCluster(); @@ -132,250 +42,23 @@ void AnnotatedCameraWidget::updateState(const UIState &s) { // Handle older routes where vEgoCluster is not set v_ego_cluster_seen = v_ego_cluster_seen || car_state.getVEgoCluster() != 0.0; float v_ego = v_ego_cluster_seen ? car_state.getVEgoCluster() : car_state.getVEgo(); - v_ego = s.scene.true_vego_ui ? car_state.getVEgo() : v_ego; speed = cs_alive ? std::max(0.0, v_ego) : 0.0; speed *= s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH; - auto speed_limit_sign = nav_instruction.getSpeedLimitSign(); - speedLimit = nav_alive ? nav_instruction.getSpeedLimit() : 0.0; - speedLimit *= (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH); - - has_us_speed_limit = (nav_alive && speed_limit_sign == cereal::NavInstruction::SpeedLimitSign::MUTCD); - has_eu_speed_limit = (nav_alive && speed_limit_sign == cereal::NavInstruction::SpeedLimitSign::VIENNA); is_metric = s.scene.is_metric; speedUnit = s.scene.is_metric ? tr("km/h") : tr("mph"); hideBottomIcons = (cs.getAlertSize() != cereal::ControlsState::AlertSize::NONE); status = s.status; - // TODO: Add minimum speed? - left_blindspot = cs_alive && car_state.getLeftBlindspot(); - right_blindspot = cs_alive && car_state.getRightBlindspot(); - - steerOverride = car_state.getSteeringPressed(); - gasOverride = car_state.getGasPressed(); - latActive = car_control.getLatActive(); - madsEnabled = car_state.getMadsEnabled(); - - brakeLights = car_state.getBrakeLightsDEPRECATED() && s.scene.visual_brake_lights; - - standStillTimer = s.scene.stand_still_timer; - standStill = car_state.getStandstill(); - standstillElapsedTime = lateral_plan_sp.getStandstillElapsed(); - - hideVEgoUi = s.scene.hide_vego_ui; - - splitPanelVisible = s.scene.map_visible || s.scene.onroad_settings_visible; - - // ############################## DEV UI START ############################## - lead_d_rel = radar_state.getLeadOne().getDRel(); - lead_v_rel = radar_state.getLeadOne().getVRel(); - lead_status = radar_state.getLeadOne().getStatus(); - lateralState = QString::fromStdString(cs_sp.getLateralState()); - angleSteers = car_state.getSteeringAngleDeg(); - steerAngleDesired = cs.getLateralControlState().getPidState().getSteeringAngleDesiredDeg(); - curvature = cs.getCurvature(); - roll = sm["liveParameters"].getLiveParameters().getRoll(); - memoryUsagePercent = sm["deviceState"].getDeviceState().getMemoryUsagePercent(); - devUiInfo = s.scene.dev_ui_info; - gpsAccuracy = is_gps_location_external ? gpsLocation.getHorizontalAccuracy() : 1.0; //External reports accuracy, internal does not. - altitude = gpsLocation.getAltitude(); - vEgo = car_state.getVEgo(); - aEgo = car_state.getAEgo(); - steeringTorqueEps = car_state.getSteeringTorqueEps(); - bearingAccuracyDeg = gpsLocation.getBearingAccuracyDeg(); - bearingDeg = gpsLocation.getBearingDeg(); - torquedUseParams = (ltp.getUseParams() || s.scene.live_torque_toggle) && !s.scene.torqued_override; - latAccelFactorFiltered = ltp.getLatAccelFactorFiltered(); - frictionCoefficientFiltered = ltp.getFrictionCoefficientFiltered(); - liveValid = ltp.getLiveValid(); - // ############################## DEV UI END ############################## - - btnPerc = s.scene.sleep_btn_opacity * 0.05; - - left_blinker = car_state.getLeftBlinker(); - right_blinker = car_state.getRightBlinker(); - lane_change_edge_block = lateral_plan_sp.getLaneChangeEdgeBlockDEPRECATED(); - // update engageability/experimental mode button experimental_btn->updateState(s); - // update onroad settings button state - onroad_settings_btn->updateState(s); - // update DM icon auto dm_state = sm["driverMonitoringState"].getDriverMonitoringState(); dmActive = dm_state.getIsActiveMode(); rightHandDM = dm_state.getIsRHD(); // DM icon transition dm_fade_state = std::clamp(dm_fade_state+0.2*(0.5-dmActive), 0.0, 1.0); - - // update buttons layout - updateButtonsLayout(rightHandDM); - - // hide map settings button for alerts and flip for right hand DM - if (map_settings_btn->isEnabled()) { - map_settings_btn->setVisible(!hideBottomIcons); - buttons_layout->setAlignment(map_settings_btn, (rightHandDM ? Qt::AlignLeft : Qt::AlignRight) | Qt::AlignBottom); - } - - // hide onroad settings button for alerts and flip for right hand DM - if (onroad_settings_btn->isEnabled()) { - onroad_settings_btn->setVisible(!hideBottomIcons); - buttons_layout->setAlignment(onroad_settings_btn, (rightHandDM ? Qt::AlignRight : Qt::AlignLeft) | Qt::AlignBottom); - } - - const auto lp_sp = sm["longitudinalPlanSP"].getLongitudinalPlanSP(); - slcState = lp_sp.getSpeedLimitControlState(); - - speedLimitControlToggle = s.scene.speed_limit_control_enabled; - - const auto vtcState = lp_sp.getVisionTurnControllerState(); - const float vtc_speed = lp_sp.getVisionTurnSpeed() * (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH); - const auto lpSoruce = lp_sp.getLongitudinalPlanSource(); - QColor vtc_color = tcs_colors[int(vtcState)]; - vtc_color.setAlpha(lpSoruce == cereal::LongitudinalPlanSP::LongitudinalPlanSource::TURN ? 255 : 100); - - showVTC = vtcState > cereal::LongitudinalPlanSP::VisionTurnControllerState::DISABLED; - vtcSpeed = QString::number(std::nearbyint(vtc_speed)); - vtcColor = vtc_color; - showDebugUI = s.scene.show_debug_ui; - - const auto lmd_sp = sm["liveMapDataSP"].getLiveMapDataSP(); - - const auto data_type = int(lmd_sp.getDataType()); - const QString data_type_draw(data_type == 2 ? "🌐 " : ""); - roadName = QString::fromStdString(lmd_sp.getCurrentRoadName()); - roadName = !roadName.isEmpty() ? data_type_draw + roadName : ""; - - float speed_limit_slc = lp_sp.getSpeedLimit() * (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH); - const float speed_limit_offset = lp_sp.getSpeedLimitOffset() * (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH); - const bool sl_force_active = speedLimitControlToggle && - seconds_since_boot() < s.scene.last_speed_limit_sign_tap + 2.0; - const bool sl_inactive = !sl_force_active && (!speedLimitControlToggle || - slcState == cereal::LongitudinalPlanSP::SpeedLimitControlState::INACTIVE); - const bool sl_temp_inactive = !sl_force_active && (speedLimitControlToggle && - slcState == cereal::LongitudinalPlanSP::SpeedLimitControlState::TEMP_INACTIVE); - const bool sl_pre_active = !sl_force_active && (speedLimitControlToggle && - slcState == cereal::LongitudinalPlanSP::SpeedLimitControlState::PRE_ACTIVE); - const int sl_distance = int(lp_sp.getDistToSpeedLimit() * (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH) / 10.0) * 10; - const QString sl_distance_str(QString::number(sl_distance) + (s.scene.is_metric ? "m" : "f")); - const QString sl_offset_str(speed_limit_offset > 0.0 ? speed_limit_offset < 0.0 ? - "-" + QString::number(std::nearbyint(std::abs(speed_limit_offset))) : - "+" + QString::number(std::nearbyint(speed_limit_offset)) : ""); - const QString sl_inactive_str(sl_temp_inactive && s.scene.speed_limit_control_engage_type == 0 ? "TEMP" : ""); - const QString sl_substring(sl_inactive || sl_temp_inactive || sl_pre_active ? sl_inactive_str : - sl_distance > 0 ? sl_distance_str : sl_offset_str); - - showSpeedLimit = speed_limit_slc > 0.0; - speedLimitSLC = speed_limit_slc; - speedLimitSLCOffset = speed_limit_offset; - slcSubText = sl_substring; - slcSubTextSize = sl_inactive || sl_temp_inactive || sl_distance > 0 ? 25.0 : 27.0; - mapSourcedSpeedLimit = lp_sp.getIsMapSpeedLimit(); - slcActive = !sl_inactive && !sl_temp_inactive; - overSpeedLimit = showSpeedLimit && s.scene.speed_limit_warning_type != 0 && - (std::nearbyint(speed_limit_slc + s.scene.speed_limit_warning_value_offset) < std::nearbyint(speed)); - plus_arrow_up_img = loadPixmap("../assets/img_plus_arrow_up", {105, 105}); - minus_arrow_down_img = loadPixmap("../assets/img_minus_arrow_down", {105, 105}); - - const float tsc_speed = lp_sp.getTurnSpeed() * (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH); - const auto tscState = lp_sp.getTurnSpeedControlState(); - const int t_distance = int(lp_sp.getDistToTurn() * (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH) / 10.0) * 10; - const QString t_distance_str(QString::number(t_distance) + (s.scene.is_metric ? "m" : "f")); - - showTurnSpeedLimit = tsc_speed > 0.0 && std::round(tsc_speed) < 224 && (tsc_speed < speed || s.scene.show_debug_ui); - turnSpeedLimit = QString::number(std::nearbyint(tsc_speed)); - tscSubText = t_distance > 0 ? t_distance_str : QString(""); - tscActive = tscState > cereal::LongitudinalPlanSP::SpeedLimitControlState::TEMP_INACTIVE; - curveSign = lp_sp.getTurnSign(); - - // TODO: Add toggle variables to cereal, and parse from cereal - longitudinalPersonality = s.scene.longitudinal_personality; - dynamicLaneProfile = s.scene.dynamic_lane_profile; - mpcMode = QString::fromStdString(lp_sp.getE2eBlended()); - mpcMode = (mpcMode == "blended") ? mpcMode.replace(0, 1, mpcMode[0].toUpper()) : mpcMode.toUpper(); - - static int reverse_delay = 0; - bool reverse_allowed = false; - if (int(car_state.getGearShifter()) != 4) { - reverse_delay = 0; - reverse_allowed = false; - } else { - reverse_delay += 50; - if (reverse_delay >= 1000) { - reverse_allowed = true; - } - } - - reversing = reverse_allowed; - - cruiseStateEnabled = car_state.getCruiseState().getEnabled(); - - int e2eLStatus = 0; - static bool chime_sent = false; - static int chime_count = 0; - int chime_prompt = 0; - static float last_lead_distance = -1; - const float lead_distance = radar_state.getLeadOne().getDRel(); - - if (s.scene.e2eX[12] > 30 && car_state.getVEgo() < 1.0) { - e2eLStatus = 2; - } else if ((s.scene.e2eX[12] > 0 && s.scene.e2eX[12] < 80) || s.scene.e2eX[12] < 0) { - e2eLStatus = 1; - } else { - e2eLStatus = 0; - } - - if (!car_state.getStandstill()) { - chime_prompt = 0; - chime_sent = false; - chime_count = 0; - - if (last_lead_distance != -1) { - last_lead_distance = -1; - } - } - - if ((cruiseStateEnabled || car_state.getBrakeLightsDEPRECATED()) && !car_state.getGasPressed() && car_state.getStandstill()) { - if (e2eLStatus == 2 && !radar_state.getLeadOne().getStatus()) { - if (chime_sent) { - chime_count = 0; - } else { - chime_count += 1; - } - if (s.scene.e2e_long_alert_light && chime_count >= 2 && !chime_sent) { - chime_prompt = 1; - chime_sent = true; - } else { - chime_prompt = 0; - } - } else if (radar_state.getLeadOne().getStatus()) { - if ((last_lead_distance == -1) || (lead_distance < last_lead_distance)) { - last_lead_distance = lead_distance; - } - if (s.scene.e2e_long_alert_lead && (lead_distance - last_lead_distance > 1.0) && !chime_sent) { - chime_prompt = 2; - chime_sent = true; - } else { - chime_prompt = 0; - } - } else { - chime_prompt = 0; - } - } else { - } - - e2eStatus = chime_prompt; - e2eState = e2eLStatus; - e2eLongAlertUi = s.scene.e2e_long_alert_ui; - dynamicExperimentalControlToggle = s.scene.dynamic_experimental_control; - speedLimitWarningFlash = s.scene.speed_limit_warning_flash; - experimentalMode = cs.getExperimentalMode(); - - featureStatusToggle = s.scene.feature_status_toggle; - - experimental_btn->setVisible(!(showDebugUI && showVTC)); - drivingModelGen = s.scene.driving_model_generation; } void AnnotatedCameraWidget::drawHud(QPainter &p) { @@ -387,33 +70,18 @@ void AnnotatedCameraWidget::drawHud(QPainter &p) { bg.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0)); p.fillRect(0, 0, width(), UI_HEADER_HEIGHT, bg); - QString speedLimitStr = (speedLimit > 1) ? QString::number(std::nearbyint(speedLimit)) : "–"; - QString speedLimitStrSlc = showSpeedLimit ? QString::number(std::nearbyint(speedLimitSLC)) : "–"; QString speedStr = QString::number(std::nearbyint(speed)); QString setSpeedStr = is_cruise_set ? QString::number(std::nearbyint(setSpeed)) : "–"; - const bool isNavSpeedLimit = has_us_speed_limit || has_eu_speed_limit; - - // Draw outer box + border to contain set speed and speed limit - const int sign_margin = 12; - const int us_sign_height = slcSubText == "" ? 186 : 216; - const int eu_sign_size = 176; + // Draw outer box + border to contain set speed const QSize default_size = {172, 204}; QSize set_speed_size = default_size; - if (is_metric || has_eu_speed_limit) set_speed_size.rwidth() = 200; - if ((mapSourcedSpeedLimit && !is_metric && speedLimitStrSlc.size() >= 3) || - (has_us_speed_limit && speedLimitStr.size() >= 3)) set_speed_size.rwidth() = 223; - - if ((mapSourcedSpeedLimit && !is_metric) || has_us_speed_limit) set_speed_size.rheight() += us_sign_height + sign_margin; - else if ((mapSourcedSpeedLimit && is_metric) || has_eu_speed_limit) set_speed_size.rheight() += eu_sign_size + sign_margin; - - int top_radius = 32; - int bottom_radius = ((mapSourcedSpeedLimit && is_metric) || has_eu_speed_limit) ? 100 : 32; + if (is_metric) set_speed_size.rwidth() = 200; QRect set_speed_rect(QPoint(60 + (default_size.width() - set_speed_size.width()) / 2, 45), set_speed_size); p.setPen(QPen(whiteColor(75), 6)); p.setBrush(blackColor(166)); - drawRoundedRect(p, set_speed_rect, top_radius, top_radius, bottom_radius, bottom_radius); + p.drawRoundedRect(set_speed_rect, 32, 32); // Draw MAX QColor max_color = QColor(0x80, 0xd8, 0xa6, 0xff); @@ -421,20 +89,8 @@ void AnnotatedCameraWidget::drawHud(QPainter &p) { if (is_cruise_set) { if (status == STATUS_DISENGAGED) { max_color = whiteColor(); - } else if (status == STATUS_OVERRIDE && gasOverride) { + } else if (status == STATUS_OVERRIDE) { max_color = QColor(0x91, 0x9b, 0x95, 0xff); - } else if (speedLimitSLC > 0) { - auto interp_color = [=](QColor c1, QColor c2, QColor c3) { - return speedLimitSLC > 0 ? interpColor(setSpeed, {speedLimitSLC + 5, speedLimitSLC + 15, speedLimitSLC + 25}, {c1, c2, c3}) : c1; - }; - max_color = interp_color(max_color, QColor(0xff, 0xe4, 0xbf), QColor(0xff, 0xbf, 0xbf)); - set_speed_color = interp_color(set_speed_color, QColor(0xff, 0x95, 0x00), QColor(0xff, 0x00, 0x00)); - } else if (speedLimit > 0) { - auto interp_color = [=](QColor c1, QColor c2, QColor c3) { - return speedLimit > 0 ? interpColor(setSpeed, {speedLimit + 5, speedLimit + 15, speedLimit + 25}, {c1, c2, c3}) : c1; - }; - max_color = interp_color(max_color, QColor(0xff, 0xe4, 0xbf), QColor(0xff, 0xbf, 0xbf)); - set_speed_color = interp_color(set_speed_color, QColor(0xff, 0x95, 0x00), QColor(0xff, 0x00, 0x00)); } } else { max_color = QColor(0xa6, 0xa6, 0xa6, 0xff); @@ -447,116 +103,11 @@ void AnnotatedCameraWidget::drawHud(QPainter &p) { p.setPen(set_speed_color); p.drawText(set_speed_rect.adjusted(0, 77, 0, 0), Qt::AlignTop | Qt::AlignHCenter, setSpeedStr); - const QRect sign_rect = set_speed_rect.adjusted(sign_margin, default_size.height(), -sign_margin, -sign_margin); - sl_sign_rect = sign_rect; - - speedLimitWarning(p, sign_rect, sign_margin); - - // US/Canada (MUTCD style) sign - if (((mapSourcedSpeedLimit && !is_metric && !isNavSpeedLimit) || has_us_speed_limit) && slcShowSign) { - p.setPen(Qt::NoPen); - p.setBrush(whiteColor()); - p.drawRoundedRect(sign_rect, 24, 24); - p.setPen(QPen(blackColor(), 6)); - p.drawRoundedRect(sign_rect.adjusted(9, 9, -9, -9), 16, 16); - - p.setFont(InterFont(28, QFont::DemiBold)); - p.drawText(sign_rect.adjusted(0, 22, 0, 0), Qt::AlignTop | Qt::AlignHCenter, tr("SPEED")); - p.drawText(sign_rect.adjusted(0, 51, 0, 0), Qt::AlignTop | Qt::AlignHCenter, tr("LIMIT")); - p.setFont(InterFont(70, QFont::Bold)); - if (overSpeedLimit) p.setPen(QColor(255, 0, 0, 255)); - else p.setPen(blackColor()); - p.drawText(sign_rect.adjusted(0, 85, 0, 0), Qt::AlignTop | Qt::AlignHCenter, speedLimitStrSlc); - - // Speed limit offset value - p.setFont(InterFont(32, QFont::Bold)); - p.setPen(blackColor()); - p.drawText(sign_rect.adjusted(0, 85 + 77, 0, 0), Qt::AlignTop | Qt::AlignHCenter, slcSubText); - } - - // EU (Vienna style) sign - if (((mapSourcedSpeedLimit && is_metric && !isNavSpeedLimit) || has_eu_speed_limit) && slcShowSign) { - p.setPen(Qt::NoPen); - p.setBrush(whiteColor()); - p.drawEllipse(sign_rect); - p.setPen(QPen(Qt::red, 20)); - p.drawEllipse(sign_rect.adjusted(16, 16, -16, -16)); - - p.setFont(InterFont((speedLimitStrSlc.size() >= 3) ? 60 : 70, QFont::Bold)); - if (overSpeedLimit) p.setPen(QColor(255, 0, 0, 255)); - else p.setPen(blackColor()); - p.drawText(sign_rect, Qt::AlignCenter, speedLimitStrSlc); - - // Speed limit offset value - p.setFont(InterFont(slcSubTextSize, QFont::Bold)); - p.setPen(blackColor()); - p.drawText(sign_rect.adjusted(0, 27, 0, 0), Qt::AlignTop | Qt::AlignHCenter, slcSubText); - } - // current speed - if (!hideVEgoUi) { - p.setFont(InterFont(176, QFont::Bold)); - drawColoredText(p, rect().center().x(), 210, speedStr, brakeLights ? QColor(0xff, 0, 0, 255) : QColor(0xff, 0xff, 0xff, 255)); - p.setFont(InterFont(66)); - drawText(p, rect().center().x(), 290, speedUnit, 200); - } - - if (!reversing) { - // ####### 1 ROW ####### - QRect bar_rect1(rect().left(), rect().bottom() - 60, rect().width(), 61); - if (!splitPanelVisible && devUiInfo == 2) { - p.setPen(Qt::NoPen); - p.setBrush(QColor(0, 0, 0, 100)); - p.drawRect(bar_rect1); - drawNewDevUi2(p, bar_rect1.left(), bar_rect1.center().y()); - } - - // ####### 1 COLUMN ######## - QRect rc2(rect().right() - (UI_BORDER_SIZE * 2), UI_BORDER_SIZE * 1.5, 184, 152); - if (devUiInfo != 0) { - drawRightDevUi(p, rect().right() - 184 - UI_BORDER_SIZE * 2, UI_BORDER_SIZE * 2 + rc2.height()); - } - - int rn_btn = 0; - rn_btn = !splitPanelVisible && devUiInfo == 2 ? 35 : 0; - rn_offset = rn_btn; - - // Stand Still Timer - if (standStillTimer && standStill && !splitPanelVisible) { - drawStandstillTimer(p, rect().right() - 650, 30 + 160 + 250); - } - - // V-TSC - if (showDebugUI && showVTC) { - drawVisionTurnControllerUI(p, rect().right() - 184 - (UI_BORDER_SIZE * 1.5), int(UI_BORDER_SIZE * 1.5), 184, vtcColor, vtcSpeed, 100); - } - - // Bottom bar road name - if (showDebugUI && !roadName.isEmpty()) { - int font_size = splitPanelVisible ? 38 : 50; - int h = splitPanelVisible ? 18 : 26; - p.setFont(InterFont(font_size, QFont::Bold)); - drawRoadNameText(p, rect().center().x(), h, roadName, QColor(255, 255, 255, 255)); - } - - // Turn Speed Sign - if (showTurnSpeedLimit) { - QRect rc = sign_rect; - rc.moveTop(sign_rect.bottom() + UI_BORDER_SIZE); - drawTrunSpeedSign(p, rc, turnSpeedLimit, tscSubText, curveSign, tscActive); - } - } - - // E2E Status - if (e2eLongAlertUi && e2eState != 0) { - drawE2eStatus(p, UI_BORDER_SIZE * 2 + 190, 45, 150, 150, e2eState); - } - - if (!hideBottomIcons && featureStatusToggle) { - int x = UI_BORDER_SIZE * 2 + (rightHandDM ? 600 : 370); - int feature_status_text_x = rightHandDM ? rect().right() - x : x; - drawFeatureStatusText(p, feature_status_text_x, rect().bottom() - 160 - rn_offset); - } + p.setFont(InterFont(176, QFont::Bold)); + drawText(p, rect().center().x(), 210, speedStr); + p.setFont(InterFont(66)); + drawText(p, rect().center().x(), 290, speedUnit, 200); p.restore(); } @@ -569,711 +120,6 @@ void AnnotatedCameraWidget::drawText(QPainter &p, int x, int y, const QString &t p.drawText(real_rect.x(), real_rect.bottom(), text); } -void AnnotatedCameraWidget::drawColoredText(QPainter &p, int x, int y, const QString &text, QColor color) { - QRect real_rect = p.fontMetrics().boundingRect(text); - real_rect.moveCenter({x, y - real_rect.height() / 2}); - - p.setPen(color); - p.drawText(real_rect.x(), real_rect.bottom(), text); -} - -void AnnotatedCameraWidget::drawCenteredText(QPainter &p, int x, int y, const QString &text, QColor color) { - QRect real_rect = p.fontMetrics().boundingRect(text); - real_rect.moveCenter({x, y}); - - p.setPen(color); - p.drawText(real_rect, Qt::AlignCenter, text); -} - -void AnnotatedCameraWidget::drawRoadNameText(QPainter &p, int x, int y, const QString &text, QColor color) { - QRect real_rect = p.fontMetrics().boundingRect(text); - real_rect.moveCenter({x, y}); - - QRect real_rect_adjusted(real_rect); - real_rect_adjusted.adjust(-UI_ROAD_NAME_MARGIN_X, 5, UI_ROAD_NAME_MARGIN_X, 0); - QPainterPath path; - path.addRoundedRect(real_rect_adjusted, 10, 10); - p.setPen(Qt::NoPen); - p.setBrush(QColor(0, 0, 0, 100)); - p.drawPath(path); - - p.setPen(color); - p.drawText(real_rect, Qt::AlignCenter, text); -} - -void AnnotatedCameraWidget::drawVisionTurnControllerUI(QPainter &p, int x, int y, int size, const QColor &color, - const QString &vision_speed, int alpha) { - QRect rvtc(x, y, size, size); - p.setPen(QPen(color, 10)); - p.setBrush(QColor(0, 0, 0, alpha)); - p.drawRoundedRect(rvtc, 20, 20); - p.setPen(Qt::NoPen); - - p.setFont(InterFont(56, QFont::DemiBold)); - drawCenteredText(p, rvtc.center().x(), rvtc.center().y(), vision_speed, color); -} - -void AnnotatedCameraWidget::drawStandstillTimer(QPainter &p, int x, int y) { - char lab_str[16]; - char val_str[16]; - int minute = (int)(standstillElapsedTime / 60); - int second = (int)((standstillElapsedTime) - (minute * 60)); - - if (standStill) { - snprintf(lab_str, sizeof(lab_str), "STOP"); - snprintf(val_str, sizeof(val_str), "%01d:%02d", minute, second); - } - - p.setFont(InterFont(125, QFont::DemiBold)); - drawColoredText(p, x, y, QString(lab_str), QColor(255, 175, 3, 240)); - p.setFont(InterFont(150, QFont::DemiBold)); - drawColoredText(p, x, y + 150, QString(val_str), QColor(255, 255, 255, 240)); -} - -void AnnotatedCameraWidget::drawCircle(QPainter &p, int x, int y, int r, QBrush bg) { - p.setPen(Qt::NoPen); - p.setBrush(bg); - p.drawEllipse(x - r, y - r, 2 * r, 2 * r); -} - -void AnnotatedCameraWidget::drawSpeedSign(QPainter &p, QRect rc, const QString &speed_limit, const QString &sub_text, - int subtext_size, bool is_map_sourced, bool is_active) { - const QColor ring_color = is_active ? QColor(255, 0, 0, 255) : QColor(0, 0, 0, 50); - const QColor inner_color = QColor(255, 255, 255, is_active ? 255 : 85); - const QColor text_color = QColor(0, 0, 0, is_active ? 255 : 85); - - const int x = rc.center().x(); - const int y = rc.center().y(); - const int r = rc.width() / 2.0f; - - drawCircle(p, x, y, r, ring_color); - drawCircle(p, x, y, int(r * 0.8f), inner_color); - - p.setFont(InterFont(89, QFont::Bold)); - drawCenteredText(p, x, y, speed_limit, text_color); - p.setFont(InterFont(subtext_size, QFont::Bold)); - drawCenteredText(p, x, y + 55, sub_text, text_color); - - if (is_map_sourced) { - p.setPen(Qt::NoPen); - p.setOpacity(is_active ? 1.0 : 0.3); - p.drawPixmap(x - subsign_img_size / 2, y - 55 - subsign_img_size / 2, map_img); - p.setOpacity(1.0); - } -} - -void AnnotatedCameraWidget::drawTrunSpeedSign(QPainter &p, QRect rc, const QString &turn_speed, const QString &sub_text, - int curv_sign, bool is_active) { - const QColor border_color = is_active ? QColor(255, 0, 0, 255) : QColor(0, 0, 0, 50); - const QColor inner_color = QColor(255, 255, 255, is_active ? 255 : 85); - const QColor text_color = QColor(0, 0, 0, is_active ? 255 : 85); - - const int x = rc.center().x(); - const int y = 184 * 2 + UI_BORDER_SIZE + 202; - const int width = 184; - - const float stroke_w = 15.0; - const float cS = stroke_w / 2.0 + 4.5; // half width of the stroke on the corners of the triangle - const float R = width / 2.0 - stroke_w / 2.0; - const float A = 0.73205; - const float h2 = 2.0 * R / (1.0 + A); - const float h1 = A * h2; - const float L = 4.0 * R / sqrt(3.0); - - // Draw the internal triangle, compensate for stroke width. Needed to improve rendering when in inactive - // state due to stroke transparency being different from inner transparency. - QPainterPath path; - path.moveTo(x, y - R + cS); - path.lineTo(x - L / 2.0 + cS, y + h1 + h2 - R - stroke_w / 2.0); - path.lineTo(x + L / 2.0 - cS, y + h1 + h2 - R - stroke_w / 2.0); - path.lineTo(x, y - R + cS); - p.setPen(Qt::NoPen); - p.setBrush(inner_color); - p.drawPath(path); - - // Draw the stroke - QPainterPath stroke_path; - stroke_path.moveTo(x, y - R); - stroke_path.lineTo(x - L / 2.0, y + h1 + h2 - R); - stroke_path.lineTo(x + L / 2.0, y + h1 + h2 - R); - stroke_path.lineTo(x, y - R); - p.setPen(QPen(border_color, stroke_w, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); - p.setBrush(Qt::NoBrush); - p.drawPath(stroke_path); - - // Draw the turn sign - if (curv_sign != 0) { - p.setPen(Qt::NoPen); - p.setOpacity(is_active ? 1.0 : 0.3); - p.drawPixmap(int(x - (subsign_img_size / 2)), int(y - R + stroke_w + 30), curv_sign > 0 ? left_img : right_img); - p.setOpacity(1.0); - } - - // Draw the texts. - p.setFont(InterFont(67, QFont::Bold)); - drawCenteredText(p, x, y + 25, turn_speed, text_color); - p.setFont(InterFont(22, QFont::Bold)); - drawCenteredText(p, x, y + 65, sub_text, text_color); -} - -// ############################## DEV UI START ############################## -void AnnotatedCameraWidget::drawCenteredLeftText(QPainter &p, int x, int y, const QString &text1, QColor color1, const QString &text2, const QString &text3, QColor color2) { - QFontMetrics fm(p.font()); - QRect init_rect = fm.boundingRect(text1 + " "); - QRect real_rect = fm.boundingRect(init_rect, 0, text1 + " "); - real_rect.moveCenter({x, y}); - - QRect init_rect3 = fm.boundingRect(text3); - QRect real_rect3 = fm.boundingRect(init_rect3, 0, text3); - real_rect3.moveTop(real_rect.top()); - real_rect3.moveLeft(real_rect.right() + 135); - - QRect init_rect2 = fm.boundingRect(text2); - QRect real_rect2 = fm.boundingRect(init_rect2, 0, text2); - real_rect2.moveTop(real_rect.top()); - real_rect2.moveRight(real_rect.right() + 125); - - p.setPen(color1); - p.drawText(real_rect, Qt::AlignLeft | Qt::AlignVCenter, text1); - - p.setPen(color2); - p.drawText(real_rect2, Qt::AlignRight | Qt::AlignVCenter, text2); - p.drawText(real_rect3, Qt::AlignLeft | Qt::AlignVCenter, text3); -} - -int AnnotatedCameraWidget::drawDevUiElementRight(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color) { - p.setFont(InterFont(30 * 2, QFont::Bold)); - drawColoredText(p, x + 92, y + 80, value, color); - - p.setFont(InterFont(28, QFont::Bold)); - drawText(p, x + 92, y + 80 + 42, label, 255); - - if (units.length() > 0) { - p.save(); - p.translate(x + 54 + 30 - 3 + 92 + 30, y + 37 + 25); - p.rotate(-90); - drawText(p, 0, 0, units, 255); - p.restore(); - } - - return 110; -} - -AnnotatedCameraWidget::UiElement AnnotatedCameraWidget::getDRel() { - QString value = lead_status ? QString::number(lead_d_rel, 'f', 0) : "-"; - QColor color = QColor(255, 255, 255, 255); - - if (lead_status) { - // Orange if close, Red if very close - if (lead_d_rel < 5) { - color = QColor(255, 0, 0, 255); - } else if (lead_d_rel < 15) { - color = QColor(255, 188, 0, 255); - } - } - - return UiElement(value, "REL DIST", "m", color); -} - -AnnotatedCameraWidget::UiElement AnnotatedCameraWidget::getVRel() { - QString value = lead_status ? QString::number(lead_v_rel * (is_metric ? MS_TO_KPH : MS_TO_MPH), 'f', 0) : "-"; - QColor color = QColor(255, 255, 255, 255); - - if (lead_status) { - // Red if approaching faster than 10mph - // Orange if approaching (negative) - if (lead_v_rel < -4.4704) { - color = QColor(255, 0, 0, 255); - } else if (lead_v_rel < 0) { - color = QColor(255, 188, 0, 255); - } - } - - return UiElement(value, "REL SPEED", speedUnit, color); -} - -AnnotatedCameraWidget::UiElement AnnotatedCameraWidget::getSteeringAngleDeg() { - QString value = QString("%1%2%3").arg(QString::number(angleSteers, 'f', 1)).arg("°").arg(""); - QColor color = (madsEnabled && latActive) ? QColor(0, 255, 0, 255) : QColor(255, 255, 255, 255); - - // Red if large steering angle - // Orange if moderate steering angle - if (std::fabs(angleSteers) > 180) { - color = QColor(255, 0, 0, 255); - } else if (std::fabs(angleSteers) > 90) { - color = QColor(255, 188, 0, 255); - } - - return UiElement(value, "REAL STEER", "", color); -} - -AnnotatedCameraWidget::UiElement AnnotatedCameraWidget::getActualLateralAccel() { - float actualLateralAccel = (curvature * pow(vEgo, 2)) - (roll * 9.81); - - QString value = QString::number(actualLateralAccel, 'f', 2); - QColor color = (madsEnabled && latActive) ? QColor(0, 255, 0, 255) : QColor(255, 255, 255, 255); - - return UiElement(value, "ACTUAL LAT", "m/s²", color); -} - -AnnotatedCameraWidget::UiElement AnnotatedCameraWidget::getSteeringAngleDesiredDeg() { - QString value = (madsEnabled && latActive) ? QString("%1%2%3").arg(QString::number(steerAngleDesired, 'f', 1)).arg("°").arg("") : "-"; - QColor color = QColor(255, 255, 255, 255); - - if (madsEnabled && latActive) { - // Red if large steering angle - // Orange if moderate steering angle - if (std::fabs(angleSteers) > 180) { - color = QColor(255, 0, 0, 255); - } else if (std::fabs(angleSteers) > 90) { - color = QColor(255, 188, 0, 255); - } else { - color = QColor(0, 255, 0, 255); - } - } - - return UiElement(value, "DESIRED STEER", "", color); -} - -AnnotatedCameraWidget::UiElement AnnotatedCameraWidget::getMemoryUsagePercent() { - QString value = QString("%1%2").arg(QString::number(memoryUsagePercent, 'd', 0)).arg("%"); - QColor color = (memoryUsagePercent > 85) ? QColor(255, 188, 0, 255) : QColor(255, 255, 255, 255); - - return UiElement(value, "RAM", "", color); -} - -AnnotatedCameraWidget::UiElement AnnotatedCameraWidget::getAEgo() { - QString value = QString::number(aEgo, 'f', 1); - QColor color = QColor(255, 255, 255, 255); - - return UiElement(value, "ACC.", "m/s²", color); -} - -AnnotatedCameraWidget::UiElement AnnotatedCameraWidget::getVEgoLead() { - QString value = lead_status ? QString::number((lead_v_rel + vEgo) * (is_metric ? MS_TO_KPH : MS_TO_MPH), 'f', 0) : "-"; - QColor color = QColor(255, 255, 255, 255); - - if (lead_status) { - // Red if approaching faster than 10mph - // Orange if approaching (negative) - if (lead_v_rel < -4.4704) { - color = QColor(255, 0, 0, 255); - } else if (lead_v_rel < 0) { - color = QColor(255, 188, 0, 255); - } - } - - return UiElement(value, "L.S.", speedUnit, color); -} - -AnnotatedCameraWidget::UiElement AnnotatedCameraWidget::getFrictionCoefficientFiltered() { - QString value = QString::number(frictionCoefficientFiltered, 'f', 3); - QColor color = liveValid ? QColor(0, 255, 0, 255) : QColor(255, 255, 255, 255); - - return UiElement(value, "FRIC.", "", color); -} - -AnnotatedCameraWidget::UiElement AnnotatedCameraWidget::getLatAccelFactorFiltered() { - QString value = QString::number(latAccelFactorFiltered, 'f', 3); - QColor color = liveValid ? QColor(0, 255, 0, 255) : QColor(255, 255, 255, 255); - - return UiElement(value, "L.A.", "m/s²", color); -} - -AnnotatedCameraWidget::UiElement AnnotatedCameraWidget::getSteeringTorqueEps() { - QString value = QString::number(std::fabs(steeringTorqueEps), 'f', 1); - QColor color = QColor(255, 255, 255, 255); - - return UiElement(value, "E.T.", "N·dm", color); -} - -AnnotatedCameraWidget::UiElement AnnotatedCameraWidget::getBearingDeg() { - QString value = (bearingAccuracyDeg != 180.00) ? QString("%1%2%3").arg(QString::number(bearingDeg, 'd', 0)).arg("°").arg("") : "-"; - QColor color = QColor(255, 255, 255, 255); - QString dir_value; - - if (bearingAccuracyDeg != 180.00) { - if (((bearingDeg >= 337.5) && (bearingDeg <= 360)) || ((bearingDeg >= 0) && (bearingDeg <= 22.5))) { - dir_value = "N"; - } else if ((bearingDeg > 22.5) && (bearingDeg < 67.5)) { - dir_value = "NE"; - } else if ((bearingDeg >= 67.5) && (bearingDeg <= 112.5)) { - dir_value = "E"; - } else if ((bearingDeg > 112.5) && (bearingDeg < 157.5)) { - dir_value = "SE"; - } else if ((bearingDeg >= 157.5) && (bearingDeg <= 202.5)) { - dir_value = "S"; - } else if ((bearingDeg > 202.5) && (bearingDeg < 247.5)) { - dir_value = "SW"; - } else if ((bearingDeg >= 247.5) && (bearingDeg <= 292.5)) { - dir_value = "W"; - } else if ((bearingDeg > 292.5) && (bearingDeg < 337.5)) { - dir_value = "NW"; - } - } else { - dir_value = "OFF"; - } - - return UiElement(QString("%1 | %2").arg(dir_value).arg(value), "B.D.", "", color); -} - -AnnotatedCameraWidget::UiElement AnnotatedCameraWidget::getAltitude() { - QString value = (gpsAccuracy != 0.00) ? QString::number(altitude, 'f', 1) : "-"; - QColor color = QColor(255, 255, 255, 255); - - return UiElement(value, "ALT.", "m", color); -} - -void AnnotatedCameraWidget::drawRightDevUi(QPainter &p, int x, int y) { - int rh = 5; - int ry = y; - - // Add Relative Distance to Primary Lead Car - // Unit: Meters - UiElement dRelElement = getDRel(); - rh += drawDevUiElementRight(p, x, ry, dRelElement.value, dRelElement.label, dRelElement.units, dRelElement.color); - ry = y + rh; - - // Add Relative Velocity vs Primary Lead Car - // Unit: kph if metric, else mph - UiElement vRelElement = getVRel(); - rh += drawDevUiElementRight(p, x, ry, vRelElement.value, vRelElement.label, vRelElement.units, vRelElement.color); - ry = y + rh; - - // Add Real Steering Angle - // Unit: Degrees - UiElement steeringAngleDegElement = getSteeringAngleDeg(); - rh += drawDevUiElementRight(p, x, ry, steeringAngleDegElement.value, steeringAngleDegElement.label, steeringAngleDegElement.units, steeringAngleDegElement.color); - ry = y + rh; - - if (lateralState == "torque") { - // Add Actual Lateral Acceleration (roll compensated) when using Torque - // Unit: m/s² - UiElement actualLateralAccelElement = getActualLateralAccel(); - rh += drawDevUiElementRight(p, x, ry, actualLateralAccelElement.value, actualLateralAccelElement.label, actualLateralAccelElement.units, actualLateralAccelElement.color); - } else { - // Add Desired Steering Angle when using PID - // Unit: Degrees - UiElement steeringAngleDesiredDegElement = getSteeringAngleDesiredDeg(); - rh += drawDevUiElementRight(p, x, ry, steeringAngleDesiredDegElement.value, steeringAngleDesiredDegElement.label, steeringAngleDesiredDegElement.units, steeringAngleDesiredDegElement.color); - } - ry = y + rh; - - // Add Device Memory (RAM) Usage - // Unit: Percent - UiElement memoryUsagePercentElement = getMemoryUsagePercent(); - rh += drawDevUiElementRight(p, x, ry, memoryUsagePercentElement.value, memoryUsagePercentElement.label, memoryUsagePercentElement.units, memoryUsagePercentElement.color); - ry = y + rh; - - rh += 25; - p.setBrush(QColor(0, 0, 0, 0)); - QRect ldu(x, y, 184, rh); -} - -int AnnotatedCameraWidget::drawNewDevUiElement(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color) { - p.setFont(InterFont(38, QFont::Bold)); - drawCenteredLeftText(p, x, y, label, whiteColor(), value, units, color); - - return 430; -} - -void AnnotatedCameraWidget::drawNewDevUi2(QPainter &p, int x, int y) { - int rw = 90; - - // Add Acceleration from Car - // Unit: Meters per Second Squared - UiElement aEgoElement = getAEgo(); - rw += drawNewDevUiElement(p, rw, y, aEgoElement.value, aEgoElement.label, aEgoElement.units, aEgoElement.color); - - // Add Velocity of Primary Lead Car - // Unit: kph if metric, else mph - UiElement vEgoLeadElement = getVEgoLead(); - rw += drawNewDevUiElement(p, rw, y, vEgoLeadElement.value, vEgoLeadElement.label, vEgoLeadElement.units, vEgoLeadElement.color); - - if (torquedUseParams) { - // Add Friction Coefficient Raw from torqued - // Unit: None - UiElement frictionCoefficientFilteredElement = getFrictionCoefficientFiltered(); - rw += drawNewDevUiElement(p, rw, y, frictionCoefficientFilteredElement.value, frictionCoefficientFilteredElement.label, frictionCoefficientFilteredElement.units, frictionCoefficientFilteredElement.color); - - // Add Lateral Acceleration Factor Raw from torqued - // Unit: m/s² - UiElement latAccelFactorFilteredElement = getLatAccelFactorFiltered(); - rw += drawNewDevUiElement(p, rw, y, latAccelFactorFilteredElement.value, latAccelFactorFilteredElement.label, latAccelFactorFilteredElement.units, latAccelFactorFilteredElement.color); - } else { - // Add Steering Torque from Car EPS - // Unit: Newton Meters - UiElement steeringTorqueEpsElement = getSteeringTorqueEps(); - rw += drawNewDevUiElement(p, rw, y, steeringTorqueEpsElement.value, steeringTorqueEpsElement.label, steeringTorqueEpsElement.units, steeringTorqueEpsElement.color); - - // Add Bearing Degree and Direction from Car (Compass) - // Unit: Meters - UiElement bearingDegElement = getBearingDeg(); - rw += drawNewDevUiElement(p, rw, y, bearingDegElement.value, bearingDegElement.label, bearingDegElement.units, bearingDegElement.color); - } - - // Add Altitude of Current Location - // Unit: Meters - UiElement altitudeElement = getAltitude(); - rw += drawNewDevUiElement(p, rw, y, altitudeElement.value, altitudeElement.label, altitudeElement.units, altitudeElement.color); -} - -// ############################## DEV UI END ############################## - -void AnnotatedCameraWidget::drawE2eStatus(QPainter &p, int x, int y, int w, int h, int e2e_long_status) { - QColor status_color; - QRect e2eStatusIcon(x, y, w, h); - p.setPen(Qt::NoPen); - p.setBrush(QBrush(blackColor(70))); - p.drawEllipse(e2eStatusIcon); - e2eStatusIcon -= QMargins(25, 25, 25, 25); - p.setPen(Qt::NoPen); - if (e2e_long_status == 2) { - status_color = QColor::fromRgbF(0.0, 1.0, 0.0, 0.9); - } else if (e2e_long_status == 1) { - status_color = QColor::fromRgbF(1.0, 0.0, 0.0, 0.9); - } - p.setBrush(QBrush(status_color)); - p.drawEllipse(e2eStatusIcon); -} - -void AnnotatedCameraWidget::drawLeftTurnSignal(QPainter &painter, int x, int y, int circle_size, int state) { - painter.setRenderHint(QPainter::Antialiasing, true); - - QColor circle_color, circle_color_0, circle_color_1; - QColor arrow_color, arrow_color_0, arrow_color_1; - if ((left_blindspot || lane_change_edge_block) && !(left_blinker && right_blinker)) { - circle_color_0 = QColor(164, 0, 1); - circle_color_1 = QColor(204, 0, 1); - arrow_color_0 = QColor(72, 1, 1); - arrow_color_1 = QColor(255, 255, 255); - } else { - circle_color_0 = QColor(22, 156, 69); - circle_color_1 = QColor(30, 215, 96); - arrow_color_0 = QColor(9, 56, 27); - arrow_color_1 = QColor(255, 255, 255); - } - - if (state == 1) { - circle_color = circle_color_1; - arrow_color = arrow_color_1; - } else if (state == 0) { - circle_color = circle_color_0; - arrow_color = arrow_color_0; - } - - // Draw the circle - int circleX = x; - int circleY = y; - painter.setPen(Qt::NoPen); - painter.setBrush(circle_color); - painter.drawEllipse(circleX, circleY, circle_size, circle_size); - - // Draw the arrow - int arrowSize = 50; - int arrowX = circleX + (circle_size - arrowSize) / 4; - int arrowY = circleY + (circle_size - arrowSize) / 2; - painter.setPen(Qt::NoPen); - painter.setBrush(arrow_color); - - // Draw the arrow shape - QPolygon arrowPolygon; - arrowPolygon << QPoint(arrowX + 10, arrowY + arrowSize / 2) - << QPoint(arrowX + arrowSize - 3, arrowY) - << QPoint(arrowX + arrowSize, arrowY) - << QPoint(arrowX + arrowSize, arrowY + arrowSize) - << QPoint(arrowX + arrowSize - 3, arrowY + arrowSize) - << QPoint(arrowX + 10, arrowY + arrowSize / 2); - painter.drawPolygon(arrowPolygon); - - // Draw the tail rectangle - int tailWidth = arrowSize / 2.25; - int tailHeight = arrowSize / 2; - QRect tailRect(arrowX + arrowSize - 3, arrowY + arrowSize / 4, tailWidth, tailHeight); - painter.fillRect(tailRect, arrow_color); -} - -void AnnotatedCameraWidget::drawRightTurnSignal(QPainter &painter, int x, int y, int circle_size, int state) { - painter.setRenderHint(QPainter::Antialiasing, true); - - QColor circle_color, circle_color_0, circle_color_1; - QColor arrow_color, arrow_color_0, arrow_color_1; - if ((right_blindspot || lane_change_edge_block) && !(left_blinker && right_blinker)) { - circle_color_0 = QColor(164, 0, 1); - circle_color_1 = QColor(204, 0, 1); - arrow_color_0 = QColor(72, 1, 1); - arrow_color_1 = QColor(255, 255, 255); - } else { - circle_color_0 = QColor(22, 156, 69); - circle_color_1 = QColor(30, 215, 96); - arrow_color_0 = QColor(9, 56, 27); - arrow_color_1 = QColor(255, 255, 255); - } - - if (state == 1) { - circle_color = circle_color_1; - arrow_color = arrow_color_1; - } else if (state == 0) { - circle_color = circle_color_0; - arrow_color = arrow_color_0; - } - - - // Draw the circle - int circleX = x; - int circleY = y; - painter.setPen(Qt::NoPen); - painter.setBrush(circle_color); - painter.drawEllipse(circleX, circleY, circle_size, circle_size); - - // Draw the arrow - int arrowSize = 50; - int arrowX = circleX + (circle_size - arrowSize) / 2 + (arrowSize / 2.5) - 3; - int arrowY = circleY + (circle_size - arrowSize) / 2; - painter.setPen(Qt::NoPen); - painter.setBrush(arrow_color); - - // Draw the arrow shape - QPolygon arrowPolygon; - arrowPolygon << QPoint(arrowX + arrowSize - 10, arrowY + arrowSize / 2) - << QPoint(arrowX + 3, arrowY) - << QPoint(arrowX, arrowY) - << QPoint(arrowX, arrowY + arrowSize) - << QPoint(arrowX + 3, arrowY + arrowSize) - << QPoint(arrowX + arrowSize - 10, arrowY + arrowSize / 2); - painter.drawPolygon(arrowPolygon); - - // Draw the tail rectangle - int tailWidth = arrowSize / 2.25; - int tailHeight = arrowSize / 2; - QRect tailRect(arrowX - tailWidth + 3, arrowY + arrowSize / 4, tailWidth, tailHeight); - painter.fillRect(tailRect, arrow_color); -} - -int AnnotatedCameraWidget::blinkerPulse(int frame) { - if (frame % UI_FREQ < (UI_FREQ / 2)) { - blinker_state = 1; - } else { - blinker_state = 0; - } - - return blinker_state; -} - -void AnnotatedCameraWidget::speedLimitSignPulse(int frame) { - if (frame % UI_FREQ < (UI_FREQ / 2.5)) { - slcShowSign = false; - } else { - slcShowSign = true; - } -} - -void AnnotatedCameraWidget::drawFeatureStatusText(QPainter &p, int x, int y) { - const FeatureStatusText feature_text; - const FeatureStatusColor feature_color; - const QColor text_color = whiteColor(); - const QColor shadow_color = blackColor(38); - const int text_height = 34; - const int drop_shadow_size = 2; - const int eclipse_x_offset = 25; - const int eclipse_y_offset = 20; - const int w = 16; - const int h = 16; - - const bool longitudinal = hasLongitudinalControl(car_params); - - p.setFont(InterFont(32, QFont::Bold)); - - // Define a function to draw a feature status button - auto drawFeatureStatusElement = [&](int value, const QStringList& text_list, const QStringList& color_list, bool condition, const QString& off_text, const QString& label) { - std::pair feature_status = getFeatureStatus(value, text_list, color_list, condition, off_text); - QRect btn(x - eclipse_x_offset, y - eclipse_y_offset, w, h); - QRect btn_shadow(x - eclipse_x_offset + drop_shadow_size, y - eclipse_y_offset + drop_shadow_size, w, h); - p.setPen(Qt::NoPen); - p.setBrush(shadow_color); - p.drawEllipse(btn_shadow); - p.setBrush(feature_status.second); - p.drawEllipse(btn); - QString status_text; - status_text.sprintf("%s: %s", label.toStdString().c_str(), (feature_status.first).toStdString().c_str()); - p.setPen(QPen(shadow_color, 2)); - p.drawText(x + drop_shadow_size, y + drop_shadow_size, status_text); - p.setPen(QPen(text_color, 2)); - p.drawText(x, y, status_text); - y += text_height; - }; - - // Driving Personality / Gap Adjust Cruise - if (longitudinal) { - drawFeatureStatusElement(longitudinalPersonality, feature_text.gac_list_text, feature_color.gac_list_color, longitudinal, "N/A", "GAP"); - } - - // Dynamic Lane Profile - if (drivingModelGen == cereal::ModelGeneration::ONE) { - drawFeatureStatusElement(dynamicLaneProfile, feature_text.dlp_list_text, feature_color.dlp_list_color, true, "OFF", "DLP"); - } - - // TODO: Add toggle variables to cereal, and parse from cereal - if (longitudinal) { - QColor dec_color((cruiseStateEnabled && dynamicExperimentalControlToggle) ? "#4bff66" : "#ffffff"); - QRect dec_btn(x - eclipse_x_offset, y - eclipse_y_offset, w, h); - QRect dec_btn_shadow(x - eclipse_x_offset + drop_shadow_size, y - eclipse_y_offset + drop_shadow_size, w, h); - p.setPen(Qt::NoPen); - p.setBrush(shadow_color); - p.drawEllipse(dec_btn_shadow); - p.setBrush(dec_color); - p.drawEllipse(dec_btn); - QString dec_status_text; - dec_status_text.sprintf("DEC: %s\n", dynamicExperimentalControlToggle ? (experimentalMode ? QString(mpcMode).toStdString().c_str() : QString("Inactive").toStdString().c_str()) : "OFF"); - p.setPen(QPen(shadow_color, 2)); - p.drawText(x + drop_shadow_size, y + drop_shadow_size, dec_status_text); - p.setPen(QPen(text_color, 2)); - p.drawText(x, y, dec_status_text); - y += text_height; - } - - // TODO: Add toggle variables to cereal, and parse from cereal - // Speed Limit Control - if (longitudinal || !car_params.getPcmCruiseSpeed()) { - drawFeatureStatusElement(int(slcState), feature_text.slc_list_text, feature_color.slc_list_color, speedLimitControlToggle, "OFF", "SLC"); - } -} - -void AnnotatedCameraWidget::speedLimitWarning(QPainter &p, QRect sign_rect, const int sign_margin) { - // PRE ACTIVE - if (slcState == cereal::LongitudinalPlanSP::SpeedLimitControlState::PRE_ACTIVE) { - int set_speed = std::nearbyint(setSpeed); - int speed_limit_offsetted = std::nearbyint(speedLimitSLC + speedLimitSLCOffset); - - // Calculate the vertical offset using a sinusoidal function for smooth bouncing - double bounce_frequency = 2.0 * M_PI / 20.0; // 20 frames for one full oscillation - int bounce_offset = 20 * sin(speed_limit_frame * bounce_frequency); // Adjust the amplitude (20 pixels) as needed - - if (set_speed < speed_limit_offsetted) { - QPoint iconPosition(sign_rect.right() + sign_margin * 3, sign_rect.center().y() - plus_arrow_up_img.height() / 2 + bounce_offset); - p.drawPixmap(iconPosition, plus_arrow_up_img); - } else if (set_speed > speed_limit_offsetted) { - QPoint iconPosition(sign_rect.right() + sign_margin * 3, sign_rect.center().y() - minus_arrow_down_img.height() / 2 - bounce_offset); - p.drawPixmap(iconPosition, minus_arrow_down_img); - } - - speed_limit_frame++; - speedLimitSignPulse(speed_limit_frame); - } - - // current speed over speed limit - else if (overSpeedLimit && speedLimitWarningFlash) { - speed_limit_frame++; - speedLimitSignPulse(speed_limit_frame); - } - - else { - speed_limit_frame = 0; - slcShowSign = true; - } -} - - void AnnotatedCameraWidget::initializeGL() { CameraWidget::initializeGL(); qInfo() << "OpenGL version:" << QString((const char*)glGetString(GL_VERSION)); @@ -1309,29 +155,12 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { const UIScene &scene = s->scene; SubMaster &sm = *(s->sm); - const auto car_state = sm["carState"].getCarState(); - - // Shane's colored lanelines + // lanelines for (int i = 0; i < std::size(scene.lane_line_vertices); ++i) { - if (i == 1 || i == 2) { - // TODO: can we just use the projected vertices somehow? - const cereal::XYZTData::Reader &line = (*s->sm)["modelV2"].getModelV2().getLaneLines()[i]; - const float default_pos = 1.4; // when lane poly isn't available - const float lane_pos = line.getY().size() > 0 ? std::abs(line.getY()[5]) : default_pos; // get redder when line is closer to car - float hue = 332.5 * lane_pos - 332.5; // equivalent to {1.4, 1.0}: {133, 0} (green to red) - hue = std::fmin(133, fmax(0, hue)) / 360.; // clip and normalize - painter.setBrush(QColor::fromHslF(hue, 1.0, 0.50, std::clamp(scene.lane_line_probs[i], 0.0, 0.7))); - } else { - painter.setBrush(QColor::fromRgbF(1.0, 1.0, 1.0, std::clamp(scene.lane_line_probs[i], 0.0, 0.7))); - } + painter.setBrush(QColor::fromRgbF(1.0, 1.0, 1.0, std::clamp(scene.lane_line_probs[i], 0.0, 0.7))); painter.drawPolygon(scene.lane_line_vertices[i]); } - // TODO: Fix empty spaces when curiving back on itself - painter.setBrush(QColor::fromRgbF(1.0, 0.0, 0.0, 0.2)); - if (left_blindspot) painter.drawPolygon(scene.lane_barrier_vertices[0]); - if (right_blindspot) painter.drawPolygon(scene.lane_barrier_vertices[1]); - // road edges for (int i = 0; i < std::size(scene.road_edge_vertices); ++i) { painter.setBrush(QColor::fromRgbF(1.0, 0, 0, std::clamp(1.0 - scene.road_edge_stds[i], 0.0, 1.0))); @@ -1340,70 +169,41 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { // paint path QLinearGradient bg(0, height(), 0, 0); - if (madsEnabled || car_state.getCruiseState().getEnabled()) { - if (steerOverride && latActive) { - bg.setColorAt(0.0, QColor::fromHslF(20 / 360., 0.94, 0.51, 0.17)); - bg.setColorAt(0.5, QColor::fromHslF(20 / 360., 1.0, 0.68, 0.17)); - bg.setColorAt(1.0, QColor::fromHslF(20 / 360., 1.0, 0.68, 0.0)); - } else if (!(latActive || car_state.getCruiseState().getEnabled())) { - bg.setColorAt(0, whiteColor()); - bg.setColorAt(1, whiteColor(0)); - } else if (sm["controlsState"].getControlsState().getExperimentalMode()) { - // The first half of track_vertices are the points for the right side of the path - const auto &acceleration = sm["modelV2"].getModelV2().getAcceleration().getX(); - const int max_len = std::min(scene.track_vertices.length() / 2, acceleration.size()); + if (sm["controlsState"].getControlsState().getExperimentalMode()) { + // The first half of track_vertices are the points for the right side of the path + const auto &acceleration = sm["modelV2"].getModelV2().getAcceleration().getX(); + const int max_len = std::min(scene.track_vertices.length() / 2, acceleration.size()); - for (int i = 0; i < max_len; ++i) { - // Some points are out of frame - if (scene.track_vertices[i].y() < 0 || scene.track_vertices[i].y() > height()) continue; + for (int i = 0; i < max_len; ++i) { + // Some points are out of frame + if (scene.track_vertices[i].y() < 0 || scene.track_vertices[i].y() > height()) continue; - // Flip so 0 is bottom of frame - float lin_grad_point = (height() - scene.track_vertices[i].y()) / height(); + // Flip so 0 is bottom of frame + float lin_grad_point = (height() - scene.track_vertices[i].y()) / height(); - // speed up: 120, slow down: 0 - float path_hue = fmax(fmin(60 + acceleration[i] * 35, 120), 0); - // FIXME: painter.drawPolygon can be slow if hue is not rounded - path_hue = int(path_hue * 100 + 0.5) / 100; + // speed up: 120, slow down: 0 + float path_hue = fmax(fmin(60 + acceleration[i] * 35, 120), 0); + // FIXME: painter.drawPolygon can be slow if hue is not rounded + path_hue = int(path_hue * 100 + 0.5) / 100; - float saturation = fmin(fabs(acceleration[i] * 1.5), 1); - float lightness = util::map_val(saturation, 0.0f, 1.0f, 0.95f, 0.62f); // lighter when grey - float alpha = util::map_val(lin_grad_point, 0.75f / 2.f, 0.75f, 0.4f, 0.0f); // matches previous alpha fade - bg.setColorAt(lin_grad_point, QColor::fromHslF(path_hue / 360., saturation, lightness, alpha)); + float saturation = fmin(fabs(acceleration[i] * 1.5), 1); + float lightness = util::map_val(saturation, 0.0f, 1.0f, 0.95f, 0.62f); // lighter when grey + float alpha = util::map_val(lin_grad_point, 0.75f / 2.f, 0.75f, 0.4f, 0.0f); // matches previous alpha fade + bg.setColorAt(lin_grad_point, QColor::fromHslF(path_hue / 360., saturation, lightness, alpha)); - // Skip a point, unless next is last - i += (i + 2) < max_len ? 1 : 0; - } - - } else { - bg.setColorAt(0.0, QColor::fromHslF(148 / 360., 0.94, 0.51, 0.4)); - bg.setColorAt(0.5, QColor::fromHslF(112 / 360., 1.0, 0.68, 0.35)); - bg.setColorAt(1.0, QColor::fromHslF(112 / 360., 1.0, 0.68, 0.0)); + // Skip a point, unless next is last + i += (i + 2) < max_len ? 1 : 0; } + } else { - bg.setColorAt(0.0, whiteColor(102)); - bg.setColorAt(0.5, whiteColor(89)); - bg.setColorAt(1.0, whiteColor(0)); + bg.setColorAt(0.0, QColor::fromHslF(148 / 360., 0.94, 0.51, 0.4)); + bg.setColorAt(0.5, QColor::fromHslF(112 / 360., 1.0, 0.68, 0.35)); + bg.setColorAt(1.0, QColor::fromHslF(112 / 360., 1.0, 0.68, 0.0)); } painter.setBrush(bg); painter.drawPolygon(scene.track_vertices); - // create path combining track vertices and track edge vertices - QPainterPath path; - path.addPolygon(scene.track_vertices); - path.addPolygon(scene.track_edge_vertices); - - // paint path edges - QLinearGradient pe(0, height(), 0, height() / 4); - if (!scene.dynamic_lane_profile_status) { - pe.setColorAt(0.0, QColor::fromHslF(240 / 360., 0.94, 0.51, 1.0)); - pe.setColorAt(0.5, QColor::fromHslF(204 / 360., 1.0, 0.68, 0.5)); - pe.setColorAt(1.0, QColor::fromHslF(204 / 360., 1.0, 0.68, 0.0)); - - painter.setBrush(pe); - painter.drawPath(path); - } - painter.restore(); } @@ -1415,7 +215,7 @@ void AnnotatedCameraWidget::drawDriverState(QPainter &painter, const UIState *s) // base icon int offset = UI_BORDER_SIZE + btn_size / 2; int x = rightHandDM ? width() - offset : offset; - int y = height() - offset - rn_offset; + int y = height() - offset; float opacity = dmActive ? 0.65 : 0.2; drawIcon(painter, QPoint(x, y), dm_img, blackColor(70), opacity); @@ -1448,56 +248,13 @@ void AnnotatedCameraWidget::drawDriverState(QPainter &painter, const UIState *s) painter.restore(); } -void AnnotatedCameraWidget::rocketFuel(QPainter &p) { - - static const int ct_n = 1; - static float ct; - - int rect_w = rect().width(); - int rect_h = rect().height(); - - const int n = 15 + 1; //Add one off screen due to timing issues - static float t[n]; - int dim_n = (sin(ct / 5) + 1) * (n - 0.01); - t[dim_n] = 1.0; - t[(int)(ct/ct_n)] = 1.0; - - UIState *s = uiState(); - float vc_accel0 = (*s->sm)["carState"].getCarState().getAEgo(); - static float vc_accel; - vc_accel = vc_accel + (vc_accel0 - vc_accel) / 5; - float hha = 0; - if (vc_accel > 0) { - hha = 0.85 - 0.1 / vc_accel; // only extend up to 85% - p.setBrush(QColor(0, 245, 0, 200)); - } - if (vc_accel < 0) { - hha = 0.85 + 0.1 / vc_accel; // only extend up to 85% - p.setBrush(QColor(245, 0, 0, 200)); - } - if (hha < 0) { - hha = 0; - } - hha = hha * rect_h; - float wp = 28; - if (vc_accel > 0) { - QRect ra = QRect(rect_w - wp, rect_h / 2 - hha / 2, wp, hha / 2); - p.drawRect(ra); - } else { - QRect ra = QRect(rect_w - wp, rect_h / 2, wp, hha / 2); - p.drawRect(ra); - } -} - -void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, - int num, const cereal::CarState::Reader &car_data, int chevron_data) { +void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd) { painter.save(); const float speedBuff = 10.; const float leadBuff = 40.; const float d_rel = lead_data.getDRel(); const float v_rel = lead_data.getVRel(); - const float v_ego = car_data.getVEgo(); float fillAlpha = 0; if (d_rel < leadBuff) { @@ -1524,62 +281,15 @@ void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState painter.setBrush(redColor(fillAlpha)); painter.drawPolygon(chevron, std::size(chevron)); - if (num == 0) { // Display metrics to the 0th lead car - const int chevron_types = 3; - const int chevron_all = chevron_types + 1; // All metrics - QStringList chevron_text[chevron_types]; - int position; - float val; - if (chevron_data == 1 || chevron_data == chevron_all) { - position = 0; - val = std::max(0.0f, d_rel); - chevron_text[position].append(QString::number(val,'f', 0) + " " + "m"); - } - if (chevron_data == 2 || chevron_data == chevron_all) { - position = (chevron_data == 2) ? 0 : 1; - val = std::max(0.0f, (v_rel + v_ego) * (is_metric ? static_cast(MS_TO_KPH) : static_cast(MS_TO_MPH))); - chevron_text[position].append(QString::number(val,'f', 0) + " " + (is_metric ? "km/h" : "mph")); - } - if (chevron_data == 3 || chevron_data == chevron_all) { - position = (chevron_data == 3) ? 0 : 2; - val = (d_rel > 0 && v_ego > 0) ? std::max(0.0f, d_rel / v_ego) : 0.0f; - - QString ttc_str = (val > 0 && val < 200) ? QString::number(val, 'f', 1) + "s" : "---"; - chevron_text[position].append(ttc_str); - } - - float str_w = 200; // Width of the text box, might need adjustment - float str_h = 50; // Height of the text box, adjust as necessary - painter.setFont(InterFont(45, QFont::Bold)); - // Calculate the center of the chevron and adjust the text box position - float text_y = y + sz + 12; // Position the text at the bottom of the chevron - QRect textRect(x - str_w / 2, text_y, str_w, str_h); // Adjust the rectangle to center the text horizontally at the chevron's bottom - QPoint shadow_offset(2, 2); - for (int i = 0; i < chevron_types; ++i) { - if (!chevron_text[i].isEmpty()) { - painter.setPen(QColor(0x0, 0x0, 0x0, 200)); // Draw shadow - painter.drawText(textRect.translated(shadow_offset.x(), shadow_offset.y() + i * str_h), Qt::AlignBottom | Qt::AlignHCenter, chevron_text[i].at(0)); - painter.setPen(QColor(0xff, 0xff, 0xff)); // Draw text - painter.drawText(textRect.translated(0, i * str_h), Qt::AlignBottom | Qt::AlignHCenter, chevron_text[i].at(0)); - painter.setPen(Qt::NoPen); // Reset pen to default - } - } - } - painter.restore(); } void AnnotatedCameraWidget::paintGL() { -} - -void AnnotatedCameraWidget::paintEvent(QPaintEvent *event) { UIState *s = uiState(); SubMaster &sm = *(s->sm); const double start_draw_t = millis_since_boot(); const cereal::ModelDataV2::Reader &model = sm["modelV2"].getModelV2(); - QPainter painter(this); - // draw camera frame { std::lock_guard lk(frame_lock); @@ -1601,10 +311,9 @@ void AnnotatedCameraWidget::paintEvent(QPaintEvent *event) { bool has_wide_cam = available_streams.count(VISION_STREAM_WIDE_ROAD); if (has_wide_cam) { float v_ego = sm["carState"].getCarState().getVEgo(); - float steer_angle = sm["carState"].getCarState().getSteeringAngleDeg(); - if ((v_ego < 10) || available_streams.size() == 1 || (std::fabs(steer_angle) > 45)) { + if ((v_ego < 10) || available_streams.size() == 1) { wide_cam_requested = true; - } else if ((v_ego > 15) && (std::fabs(steer_angle) < 30)) { + } else if (v_ego > 15) { wide_cam_requested = false; } wide_cam_requested = wide_cam_requested && sm["controlsState"].getControlsState().getExperimentalMode(); @@ -1613,10 +322,6 @@ void AnnotatedCameraWidget::paintEvent(QPaintEvent *event) { } CameraWidget::setStreamType(wide_cam_requested ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD); - if (reversing && s->scene.reverse_dm_cam) { - CameraWidget::setStreamType(VISION_STREAM_DRIVER, s->scene.reverse_dm_cam); - } - s->scene.wide_cam = CameraWidget::getStreamType() == VISION_STREAM_WIDE_ROAD; if (s->scene.calibration_valid) { auto calib = s->scene.wide_cam ? s->scene.view_from_wide_calib : s->scene.view_from_calib; @@ -1624,12 +329,11 @@ void AnnotatedCameraWidget::paintEvent(QPaintEvent *event) { } else { CameraWidget::updateCalibration(DEFAULT_CALIBRATION); } - painter.beginNativePainting(); CameraWidget::setFrameId(model.getFrameId()); CameraWidget::paintGL(); - painter.endNativePainting(); } + QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(Qt::NoPen); @@ -1639,18 +343,15 @@ void AnnotatedCameraWidget::paintEvent(QPaintEvent *event) { if (s->scene.longitudinal_control && sm.rcv_frame("radarState") > s->scene.started_frame) { auto radar_state = sm["radarState"].getRadarState(); - auto car_state = sm["carState"].getCarState(); update_leads(s, radar_state, model.getPosition()); auto lead_one = radar_state.getLeadOne(); auto lead_two = radar_state.getLeadTwo(); if (lead_one.getStatus()) { - drawLead(painter, lead_one, s->scene.lead_vertices[0], 0, car_state, s->scene.chevron_data); + drawLead(painter, lead_one, s->scene.lead_vertices[0]); } if (lead_two.getStatus() && (std::abs(lead_one.getDRel() - lead_two.getDRel()) > 3.0)) { - drawLead(painter, lead_two, s->scene.lead_vertices[1], 1, car_state, s->scene.chevron_data); + drawLead(painter, lead_two, s->scene.lead_vertices[1]); } - - rocketFuel(painter); } } @@ -1662,21 +363,6 @@ void AnnotatedCameraWidget::paintEvent(QPaintEvent *event) { drawHud(painter); - if (left_blinker || right_blinker) { - blinker_frame++; - int state = blinkerPulse(blinker_frame); - int blinker_x = splitPanelVisible ? 150 : 180; - int blinker_y = splitPanelVisible ? 220 : 90; - if (left_blinker) { - drawLeftTurnSignal(painter, rect().center().x() - (blinker_x + blinker_size), blinker_y, blinker_size, state); - } - if (right_blinker) { - drawRightTurnSignal(painter, rect().center().x() + blinker_x, blinker_y, blinker_size, state); - } - } else { - blinker_frame = 0; - } - double cur_draw_t = millis_since_boot(); double dt = cur_draw_t - prev_draw_t; double fps = fps_filter.update(1. / dt * 1000); @@ -1690,11 +376,6 @@ void AnnotatedCameraWidget::paintEvent(QPaintEvent *event) { auto m = msg.initEvent().initUiDebug(); m.setDrawTimeMillis(cur_draw_t - start_draw_t); pm->send("uiDebug", msg); - - MessageBuilder e2e_long_msg; - auto e2eLongStatus = e2e_long_msg.initEvent().initE2eLongStateSP(); - e2eLongStatus.setStatus(e2eStatus); - e2e_state->send("e2eLongStateSP", e2e_long_msg); } void AnnotatedCameraWidget::showEvent(QShowEvent *event) { diff --git a/selfdrive/ui/qt/onroad/annotated_camera.h b/selfdrive/ui/qt/onroad/annotated_camera.h index 29b9c4833b..465ba23e04 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.h +++ b/selfdrive/ui/qt/onroad/annotated_camera.h @@ -2,14 +2,10 @@ #include #include -#include #include "selfdrive/ui/qt/onroad/buttons.h" #include "selfdrive/ui/qt/widgets/cameraview.h" -const int subsign_img_size = 35; -const int blinker_size = 120; - class AnnotatedCameraWidget : public CameraWidget { Q_OBJECT @@ -17,68 +13,8 @@ public: explicit AnnotatedCameraWidget(VisionStreamType type, QWidget* parent = 0); void updateState(const UIState &s); - MapSettingsButton *map_settings_btn; - OnroadSettingsButton *onroad_settings_btn; - private: void drawText(QPainter &p, int x, int y, const QString &text, int alpha = 255); - void drawCenteredText(QPainter &p, int x, int y, const QString &text, QColor color); - void drawVisionTurnControllerUI(QPainter &p, int x, int y, int size, const QColor &color, const QString &speed, - int alpha); - void drawCircle(QPainter &p, int x, int y, int r, QBrush bg); - void drawSpeedSign(QPainter &p, QRect rc, const QString &speed, const QString &sub_text, int subtext_size, - bool is_map_sourced, bool is_active); - void drawTrunSpeedSign(QPainter &p, QRect rc, const QString &speed, const QString &sub_text, int curv_sign, - bool is_active); - - void drawColoredText(QPainter &p, int x, int y, const QString &text, QColor color); - void drawStandstillTimer(QPainter &p, int x, int y); - - // ############################## DEV UI START ############################## - void drawRightDevUi(QPainter &p, int x, int y); - int drawDevUiElementRight(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color); - int drawNewDevUiElement(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color); - void drawNewDevUi2(QPainter &p, int x, int y); - void drawCenteredLeftText(QPainter &p, int x, int y, const QString &text1, QColor color1, const QString &text2, const QString &text3, QColor color2); - struct UiElement { - QString value; - QString label; - QString units; - QColor color; - - UiElement(const QString &value, const QString &label, const QString &units, const QColor &color = QColor(255, 255, 255, 255)) - : value(value), label(label), units(units), color(color) {} - }; - - UiElement getDRel(); - UiElement getVRel(); - UiElement getSteeringAngleDeg(); - UiElement getActualLateralAccel(); - UiElement getSteeringAngleDesiredDeg(); - UiElement getMemoryUsagePercent(); - - UiElement getAEgo(); - UiElement getVEgoLead(); - UiElement getFrictionCoefficientFiltered(); - UiElement getLatAccelFactorFiltered(); - UiElement getSteeringTorqueEps(); - UiElement getBearingDeg(); - UiElement getAltitude(); - - // ############################## DEV UI END ############################## - - void drawE2eStatus(QPainter &p, int x, int y, int w, int h, int e2e_long_status); - - void drawLeftTurnSignal(QPainter &painter, int x, int y, int circle_size, int state); - void drawRightTurnSignal(QPainter &painter, int x, int y, int circle_size, int state); - int blinkerPulse(int frame); - void updateButtonsLayout(bool is_rhd); - - void drawFeatureStatusText(QPainter &p, int x, int y); - void speedLimitSignPulse(int frame); - void speedLimitWarning(QPainter &p, QRect sign_rect, const int sign_margin); - void mousePressEvent(QMouseEvent* e) override; - void drawRoadNameText(QPainter &p, int x, int y, const QString &text, QColor color); QVBoxLayout *main_layout; ExperimentalButton *experimental_btn; @@ -86,15 +22,12 @@ private: float speed; QString speedUnit; float setSpeed; - float speedLimit; bool is_cruise_set = false; bool is_metric = false; bool dmActive = false; bool hideBottomIcons = false; bool rightHandDM = false; float dm_fade_state = 1.0; - bool has_us_speed_limit = false; - bool has_eu_speed_limit = false; bool v_ego_cluster_seen = false; int status = STATUS_DISENGAGED; std::unique_ptr pm; @@ -102,126 +35,19 @@ private: int skip_frame_count = 0; bool wide_cam_requested = false; - Params params; - QHBoxLayout *buttons_layout; - QPixmap map_img; - QPixmap left_img; - QPixmap right_img; - bool left_blindspot = false; - bool right_blindspot = false; - std::unique_ptr e2e_state; - - bool steerOverride = false; - bool gasOverride = false; - bool latActive = false; - bool madsEnabled = false; - - bool brakeLights; - - bool standStillTimer; - bool standStill; - float standstillElapsedTime; - - bool showVTC = false; - QString vtcSpeed; - QColor vtcColor; - - bool showDebugUI = false; - - QString roadName = ""; - - bool showSpeedLimit = false; - float speedLimitSLC; - float speedLimitSLCOffset; - float speedLimitWarningOffset; - QString slcSubText; - float slcSubTextSize = 0.0; - bool overSpeedLimit; - bool mapSourcedSpeedLimit = false; - bool slcActive = false; - - bool showTurnSpeedLimit = false; - QString turnSpeedLimit; - QString tscSubText; - bool tscActive = false; - int curveSign = 0; - - bool hideVEgoUi; - - bool splitPanelVisible; - - // ############################## DEV UI START ############################## - bool lead_status; - float lead_d_rel = 0; - float lead_v_rel = 0; - QString lateralState; - float angleSteers = 0; - float steerAngleDesired = 0; - float curvature; - float roll; - int memoryUsagePercent; - int devUiInfo; - float gpsAccuracy; - float altitude; - float vEgo; - float aEgo; - float steeringTorqueEps; - float bearingAccuracyDeg; - float bearingDeg; - bool torquedUseParams; - float latAccelFactorFiltered; - float frictionCoefficientFiltered; - bool liveValid; - // ############################## DEV UI END ############################## - - float btnPerc; - - bool reversing; - - int e2eState; - int e2eStatus; - - bool left_blinker, right_blinker, lane_change_edge_block; - int blinker_frame; - int blinker_state = 0; - - cereal::LongitudinalPlanSP::SpeedLimitControlState slcState; - int longitudinalPersonality; - int dynamicLaneProfile; - QString mpcMode; - - int speed_limit_frame; - bool slcShowSign = true; - QPixmap plus_arrow_up_img; - QPixmap minus_arrow_down_img; - QRect sl_sign_rect; - int rn_offset = 0; - bool e2eLongAlertUi, dynamicExperimentalControlToggle, speedLimitControlToggle, speedLimitWarningFlash; - cereal::CarParams::Reader car_params; - bool cruiseStateEnabled; - bool experimentalMode; - - bool featureStatusToggle; - - cereal::ModelGeneration drivingModelGen; - protected: void paintGL() override; void initializeGL() override; void showEvent(QShowEvent *event) override; void updateFrameMat() override; void drawLaneLines(QPainter &painter, const UIState *s); - void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, - int num, const cereal::CarState::Reader &car_data, int chevron_data); + void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd); void drawHud(QPainter &p); void drawDriverState(QPainter &painter, const UIState *s); inline QColor redColor(int alpha = 255) { return QColor(201, 34, 49, alpha); } inline QColor whiteColor(int alpha = 255) { return QColor(255, 255, 255, alpha); } inline QColor blackColor(int alpha = 255) { return QColor(0, 0, 0, alpha); } - void paintEvent(QPaintEvent *event) override; - void rocketFuel(QPainter &p); - double prev_draw_t = 0; FirstOrderFilter fps_filter; }; diff --git a/selfdrive/ui/qt/onroad/buttons.cc b/selfdrive/ui/qt/onroad/buttons.cc index fbca42da7b..92bcea11b5 100644 --- a/selfdrive/ui/qt/onroad/buttons.cc +++ b/selfdrive/ui/qt/onroad/buttons.cc @@ -15,18 +15,6 @@ void drawIcon(QPainter &p, const QPoint ¢er, const QPixmap &img, const QBrus p.setOpacity(1.0); } -static void drawCustomButtonIcon(QPainter &p, const int btn_size_x, const int btn_size_y, const QPixmap &img, const QBrush &bg, float opacity) { - QPoint center(btn_size_x / 2, btn_size_y / 2); - p.setRenderHint(QPainter::Antialiasing); - p.setOpacity(1.0); // bg dictates opacity of ellipse - p.setPen(Qt::NoPen); - p.setBrush(bg); - p.drawEllipse(center, btn_size_x / 2, btn_size_y / 2); - p.setOpacity(opacity); - p.drawPixmap(center - QPoint(img.width() / 2, img.height() / 2), img); - p.setOpacity(1.0); -} - // ExperimentalButton ExperimentalButton::ExperimentalButton(QWidget *parent) : experimental_mode(false), engageable(false), QPushButton(parent) { setFixedSize(btn_size, btn_size); @@ -46,8 +34,7 @@ void ExperimentalButton::changeMode() { void ExperimentalButton::updateState(const UIState &s) { const auto cs = (*s.sm)["controlsState"].getControlsState(); - const auto lp_sp = (*s.sm)["longitudinalPlanSP"].getLongitudinalPlanSP(); - bool eng = (cs.getEngageable() || cs.getEnabled()) && !(lp_sp.getVisionTurnControllerState() > cereal::LongitudinalPlanSP::VisionTurnControllerState::DISABLED); + bool eng = cs.getEngageable() || cs.getEnabled(); if ((cs.getExperimentalMode() != experimental_mode) || (eng != engageable)) { engageable = eng; experimental_mode = cs.getExperimentalMode(); @@ -60,48 +47,3 @@ void ExperimentalButton::paintEvent(QPaintEvent *event) { QPixmap img = experimental_mode ? experimental_img : engage_img; drawIcon(p, QPoint(btn_size / 2, btn_size / 2), img, QColor(0, 0, 0, 166), (isDown() || !engageable) ? 0.6 : 1.0); } - - -// MapSettingsButton -MapSettingsButton::MapSettingsButton(QWidget *parent) : QPushButton(parent) { - // btn_size: 192 * 80% ~= 152 - // img_size: (152 / 4) * 3 = 114 - setFixedSize(152, 152); - settings_img = loadPixmap("../assets/navigation/icon_directions_outlined.svg", {114, 114}); - - // hidden by default, made visible if map is created (has prime or mapbox token) - setVisible(false); - setEnabled(false); -} - -void MapSettingsButton::paintEvent(QPaintEvent *event) { - QPainter p(this); - drawCustomButtonIcon(p, 152, 152, settings_img, QColor(0, 0, 0, 166), isDown() ? 0.6 : 1.0); -} - - -// OnroadSettingsButton -OnroadSettingsButton::OnroadSettingsButton(QWidget *parent) : QPushButton(parent) { - // btn_size: 192 * 80% ~= 152 - // img_size: (152 / 4) * 3 = 114 - setFixedSize(152, 152); - settings_img = loadPixmap("../assets/navigation/icon_settings.svg", {114, 114}); - - // hidden by default, made visible if Driving Personality / GAC, DLP, DEC, or SLC is enabled - setVisible(false); - setEnabled(false); -} - -void OnroadSettingsButton::paintEvent(QPaintEvent *event) { - QPainter p(this); - drawCustomButtonIcon(p, 152, 152, settings_img, QColor(0, 0, 0, 166), isDown() ? 0.6 : 1.0); -} - -void OnroadSettingsButton::updateState(const UIState &s) { - const auto cp = (*s.sm)["carParams"].getCarParams(); - auto dlp_enabled = s.scene.driving_model_generation == cereal::ModelGeneration::ONE; - bool allow_btn = s.scene.onroad_settings_toggle && (dlp_enabled || hasLongitudinalControl(cp) || !cp.getPcmCruiseSpeed()); - - setVisible(allow_btn); - setEnabled(allow_btn); -} diff --git a/selfdrive/ui/qt/onroad/buttons.h b/selfdrive/ui/qt/onroad/buttons.h index feee1ba639..e999480d5c 100644 --- a/selfdrive/ui/qt/onroad/buttons.h +++ b/selfdrive/ui/qt/onroad/buttons.h @@ -2,7 +2,11 @@ #include +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/ui.h" +#else #include "selfdrive/ui/ui.h" +#endif const int btn_size = 192; const int img_size = (btn_size / 4) * 3; @@ -14,6 +18,10 @@ public: explicit ExperimentalButton(QWidget *parent = 0); void updateState(const UIState &s); +protected: + bool experimental_mode; + bool engageable; + private: void paintEvent(QPaintEvent *event) override; void changeMode(); @@ -21,35 +29,6 @@ private: Params params; QPixmap engage_img; QPixmap experimental_img; - bool experimental_mode; - bool engageable; -}; - - -class MapSettingsButton : public QPushButton { - Q_OBJECT - -public: - explicit MapSettingsButton(QWidget *parent = 0); - -private: - void paintEvent(QPaintEvent *event) override; - - QPixmap settings_img; -}; - - -class OnroadSettingsButton : public QPushButton { - Q_OBJECT - -public: - explicit OnroadSettingsButton(QWidget *parent = 0); - void updateState(const UIState &s); - -private: - void paintEvent(QPaintEvent *event) override; - - QPixmap settings_img; }; void drawIcon(QPainter &p, const QPoint ¢er, const QPixmap &img, const QBrush &bg, float opacity); diff --git a/selfdrive/ui/qt/onroad/onroad_home.cc b/selfdrive/ui/qt/onroad/onroad_home.cc index 7413cdff7e..e93ded6cc2 100644 --- a/selfdrive/ui/qt/onroad/onroad_home.cc +++ b/selfdrive/ui/qt/onroad/onroad_home.cc @@ -3,12 +3,6 @@ #include #include -#ifdef ENABLE_MAPS -#include "selfdrive/ui/qt/maps/map_helpers.h" -#include "selfdrive/ui/qt/maps/map_panel.h" -#endif -#include "selfdrive/ui/qt/onroad_settings_panel.h" - #include "selfdrive/ui/qt/util.h" OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) { @@ -31,11 +25,6 @@ OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) { split->insertWidget(0, arCam); } - if (getenv("MAP_RENDER_VIEW")) { - CameraWidget *map_render = new CameraWidget("navd", VISION_STREAM_MAP, false, this); - split->insertWidget(0, map_render); - } - stacked_layout->addWidget(split_wrapper); alerts = new OnroadAlerts(this); @@ -46,9 +35,12 @@ OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) { alerts->raise(); setAttribute(Qt::WA_OpaquePaintEvent); + + // We handle the connection of the signals on the derived class +#ifndef SUNNYPILOT QObject::connect(uiState(), &UIState::uiUpdate, this, &OnroadWindow::updateState); QObject::connect(uiState(), &UIState::offroadTransition, this, &OnroadWindow::offroadTransition); - QObject::connect(uiState(), &UIState::primeChanged, this, &OnroadWindow::primeChanged); +#endif } void OnroadWindow::updateState(const UIState &s) { @@ -56,12 +48,6 @@ void OnroadWindow::updateState(const UIState &s) { return; } - if (s.scene.map_on_left || s.scene.mapbox_fullscreen) { - split->setDirection(QBoxLayout::LeftToRight); - } else { - split->setDirection(QBoxLayout::RightToLeft); - } - alerts->updateState(s); nvg->updateState(s); @@ -73,99 +59,10 @@ void OnroadWindow::updateState(const UIState &s) { } } - -void OnroadWindow::mousePressEvent(QMouseEvent* e) { -#ifdef ENABLE_MAPS - UIState *s = uiState(); - UIScene &scene = s->scene; - if (map != nullptr && !isOnroadSettingsVisible()) { - if (wakeScreenTimeout()) { - // Switch between map and sidebar when using navigate on openpilot - bool sidebarVisible = geometry().x() > 0; - bool show_map = uiState()->scene.navigate_on_openpilot_deprecated ? sidebarVisible : !sidebarVisible; - updateMapSize(scene); - map->setVisible(show_map && !map->isVisible()); - } - } -#endif - if (onroad_settings != nullptr && !isMapVisible()) { - if (wakeScreenTimeout()) { - onroad_settings->setVisible(false); - } - } - // propagation event to parent(HomeWindow) - QWidget::mousePressEvent(e); -} - -void OnroadWindow::createMapWidget() { -#ifdef ENABLE_MAPS - auto m = new MapPanel(get_mapbox_settings()); - map = m; - - QObject::connect(m, &MapPanel::mapPanelRequested, this, &OnroadWindow::mapPanelRequested); - QObject::connect(m, &MapPanel::mapPanelRequested, this, &OnroadWindow::onroadSettingsPanelNotRequested); - QObject::connect(nvg->map_settings_btn, &MapSettingsButton::clicked, m, &MapPanel::toggleMapSettings); - nvg->map_settings_btn->setEnabled(true); - - m->setFixedWidth(uiState()->scene.mapbox_fullscreen ? topWidget(this)->width() : - topWidget(this)->width() / 2 - UI_BORDER_SIZE); - split->insertWidget(0, m); - - // hidden by default, made visible when navRoute is published - m->setVisible(false); -#endif -} - -void OnroadWindow::createOnroadSettingsWidget() { - auto os = new OnroadSettingsPanel(this); - onroad_settings = os; - - QObject::connect(os, &OnroadSettingsPanel::onroadSettingsPanelRequested, this, &OnroadWindow::onroadSettingsPanelRequested); - QObject::connect(os, &OnroadSettingsPanel::onroadSettingsPanelRequested, this, &OnroadWindow::mapPanelNotRequested); - QObject::connect(nvg->onroad_settings_btn, &OnroadSettingsButton::clicked, os, &OnroadSettingsPanel::toggleOnroadSettings); - nvg->onroad_settings_btn->setEnabled(true); - - os->setFixedWidth(topWidget(this)->width() / 2.6 - UI_BORDER_SIZE); - split->insertWidget(0, os); - - // hidden by default - os->setVisible(false); -} - void OnroadWindow::offroadTransition(bool offroad) { - if (!offroad) { -#ifdef ENABLE_MAPS - if (map == nullptr && (uiState()->hasPrime() || !MAPBOX_TOKEN.isEmpty())) { - createMapWidget(); - } -#endif - if (onroad_settings == nullptr) { - createOnroadSettingsWidget(); - } - } - alerts->clear(); } -void OnroadWindow::updateMapSize(const UIScene &scene) { - map->setFixedWidth(scene.mapbox_fullscreen ? topWidget(this)->width() : - topWidget(this)->width() / 2 - UI_BORDER_SIZE); - split->insertWidget(0, map); -} - -void OnroadWindow::primeChanged(bool prime) { -#ifdef ENABLE_MAPS - if (map && (!prime && MAPBOX_TOKEN.isEmpty())) { - nvg->map_settings_btn->setEnabled(false); - nvg->map_settings_btn->setVisible(false); - map->deleteLater(); - map = nullptr; - } else if (!map && (prime || !MAPBOX_TOKEN.isEmpty())) { - createMapWidget(); - } -#endif -} - void OnroadWindow::paintEvent(QPaintEvent *event) { QPainter p(this); p.fillRect(rect(), QColor(bg.red(), bg.green(), bg.blue(), 255)); diff --git a/selfdrive/ui/qt/onroad/onroad_home.h b/selfdrive/ui/qt/onroad/onroad_home.h index 1beadcd13b..4ac37678fa 100644 --- a/selfdrive/ui/qt/onroad/onroad_home.h +++ b/selfdrive/ui/qt/onroad/onroad_home.h @@ -1,51 +1,29 @@ #pragma once -#include "common/params.h" #include "selfdrive/ui/qt/onroad/alerts.h" + +#if SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h" +#define AnnotatedCameraWidget AnnotatedCameraWidgetSP +#define UIState UIStateSP +#else #include "selfdrive/ui/qt/onroad/annotated_camera.h" +#endif class OnroadWindow : public QWidget { Q_OBJECT public: OnroadWindow(QWidget* parent = 0); - bool isMapVisible() const { return map && map->isVisible(); } - void showMapPanel(bool show) { if (map) map->setVisible(show); } - bool isOnroadSettingsVisible() const { return onroad_settings && onroad_settings->isVisible(); } - bool isMapAvailable() const { return map; } - void mapPanelNotRequested() { if (map) map->setVisible(false); } - void onroadSettingsPanelNotRequested() { if (onroad_settings) onroad_settings->setVisible(false); } - - bool wakeScreenTimeout() { - if ((uiState()->scene.sleep_btn != 0 && uiState()->scene.sleep_btn_opacity != 0) || - (uiState()->scene.sleep_time != 0 && uiState()->scene.onroadScreenOff != -2)) { - return true; - } - return false; - } - -signals: - void mapPanelRequested(); - void onroadSettingsPanelRequested(); - -private: - void createMapWidget(); - void createOnroadSettingsWidget(); - void paintEvent(QPaintEvent *event); - void mousePressEvent(QMouseEvent* e) override; +protected: + void paintEvent(QPaintEvent *event) override; OnroadAlerts *alerts; AnnotatedCameraWidget *nvg; QColor bg = bg_colors[STATUS_DISENGAGED]; - QWidget *map = nullptr; - QWidget *onroad_settings = nullptr; QHBoxLayout* split; - Params params; - -private slots: - void offroadTransition(bool offroad); - void primeChanged(bool prime); - void updateState(const UIState &s); - void updateMapSize(const UIScene &scene); +protected slots: + virtual void offroadTransition(bool offroad); + virtual void updateState(const UIState &s); }; diff --git a/selfdrive/ui/qt/onroad_settings_panel.cc b/selfdrive/ui/qt/onroad_settings_panel.cc deleted file mode 100644 index 163f0fb31f..0000000000 --- a/selfdrive/ui/qt/onroad_settings_panel.cc +++ /dev/null @@ -1,26 +0,0 @@ -#include "selfdrive/ui/qt/onroad_settings_panel.h" - -#include -#include - -#include "selfdrive/ui/qt/onroad_settings.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/ui.h" - -OnroadSettingsPanel::OnroadSettingsPanel(QWidget *parent) : QFrame(parent) { - content_stack = new QStackedLayout(this); - content_stack->setContentsMargins(0, 0, 0, 0); - - auto onroad_settings = new OnroadSettings(true, parent); - QObject::connect(onroad_settings, &OnroadSettings::closeSettings, this, &OnroadSettings::hide); - content_stack->addWidget(onroad_settings); -} - -void OnroadSettingsPanel::toggleOnroadSettings() { - if (isVisible()) { - hide(); - } else { - emit onroadSettingsPanelRequested(); - show(); - } -} diff --git a/selfdrive/ui/qt/onroad_settings_panel.h b/selfdrive/ui/qt/onroad_settings_panel.h deleted file mode 100644 index 8b81aef25a..0000000000 --- a/selfdrive/ui/qt/onroad_settings_panel.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include -#ifdef ENABLE_MAPS -#include -#endif -#include - -class OnroadSettingsPanel : public QFrame { - Q_OBJECT - -public: - explicit OnroadSettingsPanel(QWidget *parent = nullptr); - -signals: - void onroadSettingsPanelRequested(); - -public slots: - void toggleOnroadSettings(); - -private: - QStackedLayout *content_stack; -}; diff --git a/selfdrive/ui/qt/request_repeater.cc b/selfdrive/ui/qt/request_repeater.cc index 8212d3db94..d215fe42ca 100644 --- a/selfdrive/ui/qt/request_repeater.cc +++ b/selfdrive/ui/qt/request_repeater.cc @@ -1,36 +1,36 @@ #include "selfdrive/ui/qt/request_repeater.h" -#include "common/swaglog.h" - RequestRepeater::RequestRepeater(QObject *parent, const QString &requestURL, const QString &cacheKey, - int period, bool whileOnroad, bool sunnylink) : HttpRequest(parent, true, 20000, sunnylink) { - request_url = requestURL; - while_onroad = whileOnroad; + int period, bool while_onroad) : HttpRequest(parent) { timer = new QTimer(this); timer->setTimerType(Qt::VeryCoarseTimer); - connect(timer, &QTimer::timeout, [=]() { this->timerTick(); }); + + connectTimer(requestURL, while_onroad); + timer->start(period * 1000); + setupCacheProcess(cacheKey); +} + +void RequestRepeater::connectTimer(const QString &requestURL, bool while_onroad) { + QObject::connect(timer, &QTimer::timeout, [=]() { + if ((!uiState()->scene.started || while_onroad) && device()->isAwake() && !active()) { + sendRequest(requestURL); + } + }); +} + +void RequestRepeater::setupCacheProcess(const QString &cacheKey) { if (!cacheKey.isEmpty()) { prevResp = QString::fromStdString(params.get(cacheKey.toStdString())); if (!prevResp.isEmpty()) { QTimer::singleShot(500, [=]() { emit requestDone(prevResp, true, QNetworkReply::NoError); }); } - connect(this, &HttpRequest::requestDone, [=](const QString &resp, bool success) { + QObject::connect(this, &HttpRequest::requestDone, [=](const QString &resp, bool success) { if (success && resp != prevResp) { params.put(cacheKey.toStdString(), resp.toStdString()); prevResp = resp; } }); } - - // Don't wait for the timer to fire to send the first request - ForceUpdate(); -} - -void RequestRepeater::timerTick() { - if ((!uiState()->scene.started || while_onroad) && device()->isAwake() && !active()) { - LOGD("Sending request for %s", qPrintable(request_url)); - sendRequest(request_url); - } } diff --git a/selfdrive/ui/qt/request_repeater.h b/selfdrive/ui/qt/request_repeater.h index 45cb643b13..32e714b1cb 100644 --- a/selfdrive/ui/qt/request_repeater.h +++ b/selfdrive/ui/qt/request_repeater.h @@ -1,24 +1,23 @@ #pragma once -#include "common/swaglog.h" #include "common/util.h" -#include "selfdrive/ui/qt/api.h" + +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/api.h" +#else #include "selfdrive/ui/ui.h" +#include "selfdrive/ui/qt/api.h" +#endif class RequestRepeater : public HttpRequest { +public: + void connectTimer(const QString& requestURL, bool while_onroad); + void setupCacheProcess(const QString& cacheKey); + RequestRepeater(QObject *parent, const QString &requestURL, const QString &cacheKey = "", int period = 0, bool while_onroad=false); private: Params params; QTimer *timer; QString prevResp; - QString request_url; - bool while_onroad; - void timerTick(); - -public: - RequestRepeater(QObject *parent, const QString &requestURL, const QString &cacheKey = "", int period = 0, bool whileOnroad=false, bool sunnylink = false); - void ForceUpdate() { - LOGD("Forcing update for %s", qPrintable(request_url)); - timerTick(); - } }; diff --git a/selfdrive/ui/qt/sidebar.cc b/selfdrive/ui/qt/sidebar.cc index 8d45e62ce4..615276be00 100644 --- a/selfdrive/ui/qt/sidebar.cc +++ b/selfdrive/ui/qt/sidebar.cc @@ -1,11 +1,8 @@ #include "selfdrive/ui/qt/sidebar.h" -#include - #include #include "selfdrive/ui/qt/util.h" -#include "common/params.h" void Sidebar::drawMetric(QPainter &p, const QPair &label, QColor c, int y) { const QRect rect = {30, y, 240, 126}; @@ -93,58 +90,16 @@ void Sidebar::updateState(const UIState &s) { } setProperty("connectStatus", QVariant::fromValue(connectStatus)); - if (sm.frame % UI_FREQ == 0) { // Update every 1 Hz - switch (s.scene.sidebar_temp_options) { - case 0: - break; - case 1: - sidebar_temp = QString::number((int)deviceState.getMemoryTempC()); - break; - case 2: { - const auto& cpu_temp_list = deviceState.getCpuTempC(); - float max_cpu_temp = std::numeric_limits::lowest(); - - for (const float& temp : cpu_temp_list) { - max_cpu_temp = std::max(max_cpu_temp, temp); - } - - if (max_cpu_temp >= 0) { - sidebar_temp = QString::number(std::nearbyint(max_cpu_temp)); - } - break; - } - case 3: { - const auto& gpu_temp_list = deviceState.getGpuTempC(); - float max_gpu_temp = std::numeric_limits::lowest(); - - for (const float& temp : gpu_temp_list) { - max_gpu_temp = std::max(max_gpu_temp, temp); - } - - if (max_gpu_temp >= 0) { - sidebar_temp = QString::number(std::nearbyint(max_gpu_temp)); - } - break; - } - case 4: - sidebar_temp = QString::number((int)deviceState.getMaxTempC()); - break; - default: - break; - } - - setProperty("sidebarTemp", sidebar_temp + "°C"); - } - - bool show_sidebar_temp = s.scene.sidebar_temp_options != 0; - ItemStatus tempStatus = {{tr("TEMP"), show_sidebar_temp ? sidebar_temp_str : tr("HIGH")}, danger_color}; +#ifndef SUNNYPILOT + ItemStatus tempStatus = {{tr("TEMP"), tr("HIGH")}, danger_color}; auto ts = deviceState.getThermalStatus(); if (ts == cereal::DeviceState::ThermalStatus::GREEN) { - tempStatus = {{tr("TEMP"), show_sidebar_temp ? sidebar_temp_str : tr("GOOD")}, good_color}; + tempStatus = {{tr("TEMP"), tr("GOOD")}, good_color}; } else if (ts == cereal::DeviceState::ThermalStatus::YELLOW) { - tempStatus = {{tr("TEMP"), show_sidebar_temp ? sidebar_temp_str : tr("OK")}, warning_color}; + tempStatus = {{tr("TEMP"), tr("OK")}, warning_color}; } setProperty("tempStatus", QVariant::fromValue(tempStatus)); +#endif ItemStatus pandaStatus = {{tr("VEHICLE"), tr("ONLINE")}, good_color}; if (s.scene.pandaType == cereal::PandaState::PandaType::UNKNOWN) { @@ -153,32 +108,14 @@ void Sidebar::updateState(const UIState &s) { pandaStatus = {{tr("GPS"), tr("SEARCH")}, warning_color}; } setProperty("pandaStatus", QVariant::fromValue(pandaStatus)); - - ItemStatus sunnylinkStatus; - auto sl_dongle_id = getSunnylinkDongleId(); - auto last_sunnylink_ping_str = params.get("LastSunnylinkPingTime"); - auto last_sunnylink_ping = std::stoull(last_sunnylink_ping_str.empty() ? "0" : last_sunnylink_ping_str); - auto elapsed_sunnylink_ping = nanos_since_boot() - last_sunnylink_ping; - auto sunnylink_enabled = params.getBool("SunnylinkEnabled"); - - QString status = tr("DISABLED"); - QColor color = disabled_color; - - if (sunnylink_enabled && last_sunnylink_ping == 0) { - // If sunnylink is enabled, but we don't have a dongle id, and we haven't received a ping yet, we are registering - status = sl_dongle_id.has_value() ? tr("OFFLINE") : tr("REGIST..."); - color = sl_dongle_id.has_value() ? warning_color : progress_color; - } else if (sunnylink_enabled) { - // If sunnylink is enabled, we are considered online if we have received a ping in the last 80 seconds, else error. - status = elapsed_sunnylink_ping < 80000000000ULL ? tr("ONLINE") : tr("ERROR"); - color = elapsed_sunnylink_ping < 80000000000ULL ? good_color : danger_color; - } - sunnylinkStatus = ItemStatus{{tr("SUNNYLINK"), status}, color }; - setProperty("sunnylinkStatus", QVariant::fromValue(sunnylinkStatus)); } void Sidebar::paintEvent(QPaintEvent *event) { QPainter p(this); + DrawSidebar(p); // Because derived classes implement this. Otherwise QPainter gets terminated before time. +} + +void Sidebar::DrawSidebar(QPainter &p){ p.setPen(Qt::NoPen); p.setRenderHint(QPainter::Antialiasing); @@ -204,10 +141,10 @@ void Sidebar::paintEvent(QPaintEvent *event) { p.setPen(QColor(0xff, 0xff, 0xff)); const QRect r = QRect(50, 247, 100, 50); p.drawText(r, Qt::AlignCenter, net_type); + RETURN_IF_SUNNYPILOT // Because we draw ourselves // metrics - drawMetric(p, temp_status.first, temp_status.second, 310); - drawMetric(p, panda_status.first, panda_status.second, 440); - drawMetric(p, connect_status.first, connect_status.second, 570); - drawMetric(p, sunnylink_status.first, sunnylink_status.second, 700); + drawMetric(p, temp_status.first, temp_status.second, 338); + drawMetric(p, panda_status.first, panda_status.second, 496); + drawMetric(p, connect_status.first, connect_status.second, 654); } diff --git a/selfdrive/ui/qt/sidebar.h b/selfdrive/ui/qt/sidebar.h index 9012f25135..62a5486809 100644 --- a/selfdrive/ui/qt/sidebar.h +++ b/selfdrive/ui/qt/sidebar.h @@ -4,8 +4,13 @@ #include #include +#include "cereal/messaging/messaging.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/ui.h" +#else #include "selfdrive/ui/ui.h" +#endif typedef QPair, QColor> ItemStatus; Q_DECLARE_METATYPE(ItemStatus); @@ -13,12 +18,10 @@ Q_DECLARE_METATYPE(ItemStatus); class Sidebar : public QFrame { Q_OBJECT Q_PROPERTY(ItemStatus connectStatus MEMBER connect_status NOTIFY valueChanged); - Q_PROPERTY(ItemStatus sunnylinkStatus MEMBER sunnylink_status NOTIFY valueChanged); Q_PROPERTY(ItemStatus pandaStatus MEMBER panda_status NOTIFY valueChanged); Q_PROPERTY(ItemStatus tempStatus MEMBER temp_status NOTIFY valueChanged); Q_PROPERTY(QString netType MEMBER net_type NOTIFY valueChanged); Q_PROPERTY(int netStrength MEMBER net_strength NOTIFY valueChanged); - Q_PROPERTY(QString sidebarTemp MEMBER sidebar_temp_str NOTIFY valueChanged); public: explicit Sidebar(QWidget* parent = 0); @@ -36,6 +39,7 @@ protected: void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void drawMetric(QPainter &p, const QPair &label, QColor c, int y); + virtual void DrawSidebar(QPainter &p); QPixmap home_img, flag_img, settings_img; bool onroad, flag_pressed, settings_pressed; @@ -52,19 +56,13 @@ protected: const QRect home_btn = QRect(60, 860, 180, 180); const QRect settings_btn = QRect(50, 35, 200, 117); const QColor good_color = QColor(255, 255, 255); - const QColor progress_color = QColor(3, 132, 252); const QColor warning_color = QColor(218, 202, 37); const QColor danger_color = QColor(201, 34, 49); - const QColor disabled_color = QColor(128, 128, 128); - ItemStatus connect_status, panda_status, temp_status, sunnylink_status; + ItemStatus connect_status, panda_status, temp_status; QString net_type; int net_strength = 0; private: - Params params; std::unique_ptr pm; - - QString sidebar_temp = "0"; - QString sidebar_temp_str = "0"; }; diff --git a/selfdrive/ui/qt/text.cc b/selfdrive/ui/qt/text.cc index 4b5f8ee21e..21ec5eedcf 100644 --- a/selfdrive/ui/qt/text.cc +++ b/selfdrive/ui/qt/text.cc @@ -4,41 +4,12 @@ #include #include #include -#include -#include -#include -#include "common/params.h" -#include "common/swaglog.h" #include "system/hardware/hw.h" #include "selfdrive/ui/qt/util.h" #include "selfdrive/ui/qt/qt_window.h" #include "selfdrive/ui/qt/widgets/scrollview.h" -std::string executeCommand(const char* cmd) { - std::array buffer{}; - std::ostringstream result; - std::unique_ptr pipe(popen(cmd, "r"), pclose); - if (!pipe) { - LOGW("Failed to open pipe"); - throw std::runtime_error("popen() failed!"); - } - while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { - result << buffer.data(); - } - return result.str(); -} - -// The format is intentional! -QString text = QString("%1\n%2\n%3\n%4\n%5\n%6\n%7") - .arg(" ________________________________________") - .arg("| |") - .arg("| " + QObject::tr("Update downloaded. Ready to reboot.") + " |") - .arg("| |") - .arg("| " + QObject::tr("Update: Check and Download Update") + " |") - .arg("| " + QObject::tr("Reboot: Reboot Device") + " |") - .arg("|________________________________________|"); - int main(int argc, char *argv[]) { initApp(argc, argv); QApplication a(argc, argv); @@ -51,7 +22,6 @@ int main(int argc, char *argv[]) { QLabel *label = new QLabel(argv[1]); label->setWordWrap(true); label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); - label->setAlignment(Qt::AlignTop | Qt::AlignLeft); ScrollView *scroll = new ScrollView(label); scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); main_layout->addWidget(scroll, 0, 0, Qt::AlignTop); @@ -62,54 +32,16 @@ int main(int argc, char *argv[]) { }); QPushButton *btn = new QPushButton(); - QPushButton *update_btn = new QPushButton(); - update_btn->setText(QObject::tr("Update")); #ifdef __aarch64__ btn->setText(QObject::tr("Reboot")); - QFutureWatcher watcher; QObject::connect(btn, &QPushButton::clicked, [=]() { Hardware::reboot(); }); - QObject::connect(update_btn, &QPushButton::clicked, [=, &watcher]() { - btn->setEnabled(false); - update_btn->setEnabled(false); - update_btn->setText(QObject::tr("Updating...")); - const std::string git_branch = Params().get("GitBranch"); - const std::string git_remote = Params().get("GitRemote"); - const std::string to_home_dir = "cd /data/openpilot"; - const std::string check_remote = "git remote | grep origin-update"; - const std::string reset_remote = "git remote remove origin-update && git remote add origin-update " + git_remote; - const std::string add_remote = "git remote add origin-update " + git_remote; - const std::string fetch_remote = "git fetch origin-update " + git_branch; - const std::string reset_branch = "git reset --hard origin-update/" + git_branch + " 2>&1"; - - std::string remote_cmd = add_remote; - if (!std::system((to_home_dir + " && " + check_remote).c_str())) { - remote_cmd = reset_remote; - } - const std::string cmd = to_home_dir + "; " + remote_cmd + "; " + fetch_remote + "; " + reset_branch; - - QFuture future = QtConcurrent::run([=]() { - label->clear(); - std::string output = executeCommand(cmd.c_str()); - //LOGW("CHECK OUTPUT PLS\n%s", output.c_str()); - QMetaObject::invokeMethod(label, "setText", Qt::QueuedConnection, - Q_ARG(QString, QString::fromStdString(output) + text)); - }); - QObject::connect(&watcher, &QFutureWatcher::finished, [=]() { - btn->setEnabled(true); - update_btn->setEnabled(true); - update_btn->setText(QObject::tr("Update")); - }); - watcher.setFuture(future); - }); #else - update_btn->setEnabled(false); btn->setText(QObject::tr("Exit")); QObject::connect(btn, &QPushButton::clicked, &a, &QApplication::quit); #endif main_layout->addWidget(btn, 0, 0, Qt::AlignRight | Qt::AlignBottom); - main_layout->addWidget(update_btn, 0, 0, Qt::AlignLeft | Qt::AlignBottom); window.setStyleSheet(R"( * { @@ -126,10 +58,6 @@ int main(int argc, char *argv[]) { border-radius: 20px; margin-right: 40px; } - QPushButton:disabled { - color: #33FFFFFF; - border: 2px solid #33FFFFFF; - } )"); return a.exec(); diff --git a/selfdrive/ui/qt/util.cc b/selfdrive/ui/qt/util.cc index 173d9ba970..886402b157 100644 --- a/selfdrive/ui/qt/util.cc +++ b/selfdrive/ui/qt/util.cc @@ -29,54 +29,38 @@ QString getBrand() { return QObject::tr("sunnypilot"); } -QString getUserAgent(bool sunnylink) { - return (sunnylink ? "sunnypilot-" : "openpilot-") + getVersion(); +QString getUserAgent() { + return "openpilot-" + getVersion(); +} + +std::optional getParamIgnoringDefault(const std::string ¶m_name, const std::string &default_value) { + std::string value = Params().get(param_name); + + if (!value.empty() && value != default_value) + return QString::fromStdString(value); + + return {}; } std::optional getDongleId() { - std::string id = Params().get("DongleId"); - - if (!id.empty() && (id != "UnregisteredDevice")) { - return QString::fromStdString(id); - } else { - return {}; - } + return getParamIgnoringDefault("DongleId", "UnregisteredDevice"); } -std::optional getSunnylinkDongleId() { - std::string id = Params().get("SunnylinkDongleId"); +QMap getFromJsonFile(const QString &path) { + QFile f(path); + f.open(QIODevice::ReadOnly | QIODevice::Text); + QString val = f.readAll(); - if (!id.empty() && (id != "UnregisteredDevice")) { - return QString::fromStdString(id); - } else { - return {}; + QJsonObject obj = QJsonDocument::fromJson(val.toUtf8()).object(); + QMap map; + for (auto key : obj.keys()) { + map[key] = obj[key].toString(); } + return map; } QMap getSupportedLanguages() { - QFile f(":/languages.json"); - f.open(QIODevice::ReadOnly | QIODevice::Text); - QString val = f.readAll(); - - QJsonObject obj = QJsonDocument::fromJson(val.toUtf8()).object(); - QMap map; - for (auto key : obj.keys()) { - map[key] = obj[key].toString(); - } - return map; -} - -QMap getCarNames() { - QFile f("/data/openpilot/selfdrive/car/sunnypilot_carname.json"); - f.open(QIODevice::ReadOnly | QIODevice::Text); - QString val = f.readAll(); - - QJsonObject obj = QJsonDocument::fromJson(val.toUtf8()).object(); - QMap map; - for (auto key : obj.keys()) { - map[key] = obj[key].toString(); - } - return map; + return getFromJsonFile(":/languages.json"); } QString timeAgo(const QDateTime &date) { @@ -179,60 +163,6 @@ QPixmap loadPixmap(const QString &fileName, const QSize &size, Qt::AspectRatioMo } } -void drawRoundedRect(QPainter &painter, const QRectF &rect, qreal xRadiusTop, qreal yRadiusTop, qreal xRadiusBottom, qreal yRadiusBottom){ - qreal w_2 = rect.width() / 2; - qreal h_2 = rect.height() / 2; - - xRadiusTop = 100 * qMin(xRadiusTop, w_2) / w_2; - yRadiusTop = 100 * qMin(yRadiusTop, h_2) / h_2; - - xRadiusBottom = 100 * qMin(xRadiusBottom, w_2) / w_2; - yRadiusBottom = 100 * qMin(yRadiusBottom, h_2) / h_2; - - qreal x = rect.x(); - qreal y = rect.y(); - qreal w = rect.width(); - qreal h = rect.height(); - - qreal rxx2Top = w*xRadiusTop/100; - qreal ryy2Top = h*yRadiusTop/100; - - qreal rxx2Bottom = w*xRadiusBottom/100; - qreal ryy2Bottom = h*yRadiusBottom/100; - - QPainterPath path; - path.arcMoveTo(x, y, rxx2Top, ryy2Top, 180); - path.arcTo(x, y, rxx2Top, ryy2Top, 180, -90); - path.arcTo(x+w-rxx2Top, y, rxx2Top, ryy2Top, 90, -90); - path.arcTo(x+w-rxx2Bottom, y+h-ryy2Bottom, rxx2Bottom, ryy2Bottom, 0, -90); - path.arcTo(x, y+h-ryy2Bottom, rxx2Bottom, ryy2Bottom, 270, -90); - path.closeSubpath(); - - painter.drawPath(path); -} - -QColor interpColor(float xv, std::vector xp, std::vector fp) { - assert(xp.size() == fp.size()); - - int N = xp.size(); - int hi = 0; - - while (hi < N and xv > xp[hi]) hi++; - int low = hi - 1; - - if (hi == N && xv > xp[low]) { - return fp[fp.size() - 1]; - } else if (hi == 0){ - return fp[0]; - } else { - return QColor( - (xv - xp[low]) * (fp[hi].red() - fp[low].red()) / (xp[hi] - xp[low]) + fp[low].red(), - (xv - xp[low]) * (fp[hi].green() - fp[low].green()) / (xp[hi] - xp[low]) + fp[low].green(), - (xv - xp[low]) * (fp[hi].blue() - fp[low].blue()) / (xp[hi] - xp[low]) + fp[low].blue(), - (xv - xp[low]) * (fp[hi].alpha() - fp[low].alpha()) / (xp[hi] - xp[low]) + fp[low].alpha()); - } -} - static QHash load_bootstrap_icons() { QHash icons; @@ -297,4 +227,4 @@ void ParamWatcher::fileChanged(const QString &path) { void ParamWatcher::addParam(const QString ¶m_name) { watcher->addPath(QString::fromStdString(params.getParamPath(param_name.toStdString()))); -} +} \ No newline at end of file diff --git a/selfdrive/ui/qt/util.h b/selfdrive/ui/qt/util.h index 438b9677e7..20443db468 100644 --- a/selfdrive/ui/qt/util.h +++ b/selfdrive/ui/qt/util.h @@ -13,13 +13,19 @@ #include "cereal/gen/cpp/car.capnp.h" #include "common/params.h" +#ifdef SUNNYPILOT +#define RETURN_IF_SUNNYPILOT return; +#else +#define RETURN_IF_SUNNYPILOT // Do nothing +#endif + QString getVersion(); QString getBrand(); -QString getUserAgent(bool sunnylink = false); +QString getUserAgent(); +std::optional getParamIgnoringDefault(const std::string ¶m_name, const std::string &default_value); std::optional getDongleId(); -std::optional getSunnylinkDongleId(); +QMap getFromJsonFile(const QString &path); QMap getSupportedLanguages(); -QMap getCarNames(); void setQtSurfaceFormat(); void sigTermHandler(int s); QString timeAgo(const QDateTime &date); @@ -28,9 +34,6 @@ void initApp(int argc, char *argv[], bool disable_hidpi = true); QWidget* topWidget(QWidget* widget); QPixmap loadPixmap(const QString &fileName, const QSize &size = {}, Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio); QPixmap bootstrapPixmap(const QString &id); - -void drawRoundedRect(QPainter &painter, const QRectF &rect, qreal xRadiusTop, qreal yRadiusTop, qreal xRadiusBottom, qreal yRadiusBottom); -QColor interpColor(float xv, std::vector xp, std::vector fp); bool hasLongitudinalControl(const cereal::CarParams::Reader &car_params); struct InterFont : public QFont { diff --git a/selfdrive/ui/qt/widgets/cameraview.h b/selfdrive/ui/qt/widgets/cameraview.h index 526c17e77c..62999b2aa4 100644 --- a/selfdrive/ui/qt/widgets/cameraview.h +++ b/selfdrive/ui/qt/widgets/cameraview.h @@ -24,7 +24,11 @@ #include "msgq/visionipc/visionipc_client.h" #include "system/camerad/cameras/camera_common.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/ui.h" +#else #include "selfdrive/ui/ui.h" +#endif const int FRAME_BUFFER_SIZE = 5; static_assert(FRAME_BUFFER_SIZE <= YUV_BUFFER_COUNT); diff --git a/selfdrive/ui/qt/widgets/controls.cc b/selfdrive/ui/qt/widgets/controls.cc index 238051cf5e..8af48185aa 100644 --- a/selfdrive/ui/qt/widgets/controls.cc +++ b/selfdrive/ui/qt/widgets/controls.cc @@ -2,20 +2,10 @@ #include #include - -QFrame *horizontal_line(QWidget *parent) { - QFrame *line = new QFrame(parent); - line->setFrameShape(QFrame::StyledPanel); - line->setStyleSheet(R"( - border-width: 2px; - border-bottom-style: solid; - border-color: gray; - )"); - line->setFixedHeight(10); - return line; -} +#include AbstractControl::AbstractControl(const QString &title, const QString &desc, const QString &icon, QWidget *parent) : QFrame(parent) { + RETURN_IF_SUNNYPILOT QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setMargin(0); @@ -36,7 +26,7 @@ AbstractControl::AbstractControl(const QString &title, const QString &desc, cons // title title_label = new QPushButton(title); title_label->setFixedHeight(120); - title_label->setStyleSheet("font-size: 50px; font-weight: 450; text-align: left; border: none;"); + title_label->setStyleSheet("font-size: 50px; font-weight: 400; text-align: left; border: none;"); hlayout->addWidget(title_label, 1); // value next to control button @@ -74,51 +64,6 @@ void AbstractControl::hideEvent(QHideEvent *e) { } } -SPAbstractControl::SPAbstractControl(const QString &title, const QString &desc, const QString &icon, QWidget *parent) : QFrame(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setMargin(0); - - hlayout = new QHBoxLayout; - hlayout->setMargin(0); - hlayout->setSpacing(0); - - // title - if (!title.isEmpty()) { - title_label = new QPushButton(title); - title_label->setFixedHeight(120); - title_label->setStyleSheet("font-size: 50px; font-weight: 450; text-align: left; border: none;"); - main_layout->addWidget(title_label, 1); - - connect(title_label, &QPushButton::clicked, [=]() { - if (!description->isVisible()) { - emit showDescriptionEvent(); - } - - if (!description->text().isEmpty()) { - description->setVisible(!description->isVisible()); - } - }); - } else { - main_layout->addSpacing(20); - } - - main_layout->addLayout(hlayout); - main_layout->addSpacing(2); - - // description - description = new QLabel(desc); - description->setContentsMargins(0, 20, 40, 20); - description->setStyleSheet("font-size: 40px; color: grey"); - description->setWordWrap(true); - description->setVisible(false); - main_layout->addWidget(description); - - main_layout->addStretch(); -} - -void SPAbstractControl::hideEvent(QHideEvent *e) { -} - // controls ButtonControl::ButtonControl(const QString &title, const QString &text, const QString &desc, QWidget *parent) : AbstractControl(title, desc, "", parent) { @@ -178,15 +123,6 @@ ParamControl::ParamControl(const QString ¶m, const QString &title, const QSt : ToggleControl(title, desc, icon, false, parent) { key = param.toStdString(); QObject::connect(this, &ParamControl::toggleFlipped, this, &ParamControl::toggleClicked); - - hlayout->removeWidget(&toggle); - hlayout->insertWidget(0, &toggle); - - hlayout->removeWidget(this->icon_label); - this->icon_pixmap = QPixmap(icon).scaledToWidth(20, Qt::SmoothTransformation); - this->icon_label->setPixmap(this->icon_pixmap); - this->icon_label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); - hlayout->insertWidget(1, this->icon_label); } void ParamControl::toggleClicked(bool state) { diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h index 3466b67f5e..aa304e0df6 100644 --- a/selfdrive/ui/qt/widgets/controls.h +++ b/selfdrive/ui/qt/widgets/controls.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include @@ -15,8 +14,6 @@ #include "selfdrive/ui/qt/widgets/input.h" #include "selfdrive/ui/qt/widgets/toggle.h" -QFrame *horizontal_line(QWidget *parent = nullptr); - class ElidedLabel : public QLabel { Q_OBJECT @@ -24,10 +21,6 @@ public: explicit ElidedLabel(QWidget *parent = 0); explicit ElidedLabel(const QString &text, QWidget *parent = 0); - void setColor(const QString &color) { - setStyleSheet("QLabel { color : " + color + "; }"); - } - signals: void clicked(); @@ -55,11 +48,8 @@ public: title_label->setText(title); } - void setValue(const QString &val, std::optional color = std::nullopt) { + void setValue(const QString &val) { value->setText(val); - if (color.has_value()) { - value->setColor(color.value()); - } } const QString getDescription() { @@ -74,10 +64,6 @@ public slots: description->setVisible(true); } - void hideDescription() { - description->setVisible(false); - } - signals: void showDescriptionEvent(); @@ -117,7 +103,6 @@ public: ButtonControl(const QString &title, const QString &text, const QString &desc = "", QWidget *parent = nullptr); inline void setText(const QString &text) { btn.setText(text); } inline QString text() const { return btn.text(); } - inline void click() { btn.click(); } signals: void clicked(); @@ -181,8 +166,6 @@ public: refresh(); } - bool isToggled() { return params.getBool(key); } - private: void toggleClicked(bool state); void setIcon(bool state) { @@ -200,71 +183,29 @@ private: bool store_confirm = false; }; -class SPAbstractControl : public QFrame { - Q_OBJECT - -public: - void setDescription(const QString &desc) { - if (description) description->setText(desc); - } - - void setTitle(const QString &title) { - title_label->setText(title); - } - - const QString getDescription() { - return description->text(); - } - -public slots: - void showDescription() { - description->setVisible(true); - } - - void hideDescription() { - description->setVisible(false); - } - -signals: - void showDescriptionEvent(); - -protected: - SPAbstractControl(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr); - void hideEvent(QHideEvent *e) override; - - QHBoxLayout *hlayout; - QPushButton *title_label; - -private: - QLabel *description = nullptr; -}; - -class ButtonParamControl : public SPAbstractControl { +class ButtonParamControl : public AbstractControl { Q_OBJECT public: ButtonParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, - const std::vector &button_texts, const int minimum_button_width = 300) : SPAbstractControl(title, desc, icon), button_texts(button_texts) { + const std::vector &button_texts, const int minimum_button_width = 225) : AbstractControl(title, desc, icon) { const QString style = R"( QPushButton { - border-radius: 20px; - font-size: 50px; - font-weight: 450; - height:150px; + border-radius: 50px; + font-size: 40px; + font-weight: 500; + height:100px; padding: 0 25 0 25; - color: #FFFFFF; + color: #E4E4E4; + background-color: #393939; } QPushButton:pressed { background-color: #4a4a4a; } QPushButton:checked:enabled { - background-color: #696868; + background-color: #33Ab4C; } QPushButton:disabled { - color: #33FFFFFF; - } - QPushButton:checked:disabled { - background-color: #121212; - color: #33FFFFFF; + color: #33E4E4E4; } )"; key = param.toStdString(); @@ -278,16 +219,12 @@ public: button->setChecked(i == value); button->setStyleSheet(style); button->setMinimumWidth(minimum_button_width); - if (i == 0) hlayout->addSpacing(2); hlayout->addWidget(button); button_group->addButton(button, i); } - hlayout->setAlignment(Qt::AlignLeft); - QObject::connect(button_group, QOverload::of(&QButtonGroup::buttonClicked), [=](int id) { params.put(key, std::to_string(id)); - emit buttonToggled(id); }); } @@ -295,9 +232,6 @@ public: for (auto btn : button_group->buttons()) { btn->setEnabled(enable); } - button_group_enabled = enable; - - update(); } void setCheckedButton(int id) { @@ -306,14 +240,6 @@ public: void refresh() { int value = atoi(params.get(key).c_str()); - - if (value >= button_texts.size()) { - value = button_texts.size() - 1; - } - if (value < 0) { - value = 0; - } - button_group->button(value)->setChecked(true); } @@ -321,59 +247,16 @@ public: refresh(); } - void setButton(QString param) { - key = param.toStdString(); - int value = atoi(params.get(key).c_str()); - for (int i = 0; i < button_group->buttons().size(); i++) { - button_group->buttons()[i]->setChecked(i == value); - } - } - - void setDisabledSelectedButton(std::string val) { - int value = atoi(val.c_str()); - for (int i = 0; i < button_group->buttons().size(); i++) { - button_group->buttons()[i]->setEnabled(i != value); - } - } - -protected: - void paintEvent(QPaintEvent *event) override { - QPainter p(this); - p.setRenderHint(QPainter::Antialiasing); - - // Calculate the total width and height for the background rectangle - int w = 0; - int h = 150; - - for (int i = 0; i < hlayout->count(); ++i) { - QPushButton *button = qobject_cast(hlayout->itemAt(i)->widget()); - if (button) { - w += button->width(); - } - } - - // Draw the rectangle - QRect rect(0 + 2, h - 24, w, h); - p.setPen(QPen(QColor(button_group_enabled ? "#696868" : "#121212"), 3)); - p.drawRoundedRect(rect, 20, 20); - } - -signals: - void buttonToggled(int btn_id); - private: std::string key; Params params; QButtonGroup *button_group; - std::vector button_texts; - - bool button_group_enabled = true; }; class ListWidget : public QWidget { Q_OBJECT public: - explicit ListWidget(QWidget *parent = 0, const bool split_line = true) : QWidget(parent), _split_line(split_line), outer_layout(this) { + explicit ListWidget(QWidget *parent = 0) : QWidget(parent), outer_layout(this) { outer_layout.setMargin(0); outer_layout.setSpacing(0); outer_layout.addLayout(&inner_layout); @@ -385,30 +268,13 @@ class ListWidget : public QWidget { inline void addItem(QLayout *layout) { inner_layout.addLayout(layout); } inline void setSpacing(int spacing) { inner_layout.setSpacing(spacing); } - inline void AddWidgetAt(const int index, QWidget *new_widget) { inner_layout.insertWidget(index, new_widget); } - inline void RemoveWidgetAt(const int index) { - if (QLayoutItem* item; (item = inner_layout.takeAt(index)) != nullptr) { - if(item->widget()) delete item->widget(); - delete item; - } - } - - inline void ReplaceOrAddWidget(QWidget *old_widget, QWidget *new_widget) { - if (const int index = inner_layout.indexOf(old_widget); index != -1) { - RemoveWidgetAt(index); - AddWidgetAt(index, new_widget); - } else { - addItem(new_widget); - } - } - private: void paintEvent(QPaintEvent *) override { QPainter p(this); p.setPen(Qt::gray); for (int i = 0; i < inner_layout.count() - 1; ++i) { QWidget *widget = inner_layout.itemAt(i)->widget(); - if ((widget == nullptr || widget->isVisible()) && _split_line) { + if (widget == nullptr || widget->isVisible()) { QRect r = inner_layout.itemAt(i)->geometry(); int bottom = r.bottom() + inner_layout.spacing() / 2; p.drawLine(r.left() + 40, bottom, r.right() - 40, bottom); @@ -417,8 +283,6 @@ private: } QVBoxLayout outer_layout; QVBoxLayout inner_layout; - - bool _split_line; }; // convenience class for wrapping layouts @@ -430,178 +294,3 @@ public: setLayout(l); } }; - -class SPOptionControl : public SPAbstractControl { - Q_OBJECT - -private: - struct MinMaxValue { - int min_value; - int max_value; - }; - -public: - SPOptionControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, - const MinMaxValue &range, const int per_value_change = 1) : _title(title), SPAbstractControl(title, desc, icon) { - const QString style = R"( - QPushButton { - border-radius: 20px; - font-size: 60px; - font-weight: 500; - width: 150px; - height: 150px; - padding: -3 25 3 25; - color: #FFFFFF; - font-weight: bold; - } - QPushButton:pressed { - color: #5C5C5C; - } - QPushButton:disabled { - color: #5C5C5C; - } - )"; - - label.setStyleSheet(label_enabled_style); - label.setFixedWidth(300); - label.setAlignment(Qt::AlignCenter); - - const std::vector button_texts{"-", "+"}; - - key = param.toStdString(); - value = atoi(params.get(key).c_str()); - - button_group = new QButtonGroup(this); - button_group->setExclusive(true); - for (int i = 0; i < button_texts.size(); i++) { - QPushButton *button = new QPushButton(button_texts[i], this); - button->setStyleSheet(style + ((i == 0) ? "QPushButton { text-align: left; }" : - "QPushButton { text-align: right; }")); - hlayout->addWidget(button, 0, ((i == 0) ? Qt::AlignLeft : Qt::AlignRight) | Qt::AlignVCenter); - if (i == 0) { - hlayout->addWidget(&label, 0, Qt::AlignCenter); - } - button_group->addButton(button, i); - - QObject::connect(button, &QPushButton::clicked, [=]() { - int change_value = (i == 0) ? -per_value_change : per_value_change; - key = param.toStdString(); - value = atoi(params.get(key).c_str()); - value += change_value; - value = std::clamp(value, range.min_value, range.max_value); - params.put(key, QString::number(value).toStdString()); - - button_group->button(0)->setEnabled(!(value <= range.min_value)); - button_group->button(1)->setEnabled(!(value >= range.max_value)); - - updateLabels(); - - if (request_update) { - emit updateOtherToggles(); - } - }); - } - - hlayout->setAlignment(Qt::AlignLeft); - } - - void setUpdateOtherToggles(bool _update) { - request_update = _update; - } - - inline void setLabel(const QString &text) { label.setText(text); } - - void setEnabled(bool enabled) { - for (auto btn : button_group->buttons()) { - btn->setEnabled(enabled); - } - label.setEnabled(enabled); - label.setStyleSheet(enabled ? label_enabled_style : label_disabled_style); - button_enabled = enabled; - - update(); - } - -protected: - void paintEvent(QPaintEvent *event) override { - QPainter p(this); - p.setRenderHint(QPainter::Antialiasing); - - // Calculate the total width and height for the background rectangle - int w = 0; - int h = 150; - - for (int i = 0; i < hlayout->count(); ++i) { - QWidget *widget = qobject_cast(hlayout->itemAt(i)->widget()); - if (widget) { - w += widget->width(); - } - } - - // Draw the rectangle - QRect rect(0, !_title.isEmpty() ? (h - 24) : 20, w, h); - p.setBrush(QColor(button_enabled ? "#b24a4a4a" : "#121212")); // Background color - p.setPen(QPen(Qt::NoPen)); - p.drawRoundedRect(rect, 20, 20); - } - -signals: - void updateLabels(); - void updateOtherToggles(); - -private: - std::string key; - int value; - QButtonGroup *button_group; - QLabel label; - Params params; - std::map option_label = {}; - bool request_update = false; - QString _title = ""; - - const QString label_enabled_style = "font-size: 50px; font-weight: 450; color: #FFFFFF;"; - const QString label_disabled_style = "font-size: 50px; font-weight: 450; color: #5C5C5C;"; - - bool button_enabled = true; -}; - -class SubPanelButton : public QPushButton { - Q_OBJECT - -public: - SubPanelButton(const QString &text, const int minimum_button_width = 800, QWidget *parent = nullptr) : QPushButton(text, parent) { - const QString buttonStyle = R"( - QPushButton { - border-radius: 20px; - font-size: 50px; - font-weight: 450; - height: 150px; - padding: 0 25px 0 25px; - color: #FFFFFF; - } - QPushButton:enabled { - background-color: #393939; - } - QPushButton:pressed { - background-color: #4A4A4A; - } - QPushButton:disabled { - background-color: #121212; - color: #5C5C5C; - } - )"; - - setStyleSheet(buttonStyle); - setFixedWidth(minimum_button_width); - } -}; - -class PanelBackButton : public QPushButton { - Q_OBJECT - -public: - PanelBackButton(const QString &label = "Back", QWidget *parent = nullptr) : QPushButton(label, parent) { - setObjectName("back_btn"); - setFixedSize(400, 100); - } -}; diff --git a/selfdrive/ui/qt/widgets/scrollview.cc b/selfdrive/ui/qt/widgets/scrollview.cc index 7f6a5ff1cc..978bf83a63 100644 --- a/selfdrive/ui/qt/widgets/scrollview.cc +++ b/selfdrive/ui/qt/widgets/scrollview.cc @@ -47,11 +47,3 @@ ScrollView::ScrollView(QWidget *w, QWidget *parent) : QScrollArea(parent) { void ScrollView::hideEvent(QHideEvent *e) { verticalScrollBar()->setValue(0); } - -void ScrollView::setLastScrollPosition() { - lastScrollPosition = verticalScrollBar()->value(); -} - -void ScrollView::restoreScrollPosition() { - verticalScrollBar()->setValue(lastScrollPosition); -} diff --git a/selfdrive/ui/qt/widgets/scrollview.h b/selfdrive/ui/qt/widgets/scrollview.h index 7e4084412c..024331aa39 100644 --- a/selfdrive/ui/qt/widgets/scrollview.h +++ b/selfdrive/ui/qt/widgets/scrollview.h @@ -9,11 +9,4 @@ public: explicit ScrollView(QWidget *w = nullptr, QWidget *parent = nullptr); protected: void hideEvent(QHideEvent *e) override; - -public slots: - void setLastScrollPosition(); - void restoreScrollPosition(); - -private: - int lastScrollPosition = 0; }; diff --git a/selfdrive/ui/qt/widgets/ssh_keys.h b/selfdrive/ui/qt/widgets/ssh_keys.h index 920bd651e2..2834164702 100644 --- a/selfdrive/ui/qt/widgets/ssh_keys.h +++ b/selfdrive/ui/qt/widgets/ssh_keys.h @@ -3,7 +3,13 @@ #include #include "system/hardware/hw.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#define ToggleControl ToggleControlSP +#define ButtonControl ButtonControlSP +#else #include "selfdrive/ui/qt/widgets/controls.h" +#endif // SSH enable toggle class SshToggle : public ToggleControl { diff --git a/selfdrive/ui/qt/widgets/sunnypilot/drive_stats.h b/selfdrive/ui/qt/widgets/sunnypilot/drive_stats.h deleted file mode 100644 index 5e2d96b240..0000000000 --- a/selfdrive/ui/qt/widgets/sunnypilot/drive_stats.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include -#include - -class DriveStats : public QFrame { - Q_OBJECT - -public: - explicit DriveStats(QWidget* parent = 0); - -private: - void showEvent(QShowEvent *event) override; - void updateStats(); - inline QString getDistanceUnit() const { return metric_ ? tr("KM") : tr("Miles"); } - - bool metric_; - QJsonDocument stats_; - struct StatsLabels { - QLabel *routes, *distance, *distance_unit, *hours; - } all_, week_; - -private slots: - void parseResponse(const QString &response, bool success); -}; diff --git a/selfdrive/ui/qt/widgets/toggle.cc b/selfdrive/ui/qt/widgets/toggle.cc index c8f12bc272..82302ad5bc 100644 --- a/selfdrive/ui/qt/widgets/toggle.cc +++ b/selfdrive/ui/qt/widgets/toggle.cc @@ -75,9 +75,9 @@ void Toggle::setEnabled(bool value) { enabled = value; if (value) { circleColor.setRgb(0xfafafa); - green.setRgb(0x1e79e8); + green.setRgb(0x33ab4c); } else { circleColor.setRgb(0x888888); - green.setRgb(0x125db8); + green.setRgb(0x227722); } } diff --git a/selfdrive/ui/qt/widgets/toggle.h b/selfdrive/ui/qt/widgets/toggle.h index e7263a008f..a0fa434a4c 100644 --- a/selfdrive/ui/qt/widgets/toggle.h +++ b/selfdrive/ui/qt/widgets/toggle.h @@ -23,14 +23,13 @@ public: update(); } bool getEnabled(); - void setEnabled(bool value); + virtual void setEnabled(bool value); protected: void paintEvent(QPaintEvent*) override; void mouseReleaseEvent(QMouseEvent*) override; void enterEvent(QEvent*) override; -private: QColor circleColor; QColor green; bool enabled = true; diff --git a/selfdrive/ui/qt/widgets/wifi.h b/selfdrive/ui/qt/widgets/wifi.h index 60c865f2b8..3010abc6ff 100644 --- a/selfdrive/ui/qt/widgets/wifi.h +++ b/selfdrive/ui/qt/widgets/wifi.h @@ -4,7 +4,11 @@ #include #include +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/ui.h" +#else #include "selfdrive/ui/ui.h" +#endif class WiFiPromptWidget : public QFrame { Q_OBJECT diff --git a/selfdrive/ui/qt/window.cc b/selfdrive/ui/qt/window.cc index 6b6f939af4..d9ff51763b 100644 --- a/selfdrive/ui/qt/window.cc +++ b/selfdrive/ui/qt/window.cc @@ -4,16 +4,18 @@ #include "system/hardware/hw.h" -MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { +MainWindow::MainWindow(QWidget* parent, HomeWindow* hw, SettingsWindow* sw, OnboardingWindow* ow) + : QWidget(parent), + homeWindow(hw ? hw : new HomeWindow(this)), + settingsWindow(sw ? sw : new SettingsWindow(this)), + onboardingWindow(ow ? ow : new OnboardingWindow(this)) { main_layout = new QStackedLayout(this); main_layout->setMargin(0); - homeWindow = new HomeWindow(this); main_layout->addWidget(homeWindow); QObject::connect(homeWindow, &HomeWindow::openSettings, this, &MainWindow::openSettings); QObject::connect(homeWindow, &HomeWindow::closeSettings, this, &MainWindow::closeSettings); - settingsWindow = new SettingsWindow(this); main_layout->addWidget(settingsWindow); QObject::connect(settingsWindow, &SettingsWindow::closeSettings, this, &MainWindow::closeSettings); QObject::connect(settingsWindow, &SettingsWindow::reviewTrainingGuide, [=]() { @@ -24,7 +26,6 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { homeWindow->showDriverView(true); }); - onboardingWindow = new OnboardingWindow(this); main_layout->addWidget(onboardingWindow); QObject::connect(onboardingWindow, &OnboardingWindow::onboardingDone, [=]() { main_layout->setCurrentWidget(homeWindow); @@ -75,10 +76,6 @@ void MainWindow::closeSettings() { if (uiState()->scene.started) { homeWindow->showSidebar(false); - // Map is always shown when using navigate on openpilot - if (uiState()->scene.navigate_on_openpilot_deprecated) { - homeWindow->showMapPanel(true); - } } } diff --git a/selfdrive/ui/qt/window.h b/selfdrive/ui/qt/window.h index 05b61e1f76..fa0c43486e 100644 --- a/selfdrive/ui/qt/window.h +++ b/selfdrive/ui/qt/window.h @@ -11,15 +11,18 @@ class MainWindow : public QWidget { Q_OBJECT public: - explicit MainWindow(QWidget *parent = 0); + explicit MainWindow(QWidget *parent = nullptr) : MainWindow(parent, nullptr, nullptr, nullptr) {} + +protected: + explicit MainWindow(QWidget* parent, HomeWindow* hw = nullptr, SettingsWindow* sw = nullptr, OnboardingWindow* ow = nullptr); + HomeWindow *homeWindow; + SettingsWindow *settingsWindow; + OnboardingWindow *onboardingWindow; + virtual void closeSettings(); private: bool eventFilter(QObject *obj, QEvent *event) override; void openSettings(int index = 0, const QString ¶m = ""); - void closeSettings(); QStackedLayout *main_layout; - HomeWindow *homeWindow; - SettingsWindow *settingsWindow; - OnboardingWindow *onboardingWindow; }; diff --git a/selfdrive/ui/sunnypilot/SConscript b/selfdrive/ui/sunnypilot/SConscript index 9290fcea58..945c9ccdb2 100644 --- a/selfdrive/ui/sunnypilot/SConscript +++ b/selfdrive/ui/sunnypilot/SConscript @@ -1,36 +1,63 @@ widgets_src = [ - "qt/offroad/sunnypilot/custom_offsets_settings.cc", - "qt/offroad/sunnypilot/display_settings.cc", - "qt/offroad/sunnypilot/lane_change_settings.cc", - "qt/offroad/sunnypilot/mads_settings.cc", - "qt/offroad/sunnypilot/models_fetcher.cc", - "qt/offroad/sunnypilot/monitoring_settings.cc", - "qt/offroad/sunnypilot/osm_settings.cc", - "qt/offroad/sunnypilot/software_settings_sp.cc", - "qt/offroad/sunnypilot/speed_limit_control_settings.cc", - "qt/offroad/sunnypilot/speed_limit_policy_settings.cc", - "qt/offroad/sunnypilot/speed_limit_warning_settings.cc", - "qt/offroad/sunnypilot/sunnypilot_settings.cc", - "qt/offroad/sunnypilot/sunnylink_settings.cc", - "qt/offroad/sunnypilot/trips_settings.cc", - "qt/offroad/sunnypilot/vehicle_settings.cc", - "qt/offroad/sunnypilot/visuals_settings.cc", - "qt/widgets/sunnypilot/drive_stats.cc" + "sunnypilot/ui.cc", + "sunnypilot/qt/window.cc", + "sunnypilot/qt/request_repeater.cc", + "sunnypilot/qt/network/networking.cc", + "sunnypilot/qt/offroad/settings/display_settings.cc", + "sunnypilot/qt/offroad/settings/sunnypilot_settings.cc", + "sunnypilot/qt/offroad/settings/vehicle_settings.cc", + "sunnypilot/qt/offroad/settings/visuals_settings.cc", + "sunnypilot/qt/offroad/settings/trips_settings.cc", + "sunnypilot/qt/offroad/settings/sunnypilot/mads_settings.cc", + "sunnypilot/qt/offroad/settings/sunnypilot/lane_change_settings.cc", + "sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_control_settings.cc", + "sunnypilot/qt/offroad/settings/monitoring_settings.cc", + "sunnypilot/qt/offroad/settings/osm_settings.cc", + "sunnypilot/qt/offroad/settings/sunnypilot/custom_offsets_settings.cc", + "sunnypilot/qt/widgets/drive_stats.cc", + "sunnypilot/qt/offroad/settings/software_settings.cc", + "sunnypilot/qt/offroad/settings/osm/models_fetcher.cc", + "sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_warning_settings.cc", + "sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_policy_settings.cc", + "sunnypilot/qt/offroad/settings/sunnylink_settings.cc", + "sunnypilot/qt/widgets/controls.cc", + "sunnypilot/qt/widgets/scrollview.cc", + "sunnypilot/qt/widgets/toggle.cc" +] + +sp_maps_widgets_src = [ + "sunnypilot/qt/maps/map.cc" +] + +sp_qt_util = [ + # "#selfdrive/ui/sunnypilot/qt/api.cc", + "#selfdrive/ui/sunnypilot/qt/util.cc", ] network_src = [ - "qt/network/sunnylink/services/base_device_service.cc", - "qt/network/sunnylink/services/role_service.cc", - "qt/network/sunnylink/services/user_service.cc", - "qt/network/sunnylink/sunnylink_client.cc" + "sunnypilot/qt/network/sunnylink/sunnylink_client.cc", + "sunnypilot/qt/network/sunnylink/services/base_device_service.cc", + "sunnypilot/qt/network/sunnylink/services/role_service.cc", + "sunnypilot/qt/network/sunnylink/services/user_service.cc" ] qt_src = [ - "qt/onroad_settings.cc", - "qt/onroad_settings_panel.cc" + "sunnypilot/qt/api.cc", + "sunnypilot/qt/home.cc", + "sunnypilot/qt/offroad_home.cc", + "sunnypilot/qt/sidebar.cc", + "sunnypilot/qt/offroad/settings/onboarding.cc", + "sunnypilot/qt/offroad/settings/device_panel.cc", + "sunnypilot/qt/offroad/settings/settings.cc", + "sunnypilot/qt/onroad/buttons.cc", + "sunnypilot/qt/onroad/onroad_home.cc", + "sunnypilot/qt/onroad/onroad_settings.cc", + "sunnypilot/qt/onroad/annotated_camera.cc", + "sunnypilot/qt/onroad/onroad_settings_panel.cc", + "sunnypilot/qt/onroad/developer_ui/developer_ui.cc", ] sp_widgets_src = widgets_src + network_src sp_qt_src = qt_src -Export('sp_widgets_src', 'sp_qt_src') +Export('sp_widgets_src', 'sp_maps_widgets_src', 'sp_qt_src', "sp_qt_util") diff --git a/selfdrive/ui/sunnypilot/qt/api.cc b/selfdrive/ui/sunnypilot/qt/api.cc new file mode 100644 index 0000000000..fcf925fd1a --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/api.cc @@ -0,0 +1,212 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/api.h" + +#include +#include +#include + +#include +#include + +#include +#include + +#include "util.h" +#include "common/util.h" +#include "system/hardware/hw.h" +#include "selfdrive/ui/qt/util.h" + +namespace SunnylinkApi { + +QString create_jwt(const QJsonObject &payloads, int expiry, bool sunnylink) { + QJsonObject header = {{"alg", "RS256"}}; + + auto t = QDateTime::currentSecsSinceEpoch(); + auto dongle_id = sunnylink ? getSunnylinkDongleId() : getDongleId(); + QJsonObject payload = {{"identity", dongle_id.value_or("")}, {"nbf", t}, {"iat", t}, {"exp", t + expiry}}; + for (auto it = payloads.begin(); it != payloads.end(); ++it) { + payload.insert(it.key(), it.value()); + } + + auto b64_opts = QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals; + QString jwt = QJsonDocument(header).toJson(QJsonDocument::Compact).toBase64(b64_opts) + '.' + + QJsonDocument(payload).toJson(QJsonDocument::Compact).toBase64(b64_opts); + + auto hash = QCryptographicHash::hash(jwt.toUtf8(), QCryptographicHash::Sha256); + return jwt + "." + CommaApi::rsa_sign(hash).toBase64(b64_opts); +} + + void derive_aes_key_iv_from_rsa(EVP_PKEY *rsa_key, unsigned char *aes_key, unsigned char *aes_iv) { + unsigned char hash[SHA256_DIGEST_LENGTH]; + size_t pub_len; + unsigned char *pub_key; + + // Convert RSA key to public key in DER format for simplicity + pub_len = i2d_PublicKey(rsa_key, NULL); + pub_key = (unsigned char *)malloc(pub_len); + unsigned char *tmp = pub_key; + i2d_PublicKey(rsa_key, &tmp); + + // Hash the public key to derive bytes for AES key and IV + SHA256(pub_key, pub_len, hash); + + // Assuming AES-256-CBC, we need 32 bytes for the key and 16 for the IV + memcpy(aes_key, hash, 32); // First 32 bytes for AES key + memcpy(aes_iv, hash + 32 - 16, 16); // Last 16 bytes for AES IV + + free(pub_key); +} + +EVP_PKEY *load_public_key(const char *file) { + EVP_PKEY *key = NULL; + FILE *fp = fopen(file, "r"); + if (fp) { + key = PEM_read_PUBKEY(fp, NULL, NULL, NULL); + fclose(fp); + } + return key; +} + +EVP_PKEY *load_private_key(const char *file) { + EVP_PKEY *key = NULL; + FILE *fp = fopen(file, "r"); + if (fp) { + key = PEM_read_PrivateKey(fp, NULL, NULL, NULL); + fclose(fp); + } + return key; +} + +QByteArray rsa_encrypt(const QByteArray &data) { + EVP_PKEY *rsa_key = load_public_key(Path::rsa_pub_file().c_str()); // Load your RSA key + unsigned char aes_key[32], aes_iv[16]; + derive_aes_key_iv_from_rsa(rsa_key, aes_key, aes_iv); + + EVP_CIPHER_CTX *ctx; + if (!(ctx = EVP_CIPHER_CTX_new())) { + // Handle error: Allocate memory failed + return {}; + } + + if (EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, aes_key, aes_iv) != 1) { + qDebug() << "Failed to initialize encryption"; + EVP_CIPHER_CTX_free(ctx); + return {}; + } + + int ciphertext_len; + int len = data.size(); + unsigned char out[len + AES_BLOCK_SIZE]; + auto *in = (unsigned char*) data.constData(); + if (EVP_EncryptUpdate(ctx, out, &ciphertext_len, in, len) != 1) { + qDebug() << "Failed to update encryption"; + EVP_CIPHER_CTX_free(ctx); + return {}; + } + + if (EVP_EncryptFinal_ex(ctx, out + ciphertext_len, &len) != 1) { + // Handle error: Encryption finalize failed + qDebug() << "Failed to finalize encryption"; + EVP_CIPHER_CTX_free(ctx); + return {}; + } + + //qDebug() << "Encrypted data length: %d", ciphertext_len + len; // Print the length of encrypted data + EVP_CIPHER_CTX_free(ctx); + return {reinterpret_cast(out), ciphertext_len + len}; +} + +QByteArray rsa_decrypt(const QByteArray &data) { + EVP_PKEY *rsa_key = load_public_key(Path::rsa_pub_file().c_str()); // Load your RSA key + unsigned char aes_key[32], aes_iv[16]; + derive_aes_key_iv_from_rsa(rsa_key, aes_key, aes_iv); + + EVP_CIPHER_CTX *ctx; + if (!(ctx = EVP_CIPHER_CTX_new())) { + qDebug() << "Failed to allocate memory for EVP_CIPHER_CTX"; + return {}; + } + + if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, aes_key, aes_iv) != 1) { + qDebug() << "Failed to initialize EVP"; + EVP_CIPHER_CTX_free(ctx); + return {}; + } + + int len = data.size(); + unsigned char out[len + AES_BLOCK_SIZE]; + auto *in = (unsigned char*) data.constData(); + if (EVP_DecryptUpdate(ctx, out, &len, in, len) != 1) { + qDebug() << "Failed to update decryption"; + EVP_CIPHER_CTX_free(ctx); + return {}; + } + + int final_len; + if (EVP_DecryptFinal_ex(ctx, out + len, &final_len) != 1) { + qDebug() << "Failed to finalize decryption"; + EVP_CIPHER_CTX_free(ctx); + return {}; + } + EVP_CIPHER_CTX_free(ctx); + + //qDebug() << "Decrypted data length: %d", len + final_len; // Print the length of decrypted data + return {reinterpret_cast(out), len + final_len}; +} + + +} // namespace SunnylinkApi + +void HttpRequestSP::sendRequest(const QString& requestURL, Method method, const QByteArray& payload) { + if (active()) { + return; + } + QNetworkRequest request = prepareRequest(requestURL); + + if(!payload.isEmpty() && (method == Method::POST || method == Method::PUT)) { + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + } + + switch (method) { + case Method::GET: + reply = nam()->get(request); + break; + case Method::DELETE: + reply = nam()->deleteResource(request); + break; + case Method::POST: + reply = nam()->post(request, payload); + break; + case Method::PUT: + reply = nam()->put(request, payload); + break; + } + + networkTimer->start(); + connect(reply, &QNetworkReply::finished, this, &HttpRequestSP::requestFinished); +} diff --git a/selfdrive/ui/sunnypilot/qt/api.h b/selfdrive/ui/sunnypilot/qt/api.h new file mode 100644 index 0000000000..b8e835dc91 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/api.h @@ -0,0 +1,55 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include "selfdrive/ui/qt/api.h" +#include "selfdrive/ui/sunnypilot/qt/util.h" +#include "common/util.h" + +namespace SunnylinkApi { + QByteArray rsa_encrypt(const QByteArray& data); + QByteArray rsa_decrypt(const QByteArray& data); + QString create_jwt(const QJsonObject& payloads = {}, int expiry = 3600, bool sunnylink = false); +} + +class HttpRequestSP : public HttpRequest { + Q_OBJECT + +public: + explicit HttpRequestSP(QObject* parent, bool create_jwt = true, int timeout = 20000, bool sunnylink = false) : + HttpRequest(parent, create_jwt, timeout), sunnylink(sunnylink) {} + + using HttpRequest::sendRequest; + void sendRequest(const QString& requestURL, Method method, const QByteArray& payload); + +private: + bool sunnylink; + +protected: + [[nodiscard]] QString GetJwtToken() const override { return SunnylinkApi::create_jwt({}, 3600, sunnylink); } + [[nodiscard]] QString GetUserAgent() const override { return getUserAgent(sunnylink); } +}; diff --git a/selfdrive/ui/sunnypilot/qt/common/json_fetcher.h b/selfdrive/ui/sunnypilot/qt/common/json_fetcher.h new file mode 100644 index 0000000000..2002e72aa0 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/common/json_fetcher.h @@ -0,0 +1,60 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include +#include +#include + +class JsonFetcher { +public: + static QJsonObject getJsonFromURL(const QString &url) { + const auto qurl = QUrl(url); + QNetworkAccessManager manager; + const QNetworkRequest request(qurl); + QNetworkReply *reply = manager.get(request); + QEventLoop loop; + + // Send GET request + + QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + loop.exec(); + + if (reply->error() != QNetworkReply::NoError) { + qWarning() << "Failed to fetch data from URL: " << reply->errorString(); + return QJsonObject(); + } + + const QByteArray responseData = reply->readAll(); + const QJsonDocument doc = QJsonDocument::fromJson(responseData); + QJsonObject json = doc.object(); + + reply->deleteLater(); + return json; + } +}; diff --git a/selfdrive/ui/sunnypilot/qt/home.cc b/selfdrive/ui/sunnypilot/qt/home.cc new file mode 100644 index 0000000000..61abbff7dc --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/home.cc @@ -0,0 +1,80 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/home.h" + +#include +#include +#include + +#include "selfdrive/ui/qt/offroad/experimental_mode.h" +#include "selfdrive/ui/qt/util.h" + +// HomeWindowSP: the container for the offroad and onroad UIs +HomeWindowSP::HomeWindowSP(QWidget* parent) : HomeWindow(parent){ + QObject::connect(onroad, &OnroadWindow::mapPanelRequested, this, [=] { sidebar->hide(); }); + QObject::connect(onroad, &OnroadWindow::onroadSettingsPanelRequested, this, [=] { sidebar->hide(); }); +} + +void HomeWindowSP::showMapPanel(bool show) { + onroad->showMapPanel(show); +} + +void HomeWindowSP::updateState(const UIState &s) { //OVERRIDE + HomeWindow::updateState(s); + + uiStateSP()->scene.map_visible = onroad->isMapVisible(); + uiStateSP()->scene.onroad_settings_visible = onroad->isOnroadSettingsVisible(); +} + +void HomeWindowSP::mousePressEvent(QMouseEvent* e) { + // We are not calling the parent for the time being because it only handles sidebar, and the sidebar code conflicts + // with ours as we turn off the sidebar after it was turned on by the parent when the tap happens beyond the 300px of the left. + // HomeWindow::mousePressEvent(e); + + if (uiStateSP()->scene.started) { + if (uiStateSP()->scene.onroadScreenOff != -2) { + uiStateSP()->scene.touched2 = true; + QTimer::singleShot(500, []() { uiStateSP()->scene.touched2 = false; }); + } + if (uiStateSP()->scene.button_auto_hide) { + uiStateSP()->scene.touch_to_wake = true; + uiStateSP()->scene.sleep_btn_fading_in = true; + QTimer::singleShot(500, []() { uiStateSP()->scene.touch_to_wake = false; }); + } + } + + // TODO: a very similar, but not identical call is made by parent. Which made me question if I should override it here... + // Will have to revisit later if this is not behaving as expected. + // Handle sidebar collapsing + if ((onroad->isVisible() || body->isVisible()) && (!sidebar->isVisible() || e->x() > sidebar->width())) { + LOGD("HomeWindowSP sidebar->isVisible() [%d] | e->x() [%d] | sidebar->width() [%d]", sidebar->isVisible(), e->x(), sidebar->width()); + if (onroad->wakeScreenTimeout()) { + LOGD("HomeWindowSP wakeScreenTimeout() [%d]", onroad->wakeScreenTimeout()); + sidebar->setVisible(!sidebar->isVisible() && !onroad->isMapVisible()); + } + } +} diff --git a/selfdrive/ui/sunnypilot/qt/home.h b/selfdrive/ui/sunnypilot/qt/home.h new file mode 100644 index 0000000000..8bb44d81b4 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/home.h @@ -0,0 +1,59 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include + +#include "common/params.h" +#include "selfdrive/ui/qt/body.h" +#include "selfdrive/ui/qt/widgets/offroad_alerts.h" +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/qt/home.h" + +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/sidebar.h" +#define OnroadWindow OnroadWindowSP +#else +#include "selfdrive/ui/qt/sidebar.h" +#include "selfdrive/ui/qt/onroad/onroad_home.h" +#endif + +class HomeWindowSP : public HomeWindow { + Q_OBJECT + +public: + explicit HomeWindowSP(QWidget* parent = 0); + +public slots: + void showMapPanel(bool show); + +protected: + void mousePressEvent(QMouseEvent* e) override; +private slots: + void updateState(const UIState &s) override; +}; diff --git a/selfdrive/ui/sunnypilot/qt/maps/map.cc b/selfdrive/ui/sunnypilot/qt/maps/map.cc new file mode 100644 index 0000000000..f1d649980a --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/maps/map.cc @@ -0,0 +1,293 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/maps/map.h" + +#include "common/swaglog.h" +#include "selfdrive/ui/sunnypilot/qt/maps/map_helpers.h" + +const float MAX_ZOOM = 17; +const float MIN_ZOOM = 14; +const float MAX_PITCH = 50; + +MapWindowSP::MapWindowSP(const QMapLibre::Settings &settings) : MapWindow(settings) { + QObject::disconnect(uiState(), &UIState::uiUpdate, this, &MapWindow::updateState); + QObject::connect(uiStateSP(), &UIStateSP::uiUpdate, this, &MapWindowSP::updateState); +} + +MapWindowSP::~MapWindowSP() { + makeCurrent(); +} + +void MapWindowSP::initLayers() { + // This doesn't work from initializeGL + if (!m_map->layerExists("modelPathLayer")) { + qDebug() << "Initializing modelPathLayer"; + QVariantMap modelPath; + //modelPath["id"] = "modelPathLayer"; + modelPath["type"] = "line"; + modelPath["source"] = "modelPathSource"; + m_map->addLayer("modelPathLayer", modelPath); + m_map->setPaintProperty("modelPathLayer", "line-color", QColor("red")); + m_map->setPaintProperty("modelPathLayer", "line-width", 5.0); + m_map->setLayoutProperty("modelPathLayer", "line-cap", "round"); + } + if (!m_map->layerExists("navLayer")) { + qDebug() << "Initializing navLayer"; + QVariantMap nav; + nav["type"] = "line"; + nav["source"] = "navSource"; + m_map->addLayer("navLayer", nav, "road-intersection"); + + QVariantMap transition; + transition["duration"] = 400; // ms + m_map->setPaintProperty("navLayer", "line-color", getNavPathColor(uiStateSP()->scene.navigate_on_openpilot_deprecated)); + m_map->setPaintProperty("navLayer", "line-color-transition", transition); + m_map->setPaintProperty("navLayer", "line-width", 7.5); + m_map->setLayoutProperty("navLayer", "line-cap", "round"); + } + if (!m_map->layerExists("pinLayer")) { + qDebug() << "Initializing pinLayer"; + m_map->addImage("default_marker", QImage("../assets/navigation/default_marker.svg")); + QVariantMap pin; + pin["type"] = "symbol"; + pin["source"] = "pinSource"; + m_map->addLayer("pinLayer", pin); + m_map->setLayoutProperty("pinLayer", "icon-pitch-alignment", "viewport"); + m_map->setLayoutProperty("pinLayer", "icon-image", "default_marker"); + m_map->setLayoutProperty("pinLayer", "icon-ignore-placement", true); + m_map->setLayoutProperty("pinLayer", "icon-allow-overlap", true); + m_map->setLayoutProperty("pinLayer", "symbol-sort-key", 0); + m_map->setLayoutProperty("pinLayer", "icon-anchor", "bottom"); + } + if (!m_map->layerExists("carPosLayer")) { + qDebug() << "Initializing carPosLayer"; + m_map->addImage("label-arrow", QImage("../assets/images/triangle.svg")); + + QVariantMap carPos; + carPos["type"] = "symbol"; + carPos["source"] = "carPosSource"; + m_map->addLayer("carPosLayer", carPos); + m_map->setLayoutProperty("carPosLayer", "icon-pitch-alignment", "map"); + m_map->setLayoutProperty("carPosLayer", "icon-image", "label-arrow"); + m_map->setLayoutProperty("carPosLayer", "icon-size", 0.5); + m_map->setLayoutProperty("carPosLayer", "icon-ignore-placement", true); + m_map->setLayoutProperty("carPosLayer", "icon-allow-overlap", true); + // TODO: remove, symbol-sort-key does not seem to matter outside of each layer + m_map->setLayoutProperty("carPosLayer", "symbol-sort-key", 0); + } + if ((!m_map->layerExists("buildingsLayer")) && uiStateSP()->scene.map_3d_buildings) { // Could put this behind the cellular metered toggle in case it increases data usage + qDebug() << "Initializing buildingsLayer"; + QVariantMap buildings; + buildings["id"] = "buildingsLayer"; + buildings["source"] = "composite"; + buildings["source-layer"] = "building"; + buildings["type"] = "fill-extrusion"; + buildings["minzoom"] = 15; + m_map->addLayer("buildingsLayer", buildings); + m_map->setFilter("buildingsLayer", QVariantList({"==", "extrude", "true"})); + + QVariantList fillExtrusionHeight = { // scale buildings as you zoom in + "interpolate", + QVariantList{"linear"}, + QVariantList{"zoom"}, + 15, 0, + 15.05, QVariantList{"get", "height"} + }; + + QVariantList fillExtrusionBase = { + "interpolate", + QVariantList{"linear"}, + QVariantList{"zoom"}, + 15, 0, + 15.05, QVariantList{"get", "min_height"} + }; + + QVariantList fillExtrusionOpacity = { + "interpolate", + QVariantList{"linear"}, + QVariantList{"zoom"}, + 15, 0, // transparent at zoom level 15 + 15.5, .6, // fade in + 17, .6, // begin fading out + 20, 0 // fade out when zoomed in + }; + + m_map->setPaintProperty("buildingsLayer", "fill-extrusion-color", QColor("grey")); + m_map->setPaintProperty("buildingsLayer", "fill-extrusion-opacity", fillExtrusionOpacity); + m_map->setPaintProperty("buildingsLayer", "fill-extrusion-height", fillExtrusionHeight); + m_map->setPaintProperty("buildingsLayer", "fill-extrusion-base", fillExtrusionBase); + m_map->setLayoutProperty("buildingsLayer", "visibility", "visible"); + } +} + +void MapWindowSP::updateState(const UIStateSP &s) { + if (!uiState()->scene.started) { + return; + } + const SubMaster &sm = *(s.sm); + update(); + + // on rising edge of a valid system time, reinitialize the map to set a new token + if (sm.valid("clocks") && !prev_time_valid) { + LOGW("Time is now valid, reinitializing map"); + m_settings.setApiKey(get_mapbox_token()); + initializeGL(); + } + prev_time_valid = sm.valid("clocks"); + + if (sm.updated("modelV2")) { + // set path color on change, and show map on rising edge of navigate on openpilot + auto car_control = sm["carControl"].getCarControl(); + bool nav_enabled = sm["modelV2"].getModelV2().getNavEnabledDEPRECATED() && + (sm["controlsState"].getControlsState().getEnabled() || car_control.getLatActive() || car_control.getLongActive()); + if (nav_enabled != uiState()->scene.navigate_on_openpilot_deprecated) { + if (loaded_once) { + m_map->setPaintProperty("navLayer", "line-color", getNavPathColor(nav_enabled)); + } + if (nav_enabled) { + emit requestVisible(true); + } + } + uiState()->scene.navigate_on_openpilot_deprecated = nav_enabled; + } + + if (sm.updated("liveLocationKalman")) { + auto locationd_location = sm["liveLocationKalman"].getLiveLocationKalman(); + auto locationd_pos = locationd_location.getPositionGeodetic(); + auto locationd_orientation = locationd_location.getCalibratedOrientationNED(); + auto locationd_velocity = locationd_location.getVelocityCalibrated(); + auto locationd_ecef = locationd_location.getPositionECEF(); + + locationd_valid = (locationd_pos.getValid() && locationd_orientation.getValid() && locationd_velocity.getValid() && locationd_ecef.getValid()); + if (locationd_valid) { + // Check std norm + auto pos_ecef_std = locationd_ecef.getStd(); + bool pos_accurate_enough = sqrt(pow(pos_ecef_std[0], 2) + pow(pos_ecef_std[1], 2) + pow(pos_ecef_std[2], 2)) < 100; + locationd_valid = pos_accurate_enough; + } + + if (locationd_valid) { + last_position = QMapLibre::Coordinate(locationd_pos.getValue()[0], locationd_pos.getValue()[1]); + last_bearing = RAD2DEG(locationd_orientation.getValue()[2]); + velocity_filter.update(std::max(10.0, locationd_velocity.getValue()[0])); + } + } + + if (sm.updated("navRoute") && sm["navRoute"].getNavRoute().getCoordinates().size()) { + auto nav_dest = coordinate_from_param("NavDestination"); + bool allow_open = std::exchange(last_valid_nav_dest, nav_dest) != nav_dest && + nav_dest && !isVisible(); + qWarning() << "Got new navRoute from navd. Opening map:" << allow_open; + + // Show map on destination set/change + if (allow_open) { + emit requestSettings(false); + emit requestVisible(true); + } + } + + loaded_once = loaded_once || (m_map && m_map->isFullyLoaded()); + if (!loaded_once) { + setError(tr("Map Loading")); + return; + } + initLayers(); + + if (!locationd_valid) { + setError(tr("Waiting for GPS")); + } else if (routing_problem) { + setError(tr("Waiting for route")); + } else { + setError(""); + } + + if (locationd_valid) { + // Update current location marker + auto point = coordinate_to_collection(*last_position); + QMapLibre::Feature feature1(QMapLibre::Feature::PointType, point, {}, {}); + QVariantMap carPosSource; + carPosSource["type"] = "geojson"; + carPosSource["data"] = QVariant::fromValue(feature1); + m_map->updateSource("carPosSource", carPosSource); + + // Map bearing isn't updated when interacting, keep location marker up to date + if (last_bearing) { + m_map->setLayoutProperty("carPosLayer", "icon-rotate", *last_bearing - m_map->bearing()); + } + } + + if (interaction_counter == 0) { + if (last_position) m_map->setCoordinate(*last_position); + if (last_bearing) m_map->setBearing(*last_bearing); + m_map->setZoom(util::map_val(velocity_filter.x(), 0, 30, MAX_ZOOM, MIN_ZOOM)); + } else { + interaction_counter--; + } + + if (sm.updated("navInstruction")) { + // an invalid navInstruction packet with a nav destination is only possible if: + // - API exception/no internet + // - route response is empty + // - any time navd is waiting for recompute_countdown + routing_problem = !sm.valid("navInstruction") && coordinate_from_param("NavDestination").has_value(); + + if (sm.valid("navInstruction")) { + auto i = sm["navInstruction"].getNavInstruction(); + map_eta->updateETA(i.getTimeRemaining(), i.getTimeRemainingTypical(), i.getDistanceRemaining()); + + if (locationd_valid) { + m_map->setPitch(MAX_PITCH); // TODO: smooth pitching based on maneuver distance + map_instructions->updateInstructions(i); + } + } else { + clearRoute(); + } + } + + if (sm.rcv_frame("navRoute") != route_rcv_frame) { + qWarning() << "Updating navLayer with new route"; + auto route = sm["navRoute"].getNavRoute(); + auto route_points = capnp_coordinate_list_to_collection(route.getCoordinates()); + QMapLibre::Feature feature(QMapLibre::Feature::LineStringType, route_points, {}, {}); + QVariantMap navSource; + navSource["type"] = "geojson"; + navSource["data"] = QVariant::fromValue(feature); + m_map->updateSource("navSource", navSource); + m_map->setLayoutProperty("navLayer", "visibility", "visible"); + + route_rcv_frame = sm.rcv_frame("navRoute"); + updateDestinationMarker(); + } +} + +void MapWindowSP::offroadTransition(bool offroad) { + if (offroad) { + uiStateSP()->scene.navigate_on_openpilot_deprecated = false; + } + + MapWindow::offroadTransition(offroad); +} diff --git a/selfdrive/ui/sunnypilot/qt/maps/map.h b/selfdrive/ui/sunnypilot/qt/maps/map.h new file mode 100644 index 0000000000..00c20e2ae7 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/maps/map.h @@ -0,0 +1,53 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include "selfdrive/ui/qt/maps/map.h" +#include "selfdrive/ui/sunnypilot/ui.h" + +#include + +class MapWindowSP : public MapWindow { + Q_OBJECT + +public: + explicit MapWindowSP(const QMapLibre::Settings &); + ~MapWindowSP(); + +private: + void initLayers(); + // Blue with normal nav, green when nav is input into the model + QColor getNavPathColor(bool nav_enabled) { + return nav_enabled ? QColor("#31ee73") : QColor("#31a1ee"); + } + +protected slots: + void updateState(const UIStateSP &s); + +public slots: + void offroadTransition(bool offroad); +}; diff --git a/selfdrive/ui/sunnypilot/qt/maps/map_helpers.h b/selfdrive/ui/sunnypilot/qt/maps/map_helpers.h new file mode 100644 index 0000000000..464b35995c --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/maps/map_helpers.h @@ -0,0 +1,38 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include "selfdrive/ui/qt/maps/map_helpers.h" + +#define MAPBOX_TOKEN MAPBOX_TOKEN_SP +#define MAPS_HOST MAPS_HOST_SP + +#include "common/params.h" + +const QString MAPBOX_TOKEN = QString::fromStdString(Params().get("CustomMapboxTokenSk")) != "" ? + QString::fromStdString(Params().get("CustomMapboxTokenSk")) : util::getenv("MAPBOX_TOKEN").c_str(); +const QString MAPS_HOST = util::getenv("MAPS_HOST", MAPBOX_TOKEN.isEmpty() ? "https://maps.comma.ai" : "https://api.mapbox.com").c_str(); diff --git a/selfdrive/ui/sunnypilot/qt/network/networking.cc b/selfdrive/ui/sunnypilot/qt/network/networking.cc new file mode 100644 index 0000000000..bbe2cfb79c --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/network/networking.cc @@ -0,0 +1,448 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/network/networking.h" + +#include + +#include +#include +#include +#include "selfdrive/ui/qt/widgets/ssh_keys.h" + +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/qt/qt_window.h" +#include "selfdrive/ui/qt/util.h" +#include "selfdrive/ui/qt/widgets/scrollview.h" + +static const int ICON_WIDTH = 49; + +// Networking functions + +NetworkingSP::NetworkingSP(QWidget* parent, bool show_advanced) : QFrame(parent) { + main_layout = new QStackedLayout(this); + + wifi = new WifiManager(this); + connect(wifi, &WifiManager::refreshSignal, this, &NetworkingSP::refresh); + connect(wifi, &WifiManager::wrongPassword, this, &NetworkingSP::wrongPassword); + + wifiScreen = new QWidget(this); + QVBoxLayout* vlayout = new QVBoxLayout(wifiScreen); + vlayout->setContentsMargins(20, 20, 20, 20); + QHBoxLayout* hlayout = new QHBoxLayout(); + QPushButton* scanButton = new QPushButton(tr("Scan")); + scanButton->setObjectName("scan_btn"); + scanButton->setFixedSize(400, 100); + connect(wifi, &WifiManager::refreshSignal, this, [=]() { scanButton->setText(tr("Scan")); scanButton->setEnabled(true); }); + connect(scanButton, &QPushButton::clicked, [=]() { scanButton->setText(tr("Scanning...")); scanButton->setEnabled(false); wifi->requestScan(); }); + + hlayout->addWidget(scanButton); + hlayout->addStretch(1); // Pushes the button all the way to the left + + if (show_advanced) { + hlayout->setSpacing(10); + + QPushButton* advancedSettings = new QPushButton(tr("Advanced")); + advancedSettings->setObjectName("advanced_btn"); + advancedSettings->setFixedSize(400, 100); + connect(advancedSettings, &QPushButton::clicked, [=]() { main_layout->setCurrentWidget(an); }); + hlayout->addWidget(advancedSettings); + } + + vlayout->addLayout(hlayout); + vlayout->addSpacing(10); + + wifiWidget = new WifiUISP(this, wifi); + wifiWidget->setObjectName("wifiWidget"); + connect(wifiWidget, &WifiUISP::connectToNetwork, this, &NetworkingSP::connectToNetwork); + + ScrollView *wifiScroller = new ScrollView(wifiWidget, this); + wifiScroller->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + vlayout->addWidget(wifiScroller, 1); + main_layout->addWidget(wifiScreen); + + an = new AdvancedNetworkingSP(this, wifi); + connect(an, &AdvancedNetworkingSP::backPress, [=]() { main_layout->setCurrentWidget(wifiScreen); }); + connect(an, &AdvancedNetworkingSP::requestWifiScreen, [=]() { main_layout->setCurrentWidget(wifiScreen); }); + main_layout->addWidget(an); + + QPalette pal = palette(); + pal.setColor(QPalette::Window, QColor(0x29, 0x29, 0x29)); + setAutoFillBackground(true); + setPalette(pal); + + setStyleSheet(R"( + #wifiWidget > QPushButton, #back_btn, #advanced_btn, #scan_btn{ + font-size: 50px; + margin: 0px; + padding: 15px; + border-width: 0; + border-radius: 30px; + color: #dddddd; + background-color: #393939; + } + #back_btn:pressed, #advanced_btn:pressed, #scan_btn:pressed { + background-color: #4a4a4a; + } + )"); + main_layout->setCurrentWidget(wifiScreen); +} + +void NetworkingSP::refresh() { + wifiWidget->refresh(); + an->refresh(); +} + +void NetworkingSP::connectToNetwork(const Network n) { + if (wifi->isKnownConnection(n.ssid)) { + wifi->activateWifiConnection(n.ssid); + } else if (n.security_type == SecurityType::OPEN) { + wifi->connect(n, false); + } else if (n.security_type == SecurityType::WPA) { + QString pass = InputDialog::getText(tr("Enter password"), this, tr("for \"%1\"").arg(QString::fromUtf8(n.ssid)), true, 8); + if (!pass.isEmpty()) { + wifi->connect(n, false, pass); + } + } +} + +void NetworkingSP::wrongPassword(const QString &ssid) { + if (wifi->seenNetworks.contains(ssid)) { + const Network &n = wifi->seenNetworks.value(ssid); + QString pass = InputDialog::getText(tr("Wrong password"), this, tr("for \"%1\"").arg(QString::fromUtf8(n.ssid)), true, 8); + if (!pass.isEmpty()) { + wifi->connect(n, false, pass); + } + } +} + +void NetworkingSP::showEvent(QShowEvent *event) { + wifi->start(); +} + +void NetworkingSP::hideEvent(QHideEvent *event) { + main_layout->setCurrentWidget(wifiScreen); + wifi->stop(); +} + +// AdvancedNetworkingSP functions + +AdvancedNetworkingSP::AdvancedNetworkingSP(QWidget* parent, WifiManager* wifi): QWidget(parent), wifi(wifi) { + + QVBoxLayout* main_layout = new QVBoxLayout(this); + main_layout->setMargin(40); + main_layout->setSpacing(20); + + // Back button + QPushButton* back = new QPushButton(tr("Back")); + back->setObjectName("back_btn"); + back->setFixedSize(400, 100); + connect(back, &QPushButton::clicked, [=]() { emit backPress(); }); + main_layout->addWidget(back, 0, Qt::AlignLeft); + + ListWidgetSP *list = new ListWidgetSP(this); + // Enable tethering layout + const bool set_hotspot_on_boot = params.getBool("HotspotOnBoot") && params.getBool("HotspotOnBootConfirmed"); + tetheringToggle = new ToggleControlSP(tr("Enable Tethering"), "", "", wifi->isTetheringEnabled() || set_hotspot_on_boot); + list->addItem(tetheringToggle); + QObject::connect(tetheringToggle, &ToggleControlSP::toggleFlipped, this, &AdvancedNetworkingSP::toggleTethering); + + hotspotOnBootToggle = new ToggleControlSP( + tr("Retain hotspot/tethering state"), + tr("Enabling this toggle will retain the hotspot/tethering toggle state across reboots."), + "", + params.getBool("HotspotOnBoot") + ); + hotspotOnBootToggle->setEnabled(wifi->isTetheringEnabled() || set_hotspot_on_boot); + QObject::connect(hotspotOnBootToggle, &ToggleControlSP::toggleFlipped, [=](bool state) { + params.putBool("HotspotOnBoot", state); + }); + list->addItem(hotspotOnBootToggle); + + // Change tethering password + ButtonControlSP *editPasswordButton = new ButtonControlSP(tr("Tethering Password"), tr("EDIT")); + connect(editPasswordButton, &ButtonControlSP::clicked, [=]() { + QString pass = InputDialog::getText(tr("Enter new tethering password"), this, "", true, 8, wifi->getTetheringPassword()); + if (!pass.isEmpty()) { + wifi->changeTetheringPassword(pass); + } + }); + list->addItem(editPasswordButton); + + // IP address + ipLabel = new LabelControlSP(tr("IP Address"), wifi->ipv4_address); + list->addItem(ipLabel); + + // SSH keys + list->addItem(new SshToggle()); + list->addItem(new SshControl()); + + // Roaming toggle + const bool roamingEnabled = params.getBool("GsmRoaming"); + roamingToggle = new ToggleControlSP(tr("Enable Roaming"), "", "", roamingEnabled); + QObject::connect(roamingToggle, &ToggleControlSP::toggleFlipped, [=](bool state) { + params.putBool("GsmRoaming", state); + wifi->updateGsmSettings(state, QString::fromStdString(params.get("GsmApn")), params.getBool("GsmMetered")); + }); + list->addItem(roamingToggle); + + // APN settings + editApnButton = new ButtonControlSP(tr("APN Setting"), tr("EDIT")); + connect(editApnButton, &ButtonControlSP::clicked, [=]() { + const QString cur_apn = QString::fromStdString(params.get("GsmApn")); + QString apn = InputDialog::getText(tr("Enter APN"), this, tr("leave blank for automatic configuration"), false, -1, cur_apn).trimmed(); + + if (apn.isEmpty()) { + params.remove("GsmApn"); + } else { + params.put("GsmApn", apn.toStdString()); + } + wifi->updateGsmSettings(params.getBool("GsmRoaming"), apn, params.getBool("GsmMetered")); + }); + list->addItem(editApnButton); + + // Metered toggle + const bool metered = params.getBool("GsmMetered"); + meteredToggle = new ToggleControlSP(tr("Cellular Metered"), tr("Prevent large data uploads when on a metered connection"), "", metered); + QObject::connect(meteredToggle, &SshToggle::toggleFlipped, [=](bool state) { + params.putBool("GsmMetered", state); + wifi->updateGsmSettings(params.getBool("GsmRoaming"), QString::fromStdString(params.get("GsmApn")), state); + }); + list->addItem(meteredToggle); + + // Hidden Network + hiddenNetworkButton = new ButtonControlSP(tr("Hidden Network"), tr("CONNECT")); + connect(hiddenNetworkButton, &ButtonControlSP::clicked, [=]() { + QString ssid = InputDialog::getText(tr("Enter SSID"), this, "", false, 1); + if (!ssid.isEmpty()) { + QString pass = InputDialog::getText(tr("Enter password"), this, tr("for \"%1\"").arg(ssid), true, -1); + Network hidden_network; + hidden_network.ssid = ssid.toUtf8(); + if (!pass.isEmpty()) { + hidden_network.security_type = SecurityType::WPA; + wifi->connect(hidden_network, true, pass); + } else { + wifi->connect(hidden_network, true); + } + emit requestWifiScreen(); + } + }); + list->addItem(hiddenNetworkButton); + + // Ngrok + QProcess process; + process.start("sudo service ngrok status | grep running"); + process.waitForFinished(); + QString output = QString(process.readAllStandardOutput()); + bool ngrokRunning = !output.isEmpty(); + ToggleControlSP *ngrokToggle = new ToggleControlSP(tr("Ngrok Service"), "", "", ngrokRunning); + connect(ngrokToggle, &ToggleControlSP::toggleFlipped, [=](bool state) { + if (state) std::system("sudo ngrok service start"); + else std::system("sudo ngrok service stop"); + }); + list->addItem(ngrokToggle); + + // Set initial config + wifi->updateGsmSettings(roamingEnabled, QString::fromStdString(params.get("GsmApn")), metered); + + connect(uiState(), &UIState::primeTypeChanged, this, [=](PrimeType prime_type) { + bool gsmVisible = prime_type == PrimeType::NONE || prime_type == PrimeType::LITE; + roamingToggle->setVisible(gsmVisible); + editApnButton->setVisible(gsmVisible); + meteredToggle->setVisible(gsmVisible); + }); + + main_layout->addWidget(new ScrollView(list, this)); + main_layout->addStretch(1); +} + +void AdvancedNetworkingSP::refresh() { + ipLabel->setText(wifi->ipv4_address); + tetheringToggle->setEnabled(true); + update(); +} + +void AdvancedNetworkingSP::toggleTethering(bool enabled) { + params.putBool("HotspotOnBootConfirmed", enabled); + wifi->setTetheringEnabled(enabled); + tetheringToggle->setEnabled(false); + + hotspotOnBootToggle->setEnabled(enabled); + if (!enabled) { + params.remove("HotspotOnBoot"); + } +} + +// WifiUISP functions + +WifiUISP::WifiUISP(QWidget *parent, WifiManager* wifi) : QWidget(parent), wifi(wifi) { + QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(0, 0, 0, 0); + main_layout->setSpacing(0); + + // load imgs + for (const auto &s : {"low", "medium", "high", "full"}) { + QPixmap pix(ASSET_PATH + "/offroad/icon_wifi_strength_" + s + ".svg"); + strengths.push_back(pix.scaledToHeight(68, Qt::SmoothTransformation)); + } + lock = QPixmap(ASSET_PATH + "offroad/icon_lock_closed.svg").scaledToWidth(ICON_WIDTH, Qt::SmoothTransformation); + checkmark = QPixmap(ASSET_PATH + "offroad/icon_checkmark.svg").scaledToWidth(ICON_WIDTH, Qt::SmoothTransformation); + circled_slash = QPixmap(ASSET_PATH + "img_circled_slash.svg").scaledToWidth(ICON_WIDTH, Qt::SmoothTransformation); + + scanningLabel = new QLabel(tr("Scanning for networks...")); + scanningLabel->setStyleSheet("font-size: 65px;"); + main_layout->addWidget(scanningLabel, 0, Qt::AlignCenter); + + wifi_list_widget = new ListWidgetSP(this); + wifi_list_widget->setVisible(false); + main_layout->addWidget(wifi_list_widget); + + setStyleSheet(R"( + QScrollBar::handle:vertical { + min-height: 0px; + border-radius: 4px; + background-color: #8A8A8A; + } + #forgetBtn { + font-size: 32px; + font-weight: 600; + color: #292929; + background-color: #BDBDBD; + border-width: 1px solid #828282; + border-radius: 5px; + padding: 40px; + padding-bottom: 16px; + padding-top: 16px; + } + #forgetBtn:pressed { + background-color: #828282; + } + #connecting { + font-size: 32px; + font-weight: 600; + color: white; + border-radius: 0; + padding: 27px; + padding-left: 43px; + padding-right: 43px; + background-color: black; + } + #ssidLabel { + text-align: left; + border: none; + padding-top: 50px; + padding-bottom: 50px; + } + #ssidLabel:disabled { + color: #696969; + } + )"); +} + +void WifiUISP::refresh() { + bool is_empty = wifi->seenNetworks.isEmpty(); + scanningLabel->setVisible(is_empty); + wifi_list_widget->setVisible(!is_empty); + if (is_empty) return; + + setUpdatesEnabled(false); + + const bool is_tethering_enabled = wifi->isTetheringEnabled(); + QList sortedNetworks = wifi->seenNetworks.values(); + std::sort(sortedNetworks.begin(), sortedNetworks.end(), compare_by_strength); + + int n = 0; + for (Network &network : sortedNetworks) { + QPixmap status_icon; + if (network.connected == ConnectedType::CONNECTED) { + status_icon = checkmark; + } else if (network.security_type == SecurityType::UNSUPPORTED) { + status_icon = circled_slash; + } else if (network.security_type == SecurityType::WPA) { + status_icon = lock; + } + bool show_forget_btn = wifi->isKnownConnection(network.ssid) && !is_tethering_enabled; + QPixmap strength = strengths[strengthLevel(network.strength)]; + + auto item = getItem(n++); + item->setItem(network, status_icon, show_forget_btn, strength); + item->setVisible(true); + } + for (; n < wifi_items.size(); ++n) wifi_items[n]->setVisible(false); + + setUpdatesEnabled(true); +} + +WifiItemSP *WifiUISP::getItem(int n) { + auto item = n < wifi_items.size() ? wifi_items[n] : wifi_items.emplace_back(new WifiItemSP(tr("CONNECTING..."), tr("FORGET"))); + if (!item->parentWidget()) { + QObject::connect(item, &WifiItemSP::connectToNetwork, this, &WifiUISP::connectToNetwork); + QObject::connect(item, &WifiItemSP::forgotNetwork, [this](const Network n) { + if (ConfirmationDialog::confirm(tr("Forget Wi-Fi Network \"%1\"?").arg(QString::fromUtf8(n.ssid)), tr("Forget"), this)) + wifi->forgetConnection(n.ssid); + }); + wifi_list_widget->addItem(item); + } + return item; +} + +// WifiItemSP + +WifiItemSP::WifiItemSP(const QString &connecting_text, const QString &forget_text, QWidget *parent) : QWidget(parent) { + QHBoxLayout *hlayout = new QHBoxLayout(this); + hlayout->setContentsMargins(44, 0, 73, 0); + hlayout->setSpacing(50); + + hlayout->addWidget(ssidLabel = new ElidedLabelSP()); + ssidLabel->setObjectName("ssidLabel"); + ssidLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + hlayout->addWidget(connecting = new QPushButton(connecting_text), 0, Qt::AlignRight); + connecting->setObjectName("connecting"); + hlayout->addWidget(forgetBtn = new QPushButton(forget_text), 0, Qt::AlignRight); + forgetBtn->setObjectName("forgetBtn"); + hlayout->addWidget(iconLabel = new QLabel(), 0, Qt::AlignRight); + hlayout->addWidget(strengthLabel = new QLabel(), 0, Qt::AlignRight); + + iconLabel->setFixedWidth(ICON_WIDTH); + QObject::connect(forgetBtn, &QPushButton::clicked, [this]() { emit forgotNetwork(network); }); + QObject::connect(ssidLabel, &ElidedLabelSP::clicked, [this]() { + if (network.connected == ConnectedType::DISCONNECTED) emit connectToNetwork(network); + }); +} + +void WifiItemSP::setItem(const Network &n, const QPixmap &status_icon, bool show_forget_btn, const QPixmap &strength_icon) { + network = n; + + ssidLabel->setText(n.ssid); + ssidLabel->setEnabled(n.security_type != SecurityType::UNSUPPORTED); + ssidLabel->setFont(InterFont(55, network.connected == ConnectedType::DISCONNECTED ? QFont::Normal : QFont::Bold)); + + connecting->setVisible(n.connected == ConnectedType::CONNECTING); + forgetBtn->setVisible(show_forget_btn); + + iconLabel->setPixmap(status_icon); + strengthLabel->setPixmap(strength_icon); +} diff --git a/selfdrive/ui/sunnypilot/qt/network/networking.h b/selfdrive/ui/sunnypilot/qt/network/networking.h new file mode 100644 index 0000000000..931fe3443e --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/network/networking.h @@ -0,0 +1,128 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include + +#include "selfdrive/ui/qt/network/wifi_manager.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" + +class WifiItemSP : public QWidget { + Q_OBJECT +public: + explicit WifiItemSP(const QString &connecting_text, const QString &forget_text, QWidget* parent = nullptr); + void setItem(const Network& n, const QPixmap &icon, bool show_forget_btn, const QPixmap &strength); + +signals: + // Cannot pass Network by reference. it may change after the signal is sent. + void connectToNetwork(const Network n); + void forgotNetwork(const Network n); + +protected: + ElidedLabelSP* ssidLabel; + QPushButton* connecting; + QPushButton* forgetBtn; + QLabel* iconLabel; + QLabel* strengthLabel; + Network network; +}; + +class WifiUISP : public QWidget { + Q_OBJECT + +public: + explicit WifiUISP(QWidget *parent = 0, WifiManager* wifi = 0); + +private: + WifiItemSP *getItem(int n); + + WifiManager *wifi = nullptr; + QLabel *scanningLabel = nullptr; + QPixmap lock; + QPixmap checkmark; + QPixmap circled_slash; + QVector strengths; + ListWidgetSP *wifi_list_widget = nullptr; + std::vector wifi_items; + +signals: + void connectToNetwork(const Network n); + +public slots: + void refresh(); +}; + +class AdvancedNetworkingSP : public QWidget { + Q_OBJECT +public: + explicit AdvancedNetworkingSP(QWidget* parent = 0, WifiManager* wifi = 0); + +private: + LabelControlSP* ipLabel; + ToggleControlSP* tetheringToggle; + ToggleControlSP* roamingToggle; + ButtonControlSP* editApnButton; + ButtonControlSP* hiddenNetworkButton; + ToggleControlSP* meteredToggle; + WifiManager* wifi = nullptr; + Params params; + + ToggleControlSP* hotspotOnBootToggle; + +signals: + void backPress(); + void requestWifiScreen(); + +public slots: + void toggleTethering(bool enabled); + void refresh(); +}; + +class NetworkingSP : public QFrame { + Q_OBJECT + +public: + explicit NetworkingSP(QWidget* parent = 0, bool show_advanced = true); + WifiManager* wifi = nullptr; + +private: + QStackedLayout* main_layout = nullptr; + QWidget* wifiScreen = nullptr; + AdvancedNetworkingSP* an = nullptr; + WifiUISP* wifiWidget; + + void showEvent(QShowEvent* event) override; + void hideEvent(QHideEvent* event) override; + +public slots: + void refresh(); + +private slots: + void connectToNetwork(const Network n); + void wrongPassword(const QString &ssid); +}; diff --git a/selfdrive/ui/qt/network/sunnylink/models/role_model.h b/selfdrive/ui/sunnypilot/qt/network/sunnylink/models/role_model.h similarity index 53% rename from selfdrive/ui/qt/network/sunnylink/models/role_model.h rename to selfdrive/ui/sunnypilot/qt/network/sunnylink/models/role_model.h index d7f3a98281..c1e28a5f9a 100644 --- a/selfdrive/ui/qt/network/sunnylink/models/role_model.h +++ b/selfdrive/ui/sunnypilot/qt/network/sunnylink/models/role_model.h @@ -1,5 +1,30 @@ -#ifndef ROLE_MODEL_H -#define ROLE_MODEL_H +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once #include @@ -56,5 +81,3 @@ public: return T(m_raw_json_object); } }; - -#endif diff --git a/selfdrive/ui/qt/network/sunnylink/models/sponsor_role_model.h b/selfdrive/ui/sunnypilot/qt/network/sunnylink/models/sponsor_role_model.h similarity index 67% rename from selfdrive/ui/qt/network/sunnylink/models/sponsor_role_model.h rename to selfdrive/ui/sunnypilot/qt/network/sunnylink/models/sponsor_role_model.h index 64aad1ca46..6b6470f0cd 100644 --- a/selfdrive/ui/qt/network/sunnylink/models/sponsor_role_model.h +++ b/selfdrive/ui/sunnypilot/qt/network/sunnylink/models/sponsor_role_model.h @@ -1,5 +1,30 @@ -#ifndef SPONSORROLE_MODEL_H -#define SPONSORROLE_MODEL_H +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once #include @@ -24,7 +49,7 @@ public: QJsonObject json = RoleModel::toJson(); json["role_tier"] = sponsorTierToString(roleTier); return json; - }; + } static SponsorTier stringToSponsorTier(const QString &sponsorTierString) { const auto sponsorTierStringLower = sponsorTierString.toLower(); @@ -80,5 +105,3 @@ public: } [[nodiscard]] auto getSponsorTierColor() const { return sponsorTierToColor(roleTier); } }; - -#endif diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/models/user_model.h b/selfdrive/ui/sunnypilot/qt/network/sunnylink/models/user_model.h new file mode 100644 index 0000000000..259d4b39b9 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/network/sunnylink/models/user_model.h @@ -0,0 +1,56 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include + +class UserModel { +public: + QString device_id; + QString user_id; + qint64 created_at; + qint64 updated_at; + QString token_hash; + + explicit UserModel(const QJsonObject &json) { + device_id = json["device_id"].toString(); + user_id = json["user_id"].toString(); + created_at = json["created_at"].toInt(); + updated_at = json["updated_at"].toInt(); + token_hash = json["token_hash"].toString(); + } + + [[nodiscard]] QJsonObject toJson() const { + QJsonObject json; + json["device_id"] = device_id; + json["user_id"] = user_id; + json["created_at"] = created_at; + json["updated_at"] = updated_at; + json["token_hash"] = token_hash; + return json; + } +}; diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.cc b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.cc new file mode 100644 index 0000000000..13764c5749 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.cc @@ -0,0 +1,76 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/network/sunnylink//services/base_device_service.h" + +#include "selfdrive/ui/sunnypilot/qt/request_repeater.h" + +#include "common/swaglog.h" +#include "selfdrive/ui/qt/util.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_settings.h" + +BaseDeviceService::BaseDeviceService(QObject* parent) : QObject(parent), initial_request(nullptr), repeater(nullptr) { + param_watcher = new ParamWatcher(this); + connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) { + paramsRefresh(); + }); + param_watcher->addParam("SunnylinkEnabled"); +} + +void BaseDeviceService::paramsRefresh() { +} + +void BaseDeviceService::loadDeviceData(const QString &url, bool poll) { + if (!is_sunnylink_enabled()) { + LOGW("Sunnylink is not enabled, refusing to load data."); + return; + } + + auto sl_dongle_id = getSunnylinkDongleId(); + if (!sl_dongle_id.has_value()) + return; + + QString fullUrl = SUNNYLINK_BASE_URL + "/device/" + *sl_dongle_id + url; + if (poll && !isCurrentyPolling()) { + LOGD("Polling %s", qPrintable(fullUrl)); + LOGD("Cache key: SunnylinkCache_%s", qPrintable(QString(getCacheKey()))); + repeater = new RequestRepeaterSP(this, fullUrl, "SunnylinkCache_" + getCacheKey(), 60, false, true); + connect(repeater, &RequestRepeaterSP::requestDone, this, &BaseDeviceService::handleResponse); + } else if (isCurrentyPolling()) { + repeater->ForceUpdate(); + } else { + LOGD("Sending one-time %s", qPrintable(fullUrl)); + initial_request = new HttpRequestSP(this, true, 10000, true); + connect(initial_request, &HttpRequestSP::requestDone, this, &BaseDeviceService::handleResponse); + } +} + +void BaseDeviceService::stopPolling() { + if (repeater != nullptr) { + repeater->deleteLater(); + repeater = nullptr; + } +} diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.h b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.h new file mode 100644 index 0000000000..dced4edb52 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.h @@ -0,0 +1,50 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include "selfdrive/ui/sunnypilot/qt/request_repeater.h" +#include "selfdrive/ui/qt/util.h" + +class BaseDeviceService : public QObject { + Q_OBJECT + +protected: + void paramsRefresh(); + void loadDeviceData(const QString &url, bool poll = false); + virtual void handleResponse(const QString &response, bool success) = 0; + + static bool is_sunnylink_enabled() { return Params().getBool("SunnylinkEnabled");} + ParamWatcher* param_watcher; + HttpRequestSP* initial_request = nullptr; + RequestRepeaterSP* repeater = nullptr; + +public: + explicit BaseDeviceService(QObject* parent = nullptr); + virtual QString getCacheKey() const = 0; + bool isCurrentyPolling() {return repeater != nullptr;} + void stopPolling(); +}; diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.cc b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.cc new file mode 100644 index 0000000000..c835bf6f33 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.cc @@ -0,0 +1,55 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.h" + +#include +#include + +RoleService::RoleService(QObject* parent) : BaseDeviceService(parent) {} + +void RoleService::load() { + loadDeviceData(url); +} + +void RoleService::startPolling() { + loadDeviceData(url, true); +} + +void RoleService::handleResponse(const QString &response, bool success) { + if (!success) return; + + QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); + QJsonArray jsonArray = doc.array(); + + std::vector roles; + for (const auto &value : jsonArray) { + roles.emplace_back(value.toObject()); + } + + emit rolesReady(roles); + uiStateSP()->setSunnylinkRoles(roles); +} diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.h b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.h new file mode 100644 index 0000000000..91d59fe6a9 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.h @@ -0,0 +1,51 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include + +#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.h" +#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/models/role_model.h" + +class RoleService : public BaseDeviceService { + Q_OBJECT + +public: + explicit RoleService(QObject* parent = nullptr); + void load(); + void startPolling(); + [[nodiscard]] QString getCacheKey() const final { return "Roles"; } + +signals: + void rolesReady(const std::vector &roles); + +protected: + void handleResponse(const QString&response, bool success) override; + +private: + QString url = "/roles"; +}; diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.cc b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.cc new file mode 100644 index 0000000000..c0ce22ac89 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.cc @@ -0,0 +1,57 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.h" + +#include +#include + +UserService::UserService(QObject* parent) : BaseDeviceService(parent) { + url = "/users"; +} + +void UserService::load() { + loadDeviceData(url); +} + +void UserService::startPolling() { + loadDeviceData(url, true); +} + +void UserService::handleResponse(const QString &response, bool success) { + if (!success) return; + + QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); + QJsonArray jsonArray = doc.array(); + + std::vector users; + for (const auto &value : jsonArray) { + users.emplace_back(value.toObject()); + } + + emit usersReady(users); + uiStateSP()->setSunnylinkDeviceUsers(users); +} diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.h b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.h new file mode 100644 index 0000000000..aaac6c5b37 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.h @@ -0,0 +1,51 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include + +#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/services/base_device_service.h" +#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/models/user_model.h" + +class UserService : public BaseDeviceService { + Q_OBJECT + +public: + explicit UserService(QObject* parent = nullptr); + void load(); + void startPolling(); + [[nodiscard]] QString getCacheKey() const final { return "Users"; }; + +signals: + void usersReady(const std::vector&users); + +protected: + void handleResponse(const QString&response, bool success) override; + +private: + QString url = "/users"; +}; diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.cc b/selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.cc new file mode 100644 index 0000000000..3217e44dbd --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.cc @@ -0,0 +1,33 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.h" +#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.h" + +SunnylinkClient::SunnylinkClient(QObject* parent) : QObject(parent) { + role_service = new RoleService(parent); + user_service = new UserService(parent); +} diff --git a/selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.h b/selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.h new file mode 100644 index 0000000000..625f99f1f4 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.h @@ -0,0 +1,41 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include + +#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/services/role_service.h" +#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/services/user_service.h" + +class SunnylinkClient : public QObject { + Q_OBJECT + +public: + explicit SunnylinkClient(QObject* parent); + RoleService* role_service; + UserService* user_service; +}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.cc new file mode 100644 index 0000000000..99964c4681 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.cc @@ -0,0 +1,189 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h" + +#include +#include +#include + +#include "selfdrive/ui/qt/qt_window.h" +#include "selfdrive/ui/qt/widgets/prime.h" + +DevicePanelSP::DevicePanelSP(SettingsWindow *parent) : DevicePanel(parent) { + fleetManagerPin = new ButtonControlSP( + pin_title + pin, tr("TOGGLE"), + tr("Enable or disable PIN requirement for Fleet Manager access.")); + connect(fleetManagerPin, &ButtonControlSP::clicked, [=]() { + if (params.getBool("FleetManagerPin")) { + if (ConfirmationDialog::confirm(tr("Are you sure you want to turn off PIN requirement?"), tr("Turn Off"), this)) { + params.remove("FleetManagerPin"); + refreshPin(); + } + } else { + params.putBool("FleetManagerPin", true); + refreshPin(); + } + }); + AddWidgetAt(2, fleetManagerPin); + + fs_watch = new QFileSystemWatcher(this); + connect(fs_watch, &QFileSystemWatcher::fileChanged, this, &DevicePanelSP::onPinFileChanged); + + QString pin_path = "/data/otp/otp.conf"; + QString pin_require = "/data/params/d/FleetManagerPin"; + fs_watch->addPath(pin_path); + fs_watch->addPath(pin_require); + refreshPin(); + + // Error Troubleshoot + auto errorBtn = new ButtonControlSP( + tr("Error Troubleshoot"), tr("VIEW"), + tr("Display error from the tmux session when an error has occurred from a system process.")); + QFileInfo file("/data/community/crashes/error.txt"); + QDateTime modifiedTime = file.lastModified(); + QString modified_time = modifiedTime.toString("yyyy-MM-dd hh:mm:ss "); + connect(errorBtn, &ButtonControlSP::clicked, [=]() { + const std::string txt = util::read_file("/data/community/crashes/error.txt"); + ConfirmationDialog::rich(modified_time + QString::fromStdString(txt), this); + }); + AddWidgetAt(3, errorBtn); + + + auto resetMapboxTokenBtn = new ButtonControlSP(tr("Reset Access Tokens for Map Services"), tr("RESET"), tr("Reset self-service access tokens for Mapbox, Amap, and Google Maps.")); + connect(resetMapboxTokenBtn, &ButtonControlSP::clicked, [=]() { + if (ConfirmationDialog::confirm(tr("Are you sure you want to reset access tokens for all map services?"), tr("Reset"), this)) { + std::vector tokens = { + "CustomMapboxTokenPk", + "CustomMapboxTokenSk", + "AmapKey1", + "AmapKey2", + "GmapKey" + }; + for (const auto& token : tokens) { + params.remove(token); + } + } + }); + AddWidgetAt(6, resetMapboxTokenBtn); + + auto resetParamsBtn = new ButtonControlSP(tr("Reset sunnypilot Settings"), tr("RESET"), ""); + connect(resetParamsBtn, &ButtonControlSP::clicked, [=]() { + if (ConfirmationDialog::confirm(tr("Are you sure you want to reset all sunnypilot settings?"), tr("Reset"), this)) { + std::system("sudo rm -rf /data/params/d/*"); + Hardware::reboot(); + } + }); + AddWidgetAt(6, resetParamsBtn); + + QObject::connect(uiStateSP(), &UIStateSP::offroadTransition, [=](bool offroad) { + for (auto btn : findChildren()) { + if (btn != pair_device && btn != errorBtn) { + btn->setEnabled(offroad); + } + } + }); + + offroad_btn = new QPushButton(tr("Toggle Onroad/Offroad")); + offroad_btn->setObjectName("offroad_btn"); + QObject::connect(offroad_btn, &QPushButton::clicked, this, &DevicePanelSP::forceoffroad); + + QVBoxLayout *buttons_layout = new QVBoxLayout(); + buttons_layout->setSpacing(24); + buttons_layout->addLayout(power_layout); + buttons_layout->addWidget(offroad_btn); + addItem(buttons_layout); + + updateLabels(); +} + +void DevicePanelSP::onPinFileChanged(const QString &file_path) { + if (file_path == "/data/params/d/FleetManagerPin") { + refreshPin(); + } else if (file_path == "/data/otp/otp.conf") { + refreshPin(); + } +} + +void DevicePanelSP::refreshPin() { + QFile f("/data/otp/otp.conf"); + QFile require("/data/params/d/FleetManagerPin"); + if (!require.exists()) { + setSpacing(50); + fleetManagerPin->setTitle(pin_title + tr("OFF")); + } else if (f.open(QIODevice::ReadOnly | QIODevice::Text)) { + pin = f.readAll(); + f.close(); + setSpacing(50); + fleetManagerPin->setTitle(pin_title + pin); + } +} + +void DevicePanelSP::forceoffroad() { + if (!uiStateSP()->engaged()) { + if (params.getBool("ForceOffroad")) { + if (ConfirmationDialog::confirm(tr("Are you sure you want to unforce offroad?"), tr("Unforce"), this)) { + // Check engaged again in case it changed while the dialog was open + if (!uiStateSP()->engaged()) { + params.remove("ForceOffroad"); + } + } + } else { + if (ConfirmationDialog::confirm(tr("Are you sure you want to force offroad?"), tr("Force"), this)) { + // Check engaged again in case it changed while the dialog was open + if (!uiStateSP()->engaged()) { + params.putBool("ForceOffroad", true); + } + } + } + } else { + ConfirmationDialog::alert(tr("Disengage to Force Offroad"), this); + } + + updateLabels(); +} + +void DevicePanelSP::showEvent(QShowEvent *event) { + DevicePanel::showEvent(event); + updateLabels(); +} + +void DevicePanelSP::updateLabels() { + if (!isVisible()) { + return; + } + + bool force_offroad_param = params.getBool("ForceOffroad"); + QString offroad_btn_style = force_offroad_param ? "#393939" : "#E22C2C"; + QString offroad_btn_pressed_style = force_offroad_param ? "#4a4a4a" : "#FF2424"; + QString btn_common_style = QString("QPushButton { height: 120px; border-radius: 15px; background-color: %1; }" + "QPushButton:pressed { background-color: %2; }") + .arg(offroad_btn_style, + offroad_btn_pressed_style); + + offroad_btn->setText(force_offroad_param ? tr("Unforce Offroad") : tr("Force Offroad")); + offroad_btn->setStyleSheet(btn_common_style + offroad_btn_style + offroad_btn_pressed_style); +} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h new file mode 100644 index 0000000000..14319612b2 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h @@ -0,0 +1,52 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" + +class DevicePanelSP : public DevicePanel { + Q_OBJECT + +public: + explicit DevicePanelSP(SettingsWindow *parent); + void showEvent(QShowEvent *event) override; + +private slots: + void onPinFileChanged(const QString &file_path); + void refreshPin(); + void forceoffroad(); + + void updateLabels(); + +private: + ButtonControlSP *fleetManagerPin; + QString pin_title = tr("Fleet Manager PIN:") + " "; + QString pin = "OFF"; + QFileSystemWatcher *fs_watch; + + QPushButton *offroad_btn; +}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/display_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/display_settings.cc similarity index 71% rename from selfdrive/ui/qt/offroad/sunnypilot/display_settings.cc rename to selfdrive/ui/sunnypilot/qt/offroad/settings/display_settings.cc index 5d11c8526c..9000c87910 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/display_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/display_settings.cc @@ -1,6 +1,35 @@ -#include "selfdrive/ui/qt/offroad/sunnypilot/display_settings.h" +/** +The MIT License -DisplayPanel::DisplayPanel(QWidget *parent) : ListWidget(parent, false) { +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/display_settings.h" + +#include +#include + +DisplayPanel::DisplayPanel(QWidget *parent) : ListWidgetSP(parent, false) { // param, title, desc, icon std::vector> toggle_defs{ { @@ -18,27 +47,27 @@ DisplayPanel::DisplayPanel(QWidget *parent) : ListWidget(parent, false) { // General: Max Time Offroad (Shutdown timer) auto max_time_offroad = new MaxTimeOffroad(); - connect(max_time_offroad, &SPOptionControl::updateLabels, max_time_offroad, &MaxTimeOffroad::refresh); + connect(max_time_offroad, &OptionControlSP::updateLabels, max_time_offroad, &MaxTimeOffroad::refresh); addItem(max_time_offroad); // General: Onroad Screen Off (Auto Onroad Screen Timer) onroad_screen_off = new OnroadScreenOff(); onroad_screen_off->setUpdateOtherToggles(true); - connect(onroad_screen_off, &SPOptionControl::updateLabels, onroad_screen_off, &OnroadScreenOff::refresh); - connect(onroad_screen_off, &SPOptionControl::updateOtherToggles, this, &DisplayPanel::updateToggles); + connect(onroad_screen_off, &OptionControlSP::updateLabels, onroad_screen_off, &OnroadScreenOff::refresh); + connect(onroad_screen_off, &OptionControlSP::updateOtherToggles, this, &DisplayPanel::updateToggles); addItem(onroad_screen_off); // General: Onroad Screen Off Brightness onroad_screen_off_brightness = new OnroadScreenOffBrightness(); - connect(onroad_screen_off_brightness, &SPOptionControl::updateLabels, onroad_screen_off_brightness, &OnroadScreenOffBrightness::refresh); + connect(onroad_screen_off_brightness, &OptionControlSP::updateLabels, onroad_screen_off_brightness, &OnroadScreenOffBrightness::refresh); addItem(onroad_screen_off_brightness); // General: Brightness Control (Global) auto brightness_control = new BrightnessControl(); - connect(brightness_control, &SPOptionControl::updateLabels, brightness_control, &BrightnessControl::refresh); + connect(brightness_control, &OptionControlSP::updateLabels, brightness_control, &BrightnessControl::refresh); for (auto &[param, title, desc, icon] : toggle_defs) { - auto toggle = new ParamControl(param, title, desc, icon, this); + auto toggle = new ParamControlSP(param, title, desc, icon, this); addItem(toggle); toggles[param.toStdString()] = toggle; @@ -65,7 +94,7 @@ void DisplayPanel::updateToggles() { } // Max Time Offroad (Shutdown timer) -MaxTimeOffroad::MaxTimeOffroad() : SPOptionControl ( +MaxTimeOffroad::MaxTimeOffroad() : OptionControlSP( "MaxTimeOffroad", tr("Max Time Offroad"), tr("Device is automatically turned off after a set time when the engine is turned off (off-road) after driving (on-road)."), @@ -110,7 +139,7 @@ void MaxTimeOffroad::refresh() { } // Onroad Screen Off (Auto Onroad Screen Timer) -OnroadScreenOff::OnroadScreenOff() : SPOptionControl ( +OnroadScreenOff::OnroadScreenOff() : OptionControlSP( "OnroadScreenOff", tr("Driving Screen Off Timer"), tr("Turn off the device screen or reduce brightness to protect the screen after driving starts. It automatically brightens or turns on when a touch or event occurs."), @@ -136,7 +165,7 @@ void OnroadScreenOff::refresh() { } // Onroad Screen Off Brightness -OnroadScreenOffBrightness::OnroadScreenOffBrightness() : SPOptionControl ( +OnroadScreenOffBrightness::OnroadScreenOffBrightness() : OptionControlSP( "OnroadScreenOffBrightness", tr("Driving Screen Off Brightness (%)"), tr("When using the Driving Screen Off feature, the brightness is reduced according to the automatic brightness ratio."), @@ -157,7 +186,7 @@ void OnroadScreenOffBrightness::refresh() { } // Brightness Control (Global) -BrightnessControl::BrightnessControl() : SPOptionControl ( +BrightnessControl::BrightnessControl() : OptionControlSP( "BrightnessControl", tr("Brightness"), tr("Manually adjusts the global brightness of the screen."), diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/display_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/display_settings.h new file mode 100644 index 0000000000..5298b66fd6 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/display_settings.h @@ -0,0 +1,98 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include + +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" + +class OnroadScreenOff : public OptionControlSP { + Q_OBJECT + +public: + OnroadScreenOff(); + + void refresh(); + +private: + Params params; +}; + +class OnroadScreenOffBrightness : public OptionControlSP { + Q_OBJECT + +public: + OnroadScreenOffBrightness(); + + void refresh(); + +private: + Params params; +}; + +class MaxTimeOffroad : public OptionControlSP { + Q_OBJECT + +public: + MaxTimeOffroad(); + + void refresh(); + +private: + Params params; +}; + +class BrightnessControl : public OptionControlSP { + Q_OBJECT + +public: + BrightnessControl(); + + void refresh(); + +private: + Params params; +}; + +class DisplayPanel : public ListWidgetSP { + Q_OBJECT + +public: + explicit DisplayPanel(QWidget *parent = nullptr); + void showEvent(QShowEvent *event) override; + +public slots: + void updateToggles(); + +private: + Params params; + std::map toggles; + + OnroadScreenOff *onroad_screen_off; + OnroadScreenOffBrightness *onroad_screen_off_brightness; +}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/monitoring_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/monitoring_settings.cc new file mode 100644 index 0000000000..88a69842c7 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/monitoring_settings.cc @@ -0,0 +1,58 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/monitoring_settings.h" + +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" + +MonitoringPanel::MonitoringPanel(QWidget *parent) : QFrame(parent) { + main_layout = new QStackedLayout(this); + + ListWidgetSP *list = new ListWidgetSP(this, false); + // param, title, desc, icon + std::vector> toggle_defs{ + { + "HandsOnWheelMonitoring", + tr("Enable Hands on Wheel Monitoring"), + tr("Monitor and alert when driver is not keeping the hands on the steering wheel."), + "../assets/offroad/icon_blank.png", + } + }; + + for (auto &[param, title, desc, icon] : toggle_defs) { + auto toggle = new ParamControlSP(param, title, desc, icon, this); + + list->addItem(toggle); + toggles[param.toStdString()] = toggle; + } + + monitoringScreen = new QWidget(this); + QVBoxLayout* vlayout = new QVBoxLayout(monitoringScreen); + vlayout->setContentsMargins(50, 20, 50, 20); + + vlayout->addWidget(new ScrollViewSP(list, this), 1); + main_layout->addWidget(monitoringScreen); +} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/monitoring_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/monitoring_settings.h new file mode 100644 index 0000000000..091b2fd9f5 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/monitoring_settings.h @@ -0,0 +1,46 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include +#include + +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" + +class MonitoringPanel : public QFrame { + Q_OBJECT + +public: + explicit MonitoringPanel(QWidget *parent = nullptr); + +private: + QStackedLayout* main_layout = nullptr; + QWidget* monitoringScreen = nullptr; + Params params; + std::map toggles; +}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/onboarding.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/onboarding.cc new file mode 100644 index 0000000000..dd642054d9 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/onboarding.cc @@ -0,0 +1,123 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/onboarding.h" + +#include + +#include +#include +#include + +#include "common/util.h" +#include "common/params.h" +#include "selfdrive/ui/qt/util.h" +#include "selfdrive/ui/qt/widgets/input.h" + +void TermsPageSP::showEvent(QShowEvent *event) { + // late init, building QML widget takes 200ms + if (layout()) { + return; + } + + QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(45, 35, 45, 45); + main_layout->setSpacing(0); + + QLabel *title = new QLabel(tr("Terms & Conditions")); + title->setStyleSheet("font-size: 90px; font-weight: 600;"); + main_layout->addWidget(title); + + main_layout->addSpacing(30); + + QQuickWidget *text = new QQuickWidget(this); + text->setResizeMode(QQuickWidget::SizeRootObjectToView); + text->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + text->setAttribute(Qt::WA_AlwaysStackOnTop); + text->setClearColor(QColor("#1B1B1B")); + + std::string tc_text = sunnypilot_tc ? "../assets/offroad/sp_tc.html" : "../assets/offroad/tc.html"; + QString text_view = util::read_file(tc_text).c_str(); + text->rootContext()->setContextProperty("text_view", text_view); + + text->setSource(QUrl::fromLocalFile("qt/offroad/text_view.qml")); + + main_layout->addWidget(text, 1); + main_layout->addSpacing(50); + + QObject *obj = (QObject*)text->rootObject(); + QObject::connect(obj, SIGNAL(scroll()), SLOT(enableAccept())); + + QHBoxLayout* buttons = new QHBoxLayout; + buttons->setMargin(0); + buttons->setSpacing(45); + main_layout->addLayout(buttons); + + QPushButton *decline_btn = new QPushButton(tr("Decline")); + buttons->addWidget(decline_btn); + QObject::connect(decline_btn, &QPushButton::clicked, this, &TermsPage::declinedTerms); + + accept_btn = new QPushButton(tr("Scroll to accept")); + accept_btn->setEnabled(false); + accept_btn->setStyleSheet(R"( + QPushButton { + background-color: #465BEA; + } + QPushButton:pressed { + background-color: #3049F4; + } + QPushButton:disabled { + background-color: #4F4F4F; + } + )"); + buttons->addWidget(accept_btn); + QObject::connect(accept_btn, &QPushButton::clicked, this, &TermsPage::acceptedTerms); +} + +void OnboardingWindowSP::updateActiveScreen() { + if(accepted_terms && training_done && !accepted_terms_sp) { + setCurrentIndex(3); + } else { + OnboardingWindow::updateActiveScreen(); + } +} + +OnboardingWindowSP::OnboardingWindowSP(QWidget *parent) : OnboardingWindow(parent) { + std::string current_terms_version_sp = params.get("TermsVersionSunnypilot"); + accepted_terms_sp = params.get("HasAcceptedTermsSP") == current_terms_version_sp; + LOGD("accepted_terms_sp: %s", params.get("HasAcceptedTermsSP").c_str()); + + auto* terms_sp = new TermsPageSP(true, parent); + addWidget(terms_sp); // index = 3 + connect(terms_sp, &TermsPageSP::acceptedTerms, [=]() { + params.put("HasAcceptedTermsSP", current_terms_version_sp); + accepted_terms_sp = true; + updateActiveScreen(); + }); + connect(terms_sp, &TermsPageSP::declinedTerms, [=]() { setCurrentIndex(2); }); + + OnboardingWindowSP::updateActiveScreen(); +} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/onboarding.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/onboarding.h new file mode 100644 index 0000000000..f7e9bfccde --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/onboarding.h @@ -0,0 +1,57 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include + +#include "common/params.h" +#include "selfdrive/ui/qt/qt_window.h" + +class TermsPageSP : public TermsPage { + Q_OBJECT + + +public: + explicit TermsPageSP(bool sunnypilot = false, QWidget *parent = 0) : TermsPage(parent), sunnypilot_tc(sunnypilot) {} + + +private: + bool sunnypilot_tc = false; + void showEvent(QShowEvent *event) override; +}; + +class OnboardingWindowSP : public OnboardingWindow { + Q_OBJECT + +public: + explicit OnboardingWindowSP(QWidget *parent = 0); + inline bool completed() const override { return accepted_terms && accepted_terms_sp && training_done; } + +private: + bool accepted_terms_sp = false; + void updateActiveScreen() override; +}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/locations_fetcher.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm/locations_fetcher.h similarity index 64% rename from selfdrive/ui/qt/offroad/sunnypilot/locations_fetcher.h rename to selfdrive/ui/sunnypilot/qt/offroad/settings/osm/locations_fetcher.h index 1e5b20139f..f3142cfc69 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/locations_fetcher.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm/locations_fetcher.h @@ -1,11 +1,40 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + #pragma once -#include #include // for std::sort #include -#include +#include +#include -#include "selfdrive/ui/qt/offroad/sunnypilot/json_fetcher.h" +#include +#include + +#include "selfdrive/ui/sunnypilot/qt/common/json_fetcher.h" static const std::tuple defaultLocation = std::make_tuple("== None ==", ""); // New class LocationsFetcher that handles web requests and JSON parsing diff --git a/selfdrive/ui/qt/offroad/sunnypilot/models_fetcher.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm/models_fetcher.cc similarity index 80% rename from selfdrive/ui/qt/offroad/sunnypilot/models_fetcher.cc rename to selfdrive/ui/sunnypilot/qt/offroad/settings/osm/models_fetcher.cc index 3df9c09fe3..b6736c7424 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/models_fetcher.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm/models_fetcher.cc @@ -1,4 +1,31 @@ -#include "selfdrive/ui/qt/offroad/sunnypilot/models_fetcher.h" +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/osm/models_fetcher.h" + #include ModelsFetcher::ModelsFetcher(QObject* parent) : QObject(parent) { @@ -88,7 +115,7 @@ void ModelsFetcher::onFinished(QNetworkReply* reply, const QString& destinationP QFile file(finalPath); //ensure if the path exists and if not create it - if(!QDir().mkpath(destinationPath)) + if (!QDir().mkpath(destinationPath)) { LOGE("Unable to create directory: %s", destinationPath.toStdString().c_str()); emit downloadFailed(filename); diff --git a/selfdrive/ui/qt/offroad/sunnypilot/models_fetcher.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm/models_fetcher.h similarity index 75% rename from selfdrive/ui/qt/offroad/sunnypilot/models_fetcher.h rename to selfdrive/ui/sunnypilot/qt/offroad/settings/osm/models_fetcher.h index 22ab81e541..c813deedec 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/models_fetcher.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm/models_fetcher.h @@ -1,18 +1,50 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + #pragma once #include // for std::sort #include #include +#include + #include #include #include #include "common/swaglog.h" #include "common/util.h" -#include "selfdrive/ui/ui.h" +#include "selfdrive/ui/sunnypilot/ui.h" #include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/json_fetcher.h" +#include "selfdrive/ui/sunnypilot/qt/common/json_fetcher.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#else #include "selfdrive/ui/qt/widgets/controls.h" +#endif #include "system/hardware/hw.h" static const QString MODELS_PATH = Hardware::PC() ? QDir::homePath() + "/.comma/media/0/models/" : "/data/media/0/models/"; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/osm_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_settings.cc similarity index 76% rename from selfdrive/ui/qt/offroad/sunnypilot/osm_settings.cc rename to selfdrive/ui/sunnypilot/qt/offroad/settings/osm_settings.cc index 236e4406cf..8420181d16 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/osm_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_settings.cc @@ -1,18 +1,51 @@ -#include "selfdrive/ui/qt/offroad/sunnypilot/osm_settings.h" +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/osm_settings.h" + +#include +#include +#include + +#include "common/swaglog.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" OsmPanel::OsmPanel(QWidget *parent) : QFrame(parent) { main_layout = new QStackedLayout(this); - const auto list = new ListWidget(this, false); - list->addItem(mapdVersion = new LabelControl(tr("Mapd Version"), "Loading...")); + const auto list = new ListWidgetSP(this, false); + list->addItem(mapdVersion = new LabelControlSP(tr("Mapd Version"), "Loading...")); list->addItem(setupOsmDeleteMapsButton(parent)); - list->addItem(offlineMapsETA = new LabelControl(tr("Offline Maps ETA"), "")); - list->addItem(offlineMapsElapsed = new LabelControl(tr("Time Elapsed"), "")); + list->addItem(offlineMapsETA = new LabelControlSP(tr("Offline Maps ETA"), "")); + list->addItem(offlineMapsElapsed = new LabelControlSP(tr("Time Elapsed"), "")); list->addItem(setupOsmUpdateButton(parent)); list->addItem(setupOsmDownloadButton(parent)); list->addItem(setupUsStatesButton(parent)); - connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { + connect(uiStateSP(), &UIStateSP::offroadTransition, [=](bool offroad) { updateLabels(); }); @@ -24,13 +57,13 @@ OsmPanel::OsmPanel(QWidget *parent) : QFrame(parent) { osmScreen = new QWidget(this); auto *vlayout = new QVBoxLayout(osmScreen); vlayout->setContentsMargins(50, 20, 50, 20); - vlayout->addWidget(new ScrollView(list, this), 1); + vlayout->addWidget(new ScrollViewSP(list, this), 1); main_layout->addWidget(osmScreen); } -ButtonControl *OsmPanel::setupOsmDeleteMapsButton(QWidget *parent) { - osmDeleteMapsBtn = new ButtonControl(tr("Downloaded Maps"), tr("DELETE")); // Updated on updateLabels() - connect(osmDeleteMapsBtn, &ButtonControl::clicked, [=]() { +ButtonControlSP *OsmPanel::setupOsmDeleteMapsButton(QWidget *parent) { + osmDeleteMapsBtn = new ButtonControlSP(tr("Downloaded Maps"), tr("DELETE")); // Updated on updateLabels() + connect(osmDeleteMapsBtn, &ButtonControlSP::clicked, [=]() { if (showConfirmationDialog(parent, tr("This will delete ALL downloaded maps\n\nAre you sure you want to delete all the maps?"), tr("Yes, delete all the maps."))) { QtConcurrent::run([=]() { QDir dir(MAP_PATH); @@ -47,9 +80,9 @@ ButtonControl *OsmPanel::setupOsmDeleteMapsButton(QWidget *parent) { return osmDeleteMapsBtn; } -ButtonControl *OsmPanel::setupOsmUpdateButton(QWidget *parent) { - osmUpdateBtn = new ButtonControl(tr("Database Update"), tr("CHECK")); // Updated on updateLabels() - connect(osmUpdateBtn, &ButtonControl::clicked, [=]() { +ButtonControlSP *OsmPanel::setupOsmUpdateButton(QWidget *parent) { + osmUpdateBtn = new ButtonControlSP(tr("Database Update"), tr("CHECK")); // Updated on updateLabels() + connect(osmUpdateBtn, &ButtonControlSP::clicked, [=]() { if (osm_download_in_progress && !download_failed_state) { updateLabels(); } else if (showConfirmationDialog(parent)) { @@ -61,9 +94,9 @@ ButtonControl *OsmPanel::setupOsmUpdateButton(QWidget *parent) { return osmUpdateBtn; } -ButtonControl *OsmPanel::setupOsmDownloadButton(QWidget *parent) { - osmDownloadBtn = new ButtonControl(tr("Country"), tr("SELECT")); - connect(osmDownloadBtn, &ButtonControl::clicked, [=]() { +ButtonControlSP *OsmPanel::setupOsmDownloadButton(QWidget *parent) { + osmDownloadBtn = new ButtonControlSP(tr("Country"), tr("SELECT")); + connect(osmDownloadBtn, &ButtonControlSP::clicked, [=]() { osmDownloadBtn->setEnabled(false); osmDownloadBtn->setValue(tr("Fetching Country list...")); const std::vector> locations = getOsmLocations(); @@ -73,7 +106,7 @@ ButtonControl *OsmPanel::setupOsmDownloadButton(QWidget *parent) { const QString currentTitle = ((initTitle == "== None ==") || (initTitle.length() == 0)) ? "== None ==" : initTitle; QStringList locationTitles; - for (auto &loc: locations) { + for (auto &loc : locations) { locationTitles.push_back(std::get<0>(loc)); } @@ -81,7 +114,7 @@ ButtonControl *OsmPanel::setupOsmDownloadButton(QWidget *parent) { if (!selection.isEmpty()) { params.put("OsmLocal", "1"); params.put("OsmLocationTitle", selection.toStdString()); - for (auto &loc: locations) { + for (auto &loc : locations) { if (std::get<0>(loc) == selection) { params.put("OsmLocationName", std::get<1>(loc).toStdString()); break; @@ -103,9 +136,9 @@ ButtonControl *OsmPanel::setupOsmDownloadButton(QWidget *parent) { return osmDownloadBtn; } -ButtonControl *OsmPanel::setupUsStatesButton(QWidget *parent) { - usStatesBtn = new ButtonControl(tr("State"), tr("SELECT")); - connect(usStatesBtn, &ButtonControl::clicked, [=]() { +ButtonControlSP *OsmPanel::setupUsStatesButton(QWidget *parent) { + usStatesBtn = new ButtonControlSP(tr("State"), tr("SELECT")); + connect(usStatesBtn, &ButtonControlSP::clicked, [=]() { const std::tuple allStatesOption = std::make_tuple("All States (~4.8 GB)", "All"); usStatesBtn->setEnabled(false); usStatesBtn->setValue(tr("Fetching State list...")); @@ -116,14 +149,14 @@ ButtonControl *OsmPanel::setupUsStatesButton(QWidget *parent) { const QString currentTitle = ((initTitle == std::get<0>(allStatesOption)) || (initTitle.length() == 0)) ? tr("All") : initTitle; QStringList locationTitles; - for (auto &loc: locations) { + for (auto &loc : locations) { locationTitles.push_back(std::get<0>(loc)); } const QString selection = MultiOptionDialog::getSelection(tr("State"), locationTitles, currentTitle, this); if (!selection.isEmpty()) { params.put("OsmStateTitle", selection.toStdString()); - for (auto &loc: locations) { + for (auto &loc : locations) { if (std::get<0>(loc) == selection) { params.put("OsmStateName", std::get<1>(loc).toStdString()); break; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/osm_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_settings.h similarity index 77% rename from selfdrive/ui/qt/offroad/sunnypilot/osm_settings.h rename to selfdrive/ui/sunnypilot/qt/offroad/settings/osm_settings.h index 2f9cf8455f..b250e2cecd 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/osm_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_settings.h @@ -1,19 +1,47 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + #pragma once #include #include +#include #include +#include +#include +#include #include #include #include -#include "common/swaglog.h" #include "selfdrive/ui/qt/network/wifi_manager.h" -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/locations_fetcher.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/osm/locations_fetcher.h" #include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/ui.h" +#include "selfdrive/ui/sunnypilot/ui.h" #include "system/hardware/hw.h" constexpr int FAST_REFRESH_INTERVAL = 1000; // ms @@ -31,9 +59,9 @@ private: QWidget* osmScreen = nullptr; Params params; Params mem_params{ Hardware::PC() ? "": "/dev/shm/params"}; - std::map toggles; + std::map toggles; std::optional> mapSizeFuture; - const SubMaster &sm = *uiState()->sm; + const SubMaster &sm = *uiStateSP()->sm; bool is_onroad = false; @@ -45,17 +73,17 @@ private: quint64 mapsDirSize = 0; QLabel *osmUpdateLbl; - ButtonControl *osmDownloadBtn; - ButtonControl *osmUpdateBtn; - ButtonControl *usStatesBtn; - ButtonControl *osmDeleteMapsBtn; - ButtonControl *setupOsmDeleteMapsButton(QWidget *parent);; - ButtonControl* setupOsmUpdateButton(QWidget *parent); - ButtonControl* setupOsmDownloadButton(QWidget *parent); - ButtonControl* setupUsStatesButton(QWidget *parent); + ButtonControlSP *osmDownloadBtn; + ButtonControlSP *osmUpdateBtn; + ButtonControlSP *usStatesBtn; + ButtonControlSP *osmDeleteMapsBtn; + ButtonControlSP *setupOsmDeleteMapsButton(QWidget *parent);; + ButtonControlSP* setupOsmUpdateButton(QWidget *parent); + ButtonControlSP* setupOsmDownloadButton(QWidget *parent); + ButtonControlSP* setupUsStatesButton(QWidget *parent); QTimer *timer; std::string osm_download_locations; -// void updateButtonControl(ButtonControl *btnControl, QWidget *parent, const QString &initTitle, const QString &allStatesOption); +// void updateButtonControlSP(ButtonControlSP *btnControl, QWidget *parent, const QString &initTitle, const QString &allStatesOption); void showEvent(QShowEvent *event) override; void hideEvent(QHideEvent* event) override; @@ -65,10 +93,10 @@ private: QString processUpdateStatus(bool pending_update_check, int total_files, int downloaded_files, const QJsonObject& json, bool failed_state); ConfirmationDialog* confirmationDialog; - LabelControl *mapdVersion; - LabelControl *offlineMapsStatus; - LabelControl *offlineMapsETA; - LabelControl *offlineMapsElapsed; + LabelControlSP *mapdVersion; + LabelControlSP *offlineMapsStatus; + LabelControlSP *offlineMapsETA; + LabelControlSP *offlineMapsElapsed; std::optional lastDownloadedTimePoint; LocationsFetcher locationsFetcher; void updateMapSize(); diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/settings.cc new file mode 100644 index 0000000000..f99b90fb57 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/settings.cc @@ -0,0 +1,446 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" + +#include +#include + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h" +#include "selfdrive/ui/sunnypilot/qt/network/networking.h" +#include "selfdrive/ui/sunnypilot/sunnypilot_main.h" + +TogglesPanelSP::TogglesPanelSP(SettingsWindow *parent) : TogglesPanel(parent) { + // param, title, desc, icon + std::vector> toggle_defs{ + { + "OpenpilotEnabledToggle", + tr("Enable sunnypilot"), + tr("Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off."), + "../assets/offroad/icon_blank.png", + }, + { + "ExperimentalLongitudinalEnabled", + tr("openpilot Longitudinal Control (Alpha)"), + QString("%1

%2") + .arg(tr("WARNING: sunnypilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).")) + .arg(tr("On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. " + "Enable this to switch to sunnypilot longitudinal control. Enabling Experimental mode is recommended when enabling sunnypilot longitudinal control alpha.")), + "../assets/offroad/icon_blank.png", + }, + { + "CustomStockLong", + tr("Custom Stock Longitudinal Control"), + tr("When enabled, sunnypilot will attempt to control stock longitudinal control with ACC button presses.\nThis feature must be used along with SLC, and/or V-TSC, and/or M-TSC."), + "../assets/offroad/icon_blank.png", + }, + { + "ExperimentalMode", + tr("Experimental Mode"), + "", + "../assets/offroad/icon_blank.png", + }, + { + "DynamicExperimentalControl", + tr("Enable Dynamic Experimental Control"), + tr("Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal."), + "../assets/offroad/icon_blank.png", + }, + { + "DynamicPersonality", + tr("Enable Dynamic Personality"), + tr("Enable this to allow sunnypilot to dynamically adjust following distance and reaction based on your \"Driving Personality\" setting. " + "Instead of predefined settings for each personality, every personality now adapts dynamically according to your speed and the distance to the lead car."), + "../assets/offroad/icon_blank.png", + }, + { + "DisengageOnAccelerator", + tr("Disengage on Accelerator Pedal"), + tr("When enabled, pressing the accelerator pedal will disengage openpilot."), + "../assets/offroad/icon_blank.png", + }, + { + "IsLdwEnabled", + tr("Enable Lane Departure Warnings"), + tr("Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h)."), + "../assets/offroad/icon_blank.png", + }, + { + "AlwaysOnDM", + tr("Always-On Driver Monitoring"), + tr("Enable driver monitoring even when sunnypilot is not engaged."), + "../assets/offroad/icon_blank.png", + }, + { + "RecordFront", + tr("Record and Upload Driver Camera"), + tr("Upload data from the driver facing camera and help improve the driver monitoring algorithm."), + "../assets/offroad/icon_blank.png", + }, + { + "DisableOnroadUploads", + tr("Disable Onroad Uploads"), + tr("Disable uploads completely when onroad. Necessary to avoid high data usage when connected to Wi-Fi hotspot. " + "Turn on this feature if you are looking to utilize map-based features, such as Speed Limit Control (SLC) and Map-based Turn Speed Control (MTSC)."), + "../assets/offroad/icon_blank.png", + }, + { + "IsMetric", + tr("Use Metric System"), + tr("Display speed in km/h instead of mph."), + "../assets/offroad/icon_blank.png", + }, +#ifdef ENABLE_MAPS + { + "NavSettingTime24h", + tr("Show ETA in 24h Format"), + tr("Use 24h format instead of am/pm"), + "../assets/offroad/icon_blank.png", + }, + { + "NavSettingLeftSide", + tr("Show Map on Left Side of UI"), + tr("Show map on left side when in split screen view."), + "../assets/offroad/icon_blank.png", + }, +#endif + }; + + + std::vector longi_button_texts{tr("Aggressive"), tr("Moderate"), tr("Standard"), tr("Relaxed")}; + long_personality_setting = new ButtonParamControlSP("LongitudinalPersonality", tr("Driving Personality"), + tr("Standard is recommended. In moderate/aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. " + "In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with " + "your steering wheel distance button."), + "", + longi_button_texts, + 380); + long_personality_setting->showDescription(); + + // accel controller + std::vector accel_personality_texts{tr("Sport"), tr("Normal"), tr("Eco"), tr("Stock")}; + accel_personality_setting = new ButtonParamControlSP("AccelPersonality", tr("Acceleration Personality"), + tr("Normal is recommended. In sport mode, sunnypilot will provide aggressive acceleration for a dynamic driving experience. " + "In eco mode, sunnypilot will apply smoother and more relaxed acceleration. On supported cars, you can cycle through these " + "acceleration personality within Onroad Settings on the driving screen."), + "", + accel_personality_texts); + accel_personality_setting->showDescription(); + + // set up uiState update for personality setting + QObject::connect(uiStateSP(), &UIStateSP::uiUpdate, this, &TogglesPanelSP::updateState); + + for (auto &[param, title, desc, icon] : toggle_defs) { + auto toggle = new ParamControlSP(param, title, desc, icon, this); + + bool locked = params.getBool((param + "Lock").toStdString()); + toggle->setEnabled(!locked); + + addItem(toggle); + toggles[param.toStdString()] = toggle; + + // insert longitudinal personality after NDOG toggle + if (param == "DisengageOnAccelerator") { + addItem(long_personality_setting); + addItem(accel_personality_setting); + } + } + + // Toggles with confirmation dialogs + //toggles["ExperimentalMode"]->setActiveIcon("../assets/img_experimental.svg"); + toggles["ExperimentalMode"]->setConfirmation(true, true); + toggles["ExperimentalLongitudinalEnabled"]->setConfirmation(true, false); + toggles["CustomStockLong"]->setConfirmation(true, false); + + connect(toggles["ExperimentalLongitudinalEnabled"], &ToggleControlSP::toggleFlipped, [=]() { + updateToggles(); + }); + connect(toggles["CustomStockLong"], &ToggleControlSP::toggleFlipped, [=]() { + updateToggles(); + }); + + param_watcher = new ParamWatcher(this); + + QObject::connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) { + updateToggles(); + }); +} + +void TogglesPanelSP::updateState(const UIStateSP &s) { + const SubMaster &sm = *(s.sm); + + if (sm.updated("controlsState")) { + auto personality = sm["controlsState"].getControlsState().getPersonality(); + if (personality != s.scene.personality && s.scene.started && isVisible()) { + long_personality_setting->setCheckedButton(static_cast(personality)); + } + uiStateSP()->scene.personality = personality; + } + + if (sm.updated("controlsStateSP")) { + auto accel_personality = sm["controlsStateSP"].getControlsStateSP().getAccelPersonality(); + if (accel_personality != s.scene.accel_personality && s.scene.started && isVisible()) { + accel_personality_setting->setCheckedButton(static_cast(accel_personality)); + } + uiStateSP()->scene.accel_personality = accel_personality; + } +} + +void TogglesPanelSP::showEvent(QShowEvent *event) { + updateToggles(); +} + +void TogglesPanelSP::updateToggles() { + param_watcher->addParam("LongitudinalPersonality"); + + if (!isVisible()) return; + + auto experimental_mode_toggle = toggles["ExperimentalMode"]; + auto op_long_toggle = toggles["ExperimentalLongitudinalEnabled"]; + auto custom_stock_long_toggle = toggles["CustomStockLong"]; + auto dec_toggle = toggles["DynamicExperimentalControl"]; + auto dynamic_personality_toggle = toggles["DynamicPersonality"]; + const QString e2e_description = QString("%1
" + "

%2


" + "%3
" + "

%4


" + "%5
") + .arg(tr("openpilot defaults to driving in chill mode. Experimental mode enables alpha-level features that aren't ready for chill mode. Experimental features are listed below:")) + .arg(tr("End-to-End Longitudinal Control")) + .arg(tr("Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. " + "Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; " + "mistakes should be expected.")) + .arg(tr("New Driving Visualization")) + .arg(tr("The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner.")); + + const bool is_release = params.getBool("IsReleaseBranch"); + auto cp_bytes = params.get("CarParamsPersistent"); + if (!cp_bytes.empty()) { + AlignedBuffer aligned_buf; + capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); + cereal::CarParams::Reader CP = cmsg.getRoot(); + + if (!CP.getExperimentalLongitudinalAvailable() || is_release) { + params.remove("ExperimentalLongitudinalEnabled"); + } + op_long_toggle->setVisible(CP.getExperimentalLongitudinalAvailable() && !is_release); + + if (!CP.getCustomStockLongAvailable()) { + params.remove("CustomStockLong"); + } + custom_stock_long_toggle->setVisible(CP.getCustomStockLongAvailable()); + + if (hasLongitudinalControl(CP)) { + // normal description and toggle + experimental_mode_toggle->setEnabled(true); + experimental_mode_toggle->setDescription(e2e_description); + long_personality_setting->setEnabled(true); + accel_personality_setting->setEnabled(true); + op_long_toggle->setEnabled(true); + custom_stock_long_toggle->setEnabled(false); + params.remove("CustomStockLong"); + dec_toggle->setEnabled(true); + dynamic_personality_toggle->setEnabled(true); + } else if (custom_stock_long_toggle->isToggled()) { + op_long_toggle->setEnabled(false); + experimental_mode_toggle->setEnabled(false); + long_personality_setting->setEnabled(false); + accel_personality_setting->setEnabled(false); + params.remove("ExperimentalLongitudinalEnabled"); + params.remove("ExperimentalMode"); + } else { + // no long for now + experimental_mode_toggle->setEnabled(false); + long_personality_setting->setEnabled(false); + accel_personality_setting->setEnabled(false); + params.remove("ExperimentalMode"); + + const QString unavailable = tr("Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control."); + + QString long_desc = unavailable + " " + \ + tr("openpilot longitudinal control may come in a future update."); + if (CP.getExperimentalLongitudinalAvailable()) { + if (is_release) { + long_desc = unavailable + " " + tr("An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches."); + } else { + long_desc = tr("Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode."); + } + } + experimental_mode_toggle->setDescription("" + long_desc + "

" + e2e_description); + + op_long_toggle->setEnabled(CP.getExperimentalLongitudinalAvailable() && !is_release); + custom_stock_long_toggle->setEnabled(CP.getCustomStockLongAvailable()); + dec_toggle->setEnabled(false); + dynamic_personality_toggle->setEnabled(false); + params.remove("DynamicExperimentalControl"); + params.remove("DynamicPersonality"); + } + + experimental_mode_toggle->refresh(); + op_long_toggle->refresh(); + custom_stock_long_toggle->refresh(); + dec_toggle->refresh(); + dynamic_personality_toggle->refresh(); + } else { + experimental_mode_toggle->setDescription(e2e_description); + op_long_toggle->setVisible(false); + custom_stock_long_toggle->setVisible(false); + dec_toggle->setVisible(false); + dynamic_personality_toggle->setVisible(false); + } +} + +SettingsWindowSP::SettingsWindowSP(QWidget *parent) : SettingsWindow(parent) { + + // setup two main layouts + sidebar_widget = new QWidget; + QVBoxLayout *sidebar_layout = new QVBoxLayout(sidebar_widget); + panel_widget = new QStackedWidget(); + + // setup layout for close button + QVBoxLayout *close_btn_layout = new QVBoxLayout; + close_btn_layout->setContentsMargins(0, 0, 0, 20); + + // close button + QPushButton *close_btn = new QPushButton(tr("×")); + close_btn->setStyleSheet(R"( + QPushButton { + font-size: 140px; + padding-bottom: 20px; + border-radius: 76px; + background-color: #292929; + font-weight: 400; + } + QPushButton:pressed { + background-color: #3B3B3B; + } + )"); + close_btn->setFixedSize(152, 152); + close_btn_layout->addWidget(close_btn, 0, Qt::AlignLeft); + QObject::connect(close_btn, &QPushButton::clicked, this, &SettingsWindow::closeSettings); + + // setup buttons widget + QWidget *buttons_widget = new QWidget; + QVBoxLayout *buttons_layout = new QVBoxLayout(buttons_widget); + buttons_layout->setMargin(0); + buttons_layout->addSpacing(10); + + // setup panels + DevicePanelSP *device = new DevicePanelSP(this); + QObject::connect(device, &DevicePanelSP::reviewTrainingGuide, this, &SettingsWindow::reviewTrainingGuide); + QObject::connect(device, &DevicePanelSP::showDriverView, this, &SettingsWindow::showDriverView); + + TogglesPanelSP *toggles = new TogglesPanelSP(this); + QObject::connect(this, &SettingsWindow::expandToggleDescription, toggles, &TogglesPanel::expandToggleDescription); + + QList panels = { + PanelInfo(" " + tr("Device"), device, "../assets/navigation/icon_home.svg"), + PanelInfo(" " + tr("Network"), new NetworkingSP(this), "../assets/offroad/icon_network.png"), + PanelInfo(" " + tr("sunnylink"), new SunnylinkPanel(this), "../assets/offroad/icon_wifi_strength_full.svg"), + PanelInfo(" " + tr("Toggles"), toggles, "../assets/offroad/icon_toggle.png"), + PanelInfo(" " + tr("Software"), new SoftwarePanelSP(this), "../assets/offroad/icon_software.png"), + PanelInfo(" " + tr("sunnypilot"), new SunnypilotPanel(this), "../assets/offroad/icon_openpilot.png"), + PanelInfo(" " + tr("OSM"), new OsmPanel(this), "../assets/offroad/icon_map.png"), + PanelInfo(" " + tr("Monitoring"), new MonitoringPanel(this), "../assets/offroad/icon_monitoring.png"), + PanelInfo(" " + tr("Visuals"), new VisualsPanel(this), "../assets/offroad/icon_visuals.png"), + PanelInfo(" " + tr("Display"), new DisplayPanel(this), "../assets/offroad/icon_display.png"), + PanelInfo(" " + tr("Trips"), new TripsPanel(this), "../assets/offroad/icon_trips.png"), + PanelInfo(" " + tr("Vehicle"), new VehiclePanel(this), "../assets/offroad/icon_vehicle.png"), + }; + + nav_btns = new QButtonGroup(this); + for (auto &[name, panel, icon] : panels) { + QPushButton *btn = new QPushButton(name); + btn->setCheckable(true); + btn->setChecked(nav_btns->buttons().size() == 0); + btn->setIcon(QIcon(QPixmap(icon))); + btn->setIconSize(QSize(70, 70)); + btn->setStyleSheet(R"( + QPushButton { + border-radius: 20px; + width: 400px; + height: 98px; + color: #bdbdbd; + border: none; + background: none; + font-size: 50px; + font-weight: 500; + text-align: left; + padding-left: 22px; + } + QPushButton:checked { + background-color: #696868; + color: white; + } + QPushButton:pressed { + color: #ADADAD; + } + )"); + btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + nav_btns->addButton(btn); + buttons_layout->addWidget(btn, 0, Qt::AlignLeft | Qt::AlignBottom); + + const int lr_margin = (name != (" " + tr("Network")) || (name != (" " + tr("sunnypilot")))) ? 50 : 0; // Network and sunnypilot panel handles its own margins + panel->setContentsMargins(lr_margin, 25, lr_margin, 25); + + ScrollViewSP *panel_frame = new ScrollViewSP(panel, this); + panel_widget->addWidget(panel_frame); + + QObject::connect(btn, &QPushButton::clicked, [=, w = panel_frame]() { + btn->setChecked(true); + panel_widget->setCurrentWidget(w); + }); + } + sidebar_layout->setContentsMargins(50, 50, 25, 50); + + // main settings layout, sidebar + main panel + QHBoxLayout *main_layout = new QHBoxLayout(this); + + // add layout for close button + sidebar_layout->addLayout(close_btn_layout); + + // add layout for buttons scrolling + ScrollViewSP *buttons_scrollview = new ScrollViewSP(buttons_widget, this); + sidebar_layout->addWidget(buttons_scrollview); + + sidebar_widget->setFixedWidth(500); + main_layout->addWidget(sidebar_widget); + main_layout->addWidget(panel_widget); + + setStyleSheet(R"( + * { + color: white; + font-size: 50px; + } + SettingsWindow { + background-color: black; + } + QStackedWidget, ScrollViewSP { + background-color: black; + border-radius: 30px; + } + )"); +} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h new file mode 100644 index 0000000000..297a092400 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h @@ -0,0 +1,66 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include + +#include "selfdrive/ui/qt/offroad/settings.h" + +class TogglesPanelSP : public TogglesPanel { + Q_OBJECT + +public: + explicit TogglesPanelSP(SettingsWindow *parent); + void showEvent(QShowEvent *event) override; + +private slots: + void updateState(const UIStateSP &s); + +private: + ButtonParamControlSP *long_personality_setting; + ButtonParamControlSP *accel_personality_setting; + + ParamWatcher *param_watcher; + void updateToggles() override; +}; + +class SettingsWindowSP : public SettingsWindow { + Q_OBJECT + +public: + explicit SettingsWindowSP(QWidget* parent = nullptr); + +protected: + struct PanelInfo { + QString name; + QWidget *widget; + QString icon; + + PanelInfo(const QString &name, QWidget *widget, const QString &icon) : name(name), widget(widget), icon(icon) {} + }; +}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/software_settings_sp.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/software_settings.cc similarity index 86% rename from selfdrive/ui/qt/offroad/sunnypilot/software_settings_sp.cc rename to selfdrive/ui/sunnypilot/qt/offroad/settings/software_settings.cc index bbe8572797..ffe047ba4d 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/software_settings_sp.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/software_settings.cc @@ -1,9 +1,39 @@ -#include "selfdrive/ui/qt/offroad/sunnypilot/software_settings_sp.h" +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/software_settings.h" + +#include + +#include "common/model.h" SoftwarePanelSP::SoftwarePanelSP(QWidget *parent) : SoftwarePanel(parent) { - // Get current model name and create new ButtonControl + // Get current model name and create new ButtonControlSP const auto current_model = GetModelName(); - currentModelLblBtn = new ButtonControl(tr("Driving Model"), tr("SELECT"), current_model); + currentModelLblBtn = new ButtonControlSP(tr("Driving Model"), tr("SELECT"), current_model); currentModelLblBtn->setValue(current_model); connect(&models_fetcher, &ModelsFetcher::downloadProgress, this, [this](const double progress) { @@ -61,9 +91,9 @@ SoftwarePanelSP::SoftwarePanelSP(QWidget *parent) : SoftwarePanel(parent) { // Connect click event from currentModelLblBtn to local slot - connect(currentModelLblBtn, &ButtonControl::clicked, this, &SoftwarePanelSP::handleCurrentModelLblBtnClicked); + connect(currentModelLblBtn, &ButtonControlSP::clicked, this, &SoftwarePanelSP::handleCurrentModelLblBtnClicked); - ReplaceOrAddWidget(currentModelLbl, currentModelLblBtn); + AddWidgetAt(0, currentModelLblBtn); } void SoftwarePanelSP::handleDownloadFailed(const QString &modelType) { @@ -185,7 +215,7 @@ void SoftwarePanelSP::handleCurrentModelLblBtnClicked() { QMap index_to_model; // Collecting indices with display names - for (const auto &model: models) { + for (const auto &model : models) { if ((is_release_sp && model.environment == "release") || !is_release_sp) { index_to_model.insert(model.index, model.displayName); } @@ -197,7 +227,7 @@ void SoftwarePanelSP::handleCurrentModelLblBtnClicked() { return index1.toInt() > index2.toInt(); }); - for (const QString &index: indices) { + for (const QString &index : indices) { modelNames.push_back(index_to_model[index]); } @@ -213,7 +243,7 @@ void SoftwarePanelSP::handleCurrentModelLblBtnClicked() { } // Finding and setting the selected model - for (auto &model: models) { + for (auto &model : models) { if (model.displayName == selectedModelName) { selectedModelToDownload = model; selectedNavModelToDownload = model; @@ -254,7 +284,7 @@ void SoftwarePanelSP::handleCurrentModelLblBtnClicked() { } void SoftwarePanelSP::checkNetwork() { - const SubMaster &sm = *(uiState()->sm); + const SubMaster &sm = *(uiStateSP()->sm); const auto device_state = sm["deviceState"].getDeviceState(); const auto network_type = device_state.getNetworkType(); is_wifi = network_type == cereal::DeviceState::NetworkType::WIFI; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/software_settings_sp.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/software_settings.h similarity index 64% rename from selfdrive/ui/qt/offroad/sunnypilot/software_settings_sp.h rename to selfdrive/ui/sunnypilot/qt/offroad/settings/software_settings.h index 384a592de4..17b6b0bb9d 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/software_settings_sp.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/software_settings.h @@ -1,9 +1,34 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + #pragma once -#include "common/model.h" -#include "selfdrive/ui/ui.h" +#include "selfdrive/ui/sunnypilot/ui.h" #include "selfdrive/ui/qt/offroad/settings.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/models_fetcher.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/osm/models_fetcher.h" class SoftwarePanelSP final : public SoftwarePanel { Q_OBJECT @@ -19,17 +44,17 @@ private: void checkNetwork(); bool isDownloadingModel() const { - LOGD("isDownloadingModel: selectedModelToDownload.has_value() [%s] && modelDownloadProgress [%f]",selectedModelToDownload.has_value() ?"true": "false", modelDownloadProgress.value_or(0.0)); + LOGD("isDownloadingModel: selectedModelToDownload.has_value() [%s] && modelDownloadProgress [%f]", selectedModelToDownload.has_value() ? "true": "false", modelDownloadProgress.value_or(0.0)); return selectedModelToDownload.has_value() && modelDownloadProgress.value_or(0.0) > 0.0 && modelDownloadProgress.value_or(0.0) < 100.0; } bool isDownloadingNavModel() const { - LOGD("isDownloadingNavModel: selectedNavModelToDownload.has_value() [%s] && navModelDownloadProgress [%f]",selectedNavModelToDownload.has_value() ?"true": "false", navModelDownloadProgress.value_or(0.0)); + LOGD("isDownloadingNavModel: selectedNavModelToDownload.has_value() [%s] && navModelDownloadProgress [%f]", selectedNavModelToDownload.has_value() ? "true": "false", navModelDownloadProgress.value_or(0.0)); return selectedNavModelToDownload.has_value() && navModelDownloadProgress.value_or(0.0) > 0.0 && navModelDownloadProgress.value_or(0.0) < 100.0; } bool isDownloadingMetadata() const { - LOGD("isDownloadingMetadata: selectedMetadataToDownload.has_value() [%s] && metadataDownloadProgress [%f]",selectedMetadataToDownload.has_value() ?"true": "false", metadataDownloadProgress.value_or(0.0)); + LOGD("isDownloadingMetadata: selectedMetadataToDownload.has_value() [%s] && metadataDownloadProgress [%f]", selectedMetadataToDownload.has_value() ? "true": "false", metadataDownloadProgress.value_or(0.0)); return selectedMetadataToDownload.has_value() && metadataDownloadProgress.value_or(0.0) > 0.0 && metadataDownloadProgress.value_or(0.0) < 100.0; } @@ -69,7 +94,7 @@ private: std::optional selectedModelToDownload; std::optional selectedNavModelToDownload; std::optional selectedMetadataToDownload; - ButtonControl *currentModelLblBtn; + ButtonControlSP *currentModelLblBtn; ModelsFetcher models_fetcher; ModelsFetcher nav_models_fetcher; ModelsFetcher metadata_fetcher; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_settings.cc similarity index 85% rename from selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.cc rename to selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_settings.cc index 1ebaf4f14e..cf5ec4a4da 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_settings.cc @@ -1,7 +1,38 @@ -#include "selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.h" +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_settings.h" +#include "selfdrive/ui/sunnypilot/qt/api.h" + +#include +#include + +#include #include -#include SunnylinkPanel::SunnylinkPanel(QWidget* parent) : QFrame(parent) { main_layout = new QStackedLayout(this); @@ -13,28 +44,27 @@ SunnylinkPanel::SunnylinkPanel(QWidget* parent) : QFrame(parent) { }); is_sunnylink_enabled = Params().getBool("SunnylinkEnabled"); - connect(uiState(), &UIState::sunnylinkRolesChanged, this, &SunnylinkPanel::updateLabels); - connect(uiState(), &UIState::sunnylinkDeviceUsersChanged, this, &SunnylinkPanel::updateLabels); + connect(uiStateSP(), &UIStateSP::sunnylinkRolesChanged, this, &SunnylinkPanel::updateLabels); + connect(uiStateSP(), &UIStateSP::sunnylinkDeviceUsersChanged, this, &SunnylinkPanel::updateLabels); - auto list = new ListWidget(this, false); - sunnylinkEnabledBtn = new ParamControl( + auto list = new ListWidgetSP(this, false); + sunnylinkEnabledBtn = new ParamControlSP( "SunnylinkEnabled", tr("Enable sunnylink"), sunnylinkBtnDescription, - "../assets/offroad/icon_blank.png" - ); + "../assets/offroad/icon_blank.png"); sunnylinkEnabledBtn->setValue(tr("Device ID ")+ getSunnylinkDongleId().value_or(tr("N/A"))); list->addItem(sunnylinkEnabledBtn); list->addItem(horizontal_line()); sunnylinkBtnDescription = tr("This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that."); - connect(sunnylinkEnabledBtn, &ParamControl::showDescriptionEvent, [=]() { + connect(sunnylinkEnabledBtn, &ParamControlSP::showDescriptionEvent, [=]() { //resets the description to the default one for the easter egg sunnylinkEnabledBtn->setDescription(sunnylinkBtnDescription); }); - connect(sunnylinkEnabledBtn, &ParamControl::toggleFlipped, [=](bool enabled) { + connect(sunnylinkEnabledBtn, &ParamControlSP::toggleFlipped, [=](bool enabled) { if (enabled) { auto proud_description = ""+ tr("🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀")+ ""; sunnylinkEnabledBtn->showDescription(); @@ -49,23 +79,21 @@ SunnylinkPanel::SunnylinkPanel(QWidget* parent) : QFrame(parent) { }); status_popup = new SunnylinkSponsorPopup(false, this); - sponsorBtn = new ButtonControl( + sponsorBtn = new ButtonControlSP( tr("Sponsor Status"), tr("SPONSOR"), - tr("Become a sponsor of sunnypilot to get early access to sunnylink features when they become available.") - ); + tr("Become a sponsor of sunnypilot to get early access to sunnylink features when they become available.")); list->addItem(sponsorBtn); - connect(sponsorBtn, &ButtonControl::clicked, [=]() { + connect(sponsorBtn, &ButtonControlSP::clicked, [=]() { status_popup->exec(); }); list->addItem(horizontal_line()); pair_popup = new SunnylinkSponsorPopup(true, this); - pairSponsorBtn = new ButtonControl( + pairSponsorBtn = new ButtonControlSP( tr("Pair GitHub Account"), tr("PAIR"), - tr("Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink.") + "🌟" - ); + tr("Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink.") + "🌟"); list->addItem(pairSponsorBtn); - connect(pairSponsorBtn, &ButtonControl::clicked, [=]() { + connect(pairSponsorBtn, &ButtonControlSP::clicked, [=]() { if (getSunnylinkDongleId().value_or(tr("N/A")) == "N/A") { ConfirmationDialog::alert(tr("sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again."), this); } else { @@ -74,7 +102,7 @@ SunnylinkPanel::SunnylinkPanel(QWidget* parent) : QFrame(parent) { }); list->addItem(horizontal_line()); - list->addItem(new LabelControl(tr("Manage Settings"))); + list->addItem(new LabelControlSP(tr("Manage Settings"))); backup_settings = new BackupSettings; @@ -125,7 +153,7 @@ SunnylinkPanel::SunnylinkPanel(QWidget* parent) : QFrame(parent) { settings_layout->setAlignment(Qt::AlignLeft); list->addItem(settings_layout); - connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { + connect(uiStateSP(), &UIStateSP::offroadTransition, [=](bool offroad) { is_onroad = !offroad; updateLabels(); }); @@ -134,7 +162,7 @@ SunnylinkPanel::SunnylinkPanel(QWidget* parent) : QFrame(parent) { auto vlayout = new QVBoxLayout(sunnylinkScreen); vlayout->setContentsMargins(50, 20, 50, 20); - vlayout->addWidget(new ScrollView(list, this), 1); + vlayout->addWidget(new ScrollViewSP(list, this), 1); main_layout->addWidget(sunnylinkScreen); if (is_sunnylink_enabled) { startSunnylink(); @@ -186,17 +214,12 @@ void SunnylinkPanel::updateLabels() { is_sunnylink_enabled = Params().getBool("SunnylinkEnabled"); const auto sunnylinkDongleId = getSunnylinkDongleId().value_or(tr("N/A")); - bool is_sub = uiState()->isSunnylinkSponsor() && is_sunnylink_enabled; - auto max_current_sponsor_rule = uiState()->sunnylinkSponsorRole(); + bool is_sub = uiStateSP()->isSunnylinkSponsor() && is_sunnylink_enabled; + auto max_current_sponsor_rule = uiStateSP()->sunnylinkSponsorRole(); auto role_name = max_current_sponsor_rule.getSponsorTierString(); std::optional role_color = max_current_sponsor_rule.getSponsorTierColor(); - bool is_paired = uiState()->isSunnylinkPaired(); - auto paired_users = uiState()->sunnylinkDeviceUsers(); - - //little easter egg for Panda :D - if(sunnylinkDongleId == "d689627422cefcbc") { - role_name = "Panda 🐼"; - } + bool is_paired = uiStateSP()->isSunnylinkPaired(); + auto paired_users = uiStateSP()->sunnylinkDeviceUsers(); sunnylinkEnabledBtn->setEnabled(!is_onroad); sunnylinkEnabledBtn->setValue(tr("Device ID ")+ sunnylinkDongleId); @@ -252,7 +275,7 @@ QByteArray BackupSettings::backupParams(const bool encrypt) { // Compress the QByteArray. QByteArray compressedData = qCompress(jsonData); - QByteArray processed_data = encrypt ? CommaApi::rsa_encrypt(compressedData) : compressedData; + QByteArray processed_data = encrypt ? SunnylinkApi::rsa_encrypt(compressedData) : compressedData; // Encode the compressed QByteArray in Base64. auto converted_params_processed_base64_data = QString(processed_data.toBase64()); @@ -278,8 +301,8 @@ QByteArray BackupSettings::backupParams(const bool encrypt) { void BackupSettings::sendParams(const QByteArray &payload) { if (auto sl_dongle_id = getSunnylinkDongleId()) { QString url = SUNNYLINK_BASE_URL + "/backup/" + *sl_dongle_id; - auto request = new HttpRequest(this, true, 10000, true); - connect(request, &HttpRequest::requestDone, [=](const QString &resp, bool success) { + auto request = new HttpRequestSP(this, true, 10000, true); + connect(request, &HttpRequestSP::requestDone, [=](const QString &resp, bool success) { if (success && resp != "[]") { ConfirmationDialog::alert(tr("Settings backed up for sunnylink Device ID:") + " " + *sl_dongle_id, this); } else if (resp == "[]") { @@ -318,7 +341,7 @@ void BackupSettings::restoreParams(const QString &resp) { if (configValue.isString()) { // Decode the Base64-encoded "config" value const QByteArray configJsonDataDecoded = QByteArray::fromBase64(configValue.toString().toUtf8()); - const QByteArray configJsonDataCompressed = isEncrypted ? CommaApi::rsa_decrypt(configJsonDataDecoded) : configJsonDataDecoded; + const QByteArray configJsonDataCompressed = isEncrypted ? SunnylinkApi::rsa_decrypt(configJsonDataDecoded) : configJsonDataDecoded; const QByteArray configJsonData = qUncompress(configJsonDataCompressed); // Convert the decompressed JSON data to a QJsonDocument @@ -346,8 +369,8 @@ void BackupSettings::restoreParams(const QString &resp) { void BackupSettings::getParams() { if (auto sl_dongle_id = getSunnylinkDongleId()) { QString url = SUNNYLINK_BASE_URL + "/backup/" + *sl_dongle_id; - auto request = new HttpRequest(this, true, 10000, true); - connect(request, &HttpRequest::requestDone, [=](const QString &resp, bool success) { + auto request = new HttpRequestSP(this, true, 10000, true); + connect(request, &HttpRequestSP::requestDone, [=](const QString &resp, bool success) { bool restart_ui = false; if (success && resp != "[]") { restoreParams(resp); @@ -408,7 +431,7 @@ void SunnylinkSponsorQRWidget::refresh() { QString qrString; if (sponsor_pair) { - QString token = CommaApi::create_jwt({}, 3600, true); + QString token = SunnylinkApi::create_jwt({}, 3600, true); auto sl_dongle_id = getSunnylinkDongleId(); QByteArray payload = QString("1|" + sl_dongle_id.value_or("") + "|" + token).toUtf8().toBase64(); qrString = SUNNYLINK_BASE_URL + "/sso?state=" + payload; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_settings.h similarity index 58% rename from selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.h rename to selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_settings.h index fdca62d1c5..2f0885107f 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_settings.h @@ -1,14 +1,38 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + #pragma once #include #include -#include "selfdrive/ui/qt/network/sunnylink/sunnylink_client.h" +#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/sunnylink_client.h" -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" const QString SUNNYLINK_BASE_URL = util::getenv("SUNNYLINK_API_HOST", "https://stg.api.sunnypilot.ai").c_str(); // sponsor QR code @@ -78,18 +102,18 @@ public slots: private: - ParamControl* sunnylinkEnabledBtn; + ParamControlSP* sunnylinkEnabledBtn; QStackedLayout* main_layout = nullptr; QWidget* sunnylinkScreen = nullptr; - ScrollView *scrollView = nullptr; + ScrollViewSP *scrollView = nullptr; BackupSettings *backup_settings; SubPanelButton *restoreSettings; SubPanelButton *backupSettings; SunnylinkSponsorPopup *status_popup; SunnylinkSponsorPopup *pair_popup; - ButtonControl* sponsorBtn; - ButtonControl* pairSponsorBtn; + ButtonControlSP* sponsorBtn; + ButtonControlSP* pairSponsorBtn; SunnylinkClient* sunnylink_client; bool is_onroad = false; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/custom_offsets_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/custom_offsets_settings.cc similarity index 54% rename from selfdrive/ui/qt/offroad/sunnypilot/custom_offsets_settings.cc rename to selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/custom_offsets_settings.cc index 405eca50ce..ed1561be1d 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/custom_offsets_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/custom_offsets_settings.cc @@ -1,4 +1,30 @@ -#include "selfdrive/ui/qt/offroad/sunnypilot/custom_offsets_settings.h" +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/custom_offsets_settings.h" CustomOffsetsSettings::CustomOffsetsSettings(QWidget* parent) : QWidget(parent) { QVBoxLayout* main_layout = new QVBoxLayout(this); @@ -10,25 +36,25 @@ CustomOffsetsSettings::CustomOffsetsSettings(QWidget* parent) : QWidget(parent) connect(back, &QPushButton::clicked, [=]() { emit backPress(); }); main_layout->addWidget(back, 0, Qt::AlignLeft); - ListWidget *list = new ListWidget(this, false); + ListWidgetSP *list = new ListWidgetSP(this, false); // Controls: Camera Offset (cm) camera_offset = new CameraOffset(); - connect(camera_offset, &SPOptionControl::updateLabels, camera_offset, &CameraOffset::refresh); + connect(camera_offset, &OptionControlSP::updateLabels, camera_offset, &CameraOffset::refresh); camera_offset->showDescription(); list->addItem(camera_offset); // Controls: Path Offset (cm) path_offset = new PathOffset(); - connect(path_offset, &SPOptionControl::updateLabels, path_offset, &PathOffset::refresh); + connect(path_offset, &OptionControlSP::updateLabels, path_offset, &PathOffset::refresh); path_offset->showDescription(); list->addItem(path_offset); - main_layout->addWidget(new ScrollView(list, this)); + main_layout->addWidget(new ScrollViewSP(list, this)); } // Camera Offset Value -CameraOffset::CameraOffset() : SPOptionControl ( +CameraOffset::CameraOffset() : OptionControlSP( "CameraOffset", tr("Camera Offset - Laneful Only"), tr("Hack to trick vehicle to be left or right biased in its lane. Decreasing the value will make the car keep more left, increasing will make it keep more right. Changes take effect immediately. Default: +4 cm"), @@ -48,7 +74,7 @@ void CameraOffset::refresh() { } // Path Offset Value -PathOffset::PathOffset() : SPOptionControl ( +PathOffset::PathOffset() : OptionControlSP( "PathOffset", tr("Path Offset"), tr("Hack to trick the model path to be left or right biased of the lane. Decreasing the value will shift the model more left, increasing will shift the model more right. Changes take effect immediately."), diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/custom_offsets_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/custom_offsets_settings.h new file mode 100644 index 0000000000..780f5fc233 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/custom_offsets_settings.h @@ -0,0 +1,74 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include + +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" + +class CameraOffset : public OptionControlSP { + Q_OBJECT + +public: + CameraOffset(); + + void refresh(); + +private: + Params params; +}; + +class PathOffset : public OptionControlSP { + Q_OBJECT + +public: + PathOffset(); + + void refresh(); + +private: + Params params; +}; + +class CustomOffsetsSettings : public QWidget { + Q_OBJECT + +public: + explicit CustomOffsetsSettings(QWidget* parent = nullptr); + +signals: + void backPress(); + +private: + Params params; + std::map toggles; + + CameraOffset *camera_offset; + PathOffset *path_offset; +}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/lane_change_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/lane_change_settings.cc similarity index 68% rename from selfdrive/ui/qt/offroad/sunnypilot/lane_change_settings.cc rename to selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/lane_change_settings.cc index 8f16091460..5d47349837 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/lane_change_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/lane_change_settings.cc @@ -1,4 +1,35 @@ -#include "selfdrive/ui/qt/offroad/sunnypilot/lane_change_settings.h" +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/lane_change_settings.h" + +#include +#include +#include +#include LaneChangeSettings::LaneChangeSettings(QWidget* parent) : QWidget(parent) { QVBoxLayout* main_layout = new QVBoxLayout(this); @@ -10,7 +41,7 @@ LaneChangeSettings::LaneChangeSettings(QWidget* parent) : QWidget(parent) { connect(back, &QPushButton::clicked, [=]() { emit backPress(); }); main_layout->addWidget(back, 0, Qt::AlignLeft); - ListWidget *list = new ListWidget(this, false); + ListWidgetSP *list = new ListWidgetSP(this, false); // param, title, desc, icon std::vector> toggle_defs{ { @@ -37,17 +68,17 @@ LaneChangeSettings::LaneChangeSettings(QWidget* parent) : QWidget(parent) { auto_lane_change_timer = new AutoLaneChangeTimer(); auto_lane_change_timer->setUpdateOtherToggles(true); auto_lane_change_timer->showDescription(); - connect(auto_lane_change_timer, &SPOptionControl::updateLabels, auto_lane_change_timer, &AutoLaneChangeTimer::refresh); + connect(auto_lane_change_timer, &OptionControlSP::updateLabels, auto_lane_change_timer, &AutoLaneChangeTimer::refresh); connect(auto_lane_change_timer, &AutoLaneChangeTimer::updateOtherToggles, this, &LaneChangeSettings::updateToggles); list->addItem(auto_lane_change_timer); // Pause Lateral Below Speed w/ Blinker pause_lateral_speed = new PauseLateralSpeed(); pause_lateral_speed->showDescription(); - connect(pause_lateral_speed, &SPOptionControl::updateLabels, pause_lateral_speed, &PauseLateralSpeed::refresh); + connect(pause_lateral_speed, &OptionControlSP::updateLabels, pause_lateral_speed, &PauseLateralSpeed::refresh); for (auto &[param, title, desc, icon] : toggle_defs) { - auto toggle = new ParamControl(param, title, desc, icon, this); + auto toggle = new ParamControlSP(param, title, desc, icon, this); list->addItem(toggle); toggles[param.toStdString()] = toggle; @@ -57,14 +88,14 @@ LaneChangeSettings::LaneChangeSettings(QWidget* parent) : QWidget(parent) { } } - connect(toggles["BelowSpeedPause"], &ToggleControl::toggleFlipped, [=](bool state) { + connect(toggles["BelowSpeedPause"], &ToggleControlSP::toggleFlipped, [=](bool state) { pause_lateral_speed->setEnabled(state); pause_lateral_speed->setVisible(state); }); pause_lateral_speed->setEnabled(toggles["BelowSpeedPause"]->isToggled()); pause_lateral_speed->setVisible(toggles["BelowSpeedPause"]->isToggled()); - main_layout->addWidget(new ScrollView(list, this)); + main_layout->addWidget(new ScrollViewSP(list, this)); } void LaneChangeSettings::showEvent(QShowEvent *event) { @@ -97,10 +128,12 @@ void LaneChangeSettings::updateToggles() { } // Auto Lane Change Timer (ALCT) -AutoLaneChangeTimer::AutoLaneChangeTimer() : SPOptionControl ( +AutoLaneChangeTimer::AutoLaneChangeTimer() : OptionControlSP( "AutoLaneChangeTimer", tr("Auto Lane Change by Blinker"), - tr("Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge.\nPlease use caution when using this feature. Only use the blinker when traffic and road conditions permit."), + tr("Set a timer to delay the auto lane change operation when the blinker is used. " + "No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge.\n" + "Please use caution when using this feature. Only use the blinker when traffic and road conditions permit."), "../assets/offroad/icon_blank.png", {-1, 5}) { @@ -127,7 +160,7 @@ void AutoLaneChangeTimer::refresh() { } } -PauseLateralSpeed::PauseLateralSpeed() : SPOptionControl ( +PauseLateralSpeed::PauseLateralSpeed() : OptionControlSP( "PauseLateralSpeed", "", tr("Pause lateral actuation with blinker when traveling below the desired speed selected. Default is 20 MPH or 32 km/h."), diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/lane_change_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/lane_change_settings.h new file mode 100644 index 0000000000..f3cf0be588 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/lane_change_settings.h @@ -0,0 +1,86 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include + +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" + +class AutoLaneChangeTimer : public OptionControlSP { + Q_OBJECT + +public: + AutoLaneChangeTimer(); + + void refresh(); + +signals: + void toggleUpdated(); + +private: + Params params; +}; + +class PauseLateralSpeed : public OptionControlSP { + Q_OBJECT + +public: + PauseLateralSpeed(); + + void refresh(); + + signals: + void ToggleUpdated(); + +private: + Params params; +}; + + +class LaneChangeSettings : public QWidget { + Q_OBJECT + +public: + explicit LaneChangeSettings(QWidget* parent = nullptr); + void showEvent(QShowEvent *event) override; + +signals: + void backPress(); + +public slots: + void updateToggles(); + +private: + Params params; + std::map toggles; + + AutoLaneChangeTimer *auto_lane_change_timer; + PauseLateralSpeed *pause_lateral_speed; +}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/mads_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/mads_settings.cc similarity index 52% rename from selfdrive/ui/qt/offroad/sunnypilot/mads_settings.cc rename to selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/mads_settings.cc index e213cc19a7..610ee160bc 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/mads_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/mads_settings.cc @@ -1,4 +1,33 @@ -#include "selfdrive/ui/qt/offroad/sunnypilot/mads_settings.h" +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/mads_settings.h" + +#include +#include MadsSettings::MadsSettings(QWidget* parent) : QWidget(parent) { QVBoxLayout* main_layout = new QVBoxLayout(this); @@ -10,7 +39,7 @@ MadsSettings::MadsSettings(QWidget* parent) : QWidget(parent) { connect(back, &QPushButton::clicked, [=]() { emit backPress(); }); main_layout->addWidget(back, 0, Qt::AlignLeft); - ListWidget *list = new ListWidget(this, false); + ListWidgetSP *list = new ListWidgetSP(this, false); // param, title, desc, icon std::vector> toggle_defs{ { @@ -32,31 +61,31 @@ MadsSettings::MadsSettings(QWidget* parent) : QWidget(parent) { // Disengage Lateral on Brake (DLOB) std::vector dlob_settings_texts{tr("Remain Active"), tr("Pause Steering")}; - dlob_settings = new ButtonParamControl( + dlob_settings = new ButtonParamControlSP( "DisengageLateralOnBrake", tr("Steering Mode After Braking"), - tr("Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot.\n\nRemain Active: ALC will remain active even after the brake pedal is pressed.\nPause Steering: ALC will be paused after the brake pedal is manually pressed."), - "../assets/offroad/icon_blank.png", + tr("Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot.\n\n" + "Remain Active: ALC will remain active even after the brake pedal is pressed.\nPause Steering: ALC will be paused after the brake pedal is manually pressed."), + "", dlob_settings_texts, - 500 - ); + 500); dlob_settings->showDescription(); list->addItem(dlob_settings); for (auto &[param, title, desc, icon] : toggle_defs) { - auto toggle = new ParamControl(param, title, desc, icon, this); + auto toggle = new ParamControlSP(param, title, desc, icon, this); list->addItem(toggle); toggles[param.toStdString()] = toggle; // trigger offroadTransition when going onroad/offroad - connect(uiState(), &UIState::offroadTransition, toggle, &ParamControl::setEnabled); + connect(uiStateSP(), &UIStateSP::offroadTransition, toggle, &ParamControlSP::setEnabled); } // trigger offroadTransition when going onroad/offroad - connect(uiState(), &UIState::offroadTransition, dlob_settings, &ButtonParamControl::setEnabled); + connect(uiStateSP(), &UIStateSP::offroadTransition, dlob_settings, &ButtonParamControlSP::setEnabled); - main_layout->addWidget(new ScrollView(list, this)); + main_layout->addWidget(new ScrollViewSP(list, this)); } void MadsSettings::showEvent(QShowEvent *event) { @@ -68,7 +97,7 @@ void MadsSettings::updateToggles() { return; } - const bool is_offroad = !uiState()->scene.started; + const bool is_offroad = !uiStateSP()->scene.started; const bool enable_mads = params.getBool("EnableMads"); const bool enabled = is_offroad && enable_mads; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/mads_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/mads_settings.h new file mode 100644 index 0000000000..e88bf6a90d --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/mads_settings.h @@ -0,0 +1,54 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include + +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" + +class MadsSettings : public QWidget { + Q_OBJECT + +public: + explicit MadsSettings(QWidget* parent = nullptr); + void showEvent(QShowEvent *event) override; + +signals: + void backPress(); + +public slots: + void updateToggles(); + +private: + Params params; + std::map toggles; + + ButtonParamControlSP *dlob_settings; +}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/speed_limit_control_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_control_settings.cc similarity index 68% rename from selfdrive/ui/qt/offroad/sunnypilot/speed_limit_control_settings.cc rename to selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_control_settings.cc index 7686f0a873..29c1191998 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/speed_limit_control_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_control_settings.cc @@ -1,4 +1,32 @@ -#include "selfdrive/ui/qt/offroad/sunnypilot/speed_limit_control_settings.h" +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_control_settings.h" + +#include SlcSettings::SlcSettings(QWidget* parent) : QWidget(parent) { QVBoxLayout* main_layout = new QVBoxLayout(this); @@ -10,34 +38,32 @@ SlcSettings::SlcSettings(QWidget* parent) : QWidget(parent) { connect(back, &QPushButton::clicked, [=]() { emit backPress(); }); main_layout->addWidget(back, 0, Qt::AlignLeft); - ListWidget *list = new ListWidget(this, false); + ListWidgetSP *list = new ListWidgetSP(this, false); std::vector speed_limit_engage_texts{tr("Auto"), tr("User Confirm")}; - speed_limit_engage_settings = new ButtonParamControl( + speed_limit_engage_settings = new ButtonParamControlSP( "SpeedLimitEngageType", tr("Engage Mode"), "", - "../assets/offroad/icon_blank.png", + "", speed_limit_engage_texts, - 440 - ); + 440); speed_limit_engage_settings->showDescription(); list->addItem(speed_limit_engage_settings); std::vector speed_limit_offset_settings_texts{tr("Default"), tr("Fixed"), tr("Percentage")}; - speed_limit_offset_settings = new ButtonParamControl( + speed_limit_offset_settings = new ButtonParamControlSP( "SpeedLimitOffsetType", tr("Limit Offset"), tr("Set speed limit slightly higher than actual speed limit for a more natural drive."), - "../assets/offroad/icon_blank.png", + "", speed_limit_offset_settings_texts, - 380 - ); + 380); list->addItem(speed_limit_offset_settings); slvo = new SpeedLimitValueOffset(); - connect(slvo, &SPOptionControl::updateLabels, slvo, &SpeedLimitValueOffset::refresh); + connect(slvo, &OptionControlSP::updateLabels, slvo, &SpeedLimitValueOffset::refresh); list->addItem(slvo); - connect(speed_limit_offset_settings, &ButtonParamControl::buttonToggled, this, &SlcSettings::updateToggles); - connect(speed_limit_offset_settings, &ButtonParamControl::buttonToggled, slvo, &SpeedLimitValueOffset::refresh); + connect(speed_limit_offset_settings, &ButtonParamControlSP::buttonToggled, this, &SlcSettings::updateToggles); + connect(speed_limit_offset_settings, &ButtonParamControlSP::buttonToggled, slvo, &SpeedLimitValueOffset::refresh); param_watcher = new ParamWatcher(this); @@ -45,7 +71,7 @@ SlcSettings::SlcSettings(QWidget* parent) : QWidget(parent) { updateToggles(); }); - main_layout->addWidget(new ScrollView(list, this)); + main_layout->addWidget(new ScrollViewSP(list, this)); } void SlcSettings::showEvent(QShowEvent *event) { @@ -101,7 +127,7 @@ void SlcSettings::updateToggles() { } // Speed Limit Control Custom Offset -SpeedLimitValueOffset::SpeedLimitValueOffset() : SPOptionControl ( +SpeedLimitValueOffset::SpeedLimitValueOffset() : OptionControlSP( "SpeedLimitValueOffset", "", "", diff --git a/selfdrive/ui/qt/offroad/sunnypilot/speed_limit_control_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_control_settings.h similarity index 50% rename from selfdrive/ui/qt/offroad/sunnypilot/speed_limit_control_settings.h rename to selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_control_settings.h index 877064e577..a03de75b45 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/speed_limit_control_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_control_settings.h @@ -1,11 +1,41 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + #pragma once -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" +#include +#include +#include + +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" #include "selfdrive/ui/qt/util.h" -class SpeedLimitValueOffset : public SPOptionControl { +class SpeedLimitValueOffset : public OptionControlSP { Q_OBJECT public: @@ -33,11 +63,11 @@ public slots: private: Params params; - std::map toggles; + std::map toggles; SpeedLimitValueOffset *slvo; - ButtonParamControl *speed_limit_offset_settings; - ButtonParamControl *speed_limit_engage_settings; + ButtonParamControlSP *speed_limit_offset_settings; + ButtonParamControlSP *speed_limit_engage_settings; ParamWatcher *param_watcher; QString slcDescriptionBuilder(QString param, std::vector descriptions) { diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_policy_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_policy_settings.cc new file mode 100644 index 0000000000..d3e3eda41c --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_policy_settings.cc @@ -0,0 +1,76 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_policy_settings.h" + +SpeedLimitPolicySettings::SpeedLimitPolicySettings(QWidget* parent) : QWidget(parent) { + QVBoxLayout* main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(50, 20, 50, 20); + main_layout->setSpacing(20); + + // Back button + PanelBackButton* back = new PanelBackButton(); + connect(back, &QPushButton::clicked, [=]() { emit backPress(); }); + main_layout->addWidget(back, 0, Qt::AlignLeft); + + ListWidgetSP *list = new ListWidgetSP(this, false); + + speed_limit_policy = new ButtonParamControlSP( + "SpeedLimitControlPolicy", + tr("Speed Limit Source Policy"), + "", + "", + speed_limit_policy_texts, + 250); + speed_limit_policy->showDescription(); + connect(speed_limit_policy, &ButtonParamControlSP::buttonToggled, this, &SpeedLimitPolicySettings::updateToggles); + list->addItem(speed_limit_policy); + + param_watcher = new ParamWatcher(this); + + QObject::connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) { + updateToggles(); + }); + + main_layout->addWidget(new ScrollViewSP(list, this)); +} + +void SpeedLimitPolicySettings::showEvent(QShowEvent *event) { + updateToggles(); +} + +void SpeedLimitPolicySettings::updateToggles() { + param_watcher->addParam("SpeedLimitControlPolicy"); + + if (!isVisible()) { + return; + } + + // TODO: SP: use upstream's setCheckedButton + speed_limit_policy->setButton("SpeedLimitControlPolicy"); + + speed_limit_policy->setDescription(speedLimitPolicyDescriptionBuilder("SpeedLimitControlPolicy", speed_limit_policy_descriptions)); +} diff --git a/selfdrive/ui/qt/offroad/sunnypilot/speed_limit_policy_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_policy_settings.h similarity index 59% rename from selfdrive/ui/qt/offroad/sunnypilot/speed_limit_policy_settings.h rename to selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_policy_settings.h index 5b7ef66a68..68337af596 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/speed_limit_policy_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_policy_settings.h @@ -1,8 +1,37 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + #pragma once -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" +#include +#include + +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" #include "selfdrive/ui/qt/util.h" class SpeedLimitPolicySettings : public QWidget { @@ -23,7 +52,7 @@ public slots: private: Params params; - ButtonParamControl *speed_limit_policy; + ButtonParamControlSP *speed_limit_policy; ParamWatcher *param_watcher; QString speedLimitPolicyDescriptionBuilder(QString param, std::vector descriptions) { diff --git a/selfdrive/ui/qt/offroad/sunnypilot/speed_limit_warning_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_warning_settings.cc similarity index 64% rename from selfdrive/ui/qt/offroad/sunnypilot/speed_limit_warning_settings.cc rename to selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_warning_settings.cc index 6b355e2740..a521b3458b 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/speed_limit_warning_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_warning_settings.cc @@ -1,4 +1,30 @@ -#include "selfdrive/ui/qt/offroad/sunnypilot/speed_limit_warning_settings.h" +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "../../settings/sunnypilot/speed_limit_warning_settings.h" SpeedLimitWarningSettings::SpeedLimitWarningSettings(QWidget* parent) : QWidget(parent) { QVBoxLayout* main_layout = new QVBoxLayout(this); @@ -10,45 +36,42 @@ SpeedLimitWarningSettings::SpeedLimitWarningSettings(QWidget* parent) : QWidget( connect(back, &QPushButton::clicked, [=]() { emit backPress(); }); main_layout->addWidget(back, 0, Qt::AlignLeft); - ListWidget *list = new ListWidget(this, false); + ListWidgetSP *list = new ListWidgetSP(this, false); std::vector speed_limit_warning_texts{tr("Off"), tr("Display"), tr("Chime")}; - speed_limit_warning_settings = new ButtonParamControl( + speed_limit_warning_settings = new ButtonParamControlSP( "SpeedLimitWarningType", tr("Speed Limit Warning"), "", - "../assets/offroad/icon_blank.png", + "", speed_limit_warning_texts, - 380 - ); + 380); speed_limit_warning_settings->showDescription(); list->addItem(speed_limit_warning_settings); - speed_limit_warning_flash = new ParamControl( + speed_limit_warning_flash = new ParamControlSP( "SpeedLimitWarningFlash", tr("Warning with speed limit flash"), tr("When Speed Limit Warning is enabled, the speed limit sign will alert the driver when the cruising speed is faster than then speed limit plus the offset."), - "../assets/offroad/icon_blank.png" - ); + "../assets/offroad/icon_blank.png"); list->addItem(speed_limit_warning_flash); std::vector speed_limit_warning_offset_settings_texts{tr("Default"), tr("Fixed"), tr("Percentage")}; - speed_limit_warning_offset_settings = new ButtonParamControl( + speed_limit_warning_offset_settings = new ButtonParamControlSP( "SpeedLimitWarningOffsetType", tr("Warning Offset"), tr("Select the desired offset to warn the driver when the vehicle is driving faster than the speed limit."), - "../assets/offroad/icon_blank.png", + "", speed_limit_warning_offset_settings_texts, - 380 - ); + 380); list->addItem(speed_limit_warning_offset_settings); slwvo = new SpeedLimitWarningValueOffset(); - connect(slwvo, &SPOptionControl::updateLabels, slwvo, &SpeedLimitWarningValueOffset::refresh); + connect(slwvo, &OptionControlSP::updateLabels, slwvo, &SpeedLimitWarningValueOffset::refresh); list->addItem(slwvo); - connect(speed_limit_warning_settings, &ButtonParamControl::buttonToggled, this, &SpeedLimitWarningSettings::updateToggles); + connect(speed_limit_warning_settings, &ButtonParamControlSP::buttonToggled, this, &SpeedLimitWarningSettings::updateToggles); - connect(speed_limit_warning_offset_settings, &ButtonParamControl::buttonToggled, this, &SpeedLimitWarningSettings::updateToggles); - connect(speed_limit_warning_offset_settings, &ButtonParamControl::buttonToggled, slwvo, &SpeedLimitWarningValueOffset::refresh); + connect(speed_limit_warning_offset_settings, &ButtonParamControlSP::buttonToggled, this, &SpeedLimitWarningSettings::updateToggles); + connect(speed_limit_warning_offset_settings, &ButtonParamControlSP::buttonToggled, slwvo, &SpeedLimitWarningValueOffset::refresh); param_watcher = new ParamWatcher(this); @@ -56,7 +79,7 @@ SpeedLimitWarningSettings::SpeedLimitWarningSettings(QWidget* parent) : QWidget( updateToggles(); }); - main_layout->addWidget(new ScrollView(list, this)); + main_layout->addWidget(new ScrollViewSP(list, this)); } void SpeedLimitWarningSettings::showEvent(QShowEvent *event) { @@ -86,7 +109,7 @@ void SpeedLimitWarningSettings::updateToggles() { } // Speed Limit Control Custom Offset -SpeedLimitWarningValueOffset::SpeedLimitWarningValueOffset() : SPOptionControl ( +SpeedLimitWarningValueOffset::SpeedLimitWarningValueOffset() : OptionControlSP( "SpeedLimitWarningValueOffset", "", "", diff --git a/selfdrive/ui/qt/offroad/sunnypilot/speed_limit_warning_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_warning_settings.h similarity index 50% rename from selfdrive/ui/qt/offroad/sunnypilot/speed_limit_warning_settings.h rename to selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_warning_settings.h index ce3c48ac3f..95510ad0ab 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/speed_limit_warning_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_warning_settings.h @@ -1,11 +1,41 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + #pragma once -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/widgets/controls.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" +#include +#include +#include + +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" #include "selfdrive/ui/qt/util.h" -class SpeedLimitWarningValueOffset : public SPOptionControl { +class SpeedLimitWarningValueOffset : public OptionControlSP { Q_OBJECT public: @@ -33,12 +63,12 @@ public slots: private: Params params; - std::map toggles; + std::map toggles; SpeedLimitWarningValueOffset *slwvo; - ButtonParamControl *speed_limit_warning_offset_settings; - ParamControl *speed_limit_warning_flash; - ButtonParamControl *speed_limit_warning_settings; + ButtonParamControlSP *speed_limit_warning_offset_settings; + ParamControlSP *speed_limit_warning_flash; + ButtonParamControlSP *speed_limit_warning_settings; ParamWatcher *param_watcher; QString speedLimitWarningDescriptionBuilder(QString param, std::vector descriptions) { diff --git a/selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot_settings.cc similarity index 85% rename from selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.cc rename to selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot_settings.cc index 8db23500b4..c363e78844 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot_settings.cc @@ -1,9 +1,40 @@ -#include "selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.h" +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot_settings.h" + +#include +#include + +#include "common/model.h" SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) { main_layout = new QStackedLayout(this); - ListWidget *list = new ListWidget(this, false); + ListWidgetSP *list = new ListWidgetSP(this, false); // param, title, desc, icon std::vector> toggle_defs{ { @@ -21,7 +52,8 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) { { "EnableSlc", tr("Speed Limit Control (SLC)"), - tr("When you engage ACC, you will be prompted to set the cruising speed to the speed limit of the road adjusted by the Offset and Source Policy specified, or the current driving speed. The maximum cruising speed will always be the MAX set speed."), + tr("When you engage ACC, you will be prompted to set the cruising speed to the speed limit of the road adjusted by the Offset and Source Policy specified, or the current driving speed. " + "The maximum cruising speed will always be the MAX set speed."), "../assets/offroad/icon_blank.png", }, { @@ -80,7 +112,8 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) { { "CustomTorqueLateral", tr("Enable Custom Tuning"), - tr("Enables custom tuning for Torque lateral control. Modifying FRICTION and LAT_ACCEL_FACTOR below will override the offline values indicated in the YAML files within \"selfdrive/torque_data\". The values will also be used live when \"Override Self-Tune\" toggle is enabled."), + tr("Enables custom tuning for Torque lateral control. Modifying FRICTION and LAT_ACCEL_FACTOR below will override the offline values indicated in the YAML files within \"selfdrive/torque_data\". " + "The values will also be used live when \"Override Self-Tune\" toggle is enabled."), "../assets/offroad/icon_blank.png", }, { @@ -100,7 +133,8 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) { tr("Green Traffic Light Chime (Beta)"), QString("%1
" "

%2


") - .arg(tr("A chime will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. If you are waiting behind another vehicle, the chime will play once the vehicle advances unless ACC is engaged.")) + .arg(tr("A chime will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. " + "If you are waiting behind another vehicle, the chime will play once the vehicle advances unless ACC is engaged.")) .arg(tr("Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly.")), "../assets/offroad/icon_blank.png", }, @@ -235,23 +269,22 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) { // Controls: Torque - FRICTION friction = new TorqueFriction(); - connect(friction, &SPOptionControl::updateLabels, friction, &TorqueFriction::refresh); + connect(friction, &OptionControlSP::updateLabels, friction, &TorqueFriction::refresh); // Controls: Torque - LAT_ACCEL_FACTOR lat_accel_factor = new TorqueMaxLatAccel(); - connect(lat_accel_factor, &SPOptionControl::updateLabels, lat_accel_factor, &TorqueMaxLatAccel::refresh); + connect(lat_accel_factor, &OptionControlSP::updateLabels, lat_accel_factor, &TorqueMaxLatAccel::refresh); std::vector dlp_settings_texts{tr("Laneful"), tr("Laneless"), tr("Auto")}; - dlp_settings = new ButtonParamControl( + dlp_settings = new ButtonParamControlSP( "DynamicLaneProfile", tr("Dynamic Lane Profile"), "", - "../assets/offroad/icon_blank.png", + "", dlp_settings_texts, - 340 - ); + 340); dlp_settings->showDescription(); for (auto &[param, title, desc, icon] : toggle_defs) { - auto toggle = new ParamControl(param, title, desc, icon, this); + auto toggle = new ParamControlSP(param, title, desc, icon, this); list->addItem(toggle); toggles[param.toStdString()] = toggle; @@ -269,7 +302,7 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) { list->addItem(laneChangeSettingsLayout); list->addItem(horizontal_line()); - list->addItem(new LabelControl(tr("Speed Limit Assist"))); + list->addItem(new LabelControlSP(tr("Speed Limit Assist"))); } if (param == "EnableSlc") { @@ -299,7 +332,7 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) { } } - connect(toggles["NNFF"], &ToggleControl::toggleFlipped, [=](bool state) { + connect(toggles["NNFF"], &ToggleControlSP::toggleFlipped, [=](bool state) { if (state) { toggles["EnforceTorqueLateral"]->setEnabled(false); params.putBool("EnforceTorqueLateral", false); @@ -315,7 +348,7 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) { // trigger updateToggles() when toggleFlipped for (const auto& updateToggleName : updateTogglesNames) { if (toggles.find(updateToggleName) != toggles.end()) { - connect(toggles[updateToggleName], &ToggleControl::toggleFlipped, [=](bool state) { + connect(toggles[updateToggleName], &ToggleControlSP::toggleFlipped, [=](bool state) { updateToggles(); }); } @@ -324,7 +357,7 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) { // trigger offroadTransition when going onroad/offroad for (const auto& offroadName : toggleOffroad) { if (toggles.find(offroadName) != toggles.end()) { - connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { + connect(uiStateSP(), &UIStateSP::offroadTransition, [=](bool offroad) { toggles[offroadName]->setEnabled(offroad); }); } @@ -334,27 +367,27 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) { toggles["EndToEndLongAlertLight"]->setConfirmation(true, false); toggles["CustomOffsets"]->showDescription(); - connect(toggles["EnableMads"], &ToggleControl::toggleFlipped, mads_settings, &MadsSettings::updateToggles); - connect(toggles["EnableMads"], &ToggleControl::toggleFlipped, [=](bool state) { + connect(toggles["EnableMads"], &ToggleControlSP::toggleFlipped, mads_settings, &MadsSettings::updateToggles); + connect(toggles["EnableMads"], &ToggleControlSP::toggleFlipped, [=](bool state) { madsSettings->setEnabled(state); }); madsSettings->setEnabled(toggles["EnableMads"]->isToggled()); - connect(toggles["EnableSlc"], &ToggleControl::toggleFlipped, slc_settings, &SlcSettings::updateToggles); - connect(toggles["EnableSlc"], &ToggleControl::toggleFlipped, [=](bool state) { + connect(toggles["EnableSlc"], &ToggleControlSP::toggleFlipped, slc_settings, &SlcSettings::updateToggles); + connect(toggles["EnableSlc"], &ToggleControlSP::toggleFlipped, [=](bool state) { slcSettings->setEnabled(state); slcSettings->setVisible(state); }); slcSettings->setEnabled(toggles["EnableSlc"]->isToggled()); slcSettings->setVisible(toggles["EnableSlc"]->isToggled()); - connect(toggles["CustomOffsets"], &ToggleControl::toggleFlipped, [=](bool state) { + connect(toggles["CustomOffsets"], &ToggleControlSP::toggleFlipped, [=](bool state) { customOffsetsSettings->setEnabled(state); }); customOffsetsSettings->setEnabled(toggles["CustomOffsets"]->isToggled()); // update "FRICTION" and "LAT_ACCEL_FACTOR" titles when going onroad/offroad - connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { + connect(uiStateSP(), &UIStateSP::offroadTransition, [=](bool offroad) { friction->setEnabled(offroad || toggles["TorquedOverride"]->isToggled()); lat_accel_factor->setEnabled(offroad || toggles["TorquedOverride"]->isToggled()); @@ -363,7 +396,7 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) { }); // update "FRICTION" and "LAT_ACCEL_FACTOR" titles when TorquedOverride is flipped - connect(toggles["TorquedOverride"], &ToggleControl::toggleFlipped, [=](bool state) { + connect(toggles["TorquedOverride"], &ToggleControlSP::toggleFlipped, [=](bool state) { friction->setEnabled(params.getBool("IsOffroad") || state); lat_accel_factor->setEnabled(params.getBool("IsOffroad") || state); @@ -384,7 +417,7 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) { QVBoxLayout* vlayout = new QVBoxLayout(sunnypilotScreen); vlayout->setContentsMargins(50, 20, 50, 20); - scrollView = new ScrollView(list, this); + scrollView = new ScrollViewSP(list, this); vlayout->addWidget(scrollView, 1); main_layout->addWidget(sunnypilotScreen); main_layout->addWidget(mads_settings); @@ -467,7 +500,8 @@ void SunnypilotPanel::updateToggles() { // NNLC/NNFF QString nnff_available_desc = tr("NNLC is currently not available on this platform."); - QString nnff_fuzzy_desc = tr("Match: \"Exact\" is ideal, but \"Fuzzy\" is fine too. Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server if there are any issues: ") + "#tuning-nnlc"; + QString nnff_fuzzy_desc = tr("Match: \"Exact\" is ideal, but \"Fuzzy\" is fine too. Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server if there are any issues: ") + + "#tuning-nnlc"; QString nnff_status_init = "⚠️ " + tr("Start the car to check car compatibility") + ""; QString nnff_not_loaded = "⚠️ " + tr("NNLC Not Loaded") + ""; QString nnff_loaded = "✅ " + tr("NNLC Loaded") + ""; @@ -493,9 +527,11 @@ void SunnypilotPanel::updateToggles() { QString nn_model_name = QString::fromStdString(CP.getLateralTuning().getTorque().getNnModelName()); QString nn_fuzzy = CP.getLateralTuning().getTorque().getNnModelFuzzyMatch() ? tr("Fuzzy") : tr("Exact"); - nnff_toggle->setDescription(nnffDescriptionBuilder((nn_model_name == "") ? nnff_status_init : - (nn_model_name == "mock") ? (nnff_not_loaded + "
" + tr("Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server and donate logs to get NNLC loaded for your car: ") + "#tuning-nnlc") : - (nnff_loaded + " | " + tr("Match") + " = " + nn_fuzzy + " | " + _car_model + "

" + nnff_fuzzy_desc))); + nnff_toggle->setDescription(nnffDescriptionBuilder( + (nn_model_name == "") ? nnff_status_init : + (nn_model_name == "mock") ? (nnff_not_loaded + "
" + tr("Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server and donate logs to get NNLC loaded for your car: ") + + "#tuning-nnlc") : + (nnff_loaded + " | " + tr("Match") + " = " + nn_fuzzy + " | " + _car_model + "

" + nnff_fuzzy_desc))); enforce_torque_lateral->setEnabled(false); } else { nnff_toggle->setDescription(nnffDescriptionBuilder(nnff_status_init)); @@ -567,7 +603,7 @@ void SunnypilotPanel::updateToggles() { } // toggle names to update when CustomTorqueLateral is flipped - std::vector customTorqueGroup{friction, lat_accel_factor}; + std::vector customTorqueGroup{friction, lat_accel_factor}; for (const auto& customTorqueControl : customTorqueGroup) { customTorqueControl->setVisible(!(nnff_toggle->isToggled() || !custom_torque_lateral->isToggled())); customTorqueControl->setEnabled(!(nnff_toggle->isToggled() || !custom_torque_lateral->isToggled())); @@ -581,7 +617,7 @@ void SunnypilotPanel::updateToggles() { dlp_settings->setDescription((model_use_lateral_planner ? "" : dlp_incompatible_desc + "

") + dlp_description); } -TorqueFriction::TorqueFriction() : SPOptionControl ( +TorqueFriction::TorqueFriction() : OptionControlSP( "TorqueFriction", tr("FRICTION"), tr("Adjust Friction for the Torque Lateral Controller. Live: Override self-tune values; Offline: Override self-tune offline values at car restart."), @@ -597,7 +633,7 @@ void TorqueFriction::refresh() { setLabel(QString::number(torqueFrictionVal)); } -TorqueMaxLatAccel::TorqueMaxLatAccel() : SPOptionControl ( +TorqueMaxLatAccel::TorqueMaxLatAccel() : OptionControlSP( "TorqueMaxLatAccel", tr("LAT_ACCEL_FACTOR"), tr("Adjust Max Lateral Acceleration for the Torque Lateral Controller. Live: Override self-tune values; Offline: Override self-tune offline values at car restart."), diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot_settings.h new file mode 100644 index 0000000000..b87854492c --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot_settings.h @@ -0,0 +1,115 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include + +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/custom_offsets_settings.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/lane_change_settings.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/mads_settings.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_control_settings.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_warning_settings.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_policy_settings.h" +#include "selfdrive/ui/qt/util.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" + +class TorqueFriction : public OptionControlSP { + Q_OBJECT + +public: + TorqueFriction(); + + void refresh(); + +private: + Params params; +}; + +class TorqueMaxLatAccel : public OptionControlSP { + Q_OBJECT + +public: + TorqueMaxLatAccel(); + + void refresh(); + +private: + Params params; +}; + +class SunnypilotPanel : public QFrame { + Q_OBJECT + +public: + explicit SunnypilotPanel(QWidget *parent = nullptr); + void showEvent(QShowEvent *event) override; + void hideEvent(QHideEvent* event) override; + +public slots: + void updateToggles(); + +private: + QStackedLayout* main_layout = nullptr; + QWidget* sunnypilotScreen = nullptr; + MadsSettings* mads_settings = nullptr; + SubPanelButton *slcSettings = nullptr; + SlcSettings* slc_settings = nullptr; + SubPanelButton *slwSettings = nullptr; + SpeedLimitWarningSettings* slw_settings = nullptr; + SubPanelButton *slpSettings = nullptr; + SpeedLimitPolicySettings* slp_settings = nullptr; + LaneChangeSettings* lane_change_settings = nullptr; + CustomOffsetsSettings* custom_offsets_settings = nullptr; + Params params; + std::map toggles; + ParamWatcher *param_watcher; + + TorqueFriction *friction; + TorqueMaxLatAccel *lat_accel_factor; + ButtonParamControlSP *dlp_settings; + + ScrollViewSP *scrollView = nullptr; + + const QString nnff_description = QString("%1

" + "%2") + .arg(tr("Formerly known as \"NNFF\", this replaces the lateral \"torque\" controller, " + "with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy.")) + .arg(tr("Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server with feedback, " + "or to provide log data for your car if your car is currently unsupported: ") + "#tuning-nnlc"); + + QString nnffDescriptionBuilder(const QString &custom_description) { + QString description = "" + custom_description + "

" + nnff_description; + return description; + } + + const QString custom_offsets_description = QString(tr("Add custom offsets to Camera and Path in sunnypilot.")); + const QString dlp_description = QString( + tr("Default is Laneless. In Auto mode, sunnnypilot dynamically chooses between Laneline or Laneless model based on lane recognition confidence level on road and certain conditions.")); +}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/trips_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/trips_settings.cc new file mode 100644 index 0000000000..b69be20ded --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/trips_settings.cc @@ -0,0 +1,55 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/trips_settings.h" + +TripsPanel::TripsPanel(QWidget* parent) : QFrame(parent) { + QVBoxLayout* main_layout = new QVBoxLayout(this); + main_layout->setMargin(0); + + // main content + main_layout->addSpacing(25); + center_layout = new QStackedLayout(); + + driveStatsWidget = new DriveStats; + driveStatsWidget->setStyleSheet(R"( + QLabel[type="title"] { font-size: 51px; font-weight: 500; } + QLabel[type="number"] { font-size: 78px; font-weight: 500; } + QLabel[type="unit"] { font-size: 51px; font-weight: 300; color: #A0A0A0; } + )"); + center_layout->addWidget(driveStatsWidget); + + main_layout->addLayout(center_layout, 1); + + setStyleSheet(R"( + * { + color: white; + } + TripsPanel > QLabel { + font-size: 55px; + } + )"); +} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/trips_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/trips_settings.h new file mode 100644 index 0000000000..11c0798364 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/trips_settings.h @@ -0,0 +1,47 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#else +#include "selfdrive/ui/qt/widgets/controls.h" +#endif +#include "selfdrive/ui/sunnypilot/qt/widgets/drive_stats.h" + +class TripsPanel : public QFrame { + Q_OBJECT + +public: + explicit TripsPanel(QWidget* parent = 0); + +private: + Params params; + + QStackedLayout* center_layout; + DriveStats *driveStatsWidget; +}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/vehicle_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_settings.cc similarity index 75% rename from selfdrive/ui/qt/offroad/sunnypilot/vehicle_settings.cc rename to selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_settings.cc index dd5d457926..10ff22c028 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/vehicle_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_settings.cc @@ -1,4 +1,33 @@ -#include "selfdrive/ui/qt/offroad/sunnypilot/vehicle_settings.h" +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_settings.h" + +#include "selfdrive/ui/sunnypilot/qt/util.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" VehiclePanel::VehiclePanel(QWidget *parent) : QWidget(parent) { main_layout = new QStackedLayout(this); @@ -29,7 +58,7 @@ VehiclePanel::VehiclePanel(QWidget *parent) : QWidget(parent) { QVBoxLayout* toggle_layout = new QVBoxLayout(home_widget); home_widget->setObjectName("homeWidget"); - ScrollView *scroller = new ScrollView(home_widget, this); + ScrollViewSP *scroller = new ScrollViewSP(home_widget, this); scroller->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); fcr_layout->addWidget(scroller, 1); @@ -67,60 +96,55 @@ void VehiclePanel::updateToggles() { setCarBtn->setText(((set == "=== Not Selected ===") || (set.length() == 0)) ? prompt_select : set); } -SPVehiclesTogglesPanel::SPVehiclesTogglesPanel(VehiclePanel *parent) : ListWidget(parent, false) { +SPVehiclesTogglesPanel::SPVehiclesTogglesPanel(VehiclePanel *parent) : ListWidgetSP(parent, false) { setSpacing(50); // Hyundai/Kia/Genesis - addItem(new LabelControl(tr("Hyundai/Kia/Genesis"))); - auto hkgSmoothStop = new ParamControl( + addItem(new LabelControlSP(tr("Hyundai/Kia/Genesis"))); + auto hkgSmoothStop = new ParamControlSP( "HkgSmoothStop", tr("HKG CAN: Smoother Stopping Performance (Beta)"), tr("Smoother stopping behind a stopped car or desired stopping event. This is only applicable to HKG CAN platforms using openpilot longitudinal control."), - "../assets/offroad/icon_blank.png" - ); + "../assets/offroad/icon_blank.png"); hkgSmoothStop->setConfirmation(true, false); addItem(hkgSmoothStop); // Subaru - addItem(new LabelControl(tr("Subaru"))); - auto subaruManualParkingBrakeSng = new ParamControl( + addItem(new LabelControlSP(tr("Subaru"))); + auto subaruManualParkingBrakeSng = new ParamControlSP( "SubaruManualParkingBrakeSng", tr("Manual Parking Brake: Stop and Go (Beta)"), tr("Experimental feature to enable stop and go for Subaru Global models with manual handbrake. Models with electric parking brake should keep this disabled. Thanks to martinl for this implementation!"), - "../assets/offroad/icon_blank.png" - ); + "../assets/offroad/icon_blank.png"); subaruManualParkingBrakeSng->setConfirmation(true, false); addItem(subaruManualParkingBrakeSng); // Toyota/Lexus - addItem(new LabelControl(tr("Toyota/Lexus"))); - stockLongToyota = new ParamControl( + addItem(new LabelControlSP(tr("Toyota/Lexus"))); + stockLongToyota = new ParamControlSP( "StockLongToyota", tr("Enable Stock Toyota Longitudinal Control"), tr("sunnypilot will not take over control of gas and brakes. Stock Toyota longitudinal control will be used."), - "../assets/offroad/icon_blank.png" - ); + "../assets/offroad/icon_blank.png"); stockLongToyota->setConfirmation(true, false); addItem(stockLongToyota); - auto lkasToggle = new ParamControl( + auto lkasToggle = new ParamControlSP( "LkasToggle", tr("Allow M.A.D.S. toggling w/ LKAS Button (Beta)"), QString("%1
" "

%2


") .arg(tr("Allows M.A.D.S. engagement/disengagement with \"LKAS\" button from the steering wheel.")) .arg(tr("Note: Enabling this toggle may have unexpected behavior with steering control. It is the driver's responsibility to observe their environment and make decisions accordingly.")), - "../assets/offroad/icon_blank.png" - ); + "../assets/offroad/icon_blank.png"); lkasToggle->setConfirmation(true, false); addItem(lkasToggle); - auto toyotaTss2LongTune = new ParamControl( + auto toyotaTss2LongTune = new ParamControlSP( "ToyotaTSS2Long", tr("Toyota TSS2 Longitudinal: Custom Tuning"), tr("Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation."), - "../assets/offroad/icon_blank.png" - ); + "../assets/offroad/icon_blank.png"); toyotaTss2LongTune->setConfirmation(true, false); addItem(toyotaTss2LongTune); @@ -128,51 +152,46 @@ SPVehiclesTogglesPanel::SPVehiclesTogglesPanel(VehiclePanel *parent) : ListWidge "ToyotaEnhancedBsm", tr("Enable Enhanced Blind Spot Monitor"), "", - "../assets/offroad/icon_blank.png" - ); + "../assets/offroad/icon_blank.png"); toyotaEnhancedBsm->setConfirmation(true, false); addItem(toyotaEnhancedBsm); - auto toyotaSngHack = new ParamControl( + auto toyotaSngHack = new ParamControlSP( "ToyotaSnG", tr("Enable Toyota Stop and Go Hack"), tr("sunnypilot will allow some Toyota/Lexus cars to auto resume during stop and go traffic. This feature is only applicable to certain models. Use at your own risk."), - "../assets/offroad/icon_blank.png" - ); + "../assets/offroad/icon_blank.png"); toyotaSngHack->setConfirmation(true, false); addItem(toyotaSngHack); - auto toyotaAutoLock = new ParamControl( + auto toyotaAutoLock = new ParamControlSP( "ToyotaAutoLock", tr("Enable Toyota Door Auto Locking"), tr("sunnypilot will attempt to lock the doors when drive above 10 km/h (6.2 mph).\nReboot Required."), - "../assets/offroad/icon_blank.png" - ); + "../assets/offroad/icon_blank.png"); toyotaAutoLock->setConfirmation(true, false); addItem(toyotaAutoLock); - auto toyotaAutoUnlock = new ParamControl( + auto toyotaAutoUnlock = new ParamControlSP( "ToyotaAutoUnlockByShifter", tr("Enable Toyota Door Auto Unlocking"), tr("sunnypilot will attempt to unlock the doors when shift to gear P.\nReboot Required."), - "../assets/offroad/icon_blank.png" - ); + "../assets/offroad/icon_blank.png"); toyotaAutoUnlock->setConfirmation(true, false); addItem(toyotaAutoUnlock); // Volkswagen - addItem(new LabelControl(tr("Volkswagen"))); - auto volkswagenCCOnly = new ParamControl( + addItem(new LabelControlSP(tr("Volkswagen"))); + auto volkswagenCCOnly = new ParamControlSP( "VwCCOnly", tr("Enable CC Only support"), tr("sunnypilot supports Volkswagen MQB CC only platforms with this toggle enabled. Only enable this toggle if your car does not have ACC from the factory."), - "../assets/offroad/icon_blank.png" - ); + "../assets/offroad/icon_blank.png"); volkswagenCCOnly->setConfirmation(true, false); addItem(volkswagenCCOnly); // trigger offroadTransition when going onroad/offroad - connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { + connect(uiStateSP(), &UIStateSP::offroadTransition, [=](bool offroad) { is_onroad = !offroad; hkgSmoothStop->setEnabled(offroad); toyotaTss2LongTune->setEnabled(offroad); diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_settings.h new file mode 100644 index 0000000000..ddf61f6e76 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_settings.h @@ -0,0 +1,82 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include + +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" + +class VehiclePanel : public QWidget { + Q_OBJECT + +public: + explicit VehiclePanel(QWidget *parent = nullptr); + void showEvent(QShowEvent *event) override; + +public slots: + void updateToggles(); + +private: + Params params; + + QStackedLayout* main_layout = nullptr; + QWidget* home = nullptr; + + QPushButton* setCarBtn; + QString set; + + QWidget* home_widget; + QString prompt_select = tr("Select your car"); +}; + +class SPVehiclesTogglesPanel : public ListWidgetSP { + Q_OBJECT +public: + explicit SPVehiclesTogglesPanel(VehiclePanel *parent); + void showEvent(QShowEvent *event) override; + +public slots: + void updateToggles(); + +private: + Params params; + bool is_onroad = false; + + ParamControlSP *stockLongToyota; + ParamControlSP *toyotaEnhancedBsm; + + const QString toyotaEnhancedBsmDescription = QString("%1

" + "%2") + .arg(tr("sunnypilot will use debugging CAN messages to receive unfiltered BSM signals, allowing detection of more objects.")) + .arg(tr("Tested on RAV4 TSS1, Lexus LSS1, Toyota TSS1/1.5, and Prius TSS2.")); + + QString toyotaEnhancedBsmDesciptionBuilder(const QString &custom_description) { + QString description = "" + custom_description + "

" + toyotaEnhancedBsmDescription; + return description; + } +}; diff --git a/selfdrive/ui/qt/offroad/sunnypilot/visuals_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_settings.cc similarity index 68% rename from selfdrive/ui/qt/offroad/sunnypilot/visuals_settings.cc rename to selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_settings.cc index 742725e8ab..a444b546cb 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/visuals_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_settings.cc @@ -1,6 +1,35 @@ -#include "selfdrive/ui/qt/offroad/sunnypilot/visuals_settings.h" +/** +The MIT License -VisualsPanel::VisualsPanel(QWidget *parent) : ListWidget(parent) { +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_settings.h" + +#include +#include + +VisualsPanel::VisualsPanel(QWidget *parent) : ListWidgetSP(parent) { // param, title, desc, icon std::vector> toggle_defs{ { @@ -73,26 +102,24 @@ VisualsPanel::VisualsPanel(QWidget *parent) : ListWidget(parent) { // Visuals: Developer UI Info (Dev UI) std::vector dev_ui_settings_texts{tr("Off"), tr("5 Metrics"), tr("10 Metrics")}; - dev_ui_settings = new ButtonParamControl( + dev_ui_settings = new ButtonParamControlSP( "DevUIInfo", tr("Developer UI"), tr("Display real-time parameters and metrics from various sources."), - "../assets/offroad/icon_blank.png", + "", dev_ui_settings_texts, - 380 - ); + 380); dev_ui_settings->showDescription(); // Visuals: Display Metrics above Chevron std::vector chevron_info_settings_texts{tr("Off"), tr("Distance"), tr("Speed"), tr("Time"), tr("All")}; - chevron_info_settings = new ButtonParamControl( + chevron_info_settings = new ButtonParamControlSP( "ChevronInfo", tr("Display Metrics Below Chevron"), tr("Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control)."), - "../assets/offroad/icon_blank.png", + "", chevron_info_settings_texts, - 300 - ); + 300); chevron_info_settings->showDescription(); for (auto &[param, title, desc, icon] : toggle_defs) { - auto toggle = new ParamControl(param, title, desc, icon, this); + auto toggle = new ParamControlSP(param, title, desc, icon, this); addItem(toggle); toggles[param.toStdString()] = toggle; @@ -107,20 +134,19 @@ VisualsPanel::VisualsPanel(QWidget *parent) : ListWidget(parent) { } std::vector sidebar_temp_texts{tr("Off"), tr("RAM"), tr("CPU"), tr("GPU"), tr("Max")}; - sidebar_temp_setting = new ButtonParamControl( + sidebar_temp_setting = new ButtonParamControlSP( "SidebarTemperatureOptions", tr("Display Temperature on Sidebar"), "", - "../assets/offroad/icon_blank.png", + "", sidebar_temp_texts, - 255 - ); + 255); sidebar_temp_setting->showDescription(); addItem(sidebar_temp_setting); // trigger offroadTransition when going onroad/offroad - connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { + connect(uiStateSP(), &UIStateSP::offroadTransition, [=](bool offroad) { }); - QObject::connect(toggles["MapboxFullScreen"], &ToggleControl::toggleFlipped, [=](bool state) { + QObject::connect(toggles["MapboxFullScreen"], &ToggleControlSP::toggleFlipped, [=](bool state) { toggles["MapboxFullScreen"]->showDescription(); }); } diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_settings.h new file mode 100644 index 0000000000..d90b36e21d --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_settings.h @@ -0,0 +1,48 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include + +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" + +class VisualsPanel : public ListWidgetSP { + Q_OBJECT + +public: + explicit VisualsPanel(QWidget *parent = nullptr); + +private: + Params params; + std::map toggles; + + ButtonParamControlSP *dev_ui_settings; + ButtonParamControlSP *chevron_info_settings; + ButtonParamControlSP *sidebar_temp_setting; +}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad_home.cc b/selfdrive/ui/sunnypilot/qt/offroad_home.cc new file mode 100644 index 0000000000..e0791bd11e --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad_home.cc @@ -0,0 +1,58 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/offroad_home.h" + +#include + +#include "selfdrive/ui/qt/offroad/experimental_mode.h" +#include "selfdrive/ui/qt/widgets/prime.h" +#include "selfdrive/ui/sunnypilot/sunnypilot_main.h" + +#ifdef ENABLE_MAPS +#define LEFT_WIDGET MapSettings +#else +#define LEFT_WIDGET QWidget +#endif + +void OffroadHomeSP::replaceLeftWidget(){ + auto* new_left_widget = new QStackedWidget(left_widget->parentWidget()); + new_left_widget->addWidget(new LEFT_WIDGET); + if (!custom_mapbox) + new_left_widget->addWidget(new PrimeAdWidget); + + new_left_widget->setStyleSheet("border-radius: 10px;"); + new_left_widget->setCurrentIndex((uiStateSP()->hasPrime() || custom_mapbox) ? 0 : 1); + connect(uiStateSP(), &UIStateSP::primeChanged, [=](bool prime) { + new_left_widget->setCurrentIndex((prime || custom_mapbox) ? 0 : 1); + }); + ReplaceWidget(left_widget, new_left_widget); +} + +OffroadHomeSP::OffroadHomeSP(QWidget* parent) : OffroadHome(parent){ + custom_mapbox = QString::fromStdString(params.get("CustomMapboxTokenSk")) != ""; + replaceLeftWidget(); +} diff --git a/selfdrive/ui/sunnypilot/qt/offroad_home.h b/selfdrive/ui/sunnypilot/qt/offroad_home.h new file mode 100644 index 0000000000..a7c1a36ef2 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad_home.h @@ -0,0 +1,45 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once +#include "selfdrive/ui/qt/offroad_home.h" + +#ifdef ENABLE_MAPS +#include "selfdrive/ui/qt/maps/map_settings.h" +#endif + +class OffroadHomeSP : public OffroadHome { + Q_OBJECT + +public: + void replaceLeftWidget(); + explicit OffroadHomeSP(QWidget* parent = 0); + +private: + // static void replaceWidget(QWidget* old_widget, QWidget* new_widget); + Params params; + bool custom_mapbox; +}; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.cc b/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.cc new file mode 100644 index 0000000000..bebac31d90 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.cc @@ -0,0 +1,1535 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h" + +#include +#include +#include +#include + +#include "common/swaglog.h" +#include "selfdrive/ui/qt/onroad/buttons.h" +#include "selfdrive/ui/qt/util.h" +#include "selfdrive/ui/sunnypilot/qt/util.h" + +static std::pair getFeatureStatus(int value, QStringList text_list, QStringList color_list, + bool condition, QString off_text) { + + QString text("Error"); + QColor color("#ffffff"); + + for (int i = 0; i < text_list.size() && i < color_list.size(); ++i) { + if (value == i) { + text = condition ? text_list[i] : off_text; + color = condition ? QColor(color_list[i]) : QColor("#ffffff"); + break; // Exit the loop once a match is found + } + } + + return {text, color}; +} + + +// Window that shows camera view and variety of info drawn on top +AnnotatedCameraWidgetSP::AnnotatedCameraWidgetSP(VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraWidget("camerad", type, true, parent) { + pm = std::make_unique>({"uiDebug"}); + e2e_state = std::make_unique>({"e2eLongStateSP"}); + + main_layout = new QVBoxLayout(this); + main_layout->setMargin(UI_BORDER_SIZE); + main_layout->setSpacing(0); + + experimental_btn = new ExperimentalButtonSP(this); + main_layout->addWidget(experimental_btn, 0, Qt::AlignTop | Qt::AlignRight); + + onroad_settings_btn = new OnroadSettingsButton(this); + + map_settings_btn = new MapSettingsButton(this); + + dm_img = loadPixmap("../assets/img_driver_face.png", {img_size + 5, img_size + 5}); + map_img = loadPixmap("../assets/img_world_icon.png", {subsign_img_size, subsign_img_size}); + left_img = loadPixmap("../assets/img_turn_left_icon.png", {subsign_img_size, subsign_img_size}); + right_img = loadPixmap("../assets/img_turn_right_icon.png", {subsign_img_size, subsign_img_size}); + + buttons_layout = new QHBoxLayout(); + buttons_layout->setContentsMargins(0, 0, 10, 20); + main_layout->addLayout(buttons_layout); + updateButtonsLayout(false); +} + +void AnnotatedCameraWidgetSP::mousePressEvent(QMouseEvent* e) { + bool propagate_event = true; + + UIStateSP *s = uiStateSP(); + UISceneSP &scene = s->scene; + const SubMaster &sm = *(s->sm); + const auto longitudinal_plan_sp = sm["longitudinalPlanSP"].getLongitudinalPlanSP(); + + if (longitudinal_plan_sp.getSpeedLimit() > 0.0 && sl_sign_rect.contains(e->x(), e->y())) { + // If touching the speed limit sign area when visible + scene.last_speed_limit_sign_tap = seconds_since_boot(); + params.putBool("LastSpeedLimitSignTap", true); + scene.speed_limit_control_enabled = !scene.speed_limit_control_enabled; + params.putBool("EnableSlc", scene.speed_limit_control_enabled); + propagate_event = false; + } + + if (propagate_event) { + QWidget::mousePressEvent(e); + } +} + +void AnnotatedCameraWidgetSP::updateButtonsLayout(bool is_rhd) { + QLayoutItem *item; + while ((item = buttons_layout->takeAt(0)) != nullptr) { + delete item; + } + + buttons_layout->setContentsMargins(0, 0, 10, rn_offset != 0 ? rn_offset + 10 : 20); + + if (is_rhd) { + buttons_layout->addSpacing(map_settings_btn->isVisible() ? 30 : 0); + buttons_layout->addWidget(map_settings_btn, 0, Qt::AlignBottom | Qt::AlignLeft); + + buttons_layout->addStretch(1); + + buttons_layout->addWidget(onroad_settings_btn, 0, Qt::AlignBottom | Qt::AlignRight); + buttons_layout->addSpacing(onroad_settings_btn->isVisible() ? 216 : 0); + } else { + buttons_layout->addSpacing(onroad_settings_btn->isVisible() ? 216 : 0); + buttons_layout->addWidget(onroad_settings_btn, 0, Qt::AlignBottom | Qt::AlignLeft); + + buttons_layout->addStretch(1); + + buttons_layout->addWidget(map_settings_btn, 0, Qt::AlignBottom | Qt::AlignRight); + buttons_layout->addSpacing(map_settings_btn->isVisible() ? 30 : 0); // Add spacing to the right + } +} + +void AnnotatedCameraWidgetSP::updateState(const UIStateSP &s) { + const int SET_SPEED_NA = 255; + const SubMaster &sm = *(s.sm); + + const bool cs_alive = sm.alive("controlsState"); + const bool nav_alive = sm.alive("navInstruction") && sm["navInstruction"].getValid(); + const auto cs = sm["controlsState"].getControlsState(); + const auto cs_sp = sm["controlsStateSP"].getControlsStateSP(); + const auto car_state = sm["carState"].getCarState(); + const auto nav_instruction = sm["navInstruction"].getNavInstruction(); + const auto car_control = sm["carControl"].getCarControl(); + const auto radar_state = sm["radarState"].getRadarState(); + const auto is_gps_location_external = sm.rcv_frame("gpsLocationExternal") > 1; + const auto gpsLocation = is_gps_location_external ? sm["gpsLocationExternal"].getGpsLocationExternal() : sm["gpsLocation"].getGpsLocation(); + const auto ltp = sm["liveTorqueParameters"].getLiveTorqueParameters(); + const auto lateral_plan_sp = sm["lateralPlanSPDEPRECATED"].getLateralPlanSPDEPRECATED(); + car_params = sm["carParams"].getCarParams(); + + // Handle older routes where vCruiseCluster is not set + float v_cruise = cs.getVCruiseCluster() == 0.0 ? cs.getVCruise() : cs.getVCruiseCluster(); + setSpeed = cs_alive ? v_cruise : SET_SPEED_NA; + is_cruise_set = setSpeed > 0 && (int)setSpeed != SET_SPEED_NA; + if (is_cruise_set && !s.scene.is_metric) { + setSpeed *= KM_TO_MILE; + } + + // Handle older routes where vEgoCluster is not set + v_ego_cluster_seen = v_ego_cluster_seen || car_state.getVEgoCluster() != 0.0; + float v_ego = v_ego_cluster_seen ? car_state.getVEgoCluster() : car_state.getVEgo(); + v_ego = s.scene.true_vego_ui ? car_state.getVEgo() : v_ego; + speed = cs_alive ? std::max(0.0, v_ego) : 0.0; + speed *= s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH; + + auto speed_limit_sign = nav_instruction.getSpeedLimitSign(); + speedLimit = nav_alive ? nav_instruction.getSpeedLimit() : 0.0; + speedLimit *= (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH); + + has_us_speed_limit = (nav_alive && speed_limit_sign == cereal::NavInstruction::SpeedLimitSign::MUTCD); + has_eu_speed_limit = (nav_alive && speed_limit_sign == cereal::NavInstruction::SpeedLimitSign::VIENNA); + is_metric = s.scene.is_metric; + speedUnit = s.scene.is_metric ? tr("km/h") : tr("mph"); + hideBottomIcons = (cs.getAlertSize() != cereal::ControlsState::AlertSize::NONE); + status = s.status; + + // TODO: Add minimum speed? + left_blindspot = cs_alive && car_state.getLeftBlindspot(); + right_blindspot = cs_alive && car_state.getRightBlindspot(); + + steerOverride = car_state.getSteeringPressed(); + gasOverride = car_state.getGasPressed(); + latActive = car_control.getLatActive(); + madsEnabled = car_state.getMadsEnabled(); + + brakeLights = car_state.getBrakeLightsDEPRECATED() && s.scene.visual_brake_lights; + + standStillTimer = s.scene.stand_still_timer; + standStill = car_state.getStandstill(); + standstillElapsedTime = lateral_plan_sp.getStandstillElapsed(); + + hideVEgoUi = s.scene.hide_vego_ui; + + splitPanelVisible = s.scene.map_visible || s.scene.onroad_settings_visible; + + // ############################## DEV UI START ############################## + lead_d_rel = radar_state.getLeadOne().getDRel(); + lead_v_rel = radar_state.getLeadOne().getVRel(); + lead_status = radar_state.getLeadOne().getStatus(); + lateralState = QString::fromStdString(cs_sp.getLateralState()); + angleSteers = car_state.getSteeringAngleDeg(); + steerAngleDesired = cs.getLateralControlState().getPidState().getSteeringAngleDesiredDeg(); + curvature = cs.getCurvature(); + roll = sm["liveParameters"].getLiveParameters().getRoll(); + memoryUsagePercent = sm["deviceState"].getDeviceState().getMemoryUsagePercent(); + devUiInfo = s.scene.dev_ui_info; + gpsAccuracy = is_gps_location_external ? gpsLocation.getHorizontalAccuracy() : 1.0; //External reports accuracy, internal does not. + altitude = gpsLocation.getAltitude(); + vEgo = car_state.getVEgo(); + aEgo = car_state.getAEgo(); + steeringTorqueEps = car_state.getSteeringTorqueEps(); + bearingAccuracyDeg = gpsLocation.getBearingAccuracyDeg(); + bearingDeg = gpsLocation.getBearingDeg(); + torquedUseParams = (ltp.getUseParams() || s.scene.live_torque_toggle) && !s.scene.torqued_override; + latAccelFactorFiltered = ltp.getLatAccelFactorFiltered(); + frictionCoefficientFiltered = ltp.getFrictionCoefficientFiltered(); + liveValid = ltp.getLiveValid(); + // ############################## DEV UI END ############################## + + btnPerc = s.scene.sleep_btn_opacity * 0.05; + + left_blinker = car_state.getLeftBlinker(); + right_blinker = car_state.getRightBlinker(); + lane_change_edge_block = lateral_plan_sp.getLaneChangeEdgeBlockDEPRECATED(); + + // update engageability/experimental mode button + experimental_btn->updateState(s); + + // update onroad settings button state + onroad_settings_btn->updateState(s); + + // update DM icon + auto dm_state = sm["driverMonitoringState"].getDriverMonitoringState(); + dmActive = dm_state.getIsActiveMode(); + rightHandDM = dm_state.getIsRHD(); + // DM icon transition + dm_fade_state = std::clamp(dm_fade_state+0.2*(0.5-dmActive), 0.0, 1.0); + + // update buttons layout + updateButtonsLayout(rightHandDM); + + // hide map settings button for alerts and flip for right hand DM + if (map_settings_btn->isEnabled()) { + map_settings_btn->setVisible(!hideBottomIcons); + buttons_layout->setAlignment(map_settings_btn, (rightHandDM ? Qt::AlignLeft : Qt::AlignRight) | Qt::AlignBottom); + } + + // hide onroad settings button for alerts and flip for right hand DM + if (onroad_settings_btn->isEnabled()) { + onroad_settings_btn->setVisible(!hideBottomIcons); + buttons_layout->setAlignment(onroad_settings_btn, (rightHandDM ? Qt::AlignRight : Qt::AlignLeft) | Qt::AlignBottom); + } + + const auto lp_sp = sm["longitudinalPlanSP"].getLongitudinalPlanSP(); + slcState = lp_sp.getSpeedLimitControlState(); + + speedLimitControlToggle = s.scene.speed_limit_control_enabled; + + const auto vtcState = lp_sp.getVisionTurnControllerState(); + const float vtc_speed = lp_sp.getVisionTurnSpeed() * (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH); + const auto lpSoruce = lp_sp.getLongitudinalPlanSource(); + QColor vtc_color = tcs_colors[int(vtcState)]; + vtc_color.setAlpha(lpSoruce == cereal::LongitudinalPlanSP::LongitudinalPlanSource::TURN ? 255 : 100); + + showVTC = vtcState > cereal::LongitudinalPlanSP::VisionTurnControllerState::DISABLED; + vtcSpeed = QString::number(std::nearbyint(vtc_speed)); + vtcColor = vtc_color; + showDebugUI = s.scene.show_debug_ui; + + const auto lmd_sp = sm["liveMapDataSP"].getLiveMapDataSP(); + + const auto data_type = int(lmd_sp.getDataType()); + const QString data_type_draw(data_type == 2 ? "🌐 " : ""); + roadName = QString::fromStdString(lmd_sp.getCurrentRoadName()); + roadName = !roadName.isEmpty() ? data_type_draw + roadName : ""; + + float speed_limit_slc = lp_sp.getSpeedLimit() * (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH); + const float speed_limit_offset = lp_sp.getSpeedLimitOffset() * (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH); + const bool sl_force_active = speedLimitControlToggle && + seconds_since_boot() < s.scene.last_speed_limit_sign_tap + 2.0; + const bool sl_inactive = !sl_force_active && (!speedLimitControlToggle || + slcState == cereal::LongitudinalPlanSP::SpeedLimitControlState::INACTIVE); + const bool sl_temp_inactive = !sl_force_active && (speedLimitControlToggle && + slcState == cereal::LongitudinalPlanSP::SpeedLimitControlState::TEMP_INACTIVE); + const bool sl_pre_active = !sl_force_active && (speedLimitControlToggle && + slcState == cereal::LongitudinalPlanSP::SpeedLimitControlState::PRE_ACTIVE); + const int sl_distance = int(lp_sp.getDistToSpeedLimit() * (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH) / 10.0) * 10; + const QString sl_distance_str(QString::number(sl_distance) + (s.scene.is_metric ? "m" : "f")); + const QString sl_offset_str(speed_limit_offset > 0.0 ? speed_limit_offset < 0.0 ? + "-" + QString::number(std::nearbyint(std::abs(speed_limit_offset))) : + "+" + QString::number(std::nearbyint(speed_limit_offset)) : ""); + const QString sl_inactive_str(sl_temp_inactive && s.scene.speed_limit_control_engage_type == 0 ? "TEMP" : ""); + const QString sl_substring(sl_inactive || sl_temp_inactive || sl_pre_active ? sl_inactive_str : + sl_distance > 0 ? sl_distance_str : sl_offset_str); + + showSpeedLimit = speed_limit_slc > 0.0; + speedLimitSLC = speed_limit_slc; + speedLimitSLCOffset = speed_limit_offset; + slcSubText = sl_substring; + slcSubTextSize = sl_inactive || sl_temp_inactive || sl_distance > 0 ? 25.0 : 27.0; + mapSourcedSpeedLimit = lp_sp.getIsMapSpeedLimit(); + slcActive = !sl_inactive && !sl_temp_inactive; + overSpeedLimit = showSpeedLimit && s.scene.speed_limit_warning_type != 0 && + (std::nearbyint(speed_limit_slc + s.scene.speed_limit_warning_value_offset) < std::nearbyint(speed)); + plus_arrow_up_img = loadPixmap("../assets/img_plus_arrow_up", {105, 105}); + minus_arrow_down_img = loadPixmap("../assets/img_minus_arrow_down", {105, 105}); + + const float tsc_speed = lp_sp.getTurnSpeed() * (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH); + const auto tscState = lp_sp.getTurnSpeedControlState(); + const int t_distance = int(lp_sp.getDistToTurn() * (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH) / 10.0) * 10; + const QString t_distance_str(QString::number(t_distance) + (s.scene.is_metric ? "m" : "f")); + + showTurnSpeedLimit = tsc_speed > 0.0 && std::round(tsc_speed) < 224 && (tsc_speed < speed || s.scene.show_debug_ui); + turnSpeedLimit = QString::number(std::nearbyint(tsc_speed)); + tscSubText = t_distance > 0 ? t_distance_str : QString(""); + tscActive = tscState > cereal::LongitudinalPlanSP::SpeedLimitControlState::TEMP_INACTIVE; + curveSign = lp_sp.getTurnSign(); + + // TODO: Add toggle variables to cereal, and parse from cereal + longitudinalPersonality = s.scene.longitudinal_personality; + dynamicLaneProfile = s.scene.dynamic_lane_profile; + mpcMode = QString::fromStdString(lp_sp.getE2eBlended()); + mpcMode = (mpcMode == "blended") ? mpcMode.replace(0, 1, mpcMode[0].toUpper()) : mpcMode.toUpper(); + + static int reverse_delay = 0; + bool reverse_allowed = false; + if (int(car_state.getGearShifter()) != 4) { + reverse_delay = 0; + reverse_allowed = false; + } else { + reverse_delay += 50; + if (reverse_delay >= 1000) { + reverse_allowed = true; + } + } + + reversing = reverse_allowed; + + cruiseStateEnabled = car_state.getCruiseState().getEnabled(); + + int e2eLStatus = 0; + static bool chime_sent = false; + static int chime_count = 0; + int chime_prompt = 0; + static float last_lead_distance = -1; + const float lead_distance = radar_state.getLeadOne().getDRel(); + + if (s.scene.e2eX[12] > 30 && car_state.getVEgo() < 1.0) { + e2eLStatus = 2; + } else if ((s.scene.e2eX[12] > 0 && s.scene.e2eX[12] < 80) || s.scene.e2eX[12] < 0) { + e2eLStatus = 1; + } else { + e2eLStatus = 0; + } + + if (!car_state.getStandstill()) { + chime_prompt = 0; + chime_sent = false; + chime_count = 0; + + if (last_lead_distance != -1) { + last_lead_distance = -1; + } + } + + if ((cruiseStateEnabled || car_state.getBrakeLightsDEPRECATED()) && !car_state.getGasPressed() && car_state.getStandstill()) { + if (e2eLStatus == 2 && !radar_state.getLeadOne().getStatus()) { + if (chime_sent) { + chime_count = 0; + } else { + chime_count += 1; + } + if (s.scene.e2e_long_alert_light && chime_count >= 2 && !chime_sent) { + chime_prompt = 1; + chime_sent = true; + } else { + chime_prompt = 0; + } + } else if (radar_state.getLeadOne().getStatus()) { + if ((last_lead_distance == -1) || (lead_distance < last_lead_distance)) { + last_lead_distance = lead_distance; + } + if (s.scene.e2e_long_alert_lead && (lead_distance - last_lead_distance > 1.0) && !chime_sent) { + chime_prompt = 2; + chime_sent = true; + } else { + chime_prompt = 0; + } + } else { + chime_prompt = 0; + } + } else { + } + + e2eStatus = chime_prompt; + e2eState = e2eLStatus; + e2eLongAlertUi = s.scene.e2e_long_alert_ui; + dynamicExperimentalControlToggle = s.scene.dynamic_experimental_control; + speedLimitWarningFlash = s.scene.speed_limit_warning_flash; + experimentalMode = cs.getExperimentalMode(); + + featureStatusToggle = s.scene.feature_status_toggle; + + experimental_btn->setVisible(!(showDebugUI && showVTC)); + drivingModelGen = s.scene.driving_model_generation; +} + +void AnnotatedCameraWidgetSP::drawHud(QPainter &p) { + p.save(); + + // Header gradient + QLinearGradient bg(0, UI_HEADER_HEIGHT - (UI_HEADER_HEIGHT / 2.5), 0, UI_HEADER_HEIGHT); + bg.setColorAt(0, QColor::fromRgbF(0, 0, 0, 0.45)); + bg.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0)); + p.fillRect(0, 0, width(), UI_HEADER_HEIGHT, bg); + + QString speedLimitStr = (speedLimit > 1) ? QString::number(std::nearbyint(speedLimit)) : "–"; + QString speedLimitStrSlc = showSpeedLimit ? QString::number(std::nearbyint(speedLimitSLC)) : "–"; + QString speedStr = QString::number(std::nearbyint(speed)); + QString setSpeedStr = is_cruise_set ? QString::number(std::nearbyint(setSpeed)) : "–"; + const bool isNavSpeedLimit = has_us_speed_limit || has_eu_speed_limit; + + // Draw outer box + border to contain set speed and speed limit + const int sign_margin = 12; + const int us_sign_height = slcSubText == "" ? 186 : 216; + const int eu_sign_size = 176; + + const QSize default_size = {172, 204}; + QSize set_speed_size = default_size; + if (is_metric || has_eu_speed_limit) set_speed_size.rwidth() = 200; + if ((mapSourcedSpeedLimit && !is_metric && speedLimitStrSlc.size() >= 3) || + (has_us_speed_limit && speedLimitStr.size() >= 3)) set_speed_size.rwidth() = 223; + + if ((mapSourcedSpeedLimit && !is_metric) || has_us_speed_limit) set_speed_size.rheight() += us_sign_height + sign_margin; + else if ((mapSourcedSpeedLimit && is_metric) || has_eu_speed_limit) set_speed_size.rheight() += eu_sign_size + sign_margin; + + int top_radius = 32; + int bottom_radius = ((mapSourcedSpeedLimit && is_metric) || has_eu_speed_limit) ? 100 : 32; + + QRect set_speed_rect(QPoint(60 + (default_size.width() - set_speed_size.width()) / 2, 45), set_speed_size); + p.setPen(QPen(whiteColor(75), 6)); + p.setBrush(blackColor(166)); + drawRoundedRect(p, set_speed_rect, top_radius, top_radius, bottom_radius, bottom_radius); + + // Draw MAX + QColor max_color = QColor(0x80, 0xd8, 0xa6, 0xff); + QColor set_speed_color = whiteColor(); + if (is_cruise_set) { + if (status == STATUS_DISENGAGED) { + max_color = whiteColor(); + } else if (status == STATUS_OVERRIDE && gasOverride) { + max_color = QColor(0x91, 0x9b, 0x95, 0xff); + } else if (speedLimitSLC > 0) { + auto interp_color = [=](QColor c1, QColor c2, QColor c3) { + return speedLimitSLC > 0 ? interpColor(setSpeed, {speedLimitSLC + 5, speedLimitSLC + 15, speedLimitSLC + 25}, {c1, c2, c3}) : c1; + }; + max_color = interp_color(max_color, QColor(0xff, 0xe4, 0xbf), QColor(0xff, 0xbf, 0xbf)); + set_speed_color = interp_color(set_speed_color, QColor(0xff, 0x95, 0x00), QColor(0xff, 0x00, 0x00)); + } else if (speedLimit > 0) { + auto interp_color = [=](QColor c1, QColor c2, QColor c3) { + return speedLimit > 0 ? interpColor(setSpeed, {speedLimit + 5, speedLimit + 15, speedLimit + 25}, {c1, c2, c3}) : c1; + }; + max_color = interp_color(max_color, QColor(0xff, 0xe4, 0xbf), QColor(0xff, 0xbf, 0xbf)); + set_speed_color = interp_color(set_speed_color, QColor(0xff, 0x95, 0x00), QColor(0xff, 0x00, 0x00)); + } + } else { + max_color = QColor(0xa6, 0xa6, 0xa6, 0xff); + set_speed_color = QColor(0x72, 0x72, 0x72, 0xff); + } + p.setFont(InterFont(40, QFont::DemiBold)); + p.setPen(max_color); + p.drawText(set_speed_rect.adjusted(0, 27, 0, 0), Qt::AlignTop | Qt::AlignHCenter, tr("MAX")); + p.setFont(InterFont(90, QFont::Bold)); + p.setPen(set_speed_color); + p.drawText(set_speed_rect.adjusted(0, 77, 0, 0), Qt::AlignTop | Qt::AlignHCenter, setSpeedStr); + + const QRect sign_rect = set_speed_rect.adjusted(sign_margin, default_size.height(), -sign_margin, -sign_margin); + sl_sign_rect = sign_rect; + + speedLimitWarning(p, sign_rect, sign_margin); + + // US/Canada (MUTCD style) sign + if (((mapSourcedSpeedLimit && !is_metric && !isNavSpeedLimit) || has_us_speed_limit) && slcShowSign) { + p.setPen(Qt::NoPen); + p.setBrush(whiteColor()); + p.drawRoundedRect(sign_rect, 24, 24); + p.setPen(QPen(blackColor(), 6)); + p.drawRoundedRect(sign_rect.adjusted(9, 9, -9, -9), 16, 16); + + p.setFont(InterFont(28, QFont::DemiBold)); + p.drawText(sign_rect.adjusted(0, 22, 0, 0), Qt::AlignTop | Qt::AlignHCenter, tr("SPEED")); + p.drawText(sign_rect.adjusted(0, 51, 0, 0), Qt::AlignTop | Qt::AlignHCenter, tr("LIMIT")); + p.setFont(InterFont(70, QFont::Bold)); + if (overSpeedLimit) p.setPen(QColor(255, 0, 0, 255)); + else p.setPen(blackColor()); + p.drawText(sign_rect.adjusted(0, 85, 0, 0), Qt::AlignTop | Qt::AlignHCenter, speedLimitStrSlc); + + // Speed limit offset value + p.setFont(InterFont(32, QFont::Bold)); + p.setPen(blackColor()); + p.drawText(sign_rect.adjusted(0, 85 + 77, 0, 0), Qt::AlignTop | Qt::AlignHCenter, slcSubText); + } + + // EU (Vienna style) sign + if (((mapSourcedSpeedLimit && is_metric && !isNavSpeedLimit) || has_eu_speed_limit) && slcShowSign) { + p.setPen(Qt::NoPen); + p.setBrush(whiteColor()); + p.drawEllipse(sign_rect); + p.setPen(QPen(Qt::red, 20)); + p.drawEllipse(sign_rect.adjusted(16, 16, -16, -16)); + + p.setFont(InterFont((speedLimitStrSlc.size() >= 3) ? 60 : 70, QFont::Bold)); + if (overSpeedLimit) p.setPen(QColor(255, 0, 0, 255)); + else p.setPen(blackColor()); + p.drawText(sign_rect, Qt::AlignCenter, speedLimitStrSlc); + + // Speed limit offset value + p.setFont(InterFont(slcSubTextSize, QFont::Bold)); + p.setPen(blackColor()); + p.drawText(sign_rect.adjusted(0, 27, 0, 0), Qt::AlignTop | Qt::AlignHCenter, slcSubText); + } + + // current speed + if (!hideVEgoUi) { + p.setFont(InterFont(176, QFont::Bold)); + drawColoredText(p, rect().center().x(), 210, speedStr, brakeLights ? QColor(0xff, 0, 0, 255) : QColor(0xff, 0xff, 0xff, 255)); + p.setFont(InterFont(66)); + drawText(p, rect().center().x(), 290, speedUnit, 200); + } + + if (!reversing) { + // ####### 1 ROW ####### + QRect bar_rect1(rect().left(), rect().bottom() - 60, rect().width(), 61); + if (!splitPanelVisible && devUiInfo == 2) { + p.setPen(Qt::NoPen); + p.setBrush(QColor(0, 0, 0, 100)); + p.drawRect(bar_rect1); + drawNewDevUi2(p, bar_rect1.left(), bar_rect1.center().y()); + } + + // ####### 1 COLUMN ######## + QRect rc2(rect().right() - (UI_BORDER_SIZE * 2), UI_BORDER_SIZE * 1.5, 184, 152); + if (devUiInfo != 0) { + drawRightDevUi(p, rect().right() - 184 - UI_BORDER_SIZE * 2, UI_BORDER_SIZE * 2 + rc2.height()); + } + + int rn_btn = 0; + rn_btn = !splitPanelVisible && devUiInfo == 2 ? 35 : 0; + rn_offset = rn_btn; + + // Stand Still Timer + if (standStillTimer && standStill && !splitPanelVisible) { + drawStandstillTimer(p, rect().right() - 650, 30 + 160 + 250); + } + + // V-TSC + if (showDebugUI && showVTC) { + drawVisionTurnControllerUI(p, rect().right() - 184 - (UI_BORDER_SIZE * 1.5), int(UI_BORDER_SIZE * 1.5), 184, vtcColor, vtcSpeed, 100); + } + + // Bottom bar road name + if (showDebugUI && !roadName.isEmpty()) { + int font_size = splitPanelVisible ? 38 : 50; + int h = splitPanelVisible ? 18 : 26; + p.setFont(InterFont(font_size, QFont::Bold)); + drawRoadNameText(p, rect().center().x(), h, roadName, QColor(255, 255, 255, 255)); + } + + // Turn Speed Sign + if (showTurnSpeedLimit) { + QRect rc = sign_rect; + rc.moveTop(sign_rect.bottom() + UI_BORDER_SIZE); + drawTrunSpeedSign(p, rc, turnSpeedLimit, tscSubText, curveSign, tscActive); + } + } + + // E2E Status + if (e2eLongAlertUi && e2eState != 0) { + drawE2eStatus(p, UI_BORDER_SIZE * 2 + 190, 45, 150, 150, e2eState); + } + + if (!hideBottomIcons && featureStatusToggle) { + int x = UI_BORDER_SIZE * 2 + (rightHandDM ? 600 : 370); + int feature_status_text_x = rightHandDM ? rect().right() - x : x; + drawFeatureStatusText(p, feature_status_text_x, rect().bottom() - 160 - rn_offset); + } + + p.restore(); +} + +void AnnotatedCameraWidgetSP::drawText(QPainter &p, int x, int y, const QString &text, int alpha) { + QRect real_rect = p.fontMetrics().boundingRect(text); + real_rect.moveCenter({x, y - real_rect.height() / 2}); + + p.setPen(QColor(0xff, 0xff, 0xff, alpha)); + p.drawText(real_rect.x(), real_rect.bottom(), text); +} + +void AnnotatedCameraWidgetSP::drawColoredText(QPainter &p, int x, int y, const QString &text, QColor color) { + QRect real_rect = p.fontMetrics().boundingRect(text); + real_rect.moveCenter({x, y - real_rect.height() / 2}); + + p.setPen(color); + p.drawText(real_rect.x(), real_rect.bottom(), text); +} + +void AnnotatedCameraWidgetSP::drawCenteredText(QPainter &p, int x, int y, const QString &text, QColor color) { + QRect real_rect = p.fontMetrics().boundingRect(text); + real_rect.moveCenter({x, y}); + + p.setPen(color); + p.drawText(real_rect, Qt::AlignCenter, text); +} + +void AnnotatedCameraWidgetSP::drawRoadNameText(QPainter &p, int x, int y, const QString &text, QColor color) { + QRect real_rect = p.fontMetrics().boundingRect(text); + real_rect.moveCenter({x, y}); + + QRect real_rect_adjusted(real_rect); + real_rect_adjusted.adjust(-UI_ROAD_NAME_MARGIN_X, 5, UI_ROAD_NAME_MARGIN_X, 0); + QPainterPath path; + path.addRoundedRect(real_rect_adjusted, 10, 10); + p.setPen(Qt::NoPen); + p.setBrush(QColor(0, 0, 0, 100)); + p.drawPath(path); + + p.setPen(color); + p.drawText(real_rect, Qt::AlignCenter, text); +} + +void AnnotatedCameraWidgetSP::drawVisionTurnControllerUI(QPainter &p, int x, int y, int size, const QColor &color, + const QString &vision_speed, int alpha) { + QRect rvtc(x, y, size, size); + p.setPen(QPen(color, 10)); + p.setBrush(QColor(0, 0, 0, alpha)); + p.drawRoundedRect(rvtc, 20, 20); + p.setPen(Qt::NoPen); + + p.setFont(InterFont(56, QFont::DemiBold)); + drawCenteredText(p, rvtc.center().x(), rvtc.center().y(), vision_speed, color); +} + +void AnnotatedCameraWidgetSP::drawStandstillTimer(QPainter &p, int x, int y) { + char lab_str[16]; + char val_str[16]; + int minute = (int)(standstillElapsedTime / 60); + int second = (int)((standstillElapsedTime) - (minute * 60)); + + if (standStill) { + snprintf(lab_str, sizeof(lab_str), "STOP"); + snprintf(val_str, sizeof(val_str), "%01d:%02d", minute, second); + } + + p.setFont(InterFont(125, QFont::DemiBold)); + drawColoredText(p, x, y, QString(lab_str), QColor(255, 175, 3, 240)); + p.setFont(InterFont(150, QFont::DemiBold)); + drawColoredText(p, x, y + 150, QString(val_str), QColor(255, 255, 255, 240)); +} + +void AnnotatedCameraWidgetSP::drawCircle(QPainter &p, int x, int y, int r, QBrush bg) { + p.setPen(Qt::NoPen); + p.setBrush(bg); + p.drawEllipse(x - r, y - r, 2 * r, 2 * r); +} + +void AnnotatedCameraWidgetSP::drawSpeedSign(QPainter &p, QRect rc, const QString &speed_limit, const QString &sub_text, + int subtext_size, bool is_map_sourced, bool is_active) { + const QColor ring_color = is_active ? QColor(255, 0, 0, 255) : QColor(0, 0, 0, 50); + const QColor inner_color = QColor(255, 255, 255, is_active ? 255 : 85); + const QColor text_color = QColor(0, 0, 0, is_active ? 255 : 85); + + const int x = rc.center().x(); + const int y = rc.center().y(); + const int r = rc.width() / 2.0f; + + drawCircle(p, x, y, r, ring_color); + drawCircle(p, x, y, int(r * 0.8f), inner_color); + + p.setFont(InterFont(89, QFont::Bold)); + drawCenteredText(p, x, y, speed_limit, text_color); + p.setFont(InterFont(subtext_size, QFont::Bold)); + drawCenteredText(p, x, y + 55, sub_text, text_color); + + if (is_map_sourced) { + p.setPen(Qt::NoPen); + p.setOpacity(is_active ? 1.0 : 0.3); + p.drawPixmap(x - subsign_img_size / 2, y - 55 - subsign_img_size / 2, map_img); + p.setOpacity(1.0); + } +} + +void AnnotatedCameraWidgetSP::drawTrunSpeedSign(QPainter &p, QRect rc, const QString &turn_speed, const QString &sub_text, + int curv_sign, bool is_active) { + const QColor border_color = is_active ? QColor(255, 0, 0, 255) : QColor(0, 0, 0, 50); + const QColor inner_color = QColor(255, 255, 255, is_active ? 255 : 85); + const QColor text_color = QColor(0, 0, 0, is_active ? 255 : 85); + + const int x = rc.center().x(); + const int y = 184 * 2 + UI_BORDER_SIZE + 202; + const int width = 184; + + const float stroke_w = 15.0; + const float cS = stroke_w / 2.0 + 4.5; // half width of the stroke on the corners of the triangle + const float R = width / 2.0 - stroke_w / 2.0; + const float A = 0.73205; + const float h2 = 2.0 * R / (1.0 + A); + const float h1 = A * h2; + const float L = 4.0 * R / sqrt(3.0); + + // Draw the internal triangle, compensate for stroke width. Needed to improve rendering when in inactive + // state due to stroke transparency being different from inner transparency. + QPainterPath path; + path.moveTo(x, y - R + cS); + path.lineTo(x - L / 2.0 + cS, y + h1 + h2 - R - stroke_w / 2.0); + path.lineTo(x + L / 2.0 - cS, y + h1 + h2 - R - stroke_w / 2.0); + path.lineTo(x, y - R + cS); + p.setPen(Qt::NoPen); + p.setBrush(inner_color); + p.drawPath(path); + + // Draw the stroke + QPainterPath stroke_path; + stroke_path.moveTo(x, y - R); + stroke_path.lineTo(x - L / 2.0, y + h1 + h2 - R); + stroke_path.lineTo(x + L / 2.0, y + h1 + h2 - R); + stroke_path.lineTo(x, y - R); + p.setPen(QPen(border_color, stroke_w, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + p.setBrush(Qt::NoBrush); + p.drawPath(stroke_path); + + // Draw the turn sign + if (curv_sign != 0) { + p.setPen(Qt::NoPen); + p.setOpacity(is_active ? 1.0 : 0.3); + p.drawPixmap(int(x - (subsign_img_size / 2)), int(y - R + stroke_w + 30), curv_sign > 0 ? left_img : right_img); + p.setOpacity(1.0); + } + + // Draw the texts. + p.setFont(InterFont(67, QFont::Bold)); + drawCenteredText(p, x, y + 25, turn_speed, text_color); + p.setFont(InterFont(22, QFont::Bold)); + drawCenteredText(p, x, y + 65, sub_text, text_color); +} + +// ############################## DEV UI START ############################## +void AnnotatedCameraWidgetSP::drawCenteredLeftText(QPainter &p, int x, int y, const QString &text1, QColor color1, const QString &text2, const QString &text3, QColor color2) { + QFontMetrics fm(p.font()); + QRect init_rect = fm.boundingRect(text1 + " "); + QRect real_rect = fm.boundingRect(init_rect, 0, text1 + " "); + real_rect.moveCenter({x, y}); + + QRect init_rect3 = fm.boundingRect(text3); + QRect real_rect3 = fm.boundingRect(init_rect3, 0, text3); + real_rect3.moveTop(real_rect.top()); + real_rect3.moveLeft(real_rect.right() + 135); + + QRect init_rect2 = fm.boundingRect(text2); + QRect real_rect2 = fm.boundingRect(init_rect2, 0, text2); + real_rect2.moveTop(real_rect.top()); + real_rect2.moveRight(real_rect.right() + 125); + + p.setPen(color1); + p.drawText(real_rect, Qt::AlignLeft | Qt::AlignVCenter, text1); + + p.setPen(color2); + p.drawText(real_rect2, Qt::AlignRight | Qt::AlignVCenter, text2); + p.drawText(real_rect3, Qt::AlignLeft | Qt::AlignVCenter, text3); +} + +int AnnotatedCameraWidgetSP::drawDevUiRight(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color) { + p.setFont(InterFont(30 * 2, QFont::Bold)); + drawColoredText(p, x + 92, y + 80, value, color); + + p.setFont(InterFont(28, QFont::Bold)); + drawText(p, x + 92, y + 80 + 42, label, 255); + + if (units.length() > 0) { + p.save(); + p.translate(x + 54 + 30 - 3 + 92 + 30, y + 37 + 25); + p.rotate(-90); + drawText(p, 0, 0, units, 255); + p.restore(); + } + + return 110; +} + +void AnnotatedCameraWidgetSP::drawRightDevUi(QPainter &p, int x, int y) { + int rh = 5; + int ry = y; + + UiElement dRelElement = DeveloperUi::getDRel(lead_status, lead_d_rel); + rh += drawDevUiRight(p, x, ry, dRelElement.value, dRelElement.label, dRelElement.units, dRelElement.color); + ry = y + rh; + + UiElement vRelElement = DeveloperUi::getVRel(lead_status, lead_v_rel, is_metric, speedUnit); + rh += drawDevUiRight(p, x, ry, vRelElement.value, vRelElement.label, vRelElement.units, vRelElement.color); + ry = y + rh; + + UiElement steeringAngleDegElement = DeveloperUi::getSteeringAngleDeg(angleSteers, madsEnabled, latActive); + rh += drawDevUiRight(p, x, ry, steeringAngleDegElement.value, steeringAngleDegElement.label, steeringAngleDegElement.units, steeringAngleDegElement.color); + ry = y + rh; + + if (lateralState == "torque") { + UiElement actualLateralAccelElement = DeveloperUi::getActualLateralAccel(curvature, vEgo, roll, madsEnabled, latActive); + rh += drawDevUiRight(p, x, ry, actualLateralAccelElement.value, actualLateralAccelElement.label, actualLateralAccelElement.units, actualLateralAccelElement.color); + } else { + UiElement steeringAngleDesiredDegElement = DeveloperUi::getSteeringAngleDesiredDeg(madsEnabled, latActive, steerAngleDesired, angleSteers); + rh += drawDevUiRight(p, x, ry, steeringAngleDesiredDegElement.value, steeringAngleDesiredDegElement.label, steeringAngleDesiredDegElement.units, steeringAngleDesiredDegElement.color); + } + ry = y + rh; + + UiElement memoryUsagePercentElement = DeveloperUi::getMemoryUsagePercent(memoryUsagePercent); + rh += drawDevUiRight(p, x, ry, memoryUsagePercentElement.value, memoryUsagePercentElement.label, memoryUsagePercentElement.units, memoryUsagePercentElement.color); + ry = y + rh; + + rh += 25; + p.setBrush(QColor(0, 0, 0, 0)); + QRect ldu(x, y, 184, rh); +} + +int AnnotatedCameraWidgetSP::drawNewDevUi(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color) { + p.setFont(InterFont(38, QFont::Bold)); + drawCenteredLeftText(p, x, y, label, whiteColor(), value, units, color); + + return 430; +} + +void AnnotatedCameraWidgetSP::drawNewDevUi2(QPainter &p, int x, int y) { + int rw = 90; + + UiElement aEgoElement = DeveloperUi::getAEgo(aEgo); + rw += drawNewDevUi(p, rw, y, aEgoElement.value, aEgoElement.label, aEgoElement.units, aEgoElement.color); + + UiElement vEgoLeadElement = DeveloperUi::getVEgoLead(lead_status, lead_v_rel, vEgo, is_metric, speedUnit); + rw += drawNewDevUi(p, rw, y, vEgoLeadElement.value, vEgoLeadElement.label, vEgoLeadElement.units, vEgoLeadElement.color); + + if (torquedUseParams) { + UiElement frictionCoefficientFilteredElement = DeveloperUi::getFrictionCoefficientFiltered(frictionCoefficientFiltered, liveValid); + rw += drawNewDevUi(p, rw, y, frictionCoefficientFilteredElement.value, frictionCoefficientFilteredElement.label, frictionCoefficientFilteredElement.units, frictionCoefficientFilteredElement.color); + + UiElement latAccelFactorFilteredElement = DeveloperUi::getLatAccelFactorFiltered(latAccelFactorFiltered, liveValid); + rw += drawNewDevUi(p, rw, y, latAccelFactorFilteredElement.value, latAccelFactorFilteredElement.label, latAccelFactorFilteredElement.units, latAccelFactorFilteredElement.color); + } else { + UiElement steeringTorqueEpsElement = DeveloperUi::getSteeringTorqueEps(steeringTorqueEps); + rw += drawNewDevUi(p, rw, y, steeringTorqueEpsElement.value, steeringTorqueEpsElement.label, steeringTorqueEpsElement.units, steeringTorqueEpsElement.color); + + UiElement bearingDegElement = DeveloperUi::getBearingDeg(bearingAccuracyDeg, bearingDeg); + rw += drawNewDevUi(p, rw, y, bearingDegElement.value, bearingDegElement.label, bearingDegElement.units, bearingDegElement.color); + } + + UiElement altitudeElement = DeveloperUi::getAltitude(gpsAccuracy, altitude); + rw += drawNewDevUi(p, rw, y, altitudeElement.value, altitudeElement.label, altitudeElement.units, altitudeElement.color); +} + +// ############################## DEV UI END ############################## + +void AnnotatedCameraWidgetSP::drawE2eStatus(QPainter &p, int x, int y, int w, int h, int e2e_long_status) { + QColor status_color; + QRect e2eStatusIcon(x, y, w, h); + p.setPen(Qt::NoPen); + p.setBrush(QBrush(blackColor(70))); + p.drawEllipse(e2eStatusIcon); + e2eStatusIcon -= QMargins(25, 25, 25, 25); + p.setPen(Qt::NoPen); + if (e2e_long_status == 2) { + status_color = QColor::fromRgbF(0.0, 1.0, 0.0, 0.9); + } else if (e2e_long_status == 1) { + status_color = QColor::fromRgbF(1.0, 0.0, 0.0, 0.9); + } + p.setBrush(QBrush(status_color)); + p.drawEllipse(e2eStatusIcon); +} + +void AnnotatedCameraWidgetSP::drawLeftTurnSignal(QPainter &painter, int x, int y, int circle_size, int state) { + painter.setRenderHint(QPainter::Antialiasing, true); + + QColor circle_color, circle_color_0, circle_color_1; + QColor arrow_color, arrow_color_0, arrow_color_1; + if ((left_blindspot || lane_change_edge_block) && !(left_blinker && right_blinker)) { + circle_color_0 = QColor(164, 0, 1); + circle_color_1 = QColor(204, 0, 1); + arrow_color_0 = QColor(72, 1, 1); + arrow_color_1 = QColor(255, 255, 255); + } else { + circle_color_0 = QColor(22, 156, 69); + circle_color_1 = QColor(30, 215, 96); + arrow_color_0 = QColor(9, 56, 27); + arrow_color_1 = QColor(255, 255, 255); + } + + if (state == 1) { + circle_color = circle_color_1; + arrow_color = arrow_color_1; + } else if (state == 0) { + circle_color = circle_color_0; + arrow_color = arrow_color_0; + } + + // Draw the circle + int circleX = x; + int circleY = y; + painter.setPen(Qt::NoPen); + painter.setBrush(circle_color); + painter.drawEllipse(circleX, circleY, circle_size, circle_size); + + // Draw the arrow + int arrowSize = 50; + int arrowX = circleX + (circle_size - arrowSize) / 4; + int arrowY = circleY + (circle_size - arrowSize) / 2; + painter.setPen(Qt::NoPen); + painter.setBrush(arrow_color); + + // Draw the arrow shape + QPolygon arrowPolygon; + arrowPolygon << QPoint(arrowX + 10, arrowY + arrowSize / 2) + << QPoint(arrowX + arrowSize - 3, arrowY) + << QPoint(arrowX + arrowSize, arrowY) + << QPoint(arrowX + arrowSize, arrowY + arrowSize) + << QPoint(arrowX + arrowSize - 3, arrowY + arrowSize) + << QPoint(arrowX + 10, arrowY + arrowSize / 2); + painter.drawPolygon(arrowPolygon); + + // Draw the tail rectangle + int tailWidth = arrowSize / 2.25; + int tailHeight = arrowSize / 2; + QRect tailRect(arrowX + arrowSize - 3, arrowY + arrowSize / 4, tailWidth, tailHeight); + painter.fillRect(tailRect, arrow_color); +} + +void AnnotatedCameraWidgetSP::drawRightTurnSignal(QPainter &painter, int x, int y, int circle_size, int state) { + painter.setRenderHint(QPainter::Antialiasing, true); + + QColor circle_color, circle_color_0, circle_color_1; + QColor arrow_color, arrow_color_0, arrow_color_1; + if ((right_blindspot || lane_change_edge_block) && !(left_blinker && right_blinker)) { + circle_color_0 = QColor(164, 0, 1); + circle_color_1 = QColor(204, 0, 1); + arrow_color_0 = QColor(72, 1, 1); + arrow_color_1 = QColor(255, 255, 255); + } else { + circle_color_0 = QColor(22, 156, 69); + circle_color_1 = QColor(30, 215, 96); + arrow_color_0 = QColor(9, 56, 27); + arrow_color_1 = QColor(255, 255, 255); + } + + if (state == 1) { + circle_color = circle_color_1; + arrow_color = arrow_color_1; + } else if (state == 0) { + circle_color = circle_color_0; + arrow_color = arrow_color_0; + } + + + // Draw the circle + int circleX = x; + int circleY = y; + painter.setPen(Qt::NoPen); + painter.setBrush(circle_color); + painter.drawEllipse(circleX, circleY, circle_size, circle_size); + + // Draw the arrow + int arrowSize = 50; + int arrowX = circleX + (circle_size - arrowSize) / 2 + (arrowSize / 2.5) - 3; + int arrowY = circleY + (circle_size - arrowSize) / 2; + painter.setPen(Qt::NoPen); + painter.setBrush(arrow_color); + + // Draw the arrow shape + QPolygon arrowPolygon; + arrowPolygon << QPoint(arrowX + arrowSize - 10, arrowY + arrowSize / 2) + << QPoint(arrowX + 3, arrowY) + << QPoint(arrowX, arrowY) + << QPoint(arrowX, arrowY + arrowSize) + << QPoint(arrowX + 3, arrowY + arrowSize) + << QPoint(arrowX + arrowSize - 10, arrowY + arrowSize / 2); + painter.drawPolygon(arrowPolygon); + + // Draw the tail rectangle + int tailWidth = arrowSize / 2.25; + int tailHeight = arrowSize / 2; + QRect tailRect(arrowX - tailWidth + 3, arrowY + arrowSize / 4, tailWidth, tailHeight); + painter.fillRect(tailRect, arrow_color); +} + +int AnnotatedCameraWidgetSP::blinkerPulse(int frame) { + if (frame % UI_FREQ < (UI_FREQ / 2)) { + blinker_state = 1; + } else { + blinker_state = 0; + } + + return blinker_state; +} + +void AnnotatedCameraWidgetSP::speedLimitSignPulse(int frame) { + if (frame % UI_FREQ < (UI_FREQ / 2.5)) { + slcShowSign = false; + } else { + slcShowSign = true; + } +} + +void AnnotatedCameraWidgetSP::drawFeatureStatusText(QPainter &p, int x, int y) { + const FeatureStatusText feature_text; + const FeatureStatusColor feature_color; + const QColor text_color = whiteColor(); + const QColor shadow_color = blackColor(38); + const int text_height = 34; + const int drop_shadow_size = 2; + const int eclipse_x_offset = 25; + const int eclipse_y_offset = 20; + const int w = 16; + const int h = 16; + + const bool longitudinal = hasLongitudinalControl(car_params); + + p.setFont(InterFont(32, QFont::Bold)); + + // Define a function to draw a feature status button + auto drawFeatureStatusElement = [&](int value, const QStringList& text_list, const QStringList& color_list, bool condition, const QString& off_text, const QString& label) { + std::pair feature_status = getFeatureStatus(value, text_list, color_list, condition, off_text); + QRect btn(x - eclipse_x_offset, y - eclipse_y_offset, w, h); + QRect btn_shadow(x - eclipse_x_offset + drop_shadow_size, y - eclipse_y_offset + drop_shadow_size, w, h); + p.setPen(Qt::NoPen); + p.setBrush(shadow_color); + p.drawEllipse(btn_shadow); + p.setBrush(feature_status.second); + p.drawEllipse(btn); + QString status_text; + status_text.sprintf("%s: %s", label.toStdString().c_str(), (feature_status.first).toStdString().c_str()); + p.setPen(QPen(shadow_color, 2)); + p.drawText(x + drop_shadow_size, y + drop_shadow_size, status_text); + p.setPen(QPen(text_color, 2)); + p.drawText(x, y, status_text); + y += text_height; + }; + + // Driving Personality / Gap Adjust Cruise + if (longitudinal) { + drawFeatureStatusElement(longitudinalPersonality, feature_text.gac_list_text, feature_color.gac_list_color, longitudinal, "N/A", "GAP"); + } + + // Dynamic Lane Profile + if (drivingModelGen == cereal::ModelGeneration::ONE) { + drawFeatureStatusElement(dynamicLaneProfile, feature_text.dlp_list_text, feature_color.dlp_list_color, true, "OFF", "DLP"); + } + + // TODO: Add toggle variables to cereal, and parse from cereal + if (longitudinal) { + QColor dec_color((cruiseStateEnabled && dynamicExperimentalControlToggle) ? "#4bff66" : "#ffffff"); + QRect dec_btn(x - eclipse_x_offset, y - eclipse_y_offset, w, h); + QRect dec_btn_shadow(x - eclipse_x_offset + drop_shadow_size, y - eclipse_y_offset + drop_shadow_size, w, h); + p.setPen(Qt::NoPen); + p.setBrush(shadow_color); + p.drawEllipse(dec_btn_shadow); + p.setBrush(dec_color); + p.drawEllipse(dec_btn); + QString dec_status_text; + dec_status_text.sprintf("DEC: %s\n", dynamicExperimentalControlToggle ? (experimentalMode ? QString(mpcMode).toStdString().c_str() : QString("Inactive").toStdString().c_str()) : "OFF"); + p.setPen(QPen(shadow_color, 2)); + p.drawText(x + drop_shadow_size, y + drop_shadow_size, dec_status_text); + p.setPen(QPen(text_color, 2)); + p.drawText(x, y, dec_status_text); + y += text_height; + } + + // TODO: Add toggle variables to cereal, and parse from cereal + // Speed Limit Control + if (longitudinal || !car_params.getPcmCruiseSpeed()) { + drawFeatureStatusElement(int(slcState), feature_text.slc_list_text, feature_color.slc_list_color, speedLimitControlToggle, "OFF", "SLC"); + } +} + +void AnnotatedCameraWidgetSP::speedLimitWarning(QPainter &p, QRect sign_rect, const int sign_margin) { + // PRE ACTIVE + if (slcState == cereal::LongitudinalPlanSP::SpeedLimitControlState::PRE_ACTIVE) { + int set_speed = std::nearbyint(setSpeed); + int speed_limit_offsetted = std::nearbyint(speedLimitSLC + speedLimitSLCOffset); + + // Calculate the vertical offset using a sinusoidal function for smooth bouncing + double bounce_frequency = 2.0 * M_PI / 20.0; // 20 frames for one full oscillation + int bounce_offset = 20 * sin(speed_limit_frame * bounce_frequency); // Adjust the amplitude (20 pixels) as needed + + if (set_speed < speed_limit_offsetted) { + QPoint iconPosition(sign_rect.right() + sign_margin * 3, sign_rect.center().y() - plus_arrow_up_img.height() / 2 + bounce_offset); + p.drawPixmap(iconPosition, plus_arrow_up_img); + } else if (set_speed > speed_limit_offsetted) { + QPoint iconPosition(sign_rect.right() + sign_margin * 3, sign_rect.center().y() - minus_arrow_down_img.height() / 2 - bounce_offset); + p.drawPixmap(iconPosition, minus_arrow_down_img); + } + + speed_limit_frame++; + speedLimitSignPulse(speed_limit_frame); + } + + // current speed over speed limit + else if (overSpeedLimit && speedLimitWarningFlash) { + speed_limit_frame++; + speedLimitSignPulse(speed_limit_frame); + } + + else { + speed_limit_frame = 0; + slcShowSign = true; + } +} + + +void AnnotatedCameraWidgetSP::initializeGL() { + CameraWidget::initializeGL(); + qInfo() << "OpenGL version:" << QString((const char*)glGetString(GL_VERSION)); + qInfo() << "OpenGL vendor:" << QString((const char*)glGetString(GL_VENDOR)); + qInfo() << "OpenGL renderer:" << QString((const char*)glGetString(GL_RENDERER)); + qInfo() << "OpenGL language version:" << QString((const char*)glGetString(GL_SHADING_LANGUAGE_VERSION)); + + prev_draw_t = millis_since_boot(); + setBackgroundColor(bg_colors[STATUS_DISENGAGED]); +} + +void AnnotatedCameraWidgetSP::updateFrameMat() { + CameraWidget::updateFrameMat(); + UIStateSP *s = uiStateSP(); + int w = width(), h = height(); + + s->fb_w = w; + s->fb_h = h; + + // Apply transformation such that video pixel coordinates match video + // 1) Put (0, 0) in the middle of the video + // 2) Apply same scaling as video + // 3) Put (0, 0) in top left corner of video + s->car_space_transform.reset(); + s->car_space_transform.translate(w / 2 - x_offset, h / 2 - y_offset) + .scale(zoom, zoom) + .translate(-intrinsic_matrix.v[2], -intrinsic_matrix.v[5]); +} + +void AnnotatedCameraWidgetSP::drawLaneLines(QPainter &painter, const UIStateSP *s) { + painter.save(); + + const UISceneSP &scene = s->scene; + SubMaster &sm = *(s->sm); + + const auto car_state = sm["carState"].getCarState(); + + // Shane's colored lanelines + for (int i = 0; i < std::size(scene.lane_line_vertices); ++i) { + if (i == 1 || i == 2) { + // TODO: can we just use the projected vertices somehow? + const cereal::XYZTData::Reader &line = (*s->sm)["modelV2"].getModelV2().getLaneLines()[i]; + const float default_pos = 1.4; // when lane poly isn't available + const float lane_pos = line.getY().size() > 0 ? std::abs(line.getY()[5]) : default_pos; // get redder when line is closer to car + float hue = 332.5 * lane_pos - 332.5; // equivalent to {1.4, 1.0}: {133, 0} (green to red) + hue = std::fmin(133, fmax(0, hue)) / 360.; // clip and normalize + painter.setBrush(QColor::fromHslF(hue, 1.0, 0.50, std::clamp(scene.lane_line_probs[i], 0.0, 0.7))); + } else { + painter.setBrush(QColor::fromRgbF(1.0, 1.0, 1.0, std::clamp(scene.lane_line_probs[i], 0.0, 0.7))); + } + painter.drawPolygon(scene.lane_line_vertices[i]); + } + + // TODO: Fix empty spaces when curiving back on itself + painter.setBrush(QColor::fromRgbF(1.0, 0.0, 0.0, 0.2)); + if (left_blindspot) painter.drawPolygon(scene.lane_barrier_vertices[0]); + if (right_blindspot) painter.drawPolygon(scene.lane_barrier_vertices[1]); + + // road edges + for (int i = 0; i < std::size(scene.road_edge_vertices); ++i) { + painter.setBrush(QColor::fromRgbF(1.0, 0, 0, std::clamp(1.0 - scene.road_edge_stds[i], 0.0, 1.0))); + painter.drawPolygon(scene.road_edge_vertices[i]); + } + + // paint path + QLinearGradient bg(0, height(), 0, 0); + if (madsEnabled || car_state.getCruiseState().getEnabled()) { + if (steerOverride && latActive) { + bg.setColorAt(0.0, QColor::fromHslF(20 / 360., 0.94, 0.51, 0.17)); + bg.setColorAt(0.5, QColor::fromHslF(20 / 360., 1.0, 0.68, 0.17)); + bg.setColorAt(1.0, QColor::fromHslF(20 / 360., 1.0, 0.68, 0.0)); + } else if (!(latActive || car_state.getCruiseState().getEnabled())) { + bg.setColorAt(0, whiteColor()); + bg.setColorAt(1, whiteColor(0)); + } else if (sm["controlsState"].getControlsState().getExperimentalMode()) { + // The first half of track_vertices are the points for the right side of the path + const auto &acceleration = sm["modelV2"].getModelV2().getAcceleration().getX(); + const int max_len = std::min(scene.track_vertices.length() / 2, acceleration.size()); + + for (int i = 0; i < max_len; ++i) { + // Some points are out of frame + if (scene.track_vertices[i].y() < 0 || scene.track_vertices[i].y() > height()) continue; + + // Flip so 0 is bottom of frame + float lin_grad_point = (height() - scene.track_vertices[i].y()) / height(); + + // speed up: 120, slow down: 0 + float path_hue = fmax(fmin(60 + acceleration[i] * 35, 120), 0); + // FIXME: painter.drawPolygon can be slow if hue is not rounded + path_hue = int(path_hue * 100 + 0.5) / 100; + + float saturation = fmin(fabs(acceleration[i] * 1.5), 1); + float lightness = util::map_val(saturation, 0.0f, 1.0f, 0.95f, 0.62f); // lighter when grey + float alpha = util::map_val(lin_grad_point, 0.75f / 2.f, 0.75f, 0.4f, 0.0f); // matches previous alpha fade + bg.setColorAt(lin_grad_point, QColor::fromHslF(path_hue / 360., saturation, lightness, alpha)); + + // Skip a point, unless next is last + i += (i + 2) < max_len ? 1 : 0; + } + + } else { + bg.setColorAt(0.0, QColor::fromHslF(148 / 360., 0.94, 0.51, 0.4)); + bg.setColorAt(0.5, QColor::fromHslF(112 / 360., 1.0, 0.68, 0.35)); + bg.setColorAt(1.0, QColor::fromHslF(112 / 360., 1.0, 0.68, 0.0)); + } + } else { + bg.setColorAt(0.0, whiteColor(102)); + bg.setColorAt(0.5, whiteColor(89)); + bg.setColorAt(1.0, whiteColor(0)); + } + + painter.setBrush(bg); + painter.drawPolygon(scene.track_vertices); + + // create path combining track vertices and track edge vertices + QPainterPath path; + path.addPolygon(scene.track_vertices); + path.addPolygon(scene.track_edge_vertices); + + // paint path edges + QLinearGradient pe(0, height(), 0, height() / 4); + if (!scene.dynamic_lane_profile_status) { + pe.setColorAt(0.0, QColor::fromHslF(240 / 360., 0.94, 0.51, 1.0)); + pe.setColorAt(0.5, QColor::fromHslF(204 / 360., 1.0, 0.68, 0.5)); + pe.setColorAt(1.0, QColor::fromHslF(204 / 360., 1.0, 0.68, 0.0)); + + painter.setBrush(pe); + painter.drawPath(path); + } + + painter.restore(); +} + +void AnnotatedCameraWidgetSP::drawDriverState(QPainter &painter, const UIStateSP *s) { + const UIScene &scene = s->scene; + + painter.save(); + + // base icon + int offset = UI_BORDER_SIZE + btn_size / 2; + int x = rightHandDM ? width() - offset : offset; + int y = height() - offset - rn_offset; + float opacity = dmActive ? 0.65 : 0.2; + drawIcon(painter, QPoint(x, y), dm_img, blackColor(70), opacity); + + // face + QPointF face_kpts_draw[std::size(default_face_kpts_3d)]; + float kp; + for (int i = 0; i < std::size(default_face_kpts_3d); ++i) { + kp = (scene.face_kpts_draw[i].v[2] - 8) / 120 + 1.0; + face_kpts_draw[i] = QPointF(scene.face_kpts_draw[i].v[0] * kp + x, scene.face_kpts_draw[i].v[1] * kp + y); + } + + painter.setPen(QPen(QColor::fromRgbF(1.0, 1.0, 1.0, opacity), 5.2, Qt::SolidLine, Qt::RoundCap)); + painter.drawPolyline(face_kpts_draw, std::size(default_face_kpts_3d)); + + // tracking arcs + const int arc_l = 133; + const float arc_t_default = 6.7; + const float arc_t_extend = 12.0; + QColor arc_color = QColor::fromRgbF(0.545 - 0.445 * s->engaged(), + 0.545 + 0.4 * s->engaged(), + 0.545 - 0.285 * s->engaged(), + 0.4 * (1.0 - dm_fade_state)); + float delta_x = -scene.driver_pose_sins[1] * arc_l / 2; + float delta_y = -scene.driver_pose_sins[0] * arc_l / 2; + painter.setPen(QPen(arc_color, arc_t_default+arc_t_extend*fmin(1.0, scene.driver_pose_diff[1] * 5.0), Qt::SolidLine, Qt::RoundCap)); + painter.drawArc(QRectF(std::fmin(x + delta_x, x), y - arc_l / 2, fabs(delta_x), arc_l), (scene.driver_pose_sins[1]>0 ? 90 : -90) * 16, 180 * 16); + painter.setPen(QPen(arc_color, arc_t_default+arc_t_extend*fmin(1.0, scene.driver_pose_diff[0] * 5.0), Qt::SolidLine, Qt::RoundCap)); + painter.drawArc(QRectF(x - arc_l / 2, std::fmin(y + delta_y, y), arc_l, fabs(delta_y)), (scene.driver_pose_sins[0]>0 ? 0 : 180) * 16, 180 * 16); + + painter.restore(); +} + +void AnnotatedCameraWidgetSP::rocketFuel(QPainter &p) { + + static const int ct_n = 1; + static float ct; + + int rect_w = rect().width(); + int rect_h = rect().height(); + + const int n = 15 + 1; //Add one off screen due to timing issues + static float t[n]; + int dim_n = (sin(ct / 5) + 1) * (n - 0.01); + t[dim_n] = 1.0; + t[(int)(ct/ct_n)] = 1.0; + + UIStateSP *s = uiStateSP(); + float vc_accel0 = (*s->sm)["carState"].getCarState().getAEgo(); + static float vc_accel; + vc_accel = vc_accel + (vc_accel0 - vc_accel) / 5; + float hha = 0; + if (vc_accel > 0) { + hha = 0.85 - 0.1 / vc_accel; // only extend up to 85% + p.setBrush(QColor(0, 245, 0, 200)); + } + if (vc_accel < 0) { + hha = 0.85 + 0.1 / vc_accel; // only extend up to 85% + p.setBrush(QColor(245, 0, 0, 200)); + } + if (hha < 0) { + hha = 0; + } + hha = hha * rect_h; + float wp = 28; + if (vc_accel > 0) { + QRect ra = QRect(rect_w - wp, rect_h / 2 - hha / 2, wp, hha / 2); + p.drawRect(ra); + } else { + QRect ra = QRect(rect_w - wp, rect_h / 2, wp, hha / 2); + p.drawRect(ra); + } +} + +void AnnotatedCameraWidgetSP::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, + int num, const cereal::CarState::Reader &car_data, int chevron_data) { + painter.save(); + + const float speedBuff = 10.; + const float leadBuff = 40.; + const float d_rel = lead_data.getDRel(); + const float v_rel = lead_data.getVRel(); + const float v_ego = car_data.getVEgo(); + + float fillAlpha = 0; + if (d_rel < leadBuff) { + fillAlpha = 255 * (1.0 - (d_rel / leadBuff)); + if (v_rel < 0) { + fillAlpha += 255 * (-1 * (v_rel / speedBuff)); + } + fillAlpha = (int)(fmin(fillAlpha, 255)); + } + + float sz = std::clamp((25 * 30) / (d_rel / 3 + 30), 15.0f, 30.0f) * 2.35; + float x = std::clamp((float)vd.x(), 0.f, width() - sz / 2); + float y = std::fmin(height() - sz * .6, (float)vd.y()); + + float g_xo = sz / 5; + float g_yo = sz / 10; + + QPointF glow[] = {{x + (sz * 1.35) + g_xo, y + sz + g_yo}, {x, y - g_yo}, {x - (sz * 1.35) - g_xo, y + sz + g_yo}}; + painter.setBrush(QColor(218, 202, 37, 255)); + painter.drawPolygon(glow, std::size(glow)); + + // chevron + QPointF chevron[] = {{x + (sz * 1.25), y + sz}, {x, y}, {x - (sz * 1.25), y + sz}}; + painter.setBrush(redColor(fillAlpha)); + painter.drawPolygon(chevron, std::size(chevron)); + + if (num == 0) { // Display metrics to the 0th lead car + const int chevron_types = 3; + const int chevron_all = chevron_types + 1; // All metrics + QStringList chevron_text[chevron_types]; + int position; + float val; + if (chevron_data == 1 || chevron_data == chevron_all) { + position = 0; + val = std::max(0.0f, d_rel); + chevron_text[position].append(QString::number(val,'f', 0) + " " + "m"); + } + if (chevron_data == 2 || chevron_data == chevron_all) { + position = (chevron_data == 2) ? 0 : 1; + val = std::max(0.0f, (v_rel + v_ego) * (is_metric ? static_cast(MS_TO_KPH) : static_cast(MS_TO_MPH))); + chevron_text[position].append(QString::number(val,'f', 0) + " " + (is_metric ? "km/h" : "mph")); + } + if (chevron_data == 3 || chevron_data == chevron_all) { + position = (chevron_data == 3) ? 0 : 2; + val = (d_rel > 0 && v_ego > 0) ? std::max(0.0f, d_rel / v_ego) : 0.0f; + + QString ttc_str = (val > 0 && val < 200) ? QString::number(val, 'f', 1) + "s" : "---"; + chevron_text[position].append(ttc_str); + } + + float str_w = 200; // Width of the text box, might need adjustment + float str_h = 50; // Height of the text box, adjust as necessary + painter.setFont(InterFont(45, QFont::Bold)); + // Calculate the center of the chevron and adjust the text box position + float text_y = y + sz + 12; // Position the text at the bottom of the chevron + QRect textRect(x - str_w / 2, text_y, str_w, str_h); // Adjust the rectangle to center the text horizontally at the chevron's bottom + QPoint shadow_offset(2, 2); + for (int i = 0; i < chevron_types; ++i) { + if (!chevron_text[i].isEmpty()) { + painter.setPen(QColor(0x0, 0x0, 0x0, 200)); // Draw shadow + painter.drawText(textRect.translated(shadow_offset.x(), shadow_offset.y() + i * str_h), Qt::AlignBottom | Qt::AlignHCenter, chevron_text[i].at(0)); + painter.setPen(QColor(0xff, 0xff, 0xff)); // Draw text + painter.drawText(textRect.translated(0, i * str_h), Qt::AlignBottom | Qt::AlignHCenter, chevron_text[i].at(0)); + painter.setPen(Qt::NoPen); // Reset pen to default + } + } + } + + painter.restore(); +} + +void AnnotatedCameraWidgetSP::paintGL() { + UIStateSP *s = uiStateSP(); + SubMaster &sm = *(s->sm); + const double start_draw_t = millis_since_boot(); + const cereal::ModelDataV2::Reader &model = sm["modelV2"].getModelV2(); + + // draw camera frame + { + std::lock_guard lk(frame_lock); + + if (frames.empty()) { + if (skip_frame_count > 0) { + skip_frame_count--; + qDebug() << "skipping frame, not ready"; + return; + } + } else { + // skip drawing up to this many frames if we're + // missing camera frames. this smooths out the + // transitions from the narrow and wide cameras + skip_frame_count = 5; + } + + // Wide or narrow cam dependent on speed + bool has_wide_cam = available_streams.count(VISION_STREAM_WIDE_ROAD); + if (has_wide_cam) { + float v_ego = sm["carState"].getCarState().getVEgo(); + float steer_angle = sm["carState"].getCarState().getSteeringAngleDeg(); + if ((v_ego < 10) || available_streams.size() == 1 || (std::fabs(steer_angle) > 45)) { + wide_cam_requested = true; + } else if ((v_ego > 15) && (std::fabs(steer_angle) < 30)) { + wide_cam_requested = false; + } + wide_cam_requested = wide_cam_requested && sm["controlsState"].getControlsState().getExperimentalMode(); + // for replay of old routes, never go to widecam + wide_cam_requested = wide_cam_requested && s->scene.calibration_wide_valid; + } + CameraWidget::setStreamType(wide_cam_requested ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD); + + if (reversing && s->scene.reverse_dm_cam) { + CameraWidget::setStreamType(VISION_STREAM_DRIVER, s->scene.reverse_dm_cam); + } + + s->scene.wide_cam = CameraWidget::getStreamType() == VISION_STREAM_WIDE_ROAD; + if (s->scene.calibration_valid) { + auto calib = s->scene.wide_cam ? s->scene.view_from_wide_calib : s->scene.view_from_calib; + CameraWidget::updateCalibration(calib); + } else { + CameraWidget::updateCalibration(DEFAULT_CALIBRATION); + } + CameraWidget::setFrameId(model.getFrameId()); + CameraWidget::paintGL(); + } + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(Qt::NoPen); + + if (s->scene.world_objects_visible) { + sp_update_model(s, model); + drawLaneLines(painter, s); + + if (s->scene.longitudinal_control && sm.rcv_frame("radarState") > s->scene.started_frame) { + auto radar_state = sm["radarState"].getRadarState(); + auto car_state = sm["carState"].getCarState(); + update_leads(s, radar_state, model.getPosition()); + auto lead_one = radar_state.getLeadOne(); + auto lead_two = radar_state.getLeadTwo(); + if (lead_one.getStatus()) { + drawLead(painter, lead_one, s->scene.lead_vertices[0], 0, car_state, s->scene.chevron_data); + } + if (lead_two.getStatus() && (std::abs(lead_one.getDRel() - lead_two.getDRel()) > 3.0)) { + drawLead(painter, lead_two, s->scene.lead_vertices[1], 1, car_state, s->scene.chevron_data); + } + + rocketFuel(painter); + } + } + + // DMoji + if (!hideBottomIcons && (sm.rcv_frame("driverStateV2") > s->scene.started_frame)) { + update_dmonitoring(s, sm["driverStateV2"].getDriverStateV2(), dm_fade_state, rightHandDM); + drawDriverState(painter, s); + } + + drawHud(painter); + + if (left_blinker || right_blinker) { + blinker_frame++; + int state = blinkerPulse(blinker_frame); + int blinker_x = splitPanelVisible ? 150 : 180; + int blinker_y = splitPanelVisible ? 220 : 90; + if (left_blinker) { + drawLeftTurnSignal(painter, rect().center().x() - (blinker_x + blinker_size), blinker_y, blinker_size, state); + } + if (right_blinker) { + drawRightTurnSignal(painter, rect().center().x() + blinker_x, blinker_y, blinker_size, state); + } + } else { + blinker_frame = 0; + } + + double cur_draw_t = millis_since_boot(); + double dt = cur_draw_t - prev_draw_t; + double fps = fps_filter.update(1. / dt * 1000); + if (fps < 15) { + LOGW("slow frame rate: %.2f fps", fps); + } + prev_draw_t = cur_draw_t; + + // publish debug msg + MessageBuilder msg; + auto m = msg.initEvent().initUiDebug(); + m.setDrawTimeMillis(cur_draw_t - start_draw_t); + pm->send("uiDebug", msg); + + MessageBuilder e2e_long_msg; + auto e2eLongStatus = e2e_long_msg.initEvent().initE2eLongStateSP(); + e2eLongStatus.setStatus(e2eStatus); + e2e_state->send("e2eLongStateSP", e2e_long_msg); +} + +void AnnotatedCameraWidgetSP::showEvent(QShowEvent *event) { + CameraWidget::showEvent(event); + + sp_ui_update_params(uiStateSP()); + prev_draw_t = millis_since_boot(); +} diff --git a/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h b/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h new file mode 100644 index 0000000000..92bf5056b3 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h @@ -0,0 +1,230 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include +#include + +#include "selfdrive/ui/qt/onroad/buttons.h" +#include "selfdrive/ui/qt/widgets/cameraview.h" +#include "selfdrive/ui/sunnypilot/qt/onroad/buttons.h" +#include "selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.h" + +const int subsign_img_size = 35; +const int blinker_size = 120; + +class AnnotatedCameraWidgetSP : public CameraWidget { + Q_OBJECT + +public: + explicit AnnotatedCameraWidgetSP(VisionStreamType type, QWidget* parent = 0); + void updateState(const UIStateSP &s); + + MapSettingsButton *map_settings_btn; + OnroadSettingsButton *onroad_settings_btn; + +private: + void drawText(QPainter &p, int x, int y, const QString &text, int alpha = 255); + void drawCenteredText(QPainter &p, int x, int y, const QString &text, QColor color); + void drawVisionTurnControllerUI(QPainter &p, int x, int y, int size, const QColor &color, const QString &speed, + int alpha); + void drawCircle(QPainter &p, int x, int y, int r, QBrush bg); + void drawSpeedSign(QPainter &p, QRect rc, const QString &speed, const QString &sub_text, int subtext_size, + bool is_map_sourced, bool is_active); + void drawTrunSpeedSign(QPainter &p, QRect rc, const QString &speed, const QString &sub_text, int curv_sign, + bool is_active); + + void drawColoredText(QPainter &p, int x, int y, const QString &text, QColor color); + void drawStandstillTimer(QPainter &p, int x, int y); + + // ############################## DEV UI START ############################## + void drawRightDevUi(QPainter &p, int x, int y); + int drawDevUiRight(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color); + int drawNewDevUi(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color); + void drawNewDevUi2(QPainter &p, int x, int y); + void drawCenteredLeftText(QPainter &p, int x, int y, const QString &text1, QColor color1, const QString &text2, const QString &text3, QColor color2); + + // ############################## DEV UI END ############################## + + void drawE2eStatus(QPainter &p, int x, int y, int w, int h, int e2e_long_status); + + void drawLeftTurnSignal(QPainter &painter, int x, int y, int circle_size, int state); + void drawRightTurnSignal(QPainter &painter, int x, int y, int circle_size, int state); + int blinkerPulse(int frame); + void updateButtonsLayout(bool is_rhd); + + void drawFeatureStatusText(QPainter &p, int x, int y); + void speedLimitSignPulse(int frame); + void speedLimitWarning(QPainter &p, QRect sign_rect, const int sign_margin); + void mousePressEvent(QMouseEvent* e) override; + void drawRoadNameText(QPainter &p, int x, int y, const QString &text, QColor color); + + QVBoxLayout *main_layout; + ExperimentalButtonSP *experimental_btn; + QPixmap dm_img; + float speed; + QString speedUnit; + float setSpeed; + float speedLimit; + bool is_cruise_set = false; + bool is_metric = false; + bool dmActive = false; + bool hideBottomIcons = false; + bool rightHandDM = false; + float dm_fade_state = 1.0; + bool has_us_speed_limit = false; + bool has_eu_speed_limit = false; + bool v_ego_cluster_seen = false; + int status = STATUS_DISENGAGED; + std::unique_ptr pm; + + int skip_frame_count = 0; + bool wide_cam_requested = false; + + Params params; + QHBoxLayout *buttons_layout; + QPixmap map_img; + QPixmap left_img; + QPixmap right_img; + bool left_blindspot = false; + bool right_blindspot = false; + std::unique_ptr e2e_state; + + bool steerOverride = false; + bool gasOverride = false; + bool latActive = false; + bool madsEnabled = false; + + bool brakeLights; + + bool standStillTimer; + bool standStill; + float standstillElapsedTime; + + bool showVTC = false; + QString vtcSpeed; + QColor vtcColor; + + bool showDebugUI = false; + + QString roadName = ""; + + bool showSpeedLimit = false; + float speedLimitSLC; + float speedLimitSLCOffset; + float speedLimitWarningOffset; + QString slcSubText; + float slcSubTextSize = 0.0; + bool overSpeedLimit; + bool mapSourcedSpeedLimit = false; + bool slcActive = false; + + bool showTurnSpeedLimit = false; + QString turnSpeedLimit; + QString tscSubText; + bool tscActive = false; + int curveSign = 0; + + bool hideVEgoUi; + + bool splitPanelVisible; + + // ############################## DEV UI START ############################## + bool lead_status; + float lead_d_rel = 0; + float lead_v_rel = 0; + QString lateralState; + float angleSteers = 0; + float steerAngleDesired = 0; + float curvature; + float roll; + int memoryUsagePercent; + int devUiInfo; + float gpsAccuracy; + float altitude; + float vEgo; + float aEgo; + float steeringTorqueEps; + float bearingAccuracyDeg; + float bearingDeg; + bool torquedUseParams; + float latAccelFactorFiltered; + float frictionCoefficientFiltered; + bool liveValid; + // ############################## DEV UI END ############################## + + float btnPerc; + + bool reversing; + + int e2eState; + int e2eStatus; + + bool left_blinker, right_blinker, lane_change_edge_block; + int blinker_frame; + int blinker_state = 0; + + cereal::LongitudinalPlanSP::SpeedLimitControlState slcState; + int longitudinalPersonality; + int dynamicLaneProfile; + QString mpcMode; + + int speed_limit_frame; + bool slcShowSign = true; + QPixmap plus_arrow_up_img; + QPixmap minus_arrow_down_img; + QRect sl_sign_rect; + int rn_offset = 0; + bool e2eLongAlertUi, dynamicExperimentalControlToggle, speedLimitControlToggle, speedLimitWarningFlash; + cereal::CarParams::Reader car_params; + bool cruiseStateEnabled; + bool experimentalMode; + + bool featureStatusToggle; + + cereal::ModelGeneration drivingModelGen; + +protected: + void paintGL() override; + void initializeGL() override; + void showEvent(QShowEvent *event) override; + void updateFrameMat() override; + void drawLaneLines(QPainter &painter, const UIStateSP *s); + void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, + int num, const cereal::CarState::Reader &car_data, int chevron_data); + void drawHud(QPainter &p); + void drawDriverState(QPainter &painter, const UIStateSP *s); + inline QColor redColor(int alpha = 255) { return QColor(201, 34, 49, alpha); } + inline QColor whiteColor(int alpha = 255) { return QColor(255, 255, 255, alpha); } + inline QColor blackColor(int alpha = 255) { return QColor(0, 0, 0, alpha); } + + void rocketFuel(QPainter &p); + + double prev_draw_t = 0; + FirstOrderFilter fps_filter; +}; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/buttons.cc b/selfdrive/ui/sunnypilot/qt/onroad/buttons.cc new file mode 100644 index 0000000000..3a4fe68695 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/onroad/buttons.cc @@ -0,0 +1,96 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/onroad/buttons.h" + +#include "selfdrive/ui/qt/util.h" + +static void drawCustomButtonIcon(QPainter &p, const int btn_size_x, const int btn_size_y, const QPixmap &img, const QBrush &bg, float opacity) { + QPoint center(btn_size_x / 2, btn_size_y / 2); + p.setRenderHint(QPainter::Antialiasing); + p.setOpacity(1.0); // bg dictates opacity of ellipse + p.setPen(Qt::NoPen); + p.setBrush(bg); + p.drawEllipse(center, btn_size_x / 2, btn_size_y / 2); + p.setOpacity(opacity); + p.drawPixmap(center - QPoint(img.width() / 2, img.height() / 2), img); + p.setOpacity(1.0); +} + +// ExperimentalButtonSP +void ExperimentalButtonSP::updateState(const UIStateSP &s) { + const auto cs = (*s.sm)["controlsState"].getControlsState(); + bool eng = cs.getEngageable() || cs.getEnabled(); + if ((cs.getExperimentalMode() != experimental_mode) || (eng != engageable)) { + engageable = eng; + experimental_mode = cs.getExperimentalMode(); + update(); + } +} + + +// OnroadSettingsButton +OnroadSettingsButton::OnroadSettingsButton(QWidget *parent) : QPushButton(parent) { + // btn_size: 192 * 80% ~= 152 + // img_size: (152 / 4) * 3 = 114 + setFixedSize(152, 152); + settings_img = loadPixmap("../assets/navigation/icon_settings.svg", {114, 114}); + + // hidden by default, made visible if Driving Personality / GAC, DLP, DEC, or SLC is enabled + setVisible(false); + setEnabled(false); +} + +void OnroadSettingsButton::paintEvent(QPaintEvent *event) { + QPainter p(this); + drawCustomButtonIcon(p, 152, 152, settings_img, QColor(0, 0, 0, 166), isDown() ? 0.6 : 1.0); +} + +void OnroadSettingsButton::updateState(const UIStateSP &s) { + const auto cp = (*s.sm)["carParams"].getCarParams(); + auto dlp_enabled = s.scene.driving_model_generation == cereal::ModelGeneration::ONE; + bool allow_btn = s.scene.onroad_settings_toggle && (dlp_enabled || hasLongitudinalControl(cp) || !cp.getPcmCruiseSpeed()); + + setVisible(allow_btn); + setEnabled(allow_btn); +} + +// MapSettingsButton +MapSettingsButton::MapSettingsButton(QWidget *parent) : QPushButton(parent) { + // btn_size: 192 * 80% ~= 152 + // img_size: (152 / 4) * 3 = 114 + setFixedSize(152, 152); + settings_img = loadPixmap("../assets/navigation/icon_directions_outlined.svg", {114, 114}); + + // hidden by default, made visible if map is created (has prime or mapbox token) + setVisible(false); + setEnabled(false); +} + +void MapSettingsButton::paintEvent(QPaintEvent *event) { + QPainter p(this); + drawCustomButtonIcon(p, 152, 152, settings_img, QColor(0, 0, 0, 166), isDown() ? 0.6 : 1.0); +} diff --git a/selfdrive/ui/sunnypilot/qt/onroad/buttons.h b/selfdrive/ui/sunnypilot/qt/onroad/buttons.h new file mode 100644 index 0000000000..055f3dab32 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/onroad/buttons.h @@ -0,0 +1,68 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include "selfdrive/ui/qt/onroad/buttons.h" + +#include "selfdrive/ui/sunnypilot/ui.h" + +#include "selfdrive/ui/ui.h" + +class ExperimentalButtonSP : public ExperimentalButton { + Q_OBJECT + +public: + explicit ExperimentalButtonSP(QWidget *parent = 0) : ExperimentalButton(parent) {}; + void updateState(const UIStateSP &s); +}; + +class OnroadSettingsButton : public QPushButton { + Q_OBJECT + +public: + explicit OnroadSettingsButton(QWidget *parent = 0); + void updateState(const UIStateSP &s); + +private: + void paintEvent(QPaintEvent *event) override; + + QPixmap settings_img; +}; + + +class MapSettingsButton : public QPushButton { + Q_OBJECT + +public: + explicit MapSettingsButton(QWidget *parent = 0); + +private: + void paintEvent(QPaintEvent *event) override; + + QPixmap settings_img; +}; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.cc b/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.cc new file mode 100644 index 0000000000..dd22ebdcb8 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.cc @@ -0,0 +1,224 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.h" + +#include + +#include "common/util.h" + +// ********** metrics ********** + +// Add Relative Distance to Primary Lead Car +// Unit: Meters +UiElement DeveloperUi::getDRel(bool lead_status, float lead_d_rel) { + QString value = lead_status ? QString::number(lead_d_rel, 'f', 0) : "-"; + QColor color = QColor(255, 255, 255, 255); + + if (lead_status) { + // Orange if close, Red if very close + if (lead_d_rel < 5) { + color = QColor(255, 0, 0, 255); + } else if (lead_d_rel < 15) { + color = QColor(255, 188, 0, 255); + } + } + + return UiElement(value, "REL DIST", "m", color); +} + +// Add Relative Velocity vs Primary Lead Car +// Unit: kph if metric, else mph +UiElement DeveloperUi::getVRel(bool lead_status, float lead_v_rel, bool is_metric, const QString &speed_unit) { + QString value = lead_status ? QString::number(lead_v_rel * (is_metric ? MS_TO_KPH : MS_TO_MPH), 'f', 0) : "-"; + QColor color = QColor(255, 255, 255, 255); + + if (lead_status) { + // Red if approaching faster than 10mph + // Orange if approaching (negative) + if (lead_v_rel < -4.4704) { + color = QColor(255, 0, 0, 255); + } else if (lead_v_rel < 0) { + color = QColor(255, 188, 0, 255); + } + } + + return UiElement(value, "REL SPEED", speed_unit, color); +} + +// Add Real Steering Angle +// Unit: Degrees +UiElement DeveloperUi::getSteeringAngleDeg(float angle_steers, bool mads_enabled, bool lat_active) { + QString value = QString("%1%2%3").arg(QString::number(angle_steers, 'f', 1)).arg("°").arg(""); + QColor color = (mads_enabled && lat_active) ? QColor(0, 255, 0, 255) : QColor(255, 255, 255, 255); + + // Red if large steering angle + // Orange if moderate steering angle + if (std::fabs(angle_steers) > 180) { + color = QColor(255, 0, 0, 255); + } else if (std::fabs(angle_steers) > 90) { + color = QColor(255, 188, 0, 255); + } + + return UiElement(value, "REAL STEER", "", color); +} + +// Add Actual Lateral Acceleration (roll compensated) when using Torque +// Unit: m/s² +UiElement DeveloperUi::getActualLateralAccel(float curvature, float v_ego, float roll, bool mads_enabled, bool lat_active) { + double actualLateralAccel = (curvature * pow(v_ego, 2)) - (roll * 9.81); + + QString value = QString::number(actualLateralAccel, 'f', 2); + QColor color = (mads_enabled && lat_active) ? QColor(0, 255, 0, 255) : QColor(255, 255, 255, 255); + + return UiElement(value, "ACTUAL LAT", "m/s²", color); +} + +// Add Desired Steering Angle when using PID +// Unit: Degrees +UiElement DeveloperUi::getSteeringAngleDesiredDeg(bool mads_enabled, bool lat_active, float steer_angle_desired, float angle_steers) { + QString value = (mads_enabled && lat_active) ? QString("%1%2%3").arg(QString::number(steer_angle_desired, 'f', 1)).arg("°").arg("") : "-"; + QColor color = QColor(255, 255, 255, 255); + + if (mads_enabled && lat_active) { + // Red if large steering angle + // Orange if moderate steering angle + if (std::fabs(angle_steers) > 180) { + color = QColor(255, 0, 0, 255); + } else if (std::fabs(angle_steers) > 90) { + color = QColor(255, 188, 0, 255); + } else { + color = QColor(0, 255, 0, 255); + } + } + + return UiElement(value, "DESIRED STEER", "", color); +} + +// Add Device Memory (RAM) Usage +// Unit: Percent +UiElement DeveloperUi::getMemoryUsagePercent(int memory_usage_percent) { + QString value = QString("%1%2").arg(QString::number(memory_usage_percent, 'd', 0)).arg("%"); + QColor color = (memory_usage_percent > 85) ? QColor(255, 188, 0, 255) : QColor(255, 255, 255, 255); + + return UiElement(value, "RAM", "", color); +} + +// Add Vehicle Current Acceleration +// Unit: m/s² +UiElement DeveloperUi::getAEgo(float a_ego) { + QString value = QString::number(a_ego, 'f', 1); + QColor color = QColor(255, 255, 255, 255); + + return UiElement(value, "ACC.", "m/s²", color); +} + +// Add Relative Velocity to Primary Lead Car +// Unit: kph if metric, else mph +UiElement DeveloperUi::getVEgoLead(bool lead_status, float lead_v_rel, float v_ego, bool is_metric, const QString &speed_unit) { + QString value = lead_status ? QString::number((lead_v_rel + v_ego) * (is_metric ? MS_TO_KPH : MS_TO_MPH), 'f', 0) : "-"; + QColor color = QColor(255, 255, 255, 255); + + if (lead_status) { + // Red if approaching faster than 10mph + // Orange if approaching (negative) + if (lead_v_rel < -4.4704) { + color = QColor(255, 0, 0, 255); + } else if (lead_v_rel < 0) { + color = QColor(255, 188, 0, 255); + } + } + + return UiElement(value, "L.S.", speed_unit, color); +} + +// Add Friction Coefficient Raw from torqued +// Unit: None +UiElement DeveloperUi::getFrictionCoefficientFiltered(float friction_coefficient_filtered, bool live_valid) { + QString value = QString::number(friction_coefficient_filtered, 'f', 3); + QColor color = live_valid ? QColor(0, 255, 0, 255) : QColor(255, 255, 255, 255); + + return UiElement(value, "FRIC.", "", color); +} + +// Add Lateral Acceleration Factor Raw from torqued +// Unit: m/s² +UiElement DeveloperUi::getLatAccelFactorFiltered(float lat_accel_factor_filtered, bool live_valid) { + QString value = QString::number(lat_accel_factor_filtered, 'f', 3); + QColor color = live_valid ? QColor(0, 255, 0, 255) : QColor(255, 255, 255, 255); + + return UiElement(value, "L.A.", "m/s²", color); +} + +// Add Steering Torque from Car EPS +// Unit: Newton Meters +UiElement DeveloperUi::getSteeringTorqueEps(float steering_torque_eps) { + QString value = QString::number(std::fabs(steering_torque_eps), 'f', 1); + QColor color = QColor(255, 255, 255, 255); + + return UiElement(value, "E.T.", "N·dm", color); +} + +// Add Bearing Degree and Direction from Car (Compass) +// Unit: Meters +UiElement DeveloperUi::getBearingDeg(float bearing_accuracy_deg, float bearing_deg) { + QString value = (bearing_accuracy_deg != 180.00) ? QString("%1%2%3").arg(QString::number(bearing_deg, 'd', 0)).arg("°").arg("") : "-"; + QColor color = QColor(255, 255, 255, 255); + QString dir_value; + + if (bearing_accuracy_deg != 180.00) { + if (((bearing_deg >= 337.5) && (bearing_deg <= 360)) || ((bearing_deg >= 0) && (bearing_deg <= 22.5))) { + dir_value = "N"; + } else if ((bearing_deg > 22.5) && (bearing_deg < 67.5)) { + dir_value = "NE"; + } else if ((bearing_deg >= 67.5) && (bearing_deg <= 112.5)) { + dir_value = "E"; + } else if ((bearing_deg > 112.5) && (bearing_deg < 157.5)) { + dir_value = "SE"; + } else if ((bearing_deg >= 157.5) && (bearing_deg <= 202.5)) { + dir_value = "S"; + } else if ((bearing_deg > 202.5) && (bearing_deg < 247.5)) { + dir_value = "SW"; + } else if ((bearing_deg >= 247.5) && (bearing_deg <= 292.5)) { + dir_value = "W"; + } else if ((bearing_deg > 292.5) && (bearing_deg < 337.5)) { + dir_value = "NW"; + } + } else { + dir_value = "OFF"; + } + + return UiElement(QString("%1 | %2").arg(dir_value).arg(value), "B.D.", "", color); +} + +// Add Altitude of Current Location +// Unit: Meters +UiElement DeveloperUi::getAltitude(float gps_accuracy, float altitude) { + QString value = (gps_accuracy != 0.00) ? QString::number(altitude, 'f', 1) : "-"; + QColor color = QColor(255, 255, 255, 255); + + return UiElement(value, "ALT.", "m", color); +} diff --git a/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.h b/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.h new file mode 100644 index 0000000000..2cb9b9a76a --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.h @@ -0,0 +1,46 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include "selfdrive/ui/sunnypilot/qt/onroad/developer_ui/ui_elements.h" + +class DeveloperUi { +public: + static UiElement getDRel(bool lead_status, float lead_d_rel); + static UiElement getVRel(bool lead_status, float lead_v_rel, bool is_metric, const QString &speed_unit); + static UiElement getSteeringAngleDeg(float angle_steers, bool mads_enabled, bool lat_active); + static UiElement getActualLateralAccel(float curvature, float v_ego, float roll, bool mads_enabled, bool lat_active); + static UiElement getSteeringAngleDesiredDeg(bool mads_enabled, bool lat_active, float steer_angle_desired, float angle_steers); + static UiElement getMemoryUsagePercent(int memory_usage_percent); + static UiElement getAEgo(float a_ego); + static UiElement getVEgoLead(bool lead_status, float lead_v_rel, float v_ego, bool is_metric, const QString &speed_unit); + static UiElement getFrictionCoefficientFiltered(float friction_coefficient_filtered, bool live_valid); + static UiElement getLatAccelFactorFiltered(float lat_accel_factor_filtered, bool live_valid); + static UiElement getSteeringTorqueEps(float steering_torque_eps); + static UiElement getBearingDeg(float bearing_accuracy_deg, float bearing_deg); + static UiElement getAltitude(float gps_accuracy, float altitude); +}; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/ui_elements.h b/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/ui_elements.h new file mode 100644 index 0000000000..3910c83022 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/onroad/developer_ui/ui_elements.h @@ -0,0 +1,39 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include + +struct UiElement { + QString value{}; + QString label{}; + QString units{}; + QColor color{}; + + explicit UiElement(const QString &value = "", const QString &label = "", const QString &units = "", const QColor &color = QColor(255, 255, 255, 255)) + : value(value), label(label), units(units), color(color) {} +}; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/onroad_home.cc b/selfdrive/ui/sunnypilot/qt/onroad/onroad_home.cc new file mode 100644 index 0000000000..a7acf4865c --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/onroad/onroad_home.cc @@ -0,0 +1,163 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/onroad/onroad_home.h" + + +#ifdef ENABLE_MAPS +#include "selfdrive/ui/sunnypilot/qt/maps/map_helpers.h" +#include "selfdrive/ui/qt/maps/map_panel.h" +#endif +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/onroad/onroad_settings_panel.h" +#endif + +#include "common/swaglog.h" +#include "selfdrive/ui/qt/util.h" + +OnroadWindowSP::OnroadWindowSP(QWidget *parent) : OnroadWindow(parent) { + // QObject::disconnect(uiState(), &UIState::uiUpdate, this, &OnroadWindow::updateState); + // QObject::disconnect(uiState(), &UIState::offroadTransition, this, &OnroadWindow::offroadTransition); + + if (getenv("MAP_RENDER_VIEW")) { + CameraWidget *map_render = new CameraWidget("navd", VISION_STREAM_MAP, false, this); + split->insertWidget(0, map_render); //TODO: We MIGHT to override the split variable because it is added on onroad_home.cc and we need to access it before. I am not sure so we will need to test it before + } + QObject::connect(uiStateSP(), &UIStateSP::uiUpdate, this, &OnroadWindowSP::updateState); + QObject::connect(uiStateSP(), &UIStateSP::offroadTransition, this, &OnroadWindowSP::offroadTransition); +} + +void OnroadWindowSP::updateState(const UIStateSP &s) { + if (!s.scene.started) { + return; + } + + if (s.scene.map_on_left || s.scene.mapbox_fullscreen) { + split->setDirection(QBoxLayout::LeftToRight); + } else { + split->setDirection(QBoxLayout::RightToLeft); + } + + OnroadWindow::updateState(s); // Carry on with the parent class updateState method +} + + +void OnroadWindowSP::mousePressEvent(QMouseEvent* e) { +#ifdef ENABLE_MAPS + UIStateSP *s = uiStateSP(); + UISceneSP &scene = s->scene; + if (map != nullptr && !isOnroadSettingsVisible()) { + if (wakeScreenTimeout()) { + // Switch between map and sidebar when using navigate on openpilot + bool sidebarVisible = geometry().x() > 0; + bool show_map = uiStateSP()->scene.navigate_on_openpilot_deprecated ? sidebarVisible : !sidebarVisible; + updateMapSize(scene); + map->setVisible(show_map && !map->isVisible()); + } + } +#endif + if (onroad_settings != nullptr && !isMapVisible()) { + if (wakeScreenTimeout()) { + onroad_settings->setVisible(false); + } + } + // propagation event to parent(HomeWindow) + QWidget::mousePressEvent(e); +} + +void OnroadWindowSP::createMapWidget() { +#ifdef ENABLE_MAPS + LOGD("Creating map widget"); + auto m = new MapPanel(get_mapbox_settings()); + map = m; + + QObject::connect(m, &MapPanel::mapPanelRequested, this, &OnroadWindowSP::mapPanelRequested); + QObject::connect(m, &MapPanel::mapPanelRequested, this, &OnroadWindowSP::onroadSettingsPanelNotRequested); + QObject::connect(nvg->map_settings_btn, &MapSettingsButton::clicked, m, &MapPanel::toggleMapSettings); + nvg->map_settings_btn->setEnabled(true); + + m->setFixedWidth(uiStateSP()->scene.mapbox_fullscreen ? topWidget(this)->width() : + topWidget(this)->width() / 2 - UI_BORDER_SIZE); + split->insertWidget(0, m); + + // hidden by default, made visible when navRoute is published + m->setVisible(false); +#endif +} + +void OnroadWindowSP::createOnroadSettingsWidget() { + auto os = new OnroadSettingsPanel(this); + onroad_settings = os; + + QObject::connect(os, &OnroadSettingsPanel::onroadSettingsPanelRequested, this, &OnroadWindowSP::onroadSettingsPanelRequested); + QObject::connect(os, &OnroadSettingsPanel::onroadSettingsPanelRequested, this, &OnroadWindowSP::mapPanelNotRequested); + QObject::connect(nvg->onroad_settings_btn, &OnroadSettingsButton::clicked, os, &OnroadSettingsPanel::toggleOnroadSettings); + nvg->onroad_settings_btn->setEnabled(true); + + os->setFixedWidth(topWidget(this)->width() / 2.6 - UI_BORDER_SIZE); + split->insertWidget(0, os); + + // hidden by default + os->setVisible(false); +} + +void OnroadWindowSP::offroadTransition(bool offroad) { + + if (!offroad) { +#ifdef ENABLE_MAPS + LOGD("We'd like to create the map widget, the condition is map is [%s] and hasPrime is [%s] and MAPBOX_TOKEN is [%s]", map == nullptr ? "null" : "not null", uiStateSP()->hasPrime() ? "true" : "false", MAPBOX_TOKEN.isEmpty() ? "empty" : "not empty"); + if (map == nullptr && (uiStateSP()->hasPrime() || !MAPBOX_TOKEN.isEmpty())) { + createMapWidget(); + } +#else + LOGD("Maps are disabled"); +#endif + if (onroad_settings == nullptr) { + createOnroadSettingsWidget(); + } + } + + OnroadWindow::offroadTransition(offroad); // Carry on with the parent class offroadTransition method +} + +void OnroadWindowSP::updateMapSize(const UISceneSP &scene) { + map->setFixedWidth(scene.mapbox_fullscreen ? topWidget(this)->width() : + topWidget(this)->width() / 2 - UI_BORDER_SIZE); + split->insertWidget(0, map); +} + +void OnroadWindowSP::primeChanged(bool prime) { +#ifdef ENABLE_MAPS + if (map && (!prime && MAPBOX_TOKEN.isEmpty())) { + nvg->map_settings_btn->setEnabled(false); + nvg->map_settings_btn->setVisible(false); + map->deleteLater(); + map = nullptr; + } else if (!map && (prime || !MAPBOX_TOKEN.isEmpty())) { + createMapWidget(); + } +#endif +} diff --git a/selfdrive/ui/sunnypilot/qt/onroad/onroad_home.h b/selfdrive/ui/sunnypilot/qt/onroad/onroad_home.h new file mode 100644 index 0000000000..121c0ba75d --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/onroad/onroad_home.h @@ -0,0 +1,72 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include "selfdrive/ui/qt/onroad/onroad_home.h" + +#include "common/params.h" + +class OnroadWindowSP : public OnroadWindow { + Q_OBJECT + +public: + OnroadWindowSP(QWidget* parent = 0); + bool isMapVisible() const { return map && map->isVisible(); } + void showMapPanel(bool show) { if (map) map->setVisible(show); } + + bool isOnroadSettingsVisible() const { return onroad_settings && onroad_settings->isVisible(); } + bool isMapAvailable() const { return map; } + void mapPanelNotRequested() { if (map) map->setVisible(false); } + void onroadSettingsPanelNotRequested() { if (onroad_settings) onroad_settings->setVisible(false); } + + bool wakeScreenTimeout() { + if ((uiStateSP()->scene.sleep_btn != 0 && uiStateSP()->scene.sleep_btn_opacity != 0) || + (uiStateSP()->scene.sleep_time != 0 && uiStateSP()->scene.onroadScreenOff != -2)) { + return true; + } + return false; + } + +signals: + void mapPanelRequested(); + void onroadSettingsPanelRequested(); + +private: + void createMapWidget(); + void createOnroadSettingsWidget(); + void mousePressEvent(QMouseEvent* e) override; + QWidget *map = nullptr; + QWidget *onroad_settings = nullptr; + + Params params; + +protected slots: + void offroadTransition(bool offroad) override; + void updateState(const UIStateSP &s) override; + void primeChanged(bool prime); + void updateMapSize(const UISceneSP &scene); +}; diff --git a/selfdrive/ui/qt/onroad_settings.cc b/selfdrive/ui/sunnypilot/qt/onroad/onroad_settings.cc similarity index 86% rename from selfdrive/ui/qt/onroad_settings.cc rename to selfdrive/ui/sunnypilot/qt/onroad/onroad_settings.cc index 00810294ba..e886e4b43e 100644 --- a/selfdrive/ui/qt/onroad_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/onroad/onroad_settings.cc @@ -1,13 +1,40 @@ -#include "selfdrive/ui/qt/onroad_settings.h" +/** +The MIT License +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/onroad/onroad_settings.h" + +#include +#include #include #include -#include #include "common/util.h" -#include "selfdrive/ui/qt/widgets/scrollview.h" -#include "selfdrive/ui/qt/offroad/sunnypilot/speed_limit_policy_settings.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/speed_limit_policy_settings.h" OnroadSettings::OnroadSettings(bool closeable, QWidget *parent) : QFrame(parent) { setContentsMargins(0, 0, 0, 0); @@ -87,7 +114,7 @@ OnroadSettings::OnroadSettings(bool closeable, QWidget *parent) : QFrame(parent) options_layout->addStretch(); - ScrollView *options_scroller = new ScrollView(options_container, this); + ScrollViewSP *options_scroller = new ScrollViewSP(options_container, this); options_scroller->setFrameShape(QFrame::NoFrame); frame->addWidget(options_scroller); @@ -118,7 +145,7 @@ OnroadSettings::OnroadSettings(bool closeable, QWidget *parent) : QFrame(parent) } void OnroadSettings::changeDynamicLaneProfile() { - UIScene &scene = uiState()->scene; + UISceneSP &scene = uiStateSP()->scene; bool can_change = scene.driving_model_generation == cereal::ModelGeneration::ONE; if (can_change) { scene.dynamic_lane_profile++; @@ -129,8 +156,8 @@ void OnroadSettings::changeDynamicLaneProfile() { } void OnroadSettings::changeGapAdjustCruise() { - UIScene &scene = uiState()->scene; - const auto cp = (*uiState()->sm)["carParams"].getCarParams(); + UISceneSP &scene = uiStateSP()->scene; + const auto cp = (*uiStateSP()->sm)["carParams"].getCarParams(); bool can_change = hasLongitudinalControl(cp); if (can_change) { scene.longitudinal_personality--; @@ -141,8 +168,8 @@ void OnroadSettings::changeGapAdjustCruise() { } void OnroadSettings::changeAccelerationPersonality() { - UIScene &scene = uiState()->scene; - const auto cp = (*uiState()->sm)["carParams"].getCarParams(); + UISceneSP &scene = uiStateSP()->scene; + const auto cp = (*uiStateSP()->sm)["carParams"].getCarParams(); bool can_change = hasLongitudinalControl(cp); if (can_change) { scene.longitudinal_accel_personality--; @@ -153,8 +180,8 @@ void OnroadSettings::changeAccelerationPersonality() { } void OnroadSettings::changeDynamicPersonality() { - UIScene &scene = uiState()->scene; - const auto cp = (*uiState()->sm)["carParams"].getCarParams(); + UISceneSP &scene = uiStateSP()->scene; + const auto cp = (*uiStateSP()->sm)["carParams"].getCarParams(); bool can_change = hasLongitudinalControl(cp); if (can_change) { scene.dynamic_personality = !scene.dynamic_personality; @@ -164,8 +191,8 @@ void OnroadSettings::changeDynamicPersonality() { } void OnroadSettings::changeDynamicExperimentalControl() { - UIScene &scene = uiState()->scene; - const auto cp = (*uiState()->sm)["carParams"].getCarParams(); + UISceneSP &scene = uiStateSP()->scene; + const auto cp = (*uiStateSP()->sm)["carParams"].getCarParams(); bool can_change = hasLongitudinalControl(cp); if (can_change) { scene.dynamic_experimental_control = !scene.dynamic_experimental_control; @@ -175,8 +202,8 @@ void OnroadSettings::changeDynamicExperimentalControl() { } void OnroadSettings::changeSpeedLimitControl() { - UIScene &scene = uiState()->scene; - const auto cp = (*uiState()->sm)["carParams"].getCarParams(); + UISceneSP &scene = uiStateSP()->scene; + const auto cp = (*uiStateSP()->sm)["carParams"].getCarParams(); bool can_change = hasLongitudinalControl(cp) || !cp.getPcmCruiseSpeed(); int max_policy = SpeedLimitPolicySettings::speed_limit_policy_texts.size() - 1; @@ -185,7 +212,7 @@ void OnroadSettings::changeSpeedLimitControl() { // If EnableSlc is OFF, set it to ON and reset SpeedLimitControlPolicy scene.speed_limit_control_enabled = true; scene.speed_limit_control_policy = 0; - } else if(scene.speed_limit_control_policy < max_policy) { + } else if (scene.speed_limit_control_policy < max_policy) { // If EnableSlc is already ON then increase SpeedLimitControlPolicy till it reaches 6 scene.speed_limit_control_policy++; } else { @@ -211,7 +238,7 @@ void OnroadSettings::refresh() { param_watcher->addParam("DynamicExperimentalControl"); param_watcher->addParam("EnableSlc"); - UIScene &scene = uiState()->scene; + UISceneSP &scene = uiStateSP()->scene; // Update live params on Feature Status on camera view scene.dynamic_lane_profile = std::atoi(params.get("DynamicLaneProfile").c_str()); scene.longitudinal_personality = std::atoi(params.get("LongitudinalPersonality").c_str()); @@ -225,7 +252,7 @@ void OnroadSettings::refresh() { setUpdatesEnabled(false); - const auto cp = (*uiState()->sm)["carParams"].getCarParams(); + const auto cp = (*uiStateSP()->sm)["carParams"].getCarParams(); // Dynamic Lane Profile dlp_widget->updateDynamicLaneProfile("DynamicLaneProfile"); @@ -271,11 +298,11 @@ OptionWidget::OptionWidget(QWidget *parent) : QPushButton(parent) { inner_frame->setContentsMargins(0, 0, 0, 0); inner_frame->setSpacing(0); { - title = new ElidedLabel(this); + title = new ElidedLabelSP(this); title->setAttribute(Qt::WA_TransparentForMouseEvents); inner_frame->addWidget(title); - subtitle = new ElidedLabel(this); + subtitle = new ElidedLabelSP(this); subtitle->setAttribute(Qt::WA_TransparentForMouseEvents); subtitle->setObjectName("subtitle"); inner_frame->addWidget(subtitle); @@ -304,12 +331,10 @@ void OptionWidget::updateDynamicLaneProfile(QString param) { if (dlp == 0) { title_text = "Laneful"; icon_color = "#2020f8"; - } - else if (dlp == 1) { + } else if (dlp == 1) { title_text = "Laneless"; icon_color = "#0df87a"; - } - else if (dlp == 2) { + } else if (dlp == 2) { title_text = "Auto"; icon_color = "#0df8f8"; } @@ -451,8 +476,7 @@ void OptionWidget::updateSpeedLimitControl(QString param) { if (enable_slc_status == 0) { title_text = "Disabled"; icon_color = "#3B4356"; // Color for "Disabled status" - } - else if (enable_slc_status == 1) { + } else if (enable_slc_status == 1) { title_text = title_text; icon_color = color_map[speed_limit_control_policy_status]; // Color for "Enabled status" } diff --git a/selfdrive/ui/qt/onroad_settings.h b/selfdrive/ui/sunnypilot/qt/onroad/onroad_settings.h similarity index 51% rename from selfdrive/ui/qt/onroad_settings.h rename to selfdrive/ui/sunnypilot/qt/onroad/onroad_settings.h index fe881d1f07..372688bfa5 100644 --- a/selfdrive/ui/qt/onroad_settings.h +++ b/selfdrive/ui/sunnypilot/qt/onroad/onroad_settings.h @@ -1,14 +1,39 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + #pragma once -#include -#include -#include -#include - #include "common/params.h" -#include "selfdrive/ui/ui.h" +#include "selfdrive/ui/sunnypilot/ui.h" #include "selfdrive/ui/qt/util.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#else #include "selfdrive/ui/qt/widgets/controls.h" +#endif class OptionWidget; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/onroad_settings_panel.cc b/selfdrive/ui/sunnypilot/qt/onroad/onroad_settings_panel.cc new file mode 100644 index 0000000000..47a6f06235 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/onroad/onroad_settings_panel.cc @@ -0,0 +1,51 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/onroad/onroad_settings_panel.h" + +#include + +#include "selfdrive/ui/sunnypilot/qt/onroad/onroad_settings.h" +#include "selfdrive/ui/qt/util.h" +#include "selfdrive/ui/sunnypilot/ui.h" + +OnroadSettingsPanel::OnroadSettingsPanel(QWidget *parent) : QFrame(parent) { + content_stack = new QStackedLayout(this); + content_stack->setContentsMargins(0, 0, 0, 0); + + auto onroad_settings = new OnroadSettings(true, parent); + QObject::connect(onroad_settings, &OnroadSettings::closeSettings, this, &OnroadSettings::hide); + content_stack->addWidget(onroad_settings); +} + +void OnroadSettingsPanel::toggleOnroadSettings() { + if (isVisible()) { + hide(); + } else { + emit onroadSettingsPanelRequested(); + show(); + } +} diff --git a/selfdrive/ui/sunnypilot/qt/onroad/onroad_settings_panel.h b/selfdrive/ui/sunnypilot/qt/onroad/onroad_settings_panel.h new file mode 100644 index 0000000000..57603c4e88 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/onroad/onroad_settings_panel.h @@ -0,0 +1,49 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#ifdef ENABLE_MAPS +#include +#endif +#include + +class OnroadSettingsPanel : public QFrame { + Q_OBJECT + +public: + explicit OnroadSettingsPanel(QWidget *parent = nullptr); + +signals: + void onroadSettingsPanelRequested(); + +public slots: + void toggleOnroadSettings(); + +private: + QStackedLayout *content_stack; +}; diff --git a/selfdrive/ui/sunnypilot/qt/request_repeater.cc b/selfdrive/ui/sunnypilot/qt/request_repeater.cc new file mode 100644 index 0000000000..91ac3cbff8 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/request_repeater.cc @@ -0,0 +1,62 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/request_repeater.h" + +#include "common/swaglog.h" + +RequestRepeaterSP::RequestRepeaterSP(QObject *parent, const QString &requestURL, const QString &cacheKey, + int period, bool whileOnroad, bool sunnylink) : HttpRequestSP(parent, true, 20000, sunnylink) { + request_url = requestURL; + while_onroad = whileOnroad; + timer = new QTimer(this); + timer->setTimerType(Qt::VeryCoarseTimer); + connect(timer, &QTimer::timeout, [=]() { this->timerTick(); }); + timer->start(period * 1000); + + if (!cacheKey.isEmpty()) { + prevResp = QString::fromStdString(params.get(cacheKey.toStdString())); + if (!prevResp.isEmpty()) { + QTimer::singleShot(500, [=]() { emit requestDone(prevResp, true, QNetworkReply::NoError); }); + } + connect(this, &HttpRequest::requestDone, [=](const QString &resp, bool success) { + if (success && resp != prevResp) { + params.put(cacheKey.toStdString(), resp.toStdString()); + prevResp = resp; + } + }); + } + + // Don't wait for the timer to fire to send the first request + ForceUpdate(); +} + +void RequestRepeaterSP::timerTick() { + if ((!uiState()->scene.started || while_onroad) && device()->isAwake() && !active()) { + LOGD("Sending request for %s", qPrintable(request_url)); + sendRequest(request_url); + } +} diff --git a/selfdrive/ui/sunnypilot/qt/request_repeater.h b/selfdrive/ui/sunnypilot/qt/request_repeater.h new file mode 100644 index 0000000000..2af97a0fca --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/request_repeater.h @@ -0,0 +1,52 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include "selfdrive/ui/qt/request_repeater.h" + +#include "common/swaglog.h" +#include "common/util.h" +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/api.h" + +class RequestRepeaterSP : public HttpRequestSP { + +private: + Params params; + QTimer *timer; + QString prevResp; + QString request_url; + bool while_onroad; + void timerTick(); + +public: + RequestRepeaterSP(QObject *parent, const QString &requestURL, const QString &cacheKey = "", int period = 0, bool whileOnroad=false, bool sunnylink = false); + void ForceUpdate() { + LOGD("Forcing update for %s", qPrintable(request_url)); + timerTick(); + } +}; diff --git a/selfdrive/ui/sunnypilot/qt/sidebar.cc b/selfdrive/ui/sunnypilot/qt/sidebar.cc new file mode 100644 index 0000000000..67447a57e6 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/sidebar.cc @@ -0,0 +1,132 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/sidebar.h" + +#include + +#include + +#include "selfdrive/ui/qt/util.h" +#include "selfdrive/ui/sunnypilot/qt/util.h" +#include "common/params.h" + +SidebarSP::SidebarSP(QWidget *parent) : Sidebar(parent) { + // Because I know that stock sidebar makes this connection, I will disconnect it and connect it to the new updateState function + QObject::disconnect(uiState(), &UIState::uiUpdate, this, &Sidebar::updateState); + QObject::connect(uiStateSP(), &UIStateSP::uiUpdate, this, &SidebarSP::updateState); +} + +void SidebarSP::updateState(const UIStateSP &s) { + if (!isVisible()) return; + Sidebar::updateState(s); + auto &sm = *(s.sm); + auto deviceState = sm["deviceState"].getDeviceState(); + + if (sm.frame % UI_FREQ == 0) { // Update every 1 Hz + switch (s.scene.sidebar_temp_options) { + case 0: + break; + case 1: + sidebar_temp = QString::number((int)deviceState.getMemoryTempC()); + break; + case 2: { + const auto& cpu_temp_list = deviceState.getCpuTempC(); + float max_cpu_temp = std::numeric_limits::lowest(); + + for (const float& temp : cpu_temp_list) { + max_cpu_temp = std::max(max_cpu_temp, temp); + } + + if (max_cpu_temp >= 0) { + sidebar_temp = QString::number(std::nearbyint(max_cpu_temp)); + } + break; + } + case 3: { + const auto& gpu_temp_list = deviceState.getGpuTempC(); + float max_gpu_temp = std::numeric_limits::lowest(); + + for (const float& temp : gpu_temp_list) { + max_gpu_temp = std::max(max_gpu_temp, temp); + } + + if (max_gpu_temp >= 0) { + sidebar_temp = QString::number(std::nearbyint(max_gpu_temp)); + } + break; + } + case 4: + sidebar_temp = QString::number((int)deviceState.getMaxTempC()); + break; + default: + break; + } + + setProperty("sidebarTemp", sidebar_temp + "°C"); + } + + bool show_sidebar_temp = s.scene.sidebar_temp_options != 0; + ItemStatus tempStatus = {{tr("TEMP"), show_sidebar_temp ? sidebar_temp_str : tr("HIGH")}, danger_color}; + auto ts = deviceState.getThermalStatus(); + if (ts == cereal::DeviceState::ThermalStatus::GREEN) { + tempStatus = {{tr("TEMP"), show_sidebar_temp ? sidebar_temp_str : tr("GOOD")}, good_color}; + } else if (ts == cereal::DeviceState::ThermalStatus::YELLOW) { + tempStatus = {{tr("TEMP"), show_sidebar_temp ? sidebar_temp_str : tr("OK")}, warning_color}; + } + setProperty("tempStatus", QVariant::fromValue(tempStatus)); + + ItemStatus sunnylinkStatus; + auto sl_dongle_id = getSunnylinkDongleId(); + auto last_sunnylink_ping_str = params.get("LastSunnylinkPingTime"); + auto last_sunnylink_ping = std::stoull(last_sunnylink_ping_str.empty() ? "0" : last_sunnylink_ping_str); + auto elapsed_sunnylink_ping = nanos_since_boot() - last_sunnylink_ping; + auto sunnylink_enabled = params.getBool("SunnylinkEnabled"); + + QString status = tr("DISABLED"); + QColor color = disabled_color; + + if (sunnylink_enabled && last_sunnylink_ping == 0) { + // If sunnylink is enabled, but we don't have a dongle id, and we haven't received a ping yet, we are registering + status = sl_dongle_id.has_value() ? tr("OFFLINE") : tr("REGIST..."); + color = sl_dongle_id.has_value() ? warning_color : progress_color; + } else if (sunnylink_enabled) { + // If sunnylink is enabled, we are considered online if we have received a ping in the last 80 seconds, else error. + status = elapsed_sunnylink_ping < 80000000000ULL ? tr("ONLINE") : tr("ERROR"); + color = elapsed_sunnylink_ping < 80000000000ULL ? good_color : danger_color; + } + sunnylinkStatus = ItemStatus{{tr("SUNNYLINK"), status}, color }; + setProperty("sunnylinkStatus", QVariant::fromValue(sunnylinkStatus)); +} + +void SidebarSP::DrawSidebar(QPainter &p){ + Sidebar::DrawSidebar(p); + // metrics + drawMetric(p, temp_status.first, temp_status.second, 310); + drawMetric(p, panda_status.first, panda_status.second, 440); + drawMetric(p, connect_status.first, connect_status.second, 570); + drawMetric(p, sunnylink_status.first, sunnylink_status.second, 700); +} diff --git a/selfdrive/ui/sunnypilot/qt/sidebar.h b/selfdrive/ui/sunnypilot/qt/sidebar.h new file mode 100644 index 0000000000..69de76f7a0 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/sidebar.h @@ -0,0 +1,57 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include + +#include "selfdrive/ui/qt/sidebar.h" + +#include "selfdrive/ui/sunnypilot/ui.h" + +class SidebarSP : public Sidebar { + Q_OBJECT + Q_PROPERTY(ItemStatus sunnylinkStatus MEMBER sunnylink_status NOTIFY valueChanged); + Q_PROPERTY(QString sidebarTemp MEMBER sidebar_temp_str NOTIFY valueChanged); + +public: + explicit SidebarSP(QWidget* parent = 0); + +public slots: + void updateState(const UIStateSP &s); + +protected: + const QColor progress_color = QColor(3, 132, 252); + const QColor disabled_color = QColor(128, 128, 128); + + ItemStatus sunnylink_status; + +private: + Params params; + void DrawSidebar(QPainter &p) override; + QString sidebar_temp = "0"; + QString sidebar_temp_str = "0"; +}; diff --git a/selfdrive/ui/sunnypilot/qt/text.cc b/selfdrive/ui/sunnypilot/qt/text.cc new file mode 100644 index 0000000000..50e4174ece --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/text.cc @@ -0,0 +1,162 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/params.h" +#include "common/swaglog.h" +#include "system/hardware/hw.h" +#include "selfdrive/ui/qt/util.h" +#include "selfdrive/ui/qt/qt_window.h" +#include "selfdrive/ui/qt/widgets/scrollview.h" + +std::string executeCommand(const char* cmd) { + std::array buffer{}; + std::ostringstream result; + std::unique_ptr pipe(popen(cmd, "r"), pclose); + if (!pipe) { + LOGW("Failed to open pipe"); + throw std::runtime_error("popen() failed!"); + } + while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { + result << buffer.data(); + } + return result.str(); +} + +// The format is intentional! +QString text = QString("%1\n%2\n%3\n%4\n%5\n%6\n%7") + .arg(" ________________________________________") + .arg("| |") + .arg("| " + QObject::tr("Update downloaded. Ready to reboot.") + " |") + .arg("| |") + .arg("| " + QObject::tr("Update: Check and Download Update") + " |") + .arg("| " + QObject::tr("Reboot: Reboot Device") + " |") + .arg("|________________________________________|"); + +int main(int argc, char *argv[]) { + initApp(argc, argv); + QApplication a(argc, argv); + QWidget window; + setMainWindow(&window); + + QGridLayout *main_layout = new QGridLayout(&window); + main_layout->setMargin(50); + + QLabel *label = new QLabel(argv[1]); + label->setWordWrap(true); + label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); + label->setAlignment(Qt::AlignTop | Qt::AlignLeft); + ScrollView *scroll = new ScrollView(label); + scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + main_layout->addWidget(scroll, 0, 0, Qt::AlignTop); + + // Scroll to the bottom + QObject::connect(scroll->verticalScrollBar(), &QAbstractSlider::rangeChanged, [=]() { + scroll->verticalScrollBar()->setValue(scroll->verticalScrollBar()->maximum()); + }); + + QPushButton *btn = new QPushButton(); + QPushButton *update_btn = new QPushButton(); + update_btn->setText(QObject::tr("Update")); +#ifdef __aarch64__ + btn->setText(QObject::tr("Reboot")); + QFutureWatcher watcher; + QObject::connect(btn, &QPushButton::clicked, [=]() { + Hardware::reboot(); + }); + QObject::connect(update_btn, &QPushButton::clicked, [=, &watcher]() { + btn->setEnabled(false); + update_btn->setEnabled(false); + update_btn->setText(QObject::tr("Updating...")); + const std::string git_branch = Params().get("GitBranch"); + const std::string git_remote = Params().get("GitRemote"); + const std::string to_home_dir = "cd /data/openpilot"; + const std::string check_remote = "git remote | grep origin-update"; + const std::string reset_remote = "git remote remove origin-update && git remote add origin-update " + git_remote; + const std::string add_remote = "git remote add origin-update " + git_remote; + const std::string fetch_remote = "git fetch origin-update " + git_branch; + const std::string reset_branch = "git reset --hard origin-update/" + git_branch + " 2>&1"; + + std::string remote_cmd = add_remote; + if (!std::system((to_home_dir + " && " + check_remote).c_str())) { + remote_cmd = reset_remote; + } + const std::string cmd = to_home_dir + "; " + remote_cmd + "; " + fetch_remote + "; " + reset_branch; + + QFuture future = QtConcurrent::run([=]() { + label->clear(); + std::string output = executeCommand(cmd.c_str()); + //LOGW("CHECK OUTPUT PLS\n%s", output.c_str()); + QMetaObject::invokeMethod(label, "setText", Qt::QueuedConnection, + Q_ARG(QString, QString::fromStdString(output) + text)); + }); + QObject::connect(&watcher, &QFutureWatcher::finished, [=]() { + btn->setEnabled(true); + update_btn->setEnabled(true); + update_btn->setText(QObject::tr("Update")); + }); + watcher.setFuture(future); + }); +#else + update_btn->setEnabled(false); + btn->setText(QObject::tr("Exit")); + QObject::connect(btn, &QPushButton::clicked, &a, &QApplication::quit); +#endif + main_layout->addWidget(btn, 0, 0, Qt::AlignRight | Qt::AlignBottom); + main_layout->addWidget(update_btn, 0, 0, Qt::AlignLeft | Qt::AlignBottom); + + window.setStyleSheet(R"( + * { + outline: none; + color: white; + background-color: black; + font-size: 60px; + } + QPushButton { + padding: 50px; + padding-right: 100px; + padding-left: 100px; + border: 2px solid white; + border-radius: 20px; + margin-right: 40px; + } + QPushButton:disabled { + color: #33FFFFFF; + border: 2px solid #33FFFFFF; + } + )"); + + return a.exec(); +} diff --git a/selfdrive/ui/sunnypilot/qt/ui_scene.h b/selfdrive/ui/sunnypilot/qt/ui_scene.h new file mode 100644 index 0000000000..e590c94046 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/ui_scene.h @@ -0,0 +1,115 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +const float DRIVING_PATH_WIDE = 0.9; +const float DRIVING_PATH_NARROW = 0.25; + +typedef struct UISceneSP : UIScene { + cereal::ControlsState::Reader controlsState; + + // Debug UI + bool show_debug_ui; + + // Speed limit control + bool speed_limit_control_enabled; + int speed_limit_control_policy; + double last_speed_limit_sign_tap; + + QPolygonF track_edge_vertices; + QPolygonF lane_barrier_vertices[2]; + + bool navigate_on_openpilot_deprecated = false; + cereal::AccelerationPersonality accel_personality; + + bool map_on_left; + + int dynamic_lane_profile; + bool dynamic_lane_profile_status = true; + + bool visual_brake_lights; + + int onroadScreenOff, osoTimer, brightness, onroadScreenOffBrightness, awake; + bool onroadScreenOffEvent; + int sleep_time = -1; + bool touched2 = false; + + bool stand_still_timer; + + bool hide_vego_ui, true_vego_ui; + + int chevron_data; + + bool gac; + int longitudinal_personality; + int longitudinal_accel_personality; + + bool map_visible; + int dev_ui_info; + bool live_torque_toggle; + + bool touch_to_wake = false; + int sleep_btn = -1; + bool sleep_btn_fading_in = false; + int sleep_btn_opacity = 20; + bool button_auto_hide; + + bool reverse_dm_cam; + + bool e2e_long_alert_light, e2e_long_alert_lead, e2e_long_alert_ui; + float e2eX[13] = {0}; + + int sidebar_temp_options; + + float mads_path_scale = DRIVING_PATH_WIDE - DRIVING_PATH_NARROW; + float mads_path_range = DRIVING_PATH_WIDE - DRIVING_PATH_NARROW; // 0.9 - 0.25 = 0.65 + + bool onroad_settings_visible; + + bool map_3d_buildings; + + bool torqued_override; + + bool dynamic_experimental_control; + + int speed_limit_control_engage_type; + + bool mapbox_fullscreen; + + bool speed_limit_warning_flash; + int speed_limit_warning_type; + int speed_limit_warning_value_offset; + + bool custom_driving_model_valid; + cereal::ModelGeneration driving_model_generation; + uint32_t driving_model_capabilities; + + bool feature_status_toggle; + bool onroad_settings_toggle; + + bool dynamic_personality; +} UISceneSP; diff --git a/selfdrive/ui/sunnypilot/qt/util.cc b/selfdrive/ui/sunnypilot/qt/util.cc new file mode 100644 index 0000000000..871a22f04e --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/util.cc @@ -0,0 +1,104 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/util.h" +#include "selfdrive/ui/qt/util.h" + +#include +#include + +#include +#include +#include +#include + +#include "system/hardware/hw.h" + +QString getUserAgent(bool sunnylink) { + return (sunnylink ? "sunnypilot-" : "openpilot-") + getVersion(); +} + +std::optional getSunnylinkDongleId() { + return getParamIgnoringDefault("SunnylinkDongleId", "UnregisteredDevice"); +} + +QMap getCarNames() { + return getFromJsonFile("../car/sunnypilot_carname.json"); +} + +void drawRoundedRect(QPainter &painter, const QRectF &rect, qreal xRadiusTop, qreal yRadiusTop, qreal xRadiusBottom, qreal yRadiusBottom){ + qreal w_2 = rect.width() / 2; + qreal h_2 = rect.height() / 2; + + xRadiusTop = 100 * qMin(xRadiusTop, w_2) / w_2; + yRadiusTop = 100 * qMin(yRadiusTop, h_2) / h_2; + + xRadiusBottom = 100 * qMin(xRadiusBottom, w_2) / w_2; + yRadiusBottom = 100 * qMin(yRadiusBottom, h_2) / h_2; + + qreal x = rect.x(); + qreal y = rect.y(); + qreal w = rect.width(); + qreal h = rect.height(); + + qreal rxx2Top = w*xRadiusTop/100; + qreal ryy2Top = h*yRadiusTop/100; + + qreal rxx2Bottom = w*xRadiusBottom/100; + qreal ryy2Bottom = h*yRadiusBottom/100; + + QPainterPath path; + path.arcMoveTo(x, y, rxx2Top, ryy2Top, 180); + path.arcTo(x, y, rxx2Top, ryy2Top, 180, -90); + path.arcTo(x+w-rxx2Top, y, rxx2Top, ryy2Top, 90, -90); + path.arcTo(x+w-rxx2Bottom, y+h-ryy2Bottom, rxx2Bottom, ryy2Bottom, 0, -90); + path.arcTo(x, y+h-ryy2Bottom, rxx2Bottom, ryy2Bottom, 270, -90); + path.closeSubpath(); + + painter.drawPath(path); +} + +QColor interpColor(float xv, std::vector xp, std::vector fp) { + assert(xp.size() == fp.size()); + + int N = xp.size(); + int hi = 0; + + while (hi < N and xv > xp[hi]) hi++; + int low = hi - 1; + + if (hi == N && xv > xp[low]) { + return fp[fp.size() - 1]; + } else if (hi == 0){ + return fp[0]; + } else { + return QColor( + (xv - xp[low]) * (fp[hi].red() - fp[low].red()) / (xp[hi] - xp[low]) + fp[low].red(), + (xv - xp[low]) * (fp[hi].green() - fp[low].green()) / (xp[hi] - xp[low]) + fp[low].green(), + (xv - xp[low]) * (fp[hi].blue() - fp[low].blue()) / (xp[hi] - xp[low]) + fp[low].blue(), + (xv - xp[low]) * (fp[hi].alpha() - fp[low].alpha()) / (xp[hi] - xp[low]) + fp[low].alpha()); + } +} \ No newline at end of file diff --git a/selfdrive/ui/sunnypilot/qt/util.h b/selfdrive/ui/sunnypilot/qt/util.h new file mode 100644 index 0000000000..cafcfc6201 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/util.h @@ -0,0 +1,39 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include + +#include +#include + +QString getUserAgent(bool sunnylink = false); +std::optional getSunnylinkDongleId(); +QMap getCarNames(); +void drawRoundedRect(QPainter &painter, const QRectF &rect, qreal xRadiusTop, qreal yRadiusTop, qreal xRadiusBottom, qreal yRadiusBottom); +QColor interpColor(float xv, std::vector xp, std::vector fp); diff --git a/selfdrive/ui/sunnypilot/qt/widgets/controls.cc b/selfdrive/ui/sunnypilot/qt/widgets/controls.cc new file mode 100644 index 0000000000..f1168e96e8 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/widgets/controls.cc @@ -0,0 +1,247 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" + +#include +#include +#include "selfdrive/ui/sunnypilot/sunnypilot_main.h" + +QFrame *horizontal_line(QWidget *parent) { + QFrame *line = new QFrame(parent); + line->setFrameShape(QFrame::StyledPanel); + line->setStyleSheet(R"( + border-width: 2px; + border-bottom-style: solid; + border-color: gray; + )"); + line->setFixedHeight(10); + return line; +} + +AbstractControlSP::AbstractControlSP(const QString &title, const QString &desc, const QString &icon, QWidget *parent) + : AbstractControl(title, desc, icon, parent) { + + main_layout = new QVBoxLayout(this); + main_layout->setMargin(0); + + hlayout = new QHBoxLayout; + hlayout->setMargin(0); + hlayout->setSpacing(20); + + // left icon + icon_label = new QLabel(this); + hlayout->addWidget(icon_label); + if (!icon.isEmpty()) { + icon_pixmap = QPixmap(icon).scaledToWidth(80, Qt::SmoothTransformation); + icon_label->setPixmap(icon_pixmap); + icon_label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + } + icon_label->setVisible(!icon.isEmpty()); + + // title + title_label = new QPushButton(title); + title_label->setFixedHeight(120); + title_label->setStyleSheet("font-size: 50px; font-weight: 450; text-align: left; border: none;"); + hlayout->addWidget(title_label, 1); + + // value next to control button + value = new ElidedLabelSP(); + value->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + value->setStyleSheet("color: #aaaaaa"); + hlayout->addWidget(value); + + main_layout->addLayout(hlayout); + + // description + description = new QLabel(desc); + description->setContentsMargins(40, 20, 40, 20); + description->setStyleSheet("font-size: 40px; color: grey"); + description->setWordWrap(true); + description->setVisible(false); + main_layout->addWidget(description); + + connect(title_label, &QPushButton::clicked, [=]() { + if (!description->isVisible()) { + emit showDescriptionEvent(); + } + + if (!description->text().isEmpty()) { + description->setVisible(!description->isVisible()); + } + }); + + main_layout->addStretch(); +} + +void AbstractControlSP::hideEvent(QHideEvent *e) { + if (description != nullptr) { + description->hide(); + } +} + +AbstractControlSP_SELECTOR::AbstractControlSP_SELECTOR(const QString &title, const QString &desc, const QString &icon, QWidget *parent) + : AbstractControlSP(title, desc, icon, parent) { + + if (value != nullptr) { + ReplaceWidget(value, new QWidget()); + value = nullptr; + } + + QLayoutItem* item; + while ((item = main_layout->takeAt(0)) != nullptr) { + if (item->widget()) { + delete item->widget(); + } + delete item; + } + + main_layout->setMargin(0); + + hlayout = new QHBoxLayout; + hlayout->setMargin(0); + hlayout->setSpacing(0); + + // title + if (!title.isEmpty()) { + title_label = new QPushButton(title); + title_label->setFixedHeight(120); + title_label->setStyleSheet("font-size: 50px; font-weight: 450; text-align: left; border: none;"); + main_layout->addWidget(title_label, 1); + + connect(title_label, &QPushButton::clicked, [=]() { + if (!description->isVisible()) { + emit showDescriptionEvent(); + } + + if (!description->text().isEmpty()) { + description->setVisible(!description->isVisible()); + } + }); + } else { + main_layout->addSpacing(20); + } + + main_layout->addLayout(hlayout); + main_layout->addSpacing(2); + + // description + description = new QLabel(desc); + description->setContentsMargins(0, 20, 40, 20); + description->setStyleSheet("font-size: 40px; color: grey"); + description->setWordWrap(true); + description->setVisible(false); + main_layout->addWidget(description); + + main_layout->addStretch(); +} + +// controls + +ButtonControlSP::ButtonControlSP(const QString &title, const QString &text, const QString &desc, QWidget *parent) : AbstractControlSP(title, desc, "", parent) { + btn.setText(text); + btn.setStyleSheet(R"( + QPushButton { + padding: 0; + border-radius: 50px; + font-size: 35px; + font-weight: 500; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + QPushButton:disabled { + color: #33E4E4E4; + } + )"); + btn.setFixedSize(250, 100); + QObject::connect(&btn, &QPushButton::clicked, this, &ButtonControlSP::clicked); + hlayout->addWidget(&btn); +} + +// ElidedLabelSP + +ElidedLabelSP::ElidedLabelSP(QWidget *parent) : ElidedLabelSP({}, parent) {} + +ElidedLabelSP::ElidedLabelSP(const QString &text, QWidget *parent) : QLabel(text.trimmed(), parent) { + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + setMinimumWidth(1); +} + +void ElidedLabelSP::resizeEvent(QResizeEvent* event) { + QLabel::resizeEvent(event); + lastText_ = elidedText_ = ""; +} + +void ElidedLabelSP::paintEvent(QPaintEvent *event) { + const QString curText = text(); + if (curText != lastText_) { + elidedText_ = fontMetrics().elidedText(curText, Qt::ElideRight, contentsRect().width()); + lastText_ = curText; + } + + QPainter painter(this); + drawFrame(&painter); + QStyleOption opt; + opt.initFrom(this); + style()->drawItemText(&painter, contentsRect(), alignment(), opt.palette, isEnabled(), elidedText_, foregroundRole()); +} + +// ParamControlSP + +ParamControlSP::ParamControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent) + : ToggleControlSP(title, desc, icon, false, parent) { + key = param.toStdString(); + QObject::connect(this, &ParamControlSP::toggleFlipped, this, &ParamControlSP::toggleClicked); + + hlayout->removeWidget(&toggle); + hlayout->insertWidget(0, &toggle); + + hlayout->removeWidget(this->icon_label); + this->icon_pixmap = QPixmap(icon).scaledToWidth(20, Qt::SmoothTransformation); + this->icon_label->setPixmap(this->icon_pixmap); + this->icon_label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + hlayout->insertWidget(1, this->icon_label); +} + +void ParamControlSP::toggleClicked(bool state) { + auto do_confirm = [this]() { + QString content("

" + title_label->text() + "


" + "

" + getDescription() + "

"); + return ConfirmationDialog(content, tr("Enable"), tr("Cancel"), true, this).exec(); + }; + + bool confirmed = store_confirm && params.getBool(key + "Confirmed"); + if (!confirm || confirmed || !state || do_confirm()) { + if (store_confirm && state) params.putBool(key + "Confirmed", true); + params.putBool(key, state); + setIcon(state); + } else { + toggle.togglePosition(); + } +} diff --git a/selfdrive/ui/sunnypilot/qt/widgets/controls.h b/selfdrive/ui/sunnypilot/qt/widgets/controls.h new file mode 100644 index 0000000000..c7784a36c8 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/widgets/controls.h @@ -0,0 +1,582 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include +#include +#include + +#include "common/params.h" +#include "selfdrive/ui/qt/widgets/controls.h" +#include "selfdrive/ui/qt/widgets/input.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/toggle.h" + +QFrame *horizontal_line(QWidget *parent = nullptr); + +class ElidedLabelSP : public QLabel { + Q_OBJECT + +public: + explicit ElidedLabelSP(QWidget *parent = 0); + explicit ElidedLabelSP(const QString &text, QWidget *parent = 0); + + void setColor(const QString &color) { + setStyleSheet("QLabel { color : " + color + "; }"); + } + +signals: + void clicked(); + +protected: + void paintEvent(QPaintEvent *event) override; + void resizeEvent(QResizeEvent* event) override; + void mouseReleaseEvent(QMouseEvent *event) override { + if (rect().contains(event->pos())) { + emit clicked(); + } + } + QString lastText_, elidedText_; +}; + +class AbstractControlSP : public AbstractControl { + Q_OBJECT + +public: + void setDescription(const QString &desc) { + if (description) description->setText(desc); + } + + void setValue(const QString &val, std::optional color = std::nullopt) { + value->setText(val); + if (color.has_value()) { + value->setColor(color.value()); + } + } + + const QString getDescription() { + return description->text(); + } + + void hideDescription() { + description->setVisible(false); + } + +public slots: + void showDescription() { + description->setVisible(true); + } + +protected: + AbstractControlSP(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr); + void hideEvent(QHideEvent *e) override; + + QVBoxLayout *main_layout; + ElidedLabelSP *value; + QLabel *description = nullptr; +}; + +class AbstractControlSP_SELECTOR : public AbstractControlSP { + Q_OBJECT + +protected: + AbstractControlSP_SELECTOR(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr); +}; + +// widget to display a value +class LabelControlSP : public AbstractControlSP { + Q_OBJECT + +public: + LabelControlSP(const QString &title, const QString &text = "", const QString &desc = "", QWidget *parent = nullptr) : AbstractControlSP(title, desc, "", parent) { + label.setText(text); + label.setAlignment(Qt::AlignRight | Qt::AlignVCenter); + hlayout->addWidget(&label); + } + void setText(const QString &text) { label.setText(text); } + +private: + ElidedLabelSP label; +}; + +// widget for a button with a label +class ButtonControlSP : public AbstractControlSP { + Q_OBJECT + +public: + ButtonControlSP(const QString &title, const QString &text, const QString &desc = "", QWidget *parent = nullptr); + inline void setText(const QString &text) { btn.setText(text); } + inline QString text() const { return btn.text(); } + inline void click() { btn.click(); } + +signals: + void clicked(); + +public slots: + void setEnabled(bool enabled) { btn.setEnabled(enabled); } + +private: + QPushButton btn; +}; + +class ToggleControlSP : public AbstractControlSP { + Q_OBJECT + +public: + ToggleControlSP(const QString &title, const QString &desc = "", const QString &icon = "", const bool state = false, QWidget *parent = nullptr) : AbstractControlSP(title, desc, icon, parent) { + toggle.setFixedSize(150, 100); + if (state) { + toggle.togglePosition(); + } + hlayout->addWidget(&toggle); + QObject::connect(&toggle, &ToggleSP::stateChanged, this, &ToggleControlSP::toggleFlipped); + } + + void setEnabled(bool enabled) { + toggle.setEnabled(enabled); + toggle.update(); + } + +signals: + void toggleFlipped(bool state); + +protected: + ToggleSP toggle; +}; + +// widget to toggle params +class ParamControlSP : public ToggleControlSP { + Q_OBJECT + +public: + ParamControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr); + void setConfirmation(bool _confirm, bool _store_confirm) { + confirm = _confirm; + store_confirm = _store_confirm; + } + + void setActiveIcon(const QString &icon) { + active_icon_pixmap = QPixmap(icon).scaledToWidth(80, Qt::SmoothTransformation); + } + + void refresh() { + bool state = params.getBool(key); + if (state != toggle.on) { + toggle.togglePosition(); + setIcon(state); + } + } + + void showEvent(QShowEvent *event) override { + refresh(); + } + + bool isToggled() { return params.getBool(key); } + +private: + void toggleClicked(bool state); + void setIcon(bool state) { + if (state && !active_icon_pixmap.isNull()) { + icon_label->setPixmap(active_icon_pixmap); + } else if (!icon_pixmap.isNull()) { + icon_label->setPixmap(icon_pixmap); + } + } + + std::string key; + Params params; + QPixmap active_icon_pixmap; + bool confirm = false; + bool store_confirm = false; +}; + +class ButtonParamControlSP : public AbstractControlSP_SELECTOR { + Q_OBJECT +public: + ButtonParamControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon, + const std::vector &button_texts, const int minimum_button_width = 300) : AbstractControlSP_SELECTOR(title, desc, icon), button_texts(button_texts) { + const QString style = R"( + QPushButton { + border-radius: 20px; + font-size: 50px; + font-weight: 450; + height:150px; + padding: 0 25 0 25; + color: #FFFFFF; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + QPushButton:checked:enabled { + background-color: #696868; + } + QPushButton:disabled { + color: #33FFFFFF; + } + QPushButton:checked:disabled { + background-color: #121212; + color: #33FFFFFF; + } + )"; + key = param.toStdString(); + int value = atoi(params.get(key).c_str()); + + button_group = new QButtonGroup(this); + button_group->setExclusive(true); + for (int i = 0; i < button_texts.size(); i++) { + QPushButton *button = new QPushButton(button_texts[i], this); + button->setCheckable(true); + button->setChecked(i == value); + button->setStyleSheet(style); + button->setMinimumWidth(minimum_button_width); + if (i == 0) hlayout->addSpacing(2); + hlayout->addWidget(button); + button_group->addButton(button, i); + } + + hlayout->setAlignment(Qt::AlignLeft); + + QObject::connect(button_group, QOverload::of(&QButtonGroup::buttonClicked), [=](int id) { + params.put(key, std::to_string(id)); + emit buttonToggled(id); + }); + } + + void setEnabled(bool enable) { + for (auto btn : button_group->buttons()) { + btn->setEnabled(enable); + } + button_group_enabled = enable; + + update(); + } + + void setCheckedButton(int id) { + button_group->button(id)->setChecked(true); + } + + void refresh() { + int value = atoi(params.get(key).c_str()); + + if (value >= button_texts.size()) { + value = button_texts.size() - 1; + } + if (value < 0) { + value = 0; + } + + button_group->button(value)->setChecked(true); + } + + void showEvent(QShowEvent *event) override { + refresh(); + } + + void setButton(QString param) { + key = param.toStdString(); + int value = atoi(params.get(key).c_str()); + for (int i = 0; i < button_group->buttons().size(); i++) { + button_group->buttons()[i]->setChecked(i == value); + } + } + + void setDisabledSelectedButton(std::string val) { + int value = atoi(val.c_str()); + for (int i = 0; i < button_group->buttons().size(); i++) { + button_group->buttons()[i]->setEnabled(i != value); + } + } + +protected: + void paintEvent(QPaintEvent *event) override { + QPainter p(this); + p.setRenderHint(QPainter::Antialiasing); + + // Calculate the total width and height for the background rectangle + int w = 0; + int h = 150; + + for (int i = 0; i < hlayout->count(); ++i) { + QPushButton *button = qobject_cast(hlayout->itemAt(i)->widget()); + if (button) { + w += button->width(); + } + } + + // Draw the rectangle + QRect rect(0 + 2, h - 24, w, h); + p.setPen(QPen(QColor(button_group_enabled ? "#696868" : "#121212"), 3)); + p.drawRoundedRect(rect, 20, 20); + } + +signals: + void buttonToggled(int btn_id); + +private: + std::string key; + Params params; + QButtonGroup *button_group; + std::vector button_texts; + + bool button_group_enabled = true; +}; + +class ListWidgetSP : public QWidget { + Q_OBJECT + public: + explicit ListWidgetSP(QWidget *parent = 0, const bool split_line = true) : QWidget(parent), _split_line(split_line), outer_layout(this) { + outer_layout.setMargin(0); + outer_layout.setSpacing(0); + outer_layout.addLayout(&inner_layout); + inner_layout.setMargin(0); + inner_layout.setSpacing(25); // default spacing is 25 + outer_layout.addStretch(); + } + inline void addItem(QWidget *w) { inner_layout.addWidget(w); } + inline void addItem(QLayout *layout) { inner_layout.addLayout(layout); } + inline void setSpacing(int spacing) { inner_layout.setSpacing(spacing); } + + inline void AddWidgetAt(const int index, QWidget *new_widget) { inner_layout.insertWidget(index, new_widget); } + inline void RemoveWidgetAt(const int index) { + if (QLayoutItem* item; (item = inner_layout.takeAt(index)) != nullptr) { + if (item->widget()) delete item->widget(); + delete item; + } + } + + inline void ReplaceOrAddWidget(QWidget *old_widget, QWidget *new_widget) { + if (const int index = inner_layout.indexOf(old_widget); index != -1) { + RemoveWidgetAt(index); + AddWidgetAt(index, new_widget); + } else { + addItem(new_widget); + } + } + +private: + void paintEvent(QPaintEvent *) override { + QPainter p(this); + p.setPen(Qt::gray); + for (int i = 0; i < inner_layout.count() - 1; ++i) { + QWidget *widget = inner_layout.itemAt(i)->widget(); + if ((widget == nullptr || widget->isVisible()) && _split_line) { + QRect r = inner_layout.itemAt(i)->geometry(); + int bottom = r.bottom() + inner_layout.spacing() / 2; + p.drawLine(r.left() + 40, bottom, r.right() - 40, bottom); + } + } + } + QVBoxLayout outer_layout; + QVBoxLayout inner_layout; + + bool _split_line; +}; + +// convenience class for wrapping layouts +class LayoutWidgetSP : public QWidget { + Q_OBJECT + +public: + LayoutWidgetSP(QLayout *l, QWidget *parent = nullptr) : QWidget(parent) { + setLayout(l); + } +}; + +class OptionControlSP : public AbstractControlSP_SELECTOR { + Q_OBJECT + +private: + struct MinMaxValue { + int min_value; + int max_value; + }; + +public: + OptionControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon, + const MinMaxValue &range, const int per_value_change = 1) : _title(title), AbstractControlSP_SELECTOR(title, desc, icon) { + const QString style = R"( + QPushButton { + border-radius: 20px; + font-size: 60px; + font-weight: 500; + width: 150px; + height: 150px; + padding: -3 25 3 25; + color: #FFFFFF; + font-weight: bold; + } + QPushButton:pressed { + color: #5C5C5C; + } + QPushButton:disabled { + color: #5C5C5C; + } + )"; + + label.setStyleSheet(label_enabled_style); + label.setFixedWidth(300); + label.setAlignment(Qt::AlignCenter); + + const std::vector button_texts{"-", "+"}; + + key = param.toStdString(); + value = atoi(params.get(key).c_str()); + + button_group = new QButtonGroup(this); + button_group->setExclusive(true); + for (int i = 0; i < button_texts.size(); i++) { + QPushButton *button = new QPushButton(button_texts[i], this); + button->setStyleSheet(style + ((i == 0) ? "QPushButton { text-align: left; }" : + "QPushButton { text-align: right; }")); + hlayout->addWidget(button, 0, ((i == 0) ? Qt::AlignLeft : Qt::AlignRight) | Qt::AlignVCenter); + if (i == 0) { + hlayout->addWidget(&label, 0, Qt::AlignCenter); + } + button_group->addButton(button, i); + + QObject::connect(button, &QPushButton::clicked, [=]() { + int change_value = (i == 0) ? -per_value_change : per_value_change; + key = param.toStdString(); + value = atoi(params.get(key).c_str()); + value += change_value; + value = std::clamp(value, range.min_value, range.max_value); + params.put(key, QString::number(value).toStdString()); + + button_group->button(0)->setEnabled(!(value <= range.min_value)); + button_group->button(1)->setEnabled(!(value >= range.max_value)); + + updateLabels(); + + if (request_update) { + emit updateOtherToggles(); + } + }); + } + + hlayout->setAlignment(Qt::AlignLeft); + } + + void setUpdateOtherToggles(bool _update) { + request_update = _update; + } + + inline void setLabel(const QString &text) { label.setText(text); } + + void setEnabled(bool enabled) { + for (auto btn : button_group->buttons()) { + btn->setEnabled(enabled); + } + label.setEnabled(enabled); + label.setStyleSheet(enabled ? label_enabled_style : label_disabled_style); + button_enabled = enabled; + + update(); + } + +protected: + void paintEvent(QPaintEvent *event) override { + QPainter p(this); + p.setRenderHint(QPainter::Antialiasing); + + // Calculate the total width and height for the background rectangle + int w = 0; + int h = 150; + + for (int i = 0; i < hlayout->count(); ++i) { + QWidget *widget = qobject_cast(hlayout->itemAt(i)->widget()); + if (widget) { + w += widget->width(); + } + } + + // Draw the rectangle + QRect rect(0, !_title.isEmpty() ? (h - 24) : 20, w, h); + p.setBrush(QColor(button_enabled ? "#b24a4a4a" : "#121212")); // Background color + p.setPen(QPen(Qt::NoPen)); + p.drawRoundedRect(rect, 20, 20); + } + +signals: + void updateLabels(); + void updateOtherToggles(); + +private: + std::string key; + int value; + QButtonGroup *button_group; + QLabel label; + Params params; + std::map option_label = {}; + bool request_update = false; + QString _title = ""; + + const QString label_enabled_style = "font-size: 50px; font-weight: 450; color: #FFFFFF;"; + const QString label_disabled_style = "font-size: 50px; font-weight: 450; color: #5C5C5C;"; + + bool button_enabled = true; +}; + +class SubPanelButton : public QPushButton { + Q_OBJECT + +public: + SubPanelButton(const QString &text, const int minimum_button_width = 800, QWidget *parent = nullptr) : QPushButton(text, parent) { + const QString buttonStyle = R"( + QPushButton { + border-radius: 20px; + font-size: 50px; + font-weight: 450; + height: 150px; + padding: 0 25px 0 25px; + color: #FFFFFF; + } + QPushButton:enabled { + background-color: #393939; + } + QPushButton:pressed { + background-color: #4A4A4A; + } + QPushButton:disabled { + background-color: #121212; + color: #5C5C5C; + } + )"; + + setStyleSheet(buttonStyle); + setFixedWidth(minimum_button_width); + } +}; + +class PanelBackButton : public QPushButton { + Q_OBJECT + +public: + PanelBackButton(const QString &label = "Back", QWidget *parent = nullptr) : QPushButton(label, parent) { + setObjectName("back_btn"); + setFixedSize(400, 100); + } +}; diff --git a/selfdrive/ui/qt/widgets/sunnypilot/drive_stats.cc b/selfdrive/ui/sunnypilot/qt/widgets/drive_stats.cc similarity index 73% rename from selfdrive/ui/qt/widgets/sunnypilot/drive_stats.cc rename to selfdrive/ui/sunnypilot/qt/widgets/drive_stats.cc index e4c127e6b5..8d54ec4f6c 100644 --- a/selfdrive/ui/qt/widgets/sunnypilot/drive_stats.cc +++ b/selfdrive/ui/sunnypilot/qt/widgets/drive_stats.cc @@ -1,8 +1,33 @@ -#include "selfdrive/ui/qt/widgets/sunnypilot/drive_stats.h" +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/widgets/drive_stats.h" #include #include -#include #include #include "common/params.h" diff --git a/selfdrive/ui/sunnypilot/qt/widgets/drive_stats.h b/selfdrive/ui/sunnypilot/qt/widgets/drive_stats.h new file mode 100644 index 0000000000..7bd1d39cfe --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/widgets/drive_stats.h @@ -0,0 +1,51 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include + +class DriveStats : public QFrame { + Q_OBJECT + +public: + explicit DriveStats(QWidget* parent = 0); + +private: + void showEvent(QShowEvent *event) override; + void updateStats(); + inline QString getDistanceUnit() const { return metric_ ? tr("KM") : tr("Miles"); } + + bool metric_; + QJsonDocument stats_; + struct StatsLabels { + QLabel *routes, *distance, *distance_unit, *hours; + } all_, week_; + +private slots: + void parseResponse(const QString &response, bool success); +}; diff --git a/selfdrive/ui/sunnypilot/qt/widgets/scrollview.cc b/selfdrive/ui/sunnypilot/qt/widgets/scrollview.cc new file mode 100644 index 0000000000..5b87a9f6dd --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/widgets/scrollview.cc @@ -0,0 +1,37 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" + +#include + +void ScrollViewSP::setLastScrollPosition() { + lastScrollPosition = verticalScrollBar()->value(); +} + +void ScrollViewSP::restoreScrollPosition() { + verticalScrollBar()->setValue(lastScrollPosition); +} diff --git a/selfdrive/ui/sunnypilot/qt/widgets/scrollview.h b/selfdrive/ui/sunnypilot/qt/widgets/scrollview.h new file mode 100644 index 0000000000..37d3ae4457 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/widgets/scrollview.h @@ -0,0 +1,43 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include "selfdrive/ui/qt/widgets/scrollview.h" + +class ScrollViewSP : public ScrollView { + Q_OBJECT + +public: + explicit ScrollViewSP(QWidget *w = nullptr, QWidget *parent = nullptr) : ScrollView(w, parent) {} + +public slots: + void setLastScrollPosition(); + void restoreScrollPosition(); + +private: + int lastScrollPosition = 0; +}; diff --git a/selfdrive/ui/sunnypilot/qt/widgets/toggle.cc b/selfdrive/ui/sunnypilot/qt/widgets/toggle.cc new file mode 100644 index 0000000000..b6737babd2 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/widgets/toggle.cc @@ -0,0 +1,49 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/qt/widgets/toggle.h" + +#include + +ToggleSP::ToggleSP(QWidget *parent) : Toggle(parent) { + _height_rect = 80; +} + +void ToggleSP::paintEvent(QPaintEvent *e) { + this->setFixedHeight(100); + QPainter p(this); + p.setPen(Qt::NoPen); + p.setRenderHint(QPainter::Antialiasing, true); + + // Draw toggle background + enabled ? green.setRgb(0x1e79e8) : green.setRgb(0x125db8); + p.setBrush(on ? green : QColor(0x292929)); + p.drawRoundedRect(QRect(0, 10, width(), _height_rect),_height_rect/2, _height_rect/2); + + // Draw toggle circle + p.setBrush(circleColor); + p.drawEllipse(QRectF(_x_circle - _radius + 6, 16, 68, 68)); +} diff --git a/selfdrive/ui/sunnypilot/qt/widgets/toggle.h b/selfdrive/ui/sunnypilot/qt/widgets/toggle.h new file mode 100644 index 0000000000..34f41a0c29 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/widgets/toggle.h @@ -0,0 +1,39 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include "selfdrive/ui/qt/widgets/toggle.h" + +class ToggleSP : public Toggle { + Q_OBJECT + +public: + explicit ToggleSP(QWidget* parent = nullptr); + +protected: + void paintEvent(QPaintEvent*) override; +}; diff --git a/selfdrive/ui/sunnypilot/qt/window.cc b/selfdrive/ui/sunnypilot/qt/window.cc new file mode 100644 index 0000000000..43fe9a9f25 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/window.cc @@ -0,0 +1,44 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "window.h" + +MainWindowSP::MainWindowSP(QWidget *parent) : MainWindow(parent, new HomeWindowSP(parent), + new SettingsWindowSP(parent), new OnboardingWindowSP(parent)) { + homeWindow = dynamic_cast(MainWindow::homeWindow); + settingsWindow = dynamic_cast(MainWindow::settingsWindow); + onboardingWindow = dynamic_cast(MainWindow::onboardingWindow); +} + +void MainWindowSP::closeSettings() { + MainWindow::closeSettings(); + if (uiState()->scene.started) { + homeWindow->showSidebar(false); + if (uiStateSP()->scene.navigate_on_openpilot_deprecated) { + homeWindow->showMapPanel(true); + } + } +} diff --git a/selfdrive/ui/sunnypilot/qt/window.h b/selfdrive/ui/sunnypilot/qt/window.h new file mode 100644 index 0000000000..1c0e6a81cb --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/window.h @@ -0,0 +1,45 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include "selfdrive/ui/qt/window.h" +#include "selfdrive/ui/sunnypilot/qt/home.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" +#include "offroad/settings/onboarding.h" + +class MainWindowSP : public MainWindow { + Q_OBJECT + +public: + explicit MainWindowSP(QWidget *parent = 0); + +private: + HomeWindowSP *homeWindow; + SettingsWindowSP *settingsWindow; + OnboardingWindowSP *onboardingWindow; + void closeSettings() override; +}; diff --git a/selfdrive/ui/sunnypilot/sunnypilot_main.h b/selfdrive/ui/sunnypilot/sunnypilot_main.h new file mode 100644 index 0000000000..a1732da764 --- /dev/null +++ b/selfdrive/ui/sunnypilot/sunnypilot_main.h @@ -0,0 +1,45 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/display_settings.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot_settings.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_settings.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_settings.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/trips_settings.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/monitoring_settings.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/osm_settings.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/software_settings.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_settings.h" + +inline void ReplaceWidget(QWidget* old_widget, QWidget* new_widget) { + if (old_widget && old_widget->parentWidget() && old_widget->parentWidget()->layout()) { + old_widget->parentWidget()->layout()->replaceWidget(old_widget, new_widget); + old_widget->hide(); + old_widget->deleteLater(); + } +} diff --git a/selfdrive/ui/sunnypilot/ui.cc b/selfdrive/ui/sunnypilot/ui.cc new file mode 100644 index 0000000000..ce490431d1 --- /dev/null +++ b/selfdrive/ui/sunnypilot/ui.cc @@ -0,0 +1,348 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#include "selfdrive/ui/sunnypilot/ui.h" + +#include +#include +#include + +#include + +#include "common/transformations/orientation.hpp" +#include "common/params.h" +#include "common/util.h" +#include "common/watchdog.h" +#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/models/role_model.h" +#include "system/hardware/hw.h" + +#define BACKLIGHT_DT 0.05 +#define BACKLIGHT_TS 10.00 + +// Projects a point in car to space to the corresponding point in full frame +// image space. +static bool sp_calib_frame_to_full_frame(const UIStateSP *s, float in_x, float in_y, float in_z, QPointF *out) { + return calib_frame_to_full_frame(s, in_x, in_y, in_z, out, 1000.0f); +} + +//todo: revisit, we could reuse from OG update_model. But this is an overload in this case. +void update_line_data(const UIStateSP *s, const cereal::XYZTData::Reader &line, + float y_off, float z_off_left, float z_off_right, QPolygonF *pvd, int max_idx, bool allow_invert=true) { + const auto line_x = line.getX(), line_y = line.getY(), line_z = line.getZ(); + QPointF left, right; + pvd->clear(); + for (int i = 0; i <= max_idx; i++) { + // highly negative x positions are drawn above the frame and cause flickering, clip to zy plane of camera + if (line_x[i] < 0) continue; + + bool l = sp_calib_frame_to_full_frame(s, line_x[i], line_y[i] - y_off, line_z[i] + z_off_left, &left); + bool r = sp_calib_frame_to_full_frame(s, line_x[i], line_y[i] + y_off, line_z[i] + z_off_right, &right); + if (l && r) { + // For wider lines the drawn polygon will "invert" when going over a hill and cause artifacts + if (!allow_invert && pvd->size() && left.y() > pvd->back().y()) { + continue; + } + pvd->push_back(left); + pvd->push_front(right); + } + } +} + +//todo: revisit, we could reuse from OG update_model +void sp_update_model(UIStateSP *s, const cereal::ModelDataV2::Reader &model) { + UISceneSP &scene = s->scene; + auto model_position = model.getPosition(); + float max_distance = std::clamp(*(model_position.getX().end() - 1), + MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE); + + // update lane lines + const auto lane_lines = model.getLaneLines(); + const auto lane_line_probs = model.getLaneLineProbs(); + int max_idx = get_path_length_idx(lane_lines[0], max_distance); + for (int i = 0; i < std::size(scene.lane_line_vertices); i++) { + scene.lane_line_probs[i] = lane_line_probs[i]; + update_line_data(s, lane_lines[i], 0.025 * scene.lane_line_probs[i], 0, 0, &scene.lane_line_vertices[i], max_idx); + } + + // lane barriers for blind spot + int max_distance_barrier = 40; + int max_idx_barrier = std::min(max_idx, get_path_length_idx(lane_lines[0], max_distance_barrier)); + update_line_data(s, lane_lines[1], 0, -0.05, -0.6, &scene.lane_barrier_vertices[0], max_idx_barrier, false); + update_line_data(s, lane_lines[2], 0, -0.05, -0.6, &scene.lane_barrier_vertices[1], max_idx_barrier, false); + + // update road edges + const auto road_edges = model.getRoadEdges(); + const auto road_edge_stds = model.getRoadEdgeStds(); + for (int i = 0; i < std::size(scene.road_edge_vertices); i++) { + scene.road_edge_stds[i] = road_edge_stds[i]; + update_line_data(s, road_edges[i], 0.025, 0, 0, &scene.road_edge_vertices[i], max_idx); + } + + // update path + auto lead_one = (*s->sm)["radarState"].getRadarState().getLeadOne(); + if (lead_one.getStatus()) { + const float lead_d = lead_one.getDRel() * 2.; + max_distance = std::clamp((float)(lead_d - fmin(lead_d * 0.35, 10.)), 0.0f, max_distance); + } + max_idx = get_path_length_idx(model_position, max_distance); + update_line_data(s, model_position, 0.9 - scene.mads_path_range * scene.mads_path_scale, 1.22, 1.22, &scene.track_vertices, max_idx, false); + update_line_data(s, model_position, 1.0 - scene.mads_path_range * scene.mads_path_scale - 0.1 * scene.mads_path_scale, 1.22, 1.22, &scene.track_edge_vertices, max_idx, false); +} + +static void sp_update_state(UIStateSP *s) { + update_state(s); + SubMaster &sm = *(s->sm); + UISceneSP &scene = s->scene; + auto params = Params(); + scene.started = sm["deviceState"].getDeviceState().getStarted() && scene.ignition && !params.getBool("ForceOffroad"); + // TODO: SP - Set this dynamically on init with manual toggle or driving model selection + if (sm.updated("lateralPlanSPDEPRECATED")) { + scene.dynamic_lane_profile_status = sm["lateralPlanSPDEPRECATED"].getLateralPlanSPDEPRECATED().getDynamicLaneProfileStatus(); + } + if (sm.updated("controlsState")) { + scene.controlsState = sm["controlsState"].getControlsState(); + } + if (sm.updated("longitudinalPlanSP")) { + for (int i = 0; i < std::size(scene.e2eX); i++) { + scene.e2eX[i] = sm["longitudinalPlanSP"].getLongitudinalPlanSP().getE2eX()[i]; + } + } + if (sm.updated("modelV2SP")) { + auto model_v2_sp = sm["modelV2SP"].getModelV2SP(); + scene.custom_driving_model_valid = model_v2_sp.getCustomModel(); + scene.driving_model_generation = model_v2_sp.getModelGeneration(); + scene.driving_model_capabilities = model_v2_sp.getModelCapabilities(); + } +} + +void sp_ui_update_params(UIStateSP *s) { + ui_update_params(s); + auto params = Params(); + s->scene.map_on_left = params.getBool("NavSettingLeftSide"); + + s->scene.visual_brake_lights = params.getBool("BrakeLights"); + s->scene.onroadScreenOff = std::atoi(params.get("OnroadScreenOff").c_str()); + s->scene.onroadScreenOffBrightness = std::atoi(params.get("OnroadScreenOffBrightness").c_str()); + s->scene.onroadScreenOffEvent = params.getBool("OnroadScreenOffEvent"); + s->scene.stand_still_timer = params.getBool("StandStillTimer"); + s->scene.show_debug_ui = params.getBool("ShowDebugUI"); + s->scene.hide_vego_ui = params.getBool("HideVEgoUi"); + s->scene.true_vego_ui = params.getBool("TrueVEgoUi"); + s->scene.chevron_data = std::atoi(params.get("ChevronInfo").c_str()); + s->scene.dev_ui_info = std::atoi(params.get("DevUIInfo").c_str()); + s->scene.button_auto_hide = params.getBool("ButtonAutoHide"); + s->scene.reverse_dm_cam = params.getBool("ReverseDmCam"); + s->scene.e2e_long_alert_light = params.getBool("EndToEndLongAlertLight"); + s->scene.e2e_long_alert_lead = params.getBool("EndToEndLongAlertLead"); + s->scene.e2e_long_alert_ui = params.getBool("EndToEndLongAlertUI"); + s->scene.map_3d_buildings = params.getBool("Map3DBuildings"); + s->scene.live_torque_toggle = params.getBool("LiveTorque"); + s->scene.torqued_override = params.getBool("TorquedOverride"); + s->scene.speed_limit_control_engage_type = std::atoi(params.get("SpeedLimitEngageType").c_str()); + s->scene.mapbox_fullscreen = params.getBool("MapboxFullScreen"); + s->scene.speed_limit_warning_flash = params.getBool("SpeedLimitWarningFlash"); + s->scene.speed_limit_warning_type = std::atoi(params.get("SpeedLimitWarningType").c_str()); + s->scene.speed_limit_warning_value_offset = std::atoi(params.get("SpeedLimitWarningValueOffset").c_str()); + s->scene.speed_limit_control_enabled = params.getBool("EnableSlc"); + s->scene.feature_status_toggle = params.getBool("FeatureStatus"); + s->scene.onroad_settings_toggle = params.getBool("OnroadSettings"); + + // Handle Onroad Screen Off params + if (s->scene.onroadScreenOff > 0) { + s->scene.osoTimer = s->scene.onroadScreenOff * 60 * UI_FREQ; + } else if (s->scene.onroadScreenOff == 0) { + s->scene.osoTimer = 30 * UI_FREQ; + } else if (s->scene.onroadScreenOff == -1) { + s->scene.osoTimer = 15 * UI_FREQ; + } else { + s->scene.osoTimer = -1; + } +} + +void UIStateSP::updateStatus() { + UIState::updateStatus(); + auto params = Params(); + if (scene.started && sm->updated("controlsState")) { + auto car_control = (*sm)["carControl"].getCarControl(); + auto car_state = (*sm)["carState"].getCarState(); + auto mads_enabled = car_state.getMadsEnabled(); + if (status != STATUS_OVERRIDE) { + status = mads_enabled && car_control.getLongActive() ? STATUS_ENGAGED : mads_enabled ? STATUS_MADS : STATUS_DISENGAGED; + } + + if (mads_enabled != last_mads_enabled) { + mads_path_state = true; + } + last_mads_enabled = mads_enabled; + if (mads_path_state) { + if (mads_enabled) { + mads_path_count = fmax(mads_path_count - 1, 0); + if (mads_path_count == 0) { + mads_path_state = false; + } + } else { + mads_path_count = fmin(mads_path_count + 1, mads_path_timestep); + if (mads_path_count == mads_path_timestep) { + mads_path_state = false; + } + } + } + scene.mads_path_scale = mads_path_count * (1 / mads_path_timestep); + } + + if (scene.started) { + // Auto hide UI button state machine + { + if (scene.button_auto_hide) { + if (scene.touch_to_wake) { + scene.sleep_btn = 30 * UI_FREQ; + } else if (scene.sleep_btn > 0) { + scene.sleep_btn--; + } else if (scene.sleep_btn == -1) { + scene.sleep_btn = 30 * UI_FREQ; + } + // Check if the sleep button should be fading in + if (scene.sleep_btn_fading_in) { + // Increase the opacity of the sleep button by a small amount + if (scene.sleep_btn_opacity < 20) { + scene.sleep_btn_opacity+= 10; + } + if (scene.sleep_btn_opacity >= 20) { + // If the opacity has reached its maximum value, stop fading in + scene.sleep_btn_fading_in = false; + scene.sleep_btn_opacity = 20; + } + } else if (scene.sleep_btn == 0) { + // Fade out the sleep button as before + if (scene.sleep_btn_opacity > 0) { + scene.sleep_btn_opacity-= 2; + } + } else { + // Set the opacity of the sleep button to its maximum value + scene.sleep_btn_opacity = 20; + } + } else { + scene.sleep_btn_opacity = 20; + } + } + + // Onroad Screen Off Brightness + Timer + Global Brightness + { + if (scene.onroadScreenOff != -2 && scene.touched2) { + scene.sleep_time = scene.osoTimer; + } else if (scene.onroadScreenOff != -2 && + ((scene.controlsState.getAlertSize() != cereal::ControlsState::AlertSize::NONE) && + ((scene.controlsState.getAlertStatus() == cereal::ControlsState::AlertStatus::NORMAL && scene.onroadScreenOffEvent) || + (scene.controlsState.getAlertStatus() != cereal::ControlsState::AlertStatus::NORMAL)))) { + scene.sleep_time = scene.osoTimer; + } else if (scene.sleep_time > 0 && scene.onroadScreenOff != -2) { + scene.sleep_time--; + } else if (scene.sleep_time == -1 && scene.onroadScreenOff != -2) { + scene.sleep_time = scene.osoTimer; + } + } + } + + if (sm->frame % UI_FREQ == 0) { // Update every 1 Hz + scene.sidebar_temp_options = std::atoi(params.get("SidebarTemperatureOptions").c_str()); + } + + scene.brightness = std::atoi(params.get("BrightnessControl").c_str()); +} + +UIStateSP::UIStateSP(QObject *parent) : UIState(parent) { +// todo: Can we simply append to SM? + sm = std::make_unique>({ + "modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", + "pandaStates", "carParams", "driverMonitoringState", "carState", "liveLocationKalman", "driverStateV2", + "wideRoadCameraState", "managerState", "navInstruction", "navRoute", "clocks", "longitudinalPlanSP", "liveMapDataSP", + "carControl", "lateralPlanSPDEPRECATED", "gpsLocation", "gpsLocationExternal", "liveParameters", "liveTorqueParameters", + "controlsStateSP", "modelV2SP" + }); + + // update timer + timer = new QTimer(this); + QObject::connect(timer, &QTimer::timeout, this, &UIStateSP::update); + timer->start(1000 / UI_FREQ); +} + +// Note: This method overrides completely the update method from the parent class intentionally. +void UIStateSP::update() { + update_sockets(this); + sp_update_state(this); + updateStatus(); + + if (sm->frame % UI_FREQ == 0) { + watchdog_kick(nanos_since_boot()); + } + emit uiUpdate(*this); +} + + +void UIStateSP::setSunnylinkRoles(const std::vector& roles) { + sunnylinkRoles = roles; + emit sunnylinkRolesChanged(roles); +} + +void UIStateSP::setSunnylinkDeviceUsers(const std::vector& users) { + sunnylinkUsers = users; + emit sunnylinkDeviceUsersChanged(users); +} + +DeviceSP::DeviceSP(QObject *parent) : Device(parent){ + QObject::connect(uiStateSP(), &UIStateSP::uiUpdate, this, &DeviceSP::update); +} + +//todo: revisit this +void DeviceSP::updateBrightness(const UIStateSP &s) { + Device::updateBrightness(s); + int brightness = brightness_filter.update(clipped_brightness); + if (!awake) { + brightness = 0; + } else if (s.scene.started && s.scene.sleep_time == 0 && s.scene.onroadScreenOff != -2) { + brightness = s.scene.onroadScreenOffBrightness * 0.01 * brightness; + } else if (s.scene.brightness) { + brightness = s.scene.brightness * 0.99; + } + + if (brightness != last_brightness) { + if (!brightness_future.isRunning()) { + brightness_future = QtConcurrent::run(Hardware::set_brightness, brightness); + last_brightness = brightness; + } + } +} + +UIStateSP *uiStateSP() { + static UIStateSP ui_state; + return &ui_state; +} +UIStateSP *uiState() { return uiStateSP(); } + +DeviceSP *deviceSP() { + static DeviceSP _device; + return &_device; +} diff --git a/selfdrive/ui/sunnypilot/ui.h b/selfdrive/ui/sunnypilot/ui.h new file mode 100644 index 0000000000..434b334f75 --- /dev/null +++ b/selfdrive/ui/sunnypilot/ui.h @@ -0,0 +1,154 @@ +/** +The MIT License + +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Last updated: July 29, 2024 +***/ + +#pragma once + +#include +#include +#include + +#include "selfdrive/ui/ui.h" + +#include "cereal/messaging/messaging.h" +#include "qt/network/sunnylink/models/role_model.h" +#include "qt/network/sunnylink/models/sponsor_role_model.h" +#include "qt/network/sunnylink/models/user_model.h" +#include "system/hardware/hw.h" + +const int UI_ROAD_NAME_MARGIN_X = 14; + +struct FeatureStatusText { + const QStringList dlp_list_text = { "Laneful", "Laneless", "Auto"}; + const QStringList gac_list_text = { "Aggressive", "Moderate", "Standard", "Relaxed"}; + const QStringList slc_list_text = { "Inactive", "Temp Off", "Adapting", "Active", "Pre Active"}; +}; + +struct FeatureStatusColor { + const QStringList dlp_list_color = { "#2020f8", "#0df87a", "#0df8f8" }; + const QStringList gac_list_color = { "#ff4b4b", "#fcff4b", "#4bff66", "#6a0ac9" }; + const QStringList slc_list_color = { "#ffffff", "#ffffff", "#fcff4b", "#4bff66", "#fcff4b" }; +}; + + +const QColor sp_bg_colors [] = { + [STATUS_DISENGAGED] = bg_colors[STATUS_DISENGAGED], + [STATUS_OVERRIDE] = bg_colors[STATUS_OVERRIDE], + [STATUS_ENGAGED] = QColor(0x00, 0xc8, 0x00, 0xf1), + [STATUS_MADS] = QColor(0x00, 0xc8, 0xc8, 0xf1), +}; +#define bg_colors sp_bg_colors // Override the bg_colors array with the sp_bg_colors array + +const QColor tcs_colors [] = { + [int(cereal::LongitudinalPlanSP::VisionTurnControllerState::DISABLED)] = QColor(0x0, 0x0, 0x0, 0xff), + [int(cereal::LongitudinalPlanSP::VisionTurnControllerState::ENTERING)] = QColor(0xC9, 0x22, 0x31, 0xf1), + [int(cereal::LongitudinalPlanSP::VisionTurnControllerState::TURNING)] = QColor(0xDA, 0x6F, 0x25, 0xf1), + [int(cereal::LongitudinalPlanSP::VisionTurnControllerState::LEAVING)] = QColor(0x17, 0x86, 0x44, 0xf1), +}; + +class UIStateSP : public UIState { + Q_OBJECT + +public: + UIStateSP(QObject* parent = 0); + void updateStatus() override; + + void setSunnylinkRoles(const std::vector &roles); + void setSunnylinkDeviceUsers(const std::vector &users); + + inline std::vector sunnylinkDeviceRoles() const { return sunnylinkRoles; } + inline bool isSunnylinkAdmin() const { + return std::any_of(sunnylinkRoles.begin(), sunnylinkRoles.end(), [](const RoleModel &role) { + return role.roleType == RoleType::Admin; + }); + } + inline bool isSunnylinkSponsor() const { + return std::any_of(sunnylinkRoles.begin(), sunnylinkRoles.end(), [](const RoleModel &role) { + return role.roleType == RoleType::Sponsor && role.as().roleTier != SponsorTier::Free; + }); + } + inline SponsorRoleModel sunnylinkSponsorRole() const { + std::optional sponsorRoleWithHighestTier = std::nullopt; + for (const auto &role : sunnylinkRoles) { + if(role.roleType != RoleType::Sponsor) + continue; + + if (auto sponsorRole = role.as(); !sponsorRoleWithHighestTier.has_value() || sponsorRoleWithHighestTier->roleTier < sponsorRole.roleTier) { + sponsorRoleWithHighestTier = sponsorRole; + } + } + return sponsorRoleWithHighestTier.value_or(SponsorRoleModel(RoleType::Sponsor, SponsorTier::Free)); + } + inline SponsorTier sunnylinkSponsorTier() const { + return sunnylinkSponsorRole().roleTier; + } + inline std::vector sunnylinkDeviceUsers() const { return sunnylinkUsers; } + inline bool isSunnylinkPaired() const { + return std::any_of(sunnylinkUsers.begin(), sunnylinkUsers.end(), [](const UserModel &user) { + return user.user_id.toLower() != "unregisteredsponsor" && user.user_id.toLower() != "temporarysponsor"; + }); + } + +signals: + void sunnylinkRoleChanged(bool subscriber); + void sunnylinkRolesChanged(std::vector roles); + void sunnylinkDeviceUsersChanged(std::vector users); + void uiUpdate(const UIStateSP &s); + +private slots: + void update() override; + + +private: + std::vector sunnylinkRoles = {}; + std::vector sunnylinkUsers = {}; + + bool last_mads_enabled = false; + bool mads_path_state = false; + float mads_path_timestep = 4; // UI runs at 20 Hz, therefore 0.2 second is [0.2 second / (1 / 20 Hz) = 4] + float mads_path_count = 4; // UI runs at 20 Hz, therefore 0.2 second is [0.2 second / (1 / 20 Hz) = 4] +}; + +UIStateSP *uiStateSP(); +UIStateSP *uiState(); + +// device management class +class DeviceSP : public Device { + Q_OBJECT + +public: + DeviceSP(QObject *parent = 0); +protected: + void updateBrightness(const UIStateSP &s); + void updateBrightness(const UIState &s) override { updateBrightness(dynamic_cast(s)); } +}; + +DeviceSP *deviceSP(); +inline DeviceSP *device() { return deviceSP(); } + +void sp_update_model(UIStateSP *s, const cereal::ModelDataV2::Reader &model); +void sp_ui_update_params(UIStateSP *s); +void update_line_data(const UIStateSP *s, const cereal::XYZTData::Reader &line, + float y_off, float z_off_left, float z_off_right, QPolygonF *pvd, int max_idx, bool allow_invert); diff --git a/selfdrive/ui/translations/main_ar.ts b/selfdrive/ui/translations/main_ar.ts index 7dae31a53e..28610a671e 100644 --- a/selfdrive/ui/translations/main_ar.ts +++ b/selfdrive/ui/translations/main_ar.ts @@ -1517,6 +1517,22 @@ This may take up to a minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + Enable Automatic Brake Hold (AHB) + + + + WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. + + + + When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. + + + + Changing this setting takes effect when the car is powered off. + + Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index 6b8fd1efc1..ab80c261fd 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -1499,6 +1499,22 @@ This may take up to a minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + Enable Automatic Brake Hold (AHB) + + + + WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. + + + + When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. + + + + Changing this setting takes effect when the car is powered off. + + Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_es.ts b/selfdrive/ui/translations/main_es.ts index 6527ddfc12..90fc8381c9 100644 --- a/selfdrive/ui/translations/main_es.ts +++ b/selfdrive/ui/translations/main_es.ts @@ -1505,6 +1505,22 @@ Esto puede tardar hasta un minuto. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + Enable Automatic Brake Hold (AHB) + + + + WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. + + + + When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. + + + + Changing this setting takes effect when the car is powered off. + + Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_fr.ts b/selfdrive/ui/translations/main_fr.ts index 0071a33e47..22b5808a62 100644 --- a/selfdrive/ui/translations/main_fr.ts +++ b/selfdrive/ui/translations/main_fr.ts @@ -1501,6 +1501,22 @@ Cela peut prendre jusqu'à une minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + Enable Automatic Brake Hold (AHB) + + + + WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. + + + + When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. + + + + Changing this setting takes effect when the car is powered off. + + Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 5db645c9f4..0ffade1416 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -1495,6 +1495,22 @@ This may take up to a minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + Enable Automatic Brake Hold (AHB) + + + + WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. + + + + When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. + + + + Changing this setting takes effect when the car is powered off. + + Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 1a55d59a3b..337f338633 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1497,6 +1497,22 @@ This may take up to a minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + Enable Automatic Brake Hold (AHB) + + + + WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. + + + + When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. + + + + Changing this setting takes effect when the car is powered off. + + Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 856ef26ca8..63d83d7448 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -1501,6 +1501,22 @@ Isso pode levar até um minuto. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + Enable Automatic Brake Hold (AHB) + + + + WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. + + + + When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. + + + + Changing this setting takes effect when the car is powered off. + + Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_th.ts b/selfdrive/ui/translations/main_th.ts index 220b6575c4..a0ed3caf37 100644 --- a/selfdrive/ui/translations/main_th.ts +++ b/selfdrive/ui/translations/main_th.ts @@ -1497,6 +1497,22 @@ This may take up to a minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + Enable Automatic Brake Hold (AHB) + + + + WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. + + + + When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. + + + + Changing this setting takes effect when the car is powered off. + + Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_tr.ts b/selfdrive/ui/translations/main_tr.ts index a8c3992fd2..07205a2b12 100644 --- a/selfdrive/ui/translations/main_tr.ts +++ b/selfdrive/ui/translations/main_tr.ts @@ -1495,6 +1495,22 @@ This may take up to a minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + Enable Automatic Brake Hold (AHB) + + + + WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. + + + + When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. + + + + Changing this setting takes effect when the car is powered off. + + Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index fddf413a50..da8e79536c 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -1497,6 +1497,22 @@ This may take up to a minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + Enable Automatic Brake Hold (AHB) + + + + WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. + + + + When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. + + + + Changing this setting takes effect when the car is powered off. + + Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 684447b113..6c93b6239a 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -1497,6 +1497,22 @@ This may take up to a minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. + + Enable Automatic Brake Hold (AHB) + + + + WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. + + + + When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. + + + + Changing this setting takes effect when the car is powered off. + + Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 126be0d6b1..5d6b6c5722 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -11,7 +11,7 @@ #include "common/swaglog.h" #include "common/util.h" #include "common/watchdog.h" -#include "qt/network/sunnylink/models/role_model.h" +#include "qt/util.h" #include "system/hardware/hw.h" #define BACKLIGHT_DT 0.05 @@ -19,8 +19,7 @@ // Projects a point in car to space to the corresponding point in full frame // image space. -static bool calib_frame_to_full_frame(const UIState *s, float in_x, float in_y, float in_z, QPointF *out) { - const float margin = 1000.0f; +bool calib_frame_to_full_frame(const UIState *s, float in_x, float in_y, float in_z, QPointF *out, const float margin) { const QRectF clip_region{-margin, -margin, s->fb_w + 2 * margin, s->fb_h + 2 * margin}; const vec3 pt = (vec3){{in_x, in_y, in_z}}; @@ -56,7 +55,7 @@ void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, con } void update_line_data(const UIState *s, const cereal::XYZTData::Reader &line, - float y_off, float z_off_left, float z_off_right, QPolygonF *pvd, int max_idx, bool allow_invert=true) { + float y_off, float z_off, QPolygonF *pvd, int max_idx, bool allow_invert=true) { const auto line_x = line.getX(), line_y = line.getY(), line_z = line.getZ(); QPointF left, right; pvd->clear(); @@ -64,8 +63,8 @@ void update_line_data(const UIState *s, const cereal::XYZTData::Reader &line, // highly negative x positions are drawn above the frame and cause flickering, clip to zy plane of camera if (line_x[i] < 0) continue; - bool l = calib_frame_to_full_frame(s, line_x[i], line_y[i] - y_off, line_z[i] + z_off_left, &left); - bool r = calib_frame_to_full_frame(s, line_x[i], line_y[i] + y_off, line_z[i] + z_off_right, &right); + bool l = calib_frame_to_full_frame(s, line_x[i], line_y[i] - y_off, line_z[i] + z_off, &left); + bool r = calib_frame_to_full_frame(s, line_x[i], line_y[i] + y_off, line_z[i] + z_off, &right); if (l && r) { // For wider lines the drawn polygon will "invert" when going over a hill and cause artifacts if (!allow_invert && pvd->size() && left.y() > pvd->back().y()) { @@ -90,21 +89,15 @@ void update_model(UIState *s, int max_idx = get_path_length_idx(lane_lines[0], max_distance); for (int i = 0; i < std::size(scene.lane_line_vertices); i++) { scene.lane_line_probs[i] = lane_line_probs[i]; - update_line_data(s, lane_lines[i], 0.025 * scene.lane_line_probs[i], 0, 0, &scene.lane_line_vertices[i], max_idx); + update_line_data(s, lane_lines[i], 0.025 * scene.lane_line_probs[i], 0, &scene.lane_line_vertices[i], max_idx); } - // lane barriers for blind spot - int max_distance_barrier = 40; - int max_idx_barrier = std::min(max_idx, get_path_length_idx(lane_lines[0], max_distance_barrier)); - update_line_data(s, lane_lines[1], 0, -0.05, -0.6, &scene.lane_barrier_vertices[0], max_idx_barrier, false); - update_line_data(s, lane_lines[2], 0, -0.05, -0.6, &scene.lane_barrier_vertices[1], max_idx_barrier, false); - // update road edges const auto road_edges = model.getRoadEdges(); const auto road_edge_stds = model.getRoadEdgeStds(); for (int i = 0; i < std::size(scene.road_edge_vertices); i++) { scene.road_edge_stds[i] = road_edge_stds[i]; - update_line_data(s, road_edges[i], 0.025, 0, 0, &scene.road_edge_vertices[i], max_idx); + update_line_data(s, road_edges[i], 0.025, 0, &scene.road_edge_vertices[i], max_idx); } // update path @@ -114,8 +107,7 @@ void update_model(UIState *s, max_distance = std::clamp((float)(lead_d - fmin(lead_d * 0.35, 10.)), 0.0f, max_distance); } max_idx = get_path_length_idx(model_position, max_distance); - update_line_data(s, model_position, 0.9 - scene.mads_path_range * scene.mads_path_scale, 1.22, 1.22, &scene.track_vertices, max_idx, false); - update_line_data(s, model_position, 1.0 - scene.mads_path_range * scene.mads_path_scale - 0.1 * scene.mads_path_scale, 1.22, 1.22, &scene.track_edge_vertices, max_idx, false); + update_line_data(s, model_position, 0.9, 1.22, &scene.track_vertices, max_idx, false); } void update_dmonitoring(UIState *s, const cereal::DriverStateV2::Reader &driverstate, float dm_fade_state, bool is_rhd) { @@ -153,14 +145,13 @@ void update_dmonitoring(UIState *s, const cereal::DriverStateV2::Reader &drivers } } -static void update_sockets(UIState *s) { +void update_sockets(UIState *s) { s->sm->update(0); } -static void update_state(UIState *s) { +void update_state(UIState *s) { SubMaster &sm = *(s->sm); UIScene &scene = s->scene; - auto params = Params(); if (sm.updated("liveCalibration")) { auto live_calib = sm["liveCalibration"].getLiveCalibration(); @@ -212,108 +203,28 @@ static void update_state(UIState *s) { } else if (!sm.allAliveAndValid({"wideRoadCameraState"})) { scene.light_sensor = -1; } - scene.started = sm["deviceState"].getDeviceState().getStarted() && scene.ignition && !params.getBool("ForceOffroad"); + scene.started = sm["deviceState"].getDeviceState().getStarted() && scene.ignition; scene.world_objects_visible = scene.world_objects_visible || (scene.started && sm.rcv_frame("liveCalibration") > scene.started_frame && sm.rcv_frame("modelV2") > scene.started_frame); - // TODO: SP - Set this dynamically on init with manual toggle or driving model selection - if (sm.updated("lateralPlanSPDEPRECATED")) { - scene.dynamic_lane_profile_status = sm["lateralPlanSPDEPRECATED"].getLateralPlanSPDEPRECATED().getDynamicLaneProfileStatus(); - } - if (sm.updated("controlsState")) { - scene.controlsState = sm["controlsState"].getControlsState(); - } - if (sm.updated("longitudinalPlanSP")) { - for (int i = 0; i < std::size(scene.e2eX); i++) { - scene.e2eX[i] = sm["longitudinalPlanSP"].getLongitudinalPlanSP().getE2eX()[i]; - } - } - if (sm.updated("modelV2SP")) { - auto model_v2_sp = sm["modelV2SP"].getModelV2SP(); - scene.custom_driving_model_valid = model_v2_sp.getCustomModel(); - scene.driving_model_generation = model_v2_sp.getModelGeneration(); - scene.driving_model_capabilities = model_v2_sp.getModelCapabilities(); - } } void ui_update_params(UIState *s) { auto params = Params(); s->scene.is_metric = params.getBool("IsMetric"); - s->scene.map_on_left = params.getBool("NavSettingLeftSide"); - - s->scene.visual_brake_lights = params.getBool("BrakeLights"); - s->scene.onroadScreenOff = std::atoi(params.get("OnroadScreenOff").c_str()); - s->scene.onroadScreenOffBrightness = std::atoi(params.get("OnroadScreenOffBrightness").c_str()); - s->scene.onroadScreenOffEvent = params.getBool("OnroadScreenOffEvent"); - s->scene.stand_still_timer = params.getBool("StandStillTimer"); - s->scene.show_debug_ui = params.getBool("ShowDebugUI"); - s->scene.hide_vego_ui = params.getBool("HideVEgoUi"); - s->scene.true_vego_ui = params.getBool("TrueVEgoUi"); - s->scene.chevron_data = std::atoi(params.get("ChevronInfo").c_str()); - s->scene.dev_ui_info = std::atoi(params.get("DevUIInfo").c_str()); - s->scene.button_auto_hide = params.getBool("ButtonAutoHide"); - s->scene.reverse_dm_cam = params.getBool("ReverseDmCam"); - s->scene.e2e_long_alert_light = params.getBool("EndToEndLongAlertLight"); - s->scene.e2e_long_alert_lead = params.getBool("EndToEndLongAlertLead"); - s->scene.e2e_long_alert_ui = params.getBool("EndToEndLongAlertUI"); - s->scene.map_3d_buildings = params.getBool("Map3DBuildings"); - s->scene.live_torque_toggle = params.getBool("LiveTorque"); - s->scene.torqued_override = params.getBool("TorquedOverride"); - s->scene.speed_limit_control_engage_type = std::atoi(params.get("SpeedLimitEngageType").c_str()); - s->scene.mapbox_fullscreen = params.getBool("MapboxFullScreen"); - s->scene.speed_limit_warning_flash = params.getBool("SpeedLimitWarningFlash"); - s->scene.speed_limit_warning_type = std::atoi(params.get("SpeedLimitWarningType").c_str()); - s->scene.speed_limit_warning_value_offset = std::atoi(params.get("SpeedLimitWarningValueOffset").c_str()); - s->scene.speed_limit_control_enabled = params.getBool("EnableSlc"); - s->scene.feature_status_toggle = params.getBool("FeatureStatus"); - s->scene.onroad_settings_toggle = params.getBool("OnroadSettings"); - - // Handle Onroad Screen Off params - if (s->scene.onroadScreenOff > 0) { - s->scene.osoTimer = s->scene.onroadScreenOff * 60 * UI_FREQ; - } else if (s->scene.onroadScreenOff == 0) { - s->scene.osoTimer = 30 * UI_FREQ; - } else if (s->scene.onroadScreenOff == -1) { - s->scene.osoTimer = 15 * UI_FREQ; - } else { - s->scene.osoTimer = -1; - } } void UIState::updateStatus() { - auto params = Params(); if (scene.started && sm->updated("controlsState")) { auto controls_state = (*sm)["controlsState"].getControlsState(); - auto car_control = (*sm)["carControl"].getCarControl(); - auto car_state = (*sm)["carState"].getCarState(); - auto mads_enabled = car_state.getMadsEnabled(); auto state = controls_state.getState(); if (state == cereal::ControlsState::OpenpilotState::PRE_ENABLED || state == cereal::ControlsState::OpenpilotState::OVERRIDING) { status = STATUS_OVERRIDE; } else { - status = car_state.getMadsEnabled() ? car_control.getLongActive() ? STATUS_ENGAGED : STATUS_MADS : STATUS_DISENGAGED; + status = controls_state.getEnabled() ? STATUS_ENGAGED : STATUS_DISENGAGED; } - - if (mads_enabled != last_mads_enabled) { - mads_path_state = true; - } - last_mads_enabled = mads_enabled; - if (mads_path_state) { - if (mads_enabled) { - mads_path_count = fmax(mads_path_count - 1, 0); - if (mads_path_count == 0) { - mads_path_state = false; - } - } else { - mads_path_count = fmin(mads_path_count + 1, mads_path_timestep); - if (mads_path_count == mads_path_timestep) { - mads_path_state = false; - } - } - } - scene.mads_path_scale = mads_path_count * (1 / mads_path_timestep); } // Handle onroad/offroad transition @@ -326,74 +237,17 @@ void UIState::updateStatus() { scene.world_objects_visible = false; emit offroadTransition(!scene.started); } - - if (scene.started) { - // Auto hide UI button state machine - { - if (scene.button_auto_hide) { - if (scene.touch_to_wake) { - scene.sleep_btn = 30 * UI_FREQ; - } else if (scene.sleep_btn > 0) { - scene.sleep_btn--; - } else if (scene.sleep_btn == -1) { - scene.sleep_btn = 30 * UI_FREQ; - } - // Check if the sleep button should be fading in - if (scene.sleep_btn_fading_in) { - // Increase the opacity of the sleep button by a small amount - if (scene.sleep_btn_opacity < 20) { - scene.sleep_btn_opacity+= 10; - } - if (scene.sleep_btn_opacity >= 20) { - // If the opacity has reached its maximum value, stop fading in - scene.sleep_btn_fading_in = false; - scene.sleep_btn_opacity = 20; - } - } else if (scene.sleep_btn == 0) { - // Fade out the sleep button as before - if (scene.sleep_btn_opacity > 0) { - scene.sleep_btn_opacity-= 2; - } - } else { - // Set the opacity of the sleep button to its maximum value - scene.sleep_btn_opacity = 20; - } - } else { - scene.sleep_btn_opacity = 20; - } - } - - // Onroad Screen Off Brightness + Timer + Global Brightness - { - if (scene.onroadScreenOff != -2 && scene.touched2) { - scene.sleep_time = scene.osoTimer; - } else if (scene.onroadScreenOff != -2 && - ((scene.controlsState.getAlertSize() != cereal::ControlsState::AlertSize::NONE) && - ((scene.controlsState.getAlertStatus() == cereal::ControlsState::AlertStatus::NORMAL && scene.onroadScreenOffEvent) || - (scene.controlsState.getAlertStatus() != cereal::ControlsState::AlertStatus::NORMAL)))) { - scene.sleep_time = scene.osoTimer; - } else if (scene.sleep_time > 0 && scene.onroadScreenOff != -2) { - scene.sleep_time--; - } else if (scene.sleep_time == -1 && scene.onroadScreenOff != -2) { - scene.sleep_time = scene.osoTimer; - } - } - } - - if (sm->frame % UI_FREQ == 0) { // Update every 1 Hz - scene.sidebar_temp_options = std::atoi(params.get("SidebarTemperatureOptions").c_str()); - } - - scene.brightness = std::atoi(params.get("BrightnessControl").c_str()); } +// #ifdef SUNNYPILOT +// #include "selfdrive/ui/sunnypilot/qt/ui_scene.h" +// #define UIScene UISceneSP +// #endif UIState::UIState(QObject *parent) : QObject(parent) { sm = std::make_unique>({ "modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", "pandaStates", "carParams", "driverMonitoringState", "carState", "liveLocationKalman", "driverStateV2", - "wideRoadCameraState", "managerState", "navInstruction", "navRoute", "clocks", "longitudinalPlanSP", "liveMapDataSP", - "carControl", "lateralPlanSPDEPRECATED", "gpsLocation", "gpsLocationExternal", "liveParameters", "liveTorqueParameters", - "controlsStateSP", "modelV2SP" + "wideRoadCameraState", "managerState", "clocks", }); Params params; @@ -403,6 +257,7 @@ UIState::UIState(QObject *parent) : QObject(parent) { prime_type = static_cast(std::atoi(prime_value.c_str())); } + RETURN_IF_SUNNYPILOT // update timer timer = new QTimer(this); QObject::connect(timer, &QTimer::timeout, this, &UIState::update); @@ -410,10 +265,15 @@ UIState::UIState(QObject *parent) : QObject(parent) { } void UIState::update() { + RETURN_IF_SUNNYPILOT update_sockets(this); update_state(this); updateStatus(); + if (std::getenv("PRIME_TYPE")) { + setPrimeType((PrimeType)atoi(std::getenv("PRIME_TYPE"))); + } + if (sm->frame % UI_FREQ == 0) { watchdog_kick(nanos_since_boot()); } @@ -435,21 +295,12 @@ void UIState::setPrimeType(PrimeType type) { } } -void UIState::setSunnylinkRoles(const std::vector& roles) { - sunnylinkRoles = roles; - emit sunnylinkRolesChanged(roles); -} - -void UIState::setSunnylinkDeviceUsers(const std::vector& users) { - sunnylinkUsers = users; - emit sunnylinkDeviceUsersChanged(users); -} - Device::Device(QObject *parent) : brightness_filter(BACKLIGHT_OFFROAD, BACKLIGHT_TS, BACKLIGHT_DT), QObject(parent) { setAwake(true); resetInteractiveTimeout(); - +#ifndef SUNNYPILOT QObject::connect(uiState(), &UIState::uiUpdate, this, &Device::update); +#endif } void Device::update(const UIState &s) { @@ -474,7 +325,7 @@ void Device::resetInteractiveTimeout(int timeout) { } void Device::updateBrightness(const UIState &s) { - float clipped_brightness = offroad_brightness; + clipped_brightness = offroad_brightness; if (s.scene.started && s.scene.light_sensor > 0) { clipped_brightness = s.scene.light_sensor; @@ -488,14 +339,11 @@ void Device::updateBrightness(const UIState &s) { // Scale back to 10% to 100% clipped_brightness = std::clamp(100.0f * clipped_brightness, 10.0f, 100.0f); } - + RETURN_IF_SUNNYPILOT + int brightness = brightness_filter.update(clipped_brightness); if (!awake) { brightness = 0; - } else if (s.scene.started && s.scene.sleep_time == 0 && s.scene.onroadScreenOff != -2) { - brightness = s.scene.onroadScreenOffBrightness * 0.01 * brightness; - } else if (s.scene.brightness) { - brightness = s.scene.brightness * 0.99; } if (brightness != last_brightness) { @@ -519,6 +367,7 @@ void Device::updateWakefulness(const UIState &s) { setAwake(s.scene.ignition || interactive_timeout > 0); } +#ifndef SUNNYPILOT UIState *uiState() { static UIState ui_state; return &ui_state; @@ -528,3 +377,4 @@ Device *device() { static Device _device; return &_device; } +#endif \ No newline at end of file diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index a9fb6f0671..5626af6a91 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include @@ -15,31 +14,11 @@ #include "common/mat.h" #include "common/params.h" #include "common/timing.h" -#include "qt/network/sunnylink/models/role_model.h" -#include "qt/network/sunnylink/models/sponsor_role_model.h" -#include "qt/network/sunnylink/models/user_model.h" #include "system/hardware/hw.h" const int UI_BORDER_SIZE = 30; const int UI_HEADER_HEIGHT = 420; -const int UI_ROAD_NAME_MARGIN_X = 14; - -struct FeatureStatusText { - const QStringList dlp_list_text = { "Laneful", "Laneless", "Auto"}; - const QStringList gac_list_text = { "Aggressive", "Moderate", "Standard", "Relaxed"}; - const QStringList slc_list_text = { "Inactive", "Temp Off", "Adapting", "Active", "Pre Active"}; -}; - -struct FeatureStatusColor { - const QStringList dlp_list_color = { "#2020f8", "#0df87a", "#0df8f8" }; - const QStringList gac_list_color = { "#ff4b4b", "#fcff4b", "#4bff66", "#6a0ac9" }; - const QStringList slc_list_color = { "#ffffff", "#ffffff", "#fcff4b", "#4bff66", "#fcff4b" }; -}; - -const float DRIVING_PATH_WIDE = 0.9; -const float DRIVING_PATH_NARROW = 0.25; - const int UI_FREQ = 20; // Hz const int BACKLIGHT_OFFROAD = 50; @@ -66,12 +45,18 @@ constexpr vec3 default_face_kpts_3d[] = { {18.02, -49.14, 8.00}, {6.36, -51.20, 8.00}, {-5.98, -51.20, 8.00}, }; +//Example of a macro +#ifdef SUNNYPILOT +#define EXTRA_UI_STATES STATUS_MADS +#else +#define EXTRA_UI_STATES +#endif typedef enum UIStatus { STATUS_DISENGAGED, STATUS_OVERRIDE, STATUS_ENGAGED, - STATUS_MADS, + EXTRA_UI_STATES } UIStatus; enum PrimeType { @@ -88,18 +73,10 @@ enum PrimeType { const QColor bg_colors [] = { [STATUS_DISENGAGED] = QColor(0x17, 0x33, 0x49, 0xc8), [STATUS_OVERRIDE] = QColor(0x91, 0x9b, 0x95, 0xf1), - [STATUS_ENGAGED] = QColor(0x00, 0xc8, 0x00, 0xf1), - [STATUS_MADS] = QColor(0x00, 0xc8, 0xc8, 0xf1), + [STATUS_ENGAGED] = QColor(0x17, 0x86, 0x44, 0xf1), }; -const QColor tcs_colors [] = { - [int(cereal::LongitudinalPlanSP::VisionTurnControllerState::DISABLED)] = QColor(0x0, 0x0, 0x0, 0xff), - [int(cereal::LongitudinalPlanSP::VisionTurnControllerState::ENTERING)] = QColor(0xC9, 0x22, 0x31, 0xf1), - [int(cereal::LongitudinalPlanSP::VisionTurnControllerState::TURNING)] = QColor(0xDA, 0x6F, 0x25, 0xf1), - [int(cereal::LongitudinalPlanSP::VisionTurnControllerState::LEAVING)] = QColor(0x17, 0x86, 0x44, 0xf1), -}; - typedef struct UIScene { bool calibration_valid = false; bool calibration_wide_valid = false; @@ -107,24 +84,13 @@ typedef struct UIScene { mat3 view_from_calib = DEFAULT_CALIBRATION; mat3 view_from_wide_calib = DEFAULT_CALIBRATION; cereal::PandaState::PandaType pandaType; - cereal::ControlsState::Reader controlsState; - - // Debug UI - bool show_debug_ui; - - // Speed limit control - bool speed_limit_control_enabled; - int speed_limit_control_policy; - double last_speed_limit_sign_tap; // modelV2 float lane_line_probs[4]; float road_edge_stds[2]; QPolygonF track_vertices; - QPolygonF track_edge_vertices; QPolygonF lane_line_vertices[4]; QPolygonF road_edge_vertices[2]; - QPolygonF lane_barrier_vertices[2]; // lead QPointF lead_vertices[2]; @@ -136,87 +102,24 @@ typedef struct UIScene { float driver_pose_coss[3]; vec3 face_kpts_draw[std::size(default_face_kpts_3d)]; - bool navigate_on_openpilot_deprecated = false; cereal::LongitudinalPersonality personality; - cereal::AccelerationPersonality accel_personality; float light_sensor = -1; - bool started, ignition, is_metric, map_on_left, longitudinal_control; + bool started, ignition, is_metric, longitudinal_control; bool world_objects_visible = false; uint64_t started_frame; - - int dynamic_lane_profile; - bool dynamic_lane_profile_status = true; - - bool visual_brake_lights; - - int onroadScreenOff, osoTimer, brightness, onroadScreenOffBrightness, awake; - bool onroadScreenOffEvent; - int sleep_time = -1; - bool touched2 = false; - - bool stand_still_timer; - - bool hide_vego_ui, true_vego_ui; - - int chevron_data; - - bool gac; - int longitudinal_personality; - int longitudinal_accel_personality; - - bool map_visible; - int dev_ui_info; - bool live_torque_toggle; - - bool touch_to_wake = false; - int sleep_btn = -1; - bool sleep_btn_fading_in = false; - int sleep_btn_opacity = 20; - bool button_auto_hide; - - bool reverse_dm_cam; - - bool e2e_long_alert_light, e2e_long_alert_lead, e2e_long_alert_ui; - float e2eX[13] = {0}; - - int sidebar_temp_options; - - float mads_path_scale = DRIVING_PATH_WIDE - DRIVING_PATH_NARROW; - float mads_path_range = DRIVING_PATH_WIDE - DRIVING_PATH_NARROW; // 0.9 - 0.25 = 0.65 - - bool onroad_settings_visible; - - bool map_3d_buildings; - - bool torqued_override; - - bool dynamic_experimental_control; - - int speed_limit_control_engage_type; - - bool mapbox_fullscreen; - - bool speed_limit_warning_flash; - int speed_limit_warning_type; - int speed_limit_warning_value_offset; - - bool custom_driving_model_valid; - cereal::ModelGeneration driving_model_generation; - uint32_t driving_model_capabilities; - - bool feature_status_toggle; - bool onroad_settings_toggle; - - bool dynamic_personality; } UIScene; +#ifdef SUNNYPILOT +#include "sunnypilot/qt/ui_scene.h" +#define UIScene UISceneSP +#endif class UIState : public QObject { Q_OBJECT public: UIState(QObject* parent = 0); - void updateStatus(); + virtual void updateStatus(); inline bool engaged() const { return scene.started && (*sm)["controlsState"].getControlsState().getEnabled(); } @@ -225,42 +128,6 @@ public: inline PrimeType primeType() const { return prime_type; } inline bool hasPrime() const { return prime_type > PrimeType::NONE; } - void setSunnylinkRoles(const std::vector &roles); - void setSunnylinkDeviceUsers(const std::vector &users); - - inline std::vector sunnylinkDeviceRoles() const { return sunnylinkRoles; } - inline bool isSunnylinkAdmin() const { - return std::any_of(sunnylinkRoles.begin(), sunnylinkRoles.end(), [](const RoleModel &role) { - return role.roleType == RoleType::Admin; - }); - } - inline bool isSunnylinkSponsor() const { - return std::any_of(sunnylinkRoles.begin(), sunnylinkRoles.end(), [](const RoleModel &role) { - return role.roleType == RoleType::Sponsor && role.as().roleTier != SponsorTier::Free; - }); - } - inline SponsorRoleModel sunnylinkSponsorRole() const { - std::optional sponsorRoleWithHighestTier = std::nullopt; - for (const auto &role : sunnylinkRoles) { - if(role.roleType != RoleType::Sponsor) - continue; - - if (auto sponsorRole = role.as(); !sponsorRoleWithHighestTier.has_value() || sponsorRoleWithHighestTier->roleTier < sponsorRole.roleTier) { - sponsorRoleWithHighestTier = sponsorRole; - } - } - return sponsorRoleWithHighestTier.value_or(SponsorRoleModel(RoleType::Sponsor, SponsorTier::Free)); - } - inline SponsorTier sunnylinkSponsorTier() const { - return sunnylinkSponsorRole().roleTier; - } - inline std::vector sunnylinkDeviceUsers() const { return sunnylinkUsers; } - inline bool isSunnylinkPaired() const { - return std::any_of(sunnylinkUsers.begin(), sunnylinkUsers.end(), [](const UserModel &user) { - return user.user_id.toLower() != "unregisteredsponsor" && user.user_id.toLower() != "temporarysponsor"; - }); - } - int fb_w = 0, fb_h = 0; std::unique_ptr sm; @@ -278,27 +145,21 @@ signals: void primeChanged(bool prime); void primeTypeChanged(PrimeType prime_type); - void sunnylinkRoleChanged(bool subscriber); - void sunnylinkRolesChanged(std::vector roles); - void sunnylinkDeviceUsersChanged(std::vector users); +protected slots: + virtual void update(); -private slots: - void update(); - -private: +protected: QTimer *timer; - bool started_prev = false; PrimeType prime_type = PrimeType::UNKNOWN; - std::vector sunnylinkRoles = {}; - std::vector sunnylinkUsers = {}; - bool last_mads_enabled = false; - bool mads_path_state = false; - float mads_path_timestep = 4; // UI runs at 20 Hz, therefore 0.2 second is [0.2 second / (1 / 20 Hz) = 4] - float mads_path_count = 4; // UI runs at 20 Hz, therefore 0.2 second is [0.2 second / (1 / 20 Hz) = 4] +private: + bool started_prev = false; }; +#undef UIScene +#ifndef SUNNYPILOT UIState *uiState(); +#endif // device management class class Device : public QObject { @@ -311,7 +172,7 @@ public: offroad_brightness = std::clamp(brightness, 0, 100); } -private: +protected: bool awake = false; int interactive_timeout = 0; bool ignition_on = false; @@ -321,9 +182,10 @@ private: FirstOrderFilter brightness_filter; QFuture brightness_future; - void updateBrightness(const UIState &s); + virtual void updateBrightness(const UIState &s); void updateWakefulness(const UIState &s); void setAwake(bool on); + float clipped_brightness; signals: void displayPowerChanged(bool on); @@ -334,7 +196,9 @@ public slots: void update(const UIState &s); }; +#ifndef SUNNYPILOT Device *device(); +#endif void ui_update_params(UIState *s); int get_path_length_idx(const cereal::XYZTData::Reader &line, const float path_height); @@ -343,4 +207,8 @@ void update_model(UIState *s, void update_dmonitoring(UIState *s, const cereal::DriverStateV2::Reader &driverstate, float dm_fade_state, bool is_rhd); void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, const cereal::XYZTData::Reader &line); void update_line_data(const UIState *s, const cereal::XYZTData::Reader &line, - float y_off, float z_off_left, float z_off_right, QPolygonF *pvd, int max_idx, bool allow_invert); + float y_off, float z_off, QPolygonF *pvd, int max_idx, bool allow_invert); + +bool calib_frame_to_full_frame(const UIState *s, float in_x, float in_y, float in_z, QPointF *out, float margin=500.0f); +void update_state(UIState *s); +void update_sockets(UIState *s); diff --git a/system/manager/process_config.py b/system/manager/process_config.py index a718ea021b..1db62dc2c4 100644 --- a/system/manager/process_config.py +++ b/system/manager/process_config.py @@ -45,8 +45,7 @@ def only_offroad(started, params, CP: car.CarParams) -> bool: return not started def use_gitlab_runner(started, params, CP: car.CarParams) -> bool: - return (not PC and params.get_bool("EnableGitlabRunner") and only_offroad(started, params, CP) - and os.path.exists("./gitlab_runner.sh")) + return not PC and params.get_bool("EnableGitlabRunner") and only_offroad(started, params, CP) def model_use_nav(started, params, CP: car.CarParams) -> bool: custom_model_metadata = CustomModelMetadata(params=params, init_only=True) @@ -62,7 +61,7 @@ def sunnylink_need_register_shim(started, params, CP: car.CarParams) -> bool: def use_sunnylink_uploader_shim(started, params, CP: car.CarParams) -> bool: """Shim for use_sunnylink_uploader to match the process manager signature.""" - return use_sunnylink_uploader(params) and os.path.exists("../loggerd/sunnylink_uploader.py") + return use_sunnylink_uploader(params) procs = [ DaemonProcess("manage_athenad", "system.athena.manage_athenad", "AthenadPid"), @@ -120,12 +119,15 @@ procs = [ PythonProcess("webrtcd", "system.webrtc.webrtcd", notcar), PythonProcess("webjoystick", "tools.bodyteleop.web", notcar), - # Sunnypilot devs - NativeProcess("gitlab_runner_start", "system/manager", ["./gitlab_runner.sh", "start"], use_gitlab_runner, sigkill=False), - # Sunnylink <3 + # sunnylink <3 DaemonProcess("manage_sunnylinkd", "system.athena.manage_sunnylinkd", "SunnylinkdPid"), PythonProcess("sunnylink_registration", "system.manager.sunnylink", sunnylink_need_register_shim), - PythonProcess("sunnylink_uploader", "system.loggerd.sunnylink_uploader", use_sunnylink_uploader_shim), ] +if os.path.exists("./gitlab_runner.sh"): + procs += [NativeProcess("gitlab_runner_start", "system/manager", ["./gitlab_runner.sh", "start"], use_gitlab_runner, sigkill=False)] + +if os.path.exists("../loggerd/sunnylink_uploader.py"): + procs += [PythonProcess("sunnylink_uploader", "system.loggerd.sunnylink_uploader", use_sunnylink_uploader_shim)] + managed_processes = {p.name: p for p in procs} diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 15e1ee5f2f..f1700ebe20 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -6,7 +6,12 @@ #include #include +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#define ElidedLabel ElidedLabelSP +#else #include "selfdrive/ui/qt/widgets/controls.h" +#endif #include "tools/cabana/binaryview.h" #include "tools/cabana/chart/chartswidget.h" #include "tools/cabana/historylog.h" From eb1b0d7ddcc88541aefeb0081ca8be5546d490dd Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Mon, 29 Jul 2024 06:55:29 -0400 Subject: [PATCH 147/229] Update public panda submodule --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 2fb99d017c..d794b781f6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "panda"] path = panda - url = ../../sunnyhaibin/panda-special.git + url = ../../sunnyhaibin/panda.git [submodule "opendbc"] path = opendbc url = https://github.com/sunnyhaibin/opendbc.git From 1ae3adbe13cc4e9d4049b9c5e5cb398ede93f001 Mon Sep 17 00:00:00 2001 From: commaci-public <60409688+commaci-public@users.noreply.github.com> Date: Mon, 29 Jul 2024 10:24:05 -0700 Subject: [PATCH 148/229] [bot] Update Python packages and pre-commit hooks (#33122) Update Python packages and pre-commit hooks Co-authored-by: Vehicle Researcher --- .pre-commit-config.yaml | 4 ++-- uv.lock | 50 +++++++++++++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 10939f4289..a7a5379088 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,7 +33,7 @@ repos: - -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn - --builtins clear,rare,informal,usage,code,names,en-GB_to_en-US - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.4 + rev: v0.5.5 hooks: - id: ruff exclude: '^(third_party/)|(msgq/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)' @@ -93,7 +93,7 @@ repos: pass_filenames: false files: '^selfdrive/ui/translations/' - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.29.0 + rev: 0.29.1 hooks: - id: check-github-workflows - repo: local diff --git a/uv.lock b/uv.lock index a08ad9c4be..089c16464a 100644 --- a/uv.lock +++ b/uv.lock @@ -1010,11 +1010,11 @@ wheels = [ [[distribution]] name = "markdown" -version = "3.3.7" +version = "3.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/58/79df20de6e67a83f0d0bbfe6c19bb82adf68cdf362885257eb01099f930a/Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874", size = 324130 } +sdist = { url = "https://files.pythonhosted.org/packages/22/02/4785861427848cc11e452cc62bb541006a1087cf04a1de83aedd5530b948/Markdown-3.6.tar.gz", hash = "sha256:ed4f41f6daecbeeb96e576ce414c41d2d876daa9a16cb35fa8ed8c2ddfad0224", size = 354715 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/df/ca72f352e15b6f8ce32b74af029f1189abffb906f7c137501ffe69c98a65/Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621", size = 97778 }, + { url = "https://files.pythonhosted.org/packages/fc/b3/0c0c994fe49cd661084f8d5dc06562af53818cc0abefaca35bdc894577c3/Markdown-3.6-py3-none-any.whl", hash = "sha256:48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f", size = 105381 }, ] [[distribution]] @@ -1116,7 +1116,7 @@ dependencies = [ [[distribution]] name = "mkdocs" -version = "1.4.3" +version = "1.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -1124,15 +1124,32 @@ dependencies = [ { name = "ghp-import" }, { name = "jinja2" }, { name = "markdown" }, + { name = "markupsafe" }, { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, { name = "packaging" }, + { name = "pathspec" }, { name = "pyyaml" }, { name = "pyyaml-env-tag" }, { name = "watchdog" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b0/ef/49b4427e5eec761b77a3c3c421d3fd63010e2798b7401dc0fa2b875ef6b5/mkdocs-1.4.3.tar.gz", hash = "sha256:5955093bbd4dd2e9403c5afaf57324ad8b04f16886512a3ee6ef828956481c57", size = 3624951 } +sdist = { url = "https://files.pythonhosted.org/packages/cc/6b/26b33cc8ad54e8bc0345cddc061c2c5c23e364de0ecd97969df23f95a673/mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512", size = 3888392 } wheels = [ - { url = "https://files.pythonhosted.org/packages/42/7a/5ed794942ace9d00bb77a8036c64c999cda6ebaab57e9b8a6ec1aa5fc900/mkdocs-1.4.3-py3-none-any.whl", hash = "sha256:6ee46d309bda331aac915cd24aab882c179a933bd9e77b80ce7d2eaaa3f689dd", size = 3654464 }, + { url = "https://files.pythonhosted.org/packages/b8/c0/930dcf5a3e96b9c8e7ad15502603fc61d495479699e2d2c381e3d37294d1/mkdocs-1.6.0-py3-none-any.whl", hash = "sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7", size = 3862264 }, +] + +[[distribution]] +name = "mkdocs-get-deps" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mergedeep" }, + { name = "platformdirs" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521 }, ] [[distribution]] @@ -1525,9 +1542,9 @@ version = "2.2.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy", marker = "python_version == '3.11' or python_version >= '3.12'" }, - { name = "python-dateutil" }, - { name = "pytz" }, - { name = "tzdata" }, + { name = "python-dateutil", marker = "python_version == '3.11' or python_version >= '3.12' or (python_version < '3.12' and (python_version < '3.11' or python_version > '3.11'))" }, + { name = "pytz", marker = "python_version == '3.11' or python_version >= '3.12' or (python_version < '3.12' and (python_version < '3.11' or python_version > '3.11'))" }, + { name = "tzdata", marker = "python_version == '3.11' or python_version >= '3.12' or (python_version < '3.12' and (python_version < '3.11' or python_version > '3.11'))" }, ] sdist = { url = "https://files.pythonhosted.org/packages/88/d9/ecf715f34c73ccb1d8ceb82fc01cd1028a65a5f6dbc57bfa6ea155119058/pandas-2.2.2.tar.gz", hash = "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54", size = 4398391 } wheels = [ @@ -1556,6 +1573,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/31/13/fe468c8c7400a8eca204e6e160a29bf7dcd45a76e20f1c030f3eaa690d93/parameterized-0.8.1-py2.py3-none-any.whl", hash = "sha256:9cbb0b69a03e8695d68b3399a8a5825200976536fe1cb79db60ed6a4c8c9efe9", size = 26354 }, ] +[[distribution]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, +] + [[distribution]] name = "pillow" version = "10.4.0" @@ -1629,7 +1655,7 @@ wheels = [ [[distribution]] name = "pre-commit" -version = "3.7.1" +version = "3.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cfgv" }, @@ -1638,9 +1664,9 @@ dependencies = [ { name = "pyyaml" }, { name = "virtualenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/aa/46/cc214ef6514270328910083d0119d0a80a6d2c4ec8c6608c0219db0b74cf/pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a", size = 177317 } +sdist = { url = "https://files.pythonhosted.org/packages/64/10/97ee2fa54dff1e9da9badbc5e35d0bbaef0776271ea5907eccf64140f72f/pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af", size = 177815 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/0f/d6d0b4e2f5b2933a557087fc0560371aa545a18232d4d3427eb3bb3af12e/pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5", size = 204268 }, + { url = "https://files.pythonhosted.org/packages/07/92/caae8c86e94681b42c246f0bca35c059a2f0529e5b92619f6aba4cf7e7b6/pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f", size = 204643 }, ] [[distribution]] From 01c07569741a84fae9a7fe9c8ef1830d59822f63 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Mon, 29 Jul 2024 11:52:33 -0700 Subject: [PATCH 149/229] Remove control usage (#33103) * manual matrix exp * remove control --- pyproject.toml | 1 - .../controls/lib/tests/test_vehicle_model.py | 11 +++++++---- uv.lock | 15 --------------- 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 86eb08fa1c..4c1e134431 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,7 +94,6 @@ dev = [ "av", "azure-identity", "azure-storage-blob", - "control", "dictdiffer", "flaky", "inputs", diff --git a/selfdrive/controls/lib/tests/test_vehicle_model.py b/selfdrive/controls/lib/tests/test_vehicle_model.py index 4d0e41805d..f666f875a6 100644 --- a/selfdrive/controls/lib/tests/test_vehicle_model.py +++ b/selfdrive/controls/lib/tests/test_vehicle_model.py @@ -2,7 +2,6 @@ import pytest import math import numpy as np -from control import StateSpace from openpilot.selfdrive.car.honda.interface import CarInterface from openpilot.selfdrive.car.honda.values import CAR @@ -47,8 +46,12 @@ class TestVehicleModel: A, B = create_dyn_state_matrices(u, self.VM) # Convert to discrete time system - ss = StateSpace(A, B, np.eye(2), np.zeros((2, 2))) - ss = ss.sample(0.01) + dt = 0.01 + top = np.hstack((A, B)) + full = np.vstack((top, np.zeros_like(top))) * dt + Md = sum([np.linalg.matrix_power(full, k) / math.factorial(k) for k in range(25)]) + Ad = Md[:A.shape[0], :A.shape[1]] + Bd = Md[:A.shape[0], A.shape[1]:] for sa in np.linspace(math.radians(-20), math.radians(20), num=11): inp = np.array([[sa], [roll]]) @@ -56,7 +59,7 @@ class TestVehicleModel: # Simulate for 1 second x1 = np.zeros((2, 1)) for _ in range(100): - x1 = ss.A @ x1 + ss.B @ inp + x1 = Ad @ x1 + Bd @ inp # Compute steady state solution directly x2 = dyn_ss_sol(sa, u, roll, self.VM) diff --git a/uv.lock b/uv.lock index 089c16464a..2913075f5b 100644 --- a/uv.lock +++ b/uv.lock @@ -369,20 +369,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/78/38/a046bb0ebce6f530175d434e7364149e338ffe1069ee286ed8ba7f6481ee/contourpy-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:1a07fc092a4088ee952ddae19a2b2a85757b923217b7eed584fdf25f53a6e7ce", size = 189901 }, ] -[[distribution]] -name = "control" -version = "0.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "matplotlib" }, - { name = "numpy" }, - { name = "scipy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ee/64/02fedcf78b070571f5e446efb55b7ec82b68187323402b99b6f98f769530/control-0.10.0.tar.gz", hash = "sha256:2c18b767537f45c7fd07b2e4afe8fbe5964019499b5f52f888edb5d8560bab53", size = 8956376 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/de/327ab576657cb6bd5678e5d4fa266f3c4c7094e99df2bb7760e89176772d/control-0.10.0-py3-none-any.whl", hash = "sha256:ed1e0eb73f1e2945fc9af9d7b9121ef328fe980e7903b2a14b149d4f1855a808", size = 513858 }, -] - [[distribution]] name = "coverage" version = "7.6.0" @@ -1439,7 +1425,6 @@ dev = [ { name = "av" }, { name = "azure-identity" }, { name = "azure-storage-blob" }, - { name = "control" }, { name = "dictdiffer" }, { name = "flaky" }, { name = "hexdump" }, From 1f770e1bea4fd28e0b3b3789e81655f44bcb9773 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Mon, 29 Jul 2024 15:25:44 -0400 Subject: [PATCH 150/229] Submodule: Point to panda on GitHub --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index d794b781f6..223a45f69c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "panda"] path = panda - url = ../../sunnyhaibin/panda.git + url = https://github.com/sunnyhaibin/panda.git [submodule "opendbc"] path = opendbc url = https://github.com/sunnyhaibin/opendbc.git From 606890cba5ca8c65391abebba505fc211ca1e6b4 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 29 Jul 2024 12:32:51 -0700 Subject: [PATCH 151/229] [bot] Fingerprints: add missing FW versions from new users (#33123) Export fingerprints --- selfdrive/car/hyundai/fingerprints.py | 3 ++- selfdrive/car/toyota/fingerprints.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index 5f959bd68d..6c7480a15d 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -712,6 +712,7 @@ FW_VERSIONS = { ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00DEhe SCC F-CUP 1.00 1.02 99110-G5100 ', + b'\xf1\x00DEhe SCC FHCUP 1.00 1.02 99110-G5100 ', b'\xf1\x00DEhe SCC H-CUP 1.01 1.02 96400-G5100 ', ], }, @@ -764,8 +765,8 @@ FW_VERSIONS = { b'\xf1\x00JF__ SCC F-CUP 1.00 1.00 96400-D4100 ', ], (Ecu.abs, 0x7d1, None): [ - b'\xf1\x00JF ESC \x0f 16 \x16\x06\x17 58920-D5080', b'\xf1\x00JF ESC \t 17 \x16\x06# 58920-D4180', + b'\xf1\x00JF ESC \x0f 16 \x16\x06\x17 58920-D5080', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00JFWGN LDWS AT USA LHD 1.00 1.02 95895-D4100 G21', diff --git a/selfdrive/car/toyota/fingerprints.py b/selfdrive/car/toyota/fingerprints.py index 37c69b54fb..a7ea14f203 100644 --- a/selfdrive/car/toyota/fingerprints.py +++ b/selfdrive/car/toyota/fingerprints.py @@ -650,6 +650,7 @@ FW_VERSIONS = { (Ecu.dsu, 0x791, None): [ b'881510E01100\x00\x00\x00\x00', b'881510E01200\x00\x00\x00\x00', + b'881510E02100\x00\x00\x00\x00', b'881510E02200\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ From 2728c95b0d8f95faca4c1ee11a77a050f0d1c5fb Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 30 Jul 2024 04:43:31 +0800 Subject: [PATCH 152/229] uploader.py: ensure proper resource management with io.BytesIO (#33108) * ensure proper resource management with io.BytesIO * improve --- system/loggerd/uploader.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/system/loggerd/uploader.py b/system/loggerd/uploader.py index d984936e88..965d74bef8 100755 --- a/system/loggerd/uploader.py +++ b/system/loggerd/uploader.py @@ -9,7 +9,6 @@ import time import traceback import datetime import zstandard as zstd -from typing import BinaryIO from collections.abc import Iterator from cereal import log @@ -152,14 +151,12 @@ class Uploader: return FakeResponse() with open(fn, "rb") as f: - data: BinaryIO + content = f.read() if key.endswith('.zst') and not fn.endswith('.zst'): - compressed = zstd.compress(f.read(), LOG_COMPRESSION_LEVEL) - data = io.BytesIO(compressed) - else: - data = f + content = zstd.compress(content, LOG_COMPRESSION_LEVEL) - return requests.put(url, data=data, headers=headers, timeout=10) + with io.BytesIO(content) as data: + return requests.put(url, data=data, headers=headers, timeout=10) def upload(self, name: str, key: str, fn: str, network_type: int, metered: bool) -> bool: try: From 7d6ff19dead7a9bee819a143eb4c8a929a9e28fd Mon Sep 17 00:00:00 2001 From: Andrei Radulescu Date: Mon, 29 Jul 2024 23:46:13 +0300 Subject: [PATCH 153/229] update mac_setup.sh brew install (#33131) --- tools/mac_setup.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/mac_setup.sh b/tools/mac_setup.sh index 282121ef1d..3465747a50 100755 --- a/tools/mac_setup.sh +++ b/tools/mac_setup.sh @@ -22,16 +22,16 @@ fi # Install brew if required if [[ $(command -v brew) == "" ]]; then echo "Installing Homebrew" - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" echo "[ ] installed brew t=$SECONDS" # make brew available now if [[ $ARCH == "x86_64" ]]; then - echo 'eval "$(/usr/local/homebrew/bin/brew shellenv)"' >> $RC_FILE - eval "$(/usr/local/homebrew/bin/brew shellenv)" + echo 'eval "$(/usr/local/bin/brew shellenv)"' >> $RC_FILE + eval "$(/usr/local/bin/brew shellenv)" else - echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> $RC_FILE - eval "$(/opt/homebrew/bin/brew shellenv)" + echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> $RC_FILE + eval "$(/opt/homebrew/bin/brew shellenv)" fi fi From ade13722cd10261696c7b49e7a6e4f6d65f1b74e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 30 Jul 2024 04:48:06 +0800 Subject: [PATCH 154/229] replay: add support for decompressing ZST log files (#32910) * Add Support for Decompressing ZST Log Files * 2 space and check magic number * match BZ2 --------- Co-authored-by: Shane Smiskol --- tools/cabana/SConscript | 2 +- tools/install_ubuntu_dependencies.sh | 1 + tools/replay/SConscript | 2 +- tools/replay/logreader.cc | 10 ++++++-- tools/replay/route.cc | 4 +-- tools/replay/util.cc | 37 +++++++++++++++++++++++++++- tools/replay/util.h | 2 ++ 7 files changed, 51 insertions(+), 7 deletions(-) diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index ba4a142451..04b768dc69 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -15,7 +15,7 @@ else: qt_libs = ['qt_util'] + base_libs cabana_env = qt_env.Clone() -cabana_libs = [widgets, cereal, messaging, visionipc, replay_lib, 'panda', 'avutil', 'avcodec', 'avformat', 'bz2', 'curl', 'yuv', 'usb-1.0'] + qt_libs +cabana_libs = [widgets, cereal, messaging, visionipc, replay_lib, 'panda', 'avutil', 'avcodec', 'avformat', 'bz2', 'zstd', 'curl', 'yuv', 'usb-1.0'] + qt_libs opendbc_path = '-DOPENDBC_FILE_PATH=\'"%s"\'' % (cabana_env.Dir("../../opendbc").abspath) cabana_env['CXXFLAGS'] += [opendbc_path] diff --git a/tools/install_ubuntu_dependencies.sh b/tools/install_ubuntu_dependencies.sh index 4373760ce6..67b28fa280 100755 --- a/tools/install_ubuntu_dependencies.sh +++ b/tools/install_ubuntu_dependencies.sh @@ -46,6 +46,7 @@ function install_ubuntu_common_requirements() { libssl-dev \ libusb-1.0-0-dev \ libzmq3-dev \ + libzstd-dev \ libsqlite3-dev \ libsystemd-dev \ locales \ diff --git a/tools/replay/SConscript b/tools/replay/SConscript index cf9d74a894..1f966d4372 100644 --- a/tools/replay/SConscript +++ b/tools/replay/SConscript @@ -12,7 +12,7 @@ else: replay_lib_src = ["replay.cc", "consoleui.cc", "camera.cc", "filereader.cc", "logreader.cc", "framereader.cc", "route.cc", "util.cc"] replay_lib = qt_env.Library("qt_replay", replay_lib_src, LIBS=base_libs, FRAMEWORKS=base_frameworks) Export('replay_lib') -replay_libs = [replay_lib, 'avutil', 'avcodec', 'avformat', 'bz2', 'curl', 'yuv', 'ncurses'] + base_libs +replay_libs = [replay_lib, 'avutil', 'avcodec', 'avformat', 'bz2', 'zstd', 'curl', 'yuv', 'ncurses'] + base_libs qt_env.Program("replay", ["main.cc"], LIBS=replay_libs, FRAMEWORKS=base_frameworks) if GetOption('extras'): diff --git a/tools/replay/logreader.cc b/tools/replay/logreader.cc index 9b726e067d..415b8c0b5e 100644 --- a/tools/replay/logreader.cc +++ b/tools/replay/logreader.cc @@ -4,11 +4,17 @@ #include #include "tools/replay/filereader.h" #include "tools/replay/util.h" +#include "common/util.h" bool LogReader::load(const std::string &url, std::atomic *abort, bool local_cache, int chunk_size, int retries) { std::string data = FileReader(local_cache, chunk_size, retries).read(url, abort); - if (!data.empty() && url.find(".bz2") != std::string::npos) - data = decompressBZ2(data, abort); + if (!data.empty()) { + if (url.find(".bz2") != std::string::npos || util::starts_with(data, "BZh9")) { + data = decompressBZ2(data, abort); + } else if (url.find(".zst") != std::string::npos || util::starts_with(data, "\x28\xB5\x2F\xFD")) { + data = decompressZST(data, abort); + } + } bool success = !data.empty() && load(data.data(), data.size(), abort); if (filters_.empty()) diff --git a/tools/replay/route.cc b/tools/replay/route.cc index 716b02961e..c1e65526cf 100644 --- a/tools/replay/route.cc +++ b/tools/replay/route.cc @@ -122,9 +122,9 @@ void Route::addFileToSegment(int n, const QString &file) { const int pos = name.lastIndexOf("--"); name = pos != -1 ? name.mid(pos + 2) : name; - if (name == "rlog.bz2" || name == "rlog") { + if (name == "rlog.bz2" || name == "rlog.zst" || name == "rlog") { segments_[n].rlog = file; - } else if (name == "qlog.bz2" || name == "qlog") { + } else if (name == "qlog.bz2" || name == "qlog.zst" || name == "qlog") { segments_[n].qlog = file; } else if (name == "fcamera.hevc") { segments_[n].road_cam = file; diff --git a/tools/replay/util.cc b/tools/replay/util.cc index aaf73749d5..81e87b7dd3 100644 --- a/tools/replay/util.cc +++ b/tools/replay/util.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include "common/timing.h" #include "common/util.h" @@ -300,7 +301,7 @@ std::string decompressBZ2(const std::byte *in, size_t in_size, std::atomic if (bzerror == BZ_OK && prev_write_pos == strm.next_out) { // content is corrupt bzerror = BZ_STREAM_END; - rWarning("decompressBZ2 error : content is corrupt"); + rWarning("decompressBZ2 error: content is corrupt"); break; } @@ -318,6 +319,40 @@ std::string decompressBZ2(const std::byte *in, size_t in_size, std::atomic return {}; } +std::string decompressZST(const std::string &in, std::atomic *abort) { + return decompressZST((std::byte *)in.data(), in.size(), abort); +} + +std::string decompressZST(const std::byte *in, size_t in_size, std::atomic *abort) { + ZSTD_DCtx *dctx = ZSTD_createDCtx(); + assert(dctx != nullptr); + + // Initialize input and output buffers + ZSTD_inBuffer input = {in, in_size, 0}; + std::string decompressedData; + const size_t bufferSize = ZSTD_DStreamOutSize(); // recommended output buffer size + std::string outputBuffer(bufferSize, '\0'); + + while (input.pos < input.size && !(abort && *abort)) { + ZSTD_outBuffer output = {outputBuffer.data(), bufferSize, 0}; + + size_t result = ZSTD_decompressStream(dctx, &output, &input); + if (ZSTD_isError(result)) { + rWarning("decompressZST error: content is corrupt"); + break; + } + + decompressedData.append(outputBuffer.data(), output.pos); + } + + ZSTD_freeDCtx(dctx); + if (!(abort && *abort)) { + decompressedData.shrink_to_fit(); + return decompressedData; + } + return {}; +} + void precise_nano_sleep(int64_t nanoseconds, std::atomic &should_exit) { struct timespec req, rem; req.tv_sec = nanoseconds / 1000000000; diff --git a/tools/replay/util.h b/tools/replay/util.h index 97516e1814..c3b016c391 100644 --- a/tools/replay/util.h +++ b/tools/replay/util.h @@ -40,6 +40,8 @@ std::string sha256(const std::string &str); void precise_nano_sleep(int64_t nanoseconds, std::atomic &should_exit); std::string decompressBZ2(const std::string &in, std::atomic *abort = nullptr); std::string decompressBZ2(const std::byte *in, size_t in_size, std::atomic *abort = nullptr); +std::string decompressZST(const std::string &in, std::atomic *abort = nullptr); +std::string decompressZST(const std::byte *in, size_t in_size, std::atomic *abort = nullptr); std::string getUrlWithoutQuery(const std::string &url); size_t getRemoteFileSize(const std::string &url, std::atomic *abort = nullptr); std::string httpGet(const std::string &url, size_t chunk_size = 0, std::atomic *abort = nullptr); From 43dcddc68b5ac132f3d2a1b0adeea9af60ee541e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 29 Jul 2024 14:44:03 -0700 Subject: [PATCH 155/229] qlog: remove mag and less CAN --- cereal/services.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cereal/services.py b/cereal/services.py index 7d73374df1..f7aaa377a9 100755 --- a/cereal/services.py +++ b/cereal/services.py @@ -16,13 +16,13 @@ _services: dict[str, tuple] = { "gyroscope2": (True, 100., 100), "accelerometer": (True, 104., 104), "accelerometer2": (True, 100., 100), - "magnetometer": (True, 25., 25), + "magnetometer": (True, 25.), "lightSensor": (True, 100., 100), "temperatureSensor": (True, 2., 200), "temperatureSensor2": (True, 2., 200), "gpsNMEA": (True, 9.), "deviceState": (True, 2., 1), - "can": (True, 100., 1223), # decimation gives ~5 msgs in a full segment + "can": (True, 100., 2053), # decimation gives ~3 msgs in a full segment "controlsState": (True, 100., 10), "pandaStates": (True, 10., 1), "peripheralState": (True, 2., 1), From 957e6666a5549a67bca592695e548e2583205976 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Mon, 29 Jul 2024 18:27:40 -0400 Subject: [PATCH 156/229] License: Loosen restrictions --- LICENSE.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index e7062d77cf..650b6f55b3 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,10 +1,10 @@ # Custom MIT License -Copyright 2024 Haibin Wen, SUNNYPILOT LLC +Copyright (c) 2024, Haibin Wen, SUNNYPILOT LLC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to view and modify the Software, subject to the following conditions: -1. **Permission Required**: Use of the Software, in whole or in part, for any purpose requires explicit written permission from the original author(s). +1. **Permission Required**: Permission Required for Commercial, For-Profit, or Closed Source Use: Use of the Software, in whole or in part, for any commercial purposes, for-profit projects, or in closed source projects requires explicit written permission from the original author(s). 2. **Redistribution**: Any redistribution of the Software, modified or unmodified, must retain this license notice and the following acknowledgment: "This software is licensed under a custom license requiring permission for use." @@ -12,9 +12,9 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of 3. **Visibility**: Any project that uses the Software must visibly mention the following acknowledgment: "This project uses software from Haibin Wen and SUNNYPILOT LLC and is licensed under a custom license requiring permission for use." -4. **No Warranty**: The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Software or the use or other dealings in the Software. +4. **No Warranty**: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Contact sunnypilot Support for permission requests. +Contact sunnypilot Support for permission requests. --- From 6e185f4eea470fe56fc6a33de9e81779f70941ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Mon, 29 Jul 2024 17:12:05 -0700 Subject: [PATCH 157/229] process_replay: regenerate locationd logs (#33134) * Filter out non-relevant services in most_messages_valid check * Set as comprehension * Update segments * Update ref commit * New check for hyundai2 --- .../test/process_replay/process_replay.py | 4 ++ selfdrive/test/process_replay/ref_commit | 2 +- .../test/process_replay/test_processes.py | 37 ++++++++++--------- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index eae6abfaad..70ed745bac 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -819,11 +819,15 @@ def check_openpilot_enabled(msgs: LogIterable) -> bool: def check_most_messages_valid(msgs: LogIterable, threshold: float = 0.9) -> bool: + relevant_services = {sock for cfg in CONFIGS for sock in cfg.subs} msgs_counts = Counter(msg.which() for msg in msgs) msgs_valid_counts = Counter(msg.which() for msg in msgs if msg.valid) most_valid_for_service = {} for msg_type in msgs_counts.keys(): + if msg_type not in relevant_services: + continue + valid_share = msgs_valid_counts.get(msg_type, 0) / msgs_counts[msg_type] ok = valid_share >= threshold if not ok: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 02e4b997aa..1349e2650f 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -3942de8e75caa7a99828e65c3396abd94d6b3da7 +949909bd80599698c1307b3304010456dded6a15 \ No newline at end of file diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 3bd58dfacb..7fbe933434 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -41,23 +41,23 @@ source_segments = [ ] segments = [ - ("BODY", "regen29FD9FF7760|2024-05-21--06-58-51--0"), - ("HYUNDAI", "regen0B1B76A1C27|2024-05-21--06-57-53--0"), - ("HYUNDAI2", "regen3BB55FA5E20|2024-05-21--06-59-03--0"), - ("TOYOTA", "regenF6FB954C1E2|2024-05-21--06-57-53--0"), - ("TOYOTA2", "regen0AC637CE7BA|2024-05-21--06-57-54--0"), - ("TOYOTA3", "regenC7BE3FAE496|2024-05-21--06-59-01--0"), - ("HONDA", "regen58E9F8B695A|2024-05-21--06-57-55--0"), - ("HONDA2", "regen8695608EB15|2024-05-21--06-57-55--0"), - ("CHRYSLER", "regenB0F8C25C902|2024-05-21--06-59-47--0"), - ("RAM", "regenB3B2C7A105B|2024-05-21--07-00-47--0"), - ("SUBARU", "regen860FD736DCC|2024-05-21--07-00-50--0"), - ("GM", "regen8CB3048DEB9|2024-05-21--06-59-49--0"), - ("GM2", "regen379D446541D|2024-05-21--07-00-51--0"), - ("NISSAN", "regen24871108F80|2024-05-21--07-00-38--0"), - ("VOLKSWAGEN", "regenF390392F275|2024-05-21--07-00-52--0"), - ("MAZDA", "regenE5A36020581|2024-05-21--07-01-51--0"), - ("FORD", "regenDC288ED0D78|2024-05-21--07-02-18--0"), + ("BODY", "regen34ECCE11CA1|2024-07-29--22-55-10--0"), + ("HYUNDAI", "regenC713CE6FA82|2024-07-29--22-56-31--0"), + ("HYUNDAI2", "regenD81F3A374A7|2024-07-29--22-58-45--0"), + ("TOYOTA", "regenE6D76723DC2|2024-07-29--23-00-08--0"), + ("TOYOTA2", "regen198859A572C|2024-07-29--23-01-31--0"), + ("TOYOTA3", "regenDF1EB621A66|2024-07-29--23-03-49--0"), + ("HONDA", "regen0FE7C4758B5|2024-07-29--23-05-14--0"), + ("HONDA2", "regen510A1F60E60|2024-07-29--23-06-39--0"), + ("CHRYSLER", "regenDACF082E83B|2024-07-29--23-08-01--0"), + ("RAM", "regen8BFB7E62F52|2024-07-29--23-10-14--0"), + ("SUBARU", "regen4EE2D45369E|2024-07-29--23-12-31--0"), + ("GM", "regenB38D92E6A4D|2024-07-29--23-13-54--0"), + ("GM2", "regenC5488470F1A|2024-07-29--23-16-09--0"), + ("NISSAN", "regenE5400EB4689|2024-07-29--23-17-30--0"), + ("VOLKSWAGEN", "regenD0B5635A8B9|2024-07-29--23-18-54--0"), + ("MAZDA", "regen57F8511F082|2024-07-29--23-21-09--0"), + ("FORD", "regen5708620AA2E|2024-07-29--23-23-20--0"), ] # dashcamOnly makes don't need to be tested until a full port is done @@ -111,7 +111,8 @@ def test_process(cfg, lr, segment, ref_log_path, new_log_path, ignore_fields=Non if not check_most_messages_valid(log_msgs): return f"Route did not have enough valid messages: {new_log_path}", log_msgs - if cfg.proc_name != 'ubloxd' or segment != 'regen3BB55FA5E20|2024-05-21--06-59-03--0': + # skip this check if the segment is using qcom gps + if cfg.proc_name != 'ubloxd' or any(m.which() in cfg.pubs for m in lr): seen_msgs = {m.which() for m in log_msgs} expected_msgs = set(cfg.subs) if seen_msgs != expected_msgs: From 4e237e59a59576c4f67b039fee362568ce86219e Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Mon, 29 Jul 2024 21:01:11 -0400 Subject: [PATCH 158/229] Translations: Add untranslated --- selfdrive/ui/translations/main_ar.ts | 16 ---------------- selfdrive/ui/translations/main_de.ts | 16 ---------------- selfdrive/ui/translations/main_es.ts | 16 ---------------- selfdrive/ui/translations/main_fr.ts | 16 ---------------- selfdrive/ui/translations/main_ja.ts | 16 ---------------- selfdrive/ui/translations/main_ko.ts | 16 ---------------- selfdrive/ui/translations/main_pt-BR.ts | 16 ---------------- selfdrive/ui/translations/main_th.ts | 16 ---------------- selfdrive/ui/translations/main_tr.ts | 16 ---------------- selfdrive/ui/translations/main_zh-CHS.ts | 16 ---------------- selfdrive/ui/translations/main_zh-CHT.ts | 16 ---------------- 11 files changed, 176 deletions(-) diff --git a/selfdrive/ui/translations/main_ar.ts b/selfdrive/ui/translations/main_ar.ts index 28610a671e..7dae31a53e 100644 --- a/selfdrive/ui/translations/main_ar.ts +++ b/selfdrive/ui/translations/main_ar.ts @@ -1517,22 +1517,6 @@ This may take up to a minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. - - Enable Automatic Brake Hold (AHB) - - - - WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. - - - - When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. - - - - Changing this setting takes effect when the car is powered off. - - Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index ab80c261fd..6b8fd1efc1 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -1499,22 +1499,6 @@ This may take up to a minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. - - Enable Automatic Brake Hold (AHB) - - - - WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. - - - - When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. - - - - Changing this setting takes effect when the car is powered off. - - Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_es.ts b/selfdrive/ui/translations/main_es.ts index 90fc8381c9..6527ddfc12 100644 --- a/selfdrive/ui/translations/main_es.ts +++ b/selfdrive/ui/translations/main_es.ts @@ -1505,22 +1505,6 @@ Esto puede tardar hasta un minuto. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. - - Enable Automatic Brake Hold (AHB) - - - - WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. - - - - When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. - - - - Changing this setting takes effect when the car is powered off. - - Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_fr.ts b/selfdrive/ui/translations/main_fr.ts index 22b5808a62..0071a33e47 100644 --- a/selfdrive/ui/translations/main_fr.ts +++ b/selfdrive/ui/translations/main_fr.ts @@ -1501,22 +1501,6 @@ Cela peut prendre jusqu'à une minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. - - Enable Automatic Brake Hold (AHB) - - - - WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. - - - - When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. - - - - Changing this setting takes effect when the car is powered off. - - Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 0ffade1416..5db645c9f4 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -1495,22 +1495,6 @@ This may take up to a minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. - - Enable Automatic Brake Hold (AHB) - - - - WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. - - - - When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. - - - - Changing this setting takes effect when the car is powered off. - - Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 337f338633..1a55d59a3b 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1497,22 +1497,6 @@ This may take up to a minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. - - Enable Automatic Brake Hold (AHB) - - - - WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. - - - - When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. - - - - Changing this setting takes effect when the car is powered off. - - Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 63d83d7448..856ef26ca8 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -1501,22 +1501,6 @@ Isso pode levar até um minuto. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. - - Enable Automatic Brake Hold (AHB) - - - - WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. - - - - When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. - - - - Changing this setting takes effect when the car is powered off. - - Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_th.ts b/selfdrive/ui/translations/main_th.ts index a0ed3caf37..220b6575c4 100644 --- a/selfdrive/ui/translations/main_th.ts +++ b/selfdrive/ui/translations/main_th.ts @@ -1497,22 +1497,6 @@ This may take up to a minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. - - Enable Automatic Brake Hold (AHB) - - - - WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. - - - - When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. - - - - Changing this setting takes effect when the car is powered off. - - Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_tr.ts b/selfdrive/ui/translations/main_tr.ts index 07205a2b12..a8c3992fd2 100644 --- a/selfdrive/ui/translations/main_tr.ts +++ b/selfdrive/ui/translations/main_tr.ts @@ -1495,22 +1495,6 @@ This may take up to a minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. - - Enable Automatic Brake Hold (AHB) - - - - WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. - - - - When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. - - - - Changing this setting takes effect when the car is powered off. - - Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index da8e79536c..fddf413a50 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -1497,22 +1497,6 @@ This may take up to a minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. - - Enable Automatic Brake Hold (AHB) - - - - WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. - - - - When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. - - - - Changing this setting takes effect when the car is powered off. - - Enable Enhanced Blind Spot Monitor diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 6c93b6239a..684447b113 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -1497,22 +1497,6 @@ This may take up to a minute. Smoother longitudinal performance for Toyota/Lexus TSS2/LSS2 cars. Big thanks to dragonpilot-community for this implementation. - - Enable Automatic Brake Hold (AHB) - - - - WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK. - - - - When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold. - - - - Changing this setting takes effect when the car is powered off. - - Enable Enhanced Blind Spot Monitor From 84cff4fc03423acde611ba29b3b2ff9436ff2580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Mon, 29 Jul 2024 19:51:21 -0700 Subject: [PATCH 159/229] paramsd: use livePose (#33099) * Use livePose instead of llk * Update process replay sockets * Fix import * Fix calib * Fix field name * Dont store device_from_calib * Update ref commit --- selfdrive/locationd/helpers.py | 8 +++++ selfdrive/locationd/paramsd.py | 30 ++++++++++++++----- .../test/process_replay/process_replay.py | 4 +-- selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/selfdrive/locationd/helpers.py b/selfdrive/locationd/helpers.py index 8f7211aebf..af8a3d3726 100644 --- a/selfdrive/locationd/helpers.py +++ b/selfdrive/locationd/helpers.py @@ -4,6 +4,14 @@ from typing import Any from cereal import log +def rotate_cov(rot_matrix, cov_in): + return rot_matrix @ cov_in @ rot_matrix.T + + +def rotate_std(rot_matrix, std_in): + return np.sqrt(np.diag(rotate_cov(rot_matrix, np.diag(std_in**2)))) + + class NPQueue: def __init__(self, maxlen: int, rowsize: int) -> None: self.maxlen = maxlen diff --git a/selfdrive/locationd/paramsd.py b/selfdrive/locationd/paramsd.py index 650ee06017..1d5749cf34 100755 --- a/selfdrive/locationd/paramsd.py +++ b/selfdrive/locationd/paramsd.py @@ -9,8 +9,10 @@ from cereal import car, log from openpilot.common.params import Params from openpilot.common.realtime import config_realtime_process, DT_MDL from openpilot.common.numpy_fast import clip +from openpilot.common.transformations.orientation import rot_from_euler from openpilot.selfdrive.locationd.models.car_kf import CarKalman, ObservationKind, States from openpilot.selfdrive.locationd.models.constants import GENERATED_DIR +from openpilot.selfdrive.locationd.helpers import rotate_std from openpilot.common.swaglog import cloudlog @@ -38,6 +40,9 @@ class ParamsLearner: self.kf.filter.set_global("stiffness_rear", CP.tireStiffnessRear) self.active = False + self.calibrated = False + + self.calib_from_device = np.eye(3) self.speed = 0.0 self.yaw_rate = 0.0 @@ -47,12 +52,16 @@ class ParamsLearner: self.roll_valid = False def handle_log(self, t, which, msg): - if which == 'liveLocationKalman': - self.yaw_rate = msg.angularVelocityCalibrated.value[2] - self.yaw_rate_std = msg.angularVelocityCalibrated.std[2] + if which == 'livePose': + angular_velocity_device = np.array([msg.angularVelocityDevice.x, msg.angularVelocityDevice.y, msg.angularVelocityDevice.z]) + angular_velocity_device_std = np.array([msg.angularVelocityDevice.xStd, msg.angularVelocityDevice.yStd, msg.angularVelocityDevice.zStd]) + angular_velocity_calibrated = np.matmul(self.calib_from_device, angular_velocity_device) + angular_velocity_calibrated_std = rotate_std(self.calib_from_device, angular_velocity_device_std) - localizer_roll = msg.orientationNED.value[0] - localizer_roll_std = np.radians(1) if np.isnan(msg.orientationNED.std[0]) else msg.orientationNED.std[0] + self.yaw_rate, self.yaw_rate_std = angular_velocity_calibrated[2], angular_velocity_calibrated_std[2] + + localizer_roll = msg.orientationNED.x + localizer_roll_std = np.radians(1) if np.isnan(msg.orientationNED.xStd) else msg.orientationNED.xStd self.roll_valid = (localizer_roll_std < ROLL_STD_MAX) and (ROLL_MIN < localizer_roll < ROLL_MAX) and msg.sensorsOK if self.roll_valid: roll = localizer_roll @@ -64,7 +73,7 @@ class ParamsLearner: roll_std = np.radians(10.0) self.roll = clip(roll, self.roll - ROLL_MAX_DELTA, self.roll + ROLL_MAX_DELTA) - yaw_rate_valid = msg.angularVelocityCalibrated.valid + yaw_rate_valid = msg.angularVelocityDevice.valid and self.calibrated yaw_rate_valid = yaw_rate_valid and 0 < self.yaw_rate_std < 10 # rad/s yaw_rate_valid = yaw_rate_valid and abs(self.yaw_rate) < 1 # rad/s @@ -91,6 +100,11 @@ class ParamsLearner: self.kf.predict_and_observe(t, ObservationKind.STIFFNESS, np.array([[stiffness]])) self.kf.predict_and_observe(t, ObservationKind.STEER_RATIO, np.array([[steer_ratio]])) + elif which == 'liveCalibration': + self.calibrated = msg.calStatus == log.LiveCalibrationData.Status.calibrated + device_from_calib = rot_from_euler(np.array(msg.rpyCalib)) + self.calib_from_device = device_from_calib.T + elif which == 'carState': self.steering_angle = msg.steeringAngleDeg self.speed = msg.vEgo @@ -123,7 +137,7 @@ def main(): REPLAY = bool(int(os.getenv("REPLAY", "0"))) pm = messaging.PubMaster(['liveParameters']) - sm = messaging.SubMaster(['liveLocationKalman', 'carState'], poll='liveLocationKalman') + sm = messaging.SubMaster(['livePose', 'liveCalibration', 'carState'], poll='livePose') params_reader = Params() # wait for stats about the car to come in from controls @@ -188,7 +202,7 @@ def main(): t = sm.logMonoTime[which] * 1e-9 learner.handle_log(t, which, sm[which]) - if sm.updated['liveLocationKalman']: + if sm.updated['livePose']: x = learner.kf.x P = np.sqrt(learner.kf.P.diagonal()) if not all(map(math.isfinite, x)): diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 70ed745bac..84669a8bff 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -539,11 +539,11 @@ CONFIGS = [ ), ProcessConfig( proc_name="paramsd", - pubs=["liveLocationKalman", "carState"], + pubs=["livePose", "liveCalibration", "carState"], subs=["liveParameters"], ignore=["logMonoTime"], init_callback=get_car_params_callback, - should_recv_callback=FrequencyBasedRcvCallback("liveLocationKalman"), + should_recv_callback=FrequencyBasedRcvCallback("livePose"), tolerance=NUMPY_TOLERANCE, processing_time=0.004, ), diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 1349e2650f..4da168c270 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -949909bd80599698c1307b3304010456dded6a15 \ No newline at end of file +3e8feca20cd64f6a05dcbbdc0ace04a8c12bf86d \ No newline at end of file From 11cb2d3a0b3f820bb32c3de6f7ec1d2a52687f8a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 29 Jul 2024 20:13:43 -0700 Subject: [PATCH 160/229] qlog_size.py: use zstd (#33137) qlog_size: use zstd --- selfdrive/debug/internal/qlog_size.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/selfdrive/debug/internal/qlog_size.py b/selfdrive/debug/internal/qlog_size.py index 7dc61ed9df..11606c7589 100755 --- a/selfdrive/debug/internal/qlog_size.py +++ b/selfdrive/debug/internal/qlog_size.py @@ -1,11 +1,12 @@ #!/usr/bin/env python3 import argparse -import bz2 +import zstandard as zstd from collections import defaultdict import matplotlib.pyplot as plt from cereal.services import SERVICE_LIST +from openpilot.system.loggerd.uploader import LOG_COMPRESSION_LEVEL from openpilot.tools.lib.logreader import LogReader from tqdm import tqdm @@ -17,14 +18,14 @@ def make_pie(msgs, typ): for m in msgs: msgs_by_type[m.which()].append(m.as_builder().to_bytes()) - total = len(bz2.compress(b"".join([m.as_builder().to_bytes() for m in msgs]))) + total = len(zstd.compress(b"".join([m.as_builder().to_bytes() for m in msgs]), LOG_COMPRESSION_LEVEL)) uncompressed_total = len(b"".join([m.as_builder().to_bytes() for m in msgs])) length_by_type = {k: len(b"".join(v)) for k, v in msgs_by_type.items()} # calculate compressed size by calculating diff when removed from the segment compressed_length_by_type = {} for k in tqdm(msgs_by_type.keys(), desc="Compressing"): - compressed_length_by_type[k] = total - len(bz2.compress(b"".join([m.as_builder().to_bytes() for m in msgs if m.which() != k]))) + compressed_length_by_type[k] = total - len(zstd.compress(b"".join([m.as_builder().to_bytes() for m in msgs if m.which() != k]), LOG_COMPRESSION_LEVEL)) sizes = sorted(compressed_length_by_type.items(), key=lambda kv: kv[1]) From 86d8d1d99617a0808e0a17031965a056cdc5a1b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Mon, 29 Jul 2024 20:20:31 -0700 Subject: [PATCH 161/229] torqued: use livePose (#33136) * Use livePose * Replace it in process replay * Add liveCalibration to messages * Update ref commit --- selfdrive/locationd/torqued.py | 19 ++++++++++++++----- .../test/process_replay/process_replay.py | 4 ++-- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/selfdrive/locationd/torqued.py b/selfdrive/locationd/torqued.py index e0784eb8e6..edcf42ebcd 100755 --- a/selfdrive/locationd/torqued.py +++ b/selfdrive/locationd/torqued.py @@ -8,6 +8,7 @@ from openpilot.common.params import Params from openpilot.common.realtime import config_realtime_process, DT_MDL from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.swaglog import cloudlog +from openpilot.common.transformations.orientation import rot_from_euler from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY from openpilot.selfdrive.locationd.helpers import PointBuckets, ParameterEstimator @@ -77,6 +78,8 @@ class TorqueEstimator(ParameterEstimator): self.offline_friction = CP.lateralTuning.torque.friction self.offline_latAccelFactor = CP.lateralTuning.torque.latAccelFactor + self.calib_from_device = np.eye(3) + self.reset() initial_params = { @@ -171,12 +174,18 @@ class TorqueEstimator(ParameterEstimator): # TODO: check if high aEgo affects resulting lateral accel self.raw_points["vego"].append(msg.vEgo) self.raw_points["steer_override"].append(msg.steeringPressed) + elif which == "liveCalibration": + device_from_calib = rot_from_euler(np.array(msg.rpyCalib)) + self.calib_from_device = device_from_calib.T # calculate lateral accel from past steering torque - elif which == "liveLocationKalman": + elif which == "livePose": if len(self.raw_points['steer_torque']) == self.hist_len: - yaw_rate = msg.angularVelocityCalibrated.value[2] - roll = msg.orientationNED.value[0] + angular_velocity_device = np.array([msg.angularVelocityDevice.x, msg.angularVelocityDevice.y, msg.angularVelocityDevice.z]) + angular_velocity_calibrated = np.matmul(self.calib_from_device, angular_velocity_device) + + yaw_rate = angular_velocity_calibrated[2] + roll = msg.orientationNED.x # check lat active up to now (without lag compensation) lat_active = np.interp(np.arange(t - MIN_ENGAGE_BUFFER, t + self.lag, DT_MDL), self.raw_points['carControl_t'], self.raw_points['lat_active']).astype(bool) @@ -233,7 +242,7 @@ def main(demo=False): config_realtime_process([0, 1, 2, 3], 5) pm = messaging.PubMaster(['liveTorqueParameters']) - sm = messaging.SubMaster(['carControl', 'carOutput', 'carState', 'liveLocationKalman'], poll='liveLocationKalman') + sm = messaging.SubMaster(['carControl', 'carOutput', 'carState', 'liveCalibration', 'livePose'], poll='livePose') params = Params() estimator = TorqueEstimator(messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams)) @@ -246,7 +255,7 @@ def main(demo=False): t = sm.logMonoTime[which] * 1e-9 estimator.handle_log(t, which, sm[which]) - # 4Hz driven by liveLocationKalman + # 4Hz driven by livePose if sm.frame % 5 == 0: pm.send('liveTorqueParameters', estimator.get_msg(valid=sm.all_checks())) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 84669a8bff..1731bf2e1e 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -390,7 +390,7 @@ def calibration_rcv_callback(msg, cfg, frame): def torqued_rcv_callback(msg, cfg, frame): # should_recv always true to increment frame - return (frame - 1) == 0 or msg.which() == 'liveLocationKalman' + return (frame - 1) == 0 or msg.which() == 'livePose' def dmonitoringmodeld_rcv_callback(msg, cfg, frame): @@ -555,7 +555,7 @@ CONFIGS = [ ), ProcessConfig( proc_name="torqued", - pubs=["liveLocationKalman", "carState", "carControl", "carOutput"], + pubs=["livePose", "liveCalibration", "carState", "carControl", "carOutput"], subs=["liveTorqueParameters"], ignore=["logMonoTime"], init_callback=get_car_params_callback, diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 4da168c270..3af1f282fb 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -3e8feca20cd64f6a05dcbbdc0ace04a8c12bf86d \ No newline at end of file +7eb60abe8030b97f79f858315d67d080704733f7 \ No newline at end of file From dfd387520e88fa68f0485b6ce8dcf5befa82bafa Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 30 Jul 2024 01:46:03 -0700 Subject: [PATCH 162/229] process replay: use zst (#33138) * test * update refs to zst * update --- selfdrive/test/process_replay/ref_commit | 2 +- selfdrive/test/process_replay/regen.py | 4 ++-- selfdrive/test/process_replay/test_processes.py | 4 ++-- tools/lib/logreader.py | 4 +++- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 3af1f282fb..a85e8919c4 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -7eb60abe8030b97f79f858315d67d080704733f7 \ No newline at end of file +6ca7313b9c1337fad1334d9e087cb4984fdce74d \ No newline at end of file diff --git a/selfdrive/test/process_replay/regen.py b/selfdrive/test/process_replay/regen.py index fe33443b49..e87b8347e1 100755 --- a/selfdrive/test/process_replay/regen.py +++ b/selfdrive/test/process_replay/regen.py @@ -74,7 +74,7 @@ def setup_data_readers( assert device_type != "neo", "Driver camera not supported on neo segments. Use dummy dcamera." frs['driverCameraState'] = FrameReader(r.dcamera_paths()[sidx]) else: - lr = LogReader(f"cd:/{route.replace('|', '/')}/{sidx}/rlog.bz2") + lr = LogReader(f"{route}/{sidx}/r") frs = {} if needs_road_cam: frs['roadCameraState'] = FrameReader(f"cd:/{route.replace('|', '/')}/{sidx}/fcamera.hevc") @@ -118,7 +118,7 @@ def regen_and_save( log_dir = os.path.join(outdir, time.strftime("%Y-%m-%d--%H-%M-%S--0", time.gmtime())) rel_log_dir = os.path.relpath(log_dir) - rpath = os.path.join(log_dir, "rlog.bz2") + rpath = os.path.join(log_dir, "rlog.zst") os.makedirs(log_dir) save_log(rpath, output_logs, compress=True) diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 7fbe933434..84a19aa0a9 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -198,11 +198,11 @@ if __name__ == "__main__": if cfg.proc_name not in tested_procs: continue - cur_log_fn = os.path.join(FAKEDATA, f"{segment}_{cfg.proc_name}_{cur_commit}.bz2") + cur_log_fn = os.path.join(FAKEDATA, f"{segment}_{cfg.proc_name}_{cur_commit}.zst") if args.update_refs: # reference logs will not exist if routes were just regenerated ref_log_path = get_url(*segment.rsplit("--", 1)) else: - ref_log_fn = os.path.join(FAKEDATA, f"{segment}_{cfg.proc_name}_{ref_commit}.bz2") + ref_log_fn = os.path.join(FAKEDATA, f"{segment}_{cfg.proc_name}_{ref_commit}.zst") ref_log_path = ref_log_fn if os.path.exists(ref_log_fn) else BASE_URL + os.path.basename(ref_log_fn) dat = None if args.upload_only else log_data[segment] diff --git a/tools/lib/logreader.py b/tools/lib/logreader.py index 0f00596141..50c14ce4c3 100755 --- a/tools/lib/logreader.py +++ b/tools/lib/logreader.py @@ -30,8 +30,10 @@ RawLogIterable = Iterable[bytes] def save_log(dest, log_msgs, compress=True): dat = b"".join(msg.as_builder().to_bytes() for msg in log_msgs) - if compress: + if compress and dest.endswith(".bz2"): dat = bz2.compress(dat) + elif compress and dest.endswith(".zst"): + dat = zstd.compress(dat, 10) with open(dest, "wb") as f: f.write(dat) From 4d7afe3a7bbcd4f31ee309a6aa2f5db93367daae Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Tue, 30 Jul 2024 06:58:35 -0800 Subject: [PATCH 163/229] MADS: Map cruise main and lateral buttons to button events (#361) * MADS: Map cruise main and lateral buttons to button events * different style * nah --- selfdrive/car/chrysler/interface.py | 3 ++- selfdrive/car/ford/interface.py | 3 ++- selfdrive/car/gm/interface.py | 4 +++- selfdrive/car/honda/interface.py | 2 +- selfdrive/car/hyundai/interface.py | 14 ++++++-------- selfdrive/car/mazda/interface.py | 8 +++----- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index d4911375e7..f4881dd363 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -94,6 +94,7 @@ class CarInterface(CarInterfaceBase): self.sp_update_params() self.CS.button_events.extend(create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})) + self.CS.button_events.extend(create_button_events(self.CS.lkas_enabled, self.CS.prev_lkas_enabled, {1: ButtonType.altButton1})) self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) @@ -108,7 +109,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if self.CS.prev_lkas_enabled != 1 and self.CS.lkas_enabled == 1: + if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): self.CS.madsEnabled = not self.CS.madsEnabled self.CS.lkas_disabled = not self.CS.lkas_disabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 18dd7b4fa3..b0a1c15f34 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -75,6 +75,7 @@ class CarInterface(CarInterfaceBase): self.sp_update_params() self.CS.button_events.extend(create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})) + self.CS.button_events.extend(create_button_events(self.CS.lkas_enabled, self.CS.prev_lkas_enabled, {1: ButtonType.altButton1})) self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) @@ -85,7 +86,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if not self.CS.prev_lkas_enabled and self.CS.lkas_enabled: + if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): self.CS.madsEnabled = not self.CS.madsEnabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) else: diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 0e428bc13b..4a1e459722 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -218,6 +218,8 @@ class CarInterface(CarInterfaceBase): ] distance_button = self.CS.distance_button + self.CS.button_events.extend(create_button_events(self.CS.lkas_enabled, self.CS.prev_lkas_enabled, {1: ButtonType.altButton1})) + self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) if not self.CP.pcmCruise: @@ -231,7 +233,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if self.CS.prev_lkas_enabled != 1 and self.CS.lkas_enabled == 1: + if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): self.CS.madsEnabled = not self.CS.madsEnabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) else: diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 72ab68647f..af294a63a7 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -282,7 +282,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if self.CS.prev_cruise_setting != 1 and self.CS.cruise_setting == 1: + if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): self.CS.madsEnabled = not self.CS.madsEnabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) else: diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index dbe0b62895..72a12b0ba8 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -205,7 +205,9 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_cam) self.sp_update_params() - self.CS.button_events = create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT) + self.CS.button_events.extend(create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT)) + self.CS.button_events.extend(create_button_events(self.CS.lfa_enabled, self.CS.prev_lfa_enabled, {1: ButtonType.altButton1})) + self.CS.button_events.extend(create_button_events(self.CS.main_buttons[-1], self.CS.prev_main_buttons, {1: ButtonType.altButton3})) self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled, self.CS.button_events, c.vCruise) @@ -214,16 +216,12 @@ class CarInterface(CarInterfaceBase): if ret.cruiseState.available: if not self.CP.pcmCruiseSpeed: - if self.CS.prev_main_buttons == 1: - if self.CS.main_buttons[-1] != 1: - self.CS.accEnabled = True - elif self.CS.prev_cruise_buttons == 4: - if self.CS.cruise_buttons[-1] != 4: - self.accEnabled = True + if any(b.type in (ButtonType.altButton3, ButtonType.cancel) and not b.pressed for b in self.CS.button_events): + self.CS.accEnabled = True if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if self.CS.prev_lfa_enabled != 1 and self.CS.lfa_enabled == 1: + if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): self.CS.madsEnabled = not self.CS.madsEnabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) else: diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py index 9447803ae6..2bd4f71c78 100755 --- a/selfdrive/car/mazda/interface.py +++ b/selfdrive/car/mazda/interface.py @@ -40,10 +40,8 @@ class CarInterface(CarInterfaceBase): self.sp_update_params() # TODO: add button types for inc and dec - self.CS.button_events = [ - *self.CS.button_events, - *create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}) - ] + self.CS.button_events.extend(create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})) + self.CS.button_events.extend(create_button_events(self.CS.lkas_enabled, self.CS.prev_lkas_enabled, {1: ButtonType.altButton1})) self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) @@ -54,7 +52,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if self.CS.prev_lkas_enabled != self.CS.lkas_enabled: + if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): self.CS.madsEnabled = not self.CS.madsEnabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) else: From 4e73b76a12f867dc7a831e811c33a8458e705f4c Mon Sep 17 00:00:00 2001 From: Andrei Radulescu Date: Tue, 30 Jul 2024 20:34:46 +0300 Subject: [PATCH 164/229] fix multiprocessing issue with can_replay.py on macOS (#33139) fix multiprocessing issue with can_replay.py on mac --- tools/replay/can_replay.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/tools/replay/can_replay.py b/tools/replay/can_replay.py index 3ab33a1dfd..9b76edde10 100755 --- a/tools/replay/can_replay.py +++ b/tools/replay/can_replay.py @@ -80,6 +80,17 @@ def connect(): time.sleep(1) +def process(lr): + return [can_capnp_to_can_list(m.can) for m in lr if m.which() == 'can'] + +def load_route(route_or_segment_name): + print("Loading log...") + sr = LogReader(route_or_segment_name) + CP = sr.first("carParams") + print(f"carFingerprint (for hardcoding fingerprint): '{CP.carFingerprint}'") + CAN_MSGS = sr.run_across_segments(24, process) + print("Finished loading...") + return CAN_MSGS if __name__ == "__main__": parser = argparse.ArgumentParser(description="Replay CAN messages from a route to all connected pandas and jungles in a loop.", @@ -87,22 +98,10 @@ if __name__ == "__main__": parser.add_argument("route_or_segment_name", nargs='?', help="The route or segment name to replay. If not specified, a default public route will be used.") args = parser.parse_args() - def process(lr): - return [can_capnp_to_can_list(m.can) for m in lr if m.which() == 'can'] - - print("Loading log...") if args.route_or_segment_name is None: args.route_or_segment_name = "77611a1fac303767/2020-03-24--09-50-38/1:3" - sr = LogReader(args.route_or_segment_name) - - CP = sr.first("carParams") - - print(f"carFingerprint (for hardcoding fingerprint): '{CP.carFingerprint}'") - - CAN_MSGS = sr.run_across_segments(24, process) - - print("Finished loading...") + CAN_MSGS = load_route(args.route_or_segment_name) if ENABLE_PWR: print(f"Cycling power: on for {PWR_ON}s, off for {PWR_OFF}s") From 0b29db5c3eed58eaaea746beb0079e3542075407 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 30 Jul 2024 13:03:34 -0700 Subject: [PATCH 165/229] add roadmap to readme --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8ebc733e63..9772ad646f 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,9 @@

- Read the docs + Docs + · + Roadmap · Contribute · From 9536dd07c6b0f972db70b344ae2f676e031ea038 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Tue, 30 Jul 2024 13:11:05 -0700 Subject: [PATCH 166/229] unpin numpy (#33132) * unlock numpy * remove old cache * sheel * lock * remove temp * depends * export * put this back * use __version__ * move this --------- Co-authored-by: quebec --- SConstruct | 5 +++-- pyproject.toml | 2 +- selfdrive/controls/lib/lateral_mpc_lib/SConscript | 3 ++- selfdrive/controls/lib/longitudinal_mpc_lib/SConscript | 3 ++- site_scons/site_tools/cython.py | 3 +++ uv.lock | 6 +++--- 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/SConstruct b/SConstruct index fb5c43c9ad..47f2db9661 100644 --- a/SConstruct +++ b/SConstruct @@ -229,7 +229,7 @@ env = Environment( COMPILATIONDB_USE_ABSPATH=True, REDNOSE_ROOT="#", tools=["default", "cython", "compilation_db", "rednose_filter"], - toolpath=["#rednose_repo/site_scons/site_tools"], + toolpath=["#site_scons/site_tools", "#rednose_repo/site_scons/site_tools"], ) if arch == "Darwin": @@ -268,7 +268,8 @@ if arch == "Darwin": else: envCython["LINKFLAGS"] = ["-pthread", "-shared"] -Export('envCython') +np_version = SCons.Script.Value(np.__version__) +Export('envCython', 'np_version') # Qt build environment qt_env = env.Clone() diff --git a/pyproject.toml b/pyproject.toml index 4c1e134431..1473cf5707 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ dependencies = [ "pycapnp", "Cython", "setuptools", - "numpy < 2.0.0", # control does not support numpy 2 + "numpy", # body / webrtcd "aiohttp", diff --git a/selfdrive/controls/lib/lateral_mpc_lib/SConscript b/selfdrive/controls/lib/lateral_mpc_lib/SConscript index 73242cb8f9..2c03da06a6 100644 --- a/selfdrive/controls/lib/lateral_mpc_lib/SConscript +++ b/selfdrive/controls/lib/lateral_mpc_lib/SConscript @@ -1,4 +1,4 @@ -Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python') +Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python', 'np_version') gen = "c_generated_code" @@ -88,3 +88,4 @@ lenv2.Command(libacados_ocp_solver_c, f' {acados_ocp_solver_pyx.get_labspath()}') lib_cython = lenv2.Program(f'{gen}/acados_ocp_solver_pyx.so', [libacados_ocp_solver_c]) lenv2.Depends(lib_cython, lib_solver) +lenv2.Depends(libacados_ocp_solver_c, np_version) diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript index 592c1c2c2d..fc1e844d50 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript @@ -1,4 +1,4 @@ -Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python') +Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python', 'np_version') gen = "c_generated_code" @@ -94,3 +94,4 @@ lenv2.Command(libacados_ocp_solver_c, f' {acados_ocp_solver_pyx.get_labspath()}') lib_cython = lenv2.Program(f'{gen}/acados_ocp_solver_pyx.so', [libacados_ocp_solver_c]) lenv2.Depends(lib_cython, lib_solver) +lenv2.Depends(libacados_ocp_solver_c, np_version) diff --git a/site_scons/site_tools/cython.py b/site_scons/site_tools/cython.py index c291475533..f11db1d71b 100644 --- a/site_scons/site_tools/cython.py +++ b/site_scons/site_tools/cython.py @@ -2,14 +2,17 @@ import re import SCons from SCons.Action import Action from SCons.Scanner import Scanner +import numpy as np pyx_from_import_re = re.compile(r'^from\s+(\S+)\s+cimport', re.M) pyx_import_re = re.compile(r'^cimport\s+(\S+)', re.M) cdef_import_re = re.compile(r'^cdef extern from\s+.(\S+).:', re.M) +np_version = SCons.Script.Value(np.__version__) def pyx_scan(node, env, path, arg=None): contents = node.get_text_contents() + env.Depends(str(node).split('.')[0] + env['CYTHONCFILESUFFIX'], np_version) # from cimport ... matches = pyx_from_import_re.findall(contents) diff --git a/uv.lock b/uv.lock index 2913075f5b..ded3ddec7c 100644 --- a/uv.lock +++ b/uv.lock @@ -4977,11 +4977,11 @@ wheels = [ [[distribution]] name = "setuptools" -version = "71.1.0" +version = "72.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/32/c0/5b8013b5a812701c72e3b1e2b378edaa6514d06bee6704a5ab0d7fa52931/setuptools-71.1.0.tar.gz", hash = "sha256:032d42ee9fb536e33087fb66cac5f840eb9391ed05637b3f2a76a7c8fb477936", size = 2422233 } +sdist = { url = "https://files.pythonhosted.org/packages/5e/11/487b18cc768e2ae25a919f230417983c8d5afa1b6ee0abd8b6db0b89fa1d/setuptools-72.1.0.tar.gz", hash = "sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec", size = 2419487 } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/a0/ee460cc54e68afcf33190d198299c9579a5eafeadef0016ae8563237ccb6/setuptools-71.1.0-py3-none-any.whl", hash = "sha256:33874fdc59b3188304b2e7c80d9029097ea31627180896fb549c578ceb8a0855", size = 2341722 }, + { url = "https://files.pythonhosted.org/packages/e1/58/e0ef3b9974a04ce9cde2a7a33881ddcb2d68450803745804545cdd8d258f/setuptools-72.1.0-py3-none-any.whl", hash = "sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1", size = 2337965 }, ] [[distribution]] From 086dcfe715985447fa33f120d16a496309718ba2 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Tue, 30 Jul 2024 13:57:42 -0700 Subject: [PATCH 167/229] docs: fix README.md (#33142) * md * Update README.md * rename * exclude * Update README.md --- docs/{README => README.md} | 22 +++++++++++++--------- mkdocs.yml | 2 ++ 2 files changed, 15 insertions(+), 9 deletions(-) rename docs/{README => README.md} (59%) diff --git a/docs/README b/docs/README.md similarity index 59% rename from docs/README rename to docs/README.md index a16c772530..08dd4fa8bc 100644 --- a/docs/README +++ b/docs/README.md @@ -3,20 +3,24 @@ This is the source for [docs.comma.ai](https://docs.comma.ai). The site is updated on pushes to master by this [workflow](../.github/workflows/docs.yaml). -## development -``` -# install the docs dependencies +## Development +NOTE: Those commands must be run in the root directory of openpilot, **not /docs** + +**1. Install the docs dependencies** +``` bash pip install .[docs] +``` -cd docs/ - -# for a development server -mkdocs serve - -# build the site +**2. Build the new site** +``` bash mkdocs build ``` +**3. Run the new site locally** +``` bash +mkdocs serve +``` + References: * https://www.mkdocs.org/getting-started/ * https://github.com/ntno/mkdocs-terminal diff --git a/mkdocs.yml b/mkdocs.yml index 8778e28863..743b8fa1b7 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -2,6 +2,8 @@ site_name: openpilot docs repo_url: https://github.com/commaai/openpilot/ site_url: https://docs.comma.ai +exclude_docs: README.md + strict: true docs_dir: docs site_dir: docs_site/ From 0fe143e4a75e7657f4d815a5616fc29f70de5ad5 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 30 Jul 2024 14:07:47 -0700 Subject: [PATCH 168/229] test_onroad: lower lower log size bound --- selfdrive/test/test_onroad.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index e29e241da9..27feb344f2 100644 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -207,7 +207,7 @@ class TestOnroad: if f.name == "qcamera.ts": assert 2.15 < sz < 2.35 elif f.name == "qlog": - assert 0.45 < sz < 0.55 + assert 0.4 < sz < 0.55 elif f.name == "rlog": assert 5 < sz < 50 elif f.name.endswith('.hevc'): From 0739d79a512965abbe22f0b15c7fddcdd71478d0 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 30 Jul 2024 14:27:27 -0700 Subject: [PATCH 169/229] cars: remove some external imports (#33133) * ford and gm * clean that up * also this * honda * temp fix * move into selfdrive.car * clean up * more --- .importlinter | 3 --- selfdrive/car/__init__.py | 21 +++++++++++++++++++++ selfdrive/car/ford/carcontroller.py | 2 +- selfdrive/car/gm/interface.py | 3 +-- selfdrive/car/honda/carcontroller.py | 3 +-- selfdrive/car/interfaces.py | 4 ++-- selfdrive/controls/lib/drive_helpers.py | 23 +---------------------- 7 files changed, 27 insertions(+), 32 deletions(-) diff --git a/.importlinter b/.importlinter index 594d75ee4a..f77ea24b39 100644 --- a/.importlinter +++ b/.importlinter @@ -33,9 +33,6 @@ ignore_imports = openpilot.selfdrive.car.ecu_addrs -> openpilot.common.swaglog openpilot.selfdrive.car.car_helpers -> openpilot.common.swaglog openpilot.selfdrive.car.car_helpers -> openpilot.system.version - openpilot.selfdrive.car.ford.carcontroller -> openpilot.selfdrive.controls.lib.drive_helpers - openpilot.selfdrive.car.gm.interface -> openpilot.selfdrive.controls.lib.drive_helpers - openpilot.selfdrive.car.honda.carcontroller -> openpilot.selfdrive.controls.lib.drive_helpers openpilot.selfdrive.car.interfaces -> openpilot.selfdrive.controls.lib.drive_helpers openpilot.selfdrive.car.tests.test_car_interfaces -> openpilot.selfdrive.controls.lib.latcontrol_angle openpilot.selfdrive.car.tests.test_car_interfaces -> openpilot.selfdrive.controls.lib.longcontrol diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index 6f3bde7f0c..b685c6a435 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -166,6 +166,27 @@ def common_fault_avoidance(fault_condition: bool, request: bool, above_limit_fra return above_limit_frames, request +def apply_center_deadzone(error, deadzone): + if (error > - deadzone) and (error < deadzone): + error = 0. + return error + + +def rate_limit(new_value, last_value, dw_step, up_step): + return clip(new_value, last_value + dw_step, last_value + up_step) + + +def get_friction(lateral_accel_error: float, lateral_accel_deadzone: float, friction_threshold: float, + torque_params: car.CarParams.LateralTorqueTuning, friction_compensation: bool) -> float: + friction_interp = interp( + apply_center_deadzone(lateral_accel_error, lateral_accel_deadzone), + [-friction_threshold, friction_threshold], + [-torque_params.friction, torque_params.friction] + ) + friction = float(friction_interp) if friction_compensation else 0.0 + return friction + + def make_can_msg(addr, dat, bus): return [addr, 0, dat, bus] diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index 7be3b2ebe9..36589f34e5 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -5,10 +5,10 @@ from openpilot.selfdrive.car import apply_std_steer_angle_limits from openpilot.selfdrive.car.ford import fordcan from openpilot.selfdrive.car.ford.values import CarControllerParams, FordFlags from openpilot.selfdrive.car.interfaces import CarControllerBase -from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX LongCtrlState = car.CarControl.Actuators.LongControlState VisualAlert = car.CarControl.HUDControl.VisualAlert +V_CRUISE_MAX = 145 def apply_ford_curvature_limits(apply_curvature, apply_curvature_last, current_curvature, v_ego_raw): diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index d088050482..1d4a6066cc 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -6,11 +6,10 @@ from panda import Panda from openpilot.common.basedir import BASEDIR from openpilot.common.conversions import Conversions as CV -from openpilot.selfdrive.car import create_button_events, get_safety_config +from openpilot.selfdrive.car import create_button_events, get_safety_config, get_friction from openpilot.selfdrive.car.gm.radar_interface import RADAR_HEADER_MSG from openpilot.selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, CanBus from openpilot.selfdrive.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, FRICTION_THRESHOLD, LatControlInputs, NanoFFModel -from openpilot.selfdrive.controls.lib.drive_helpers import get_friction ButtonType = car.CarState.ButtonEvent.Type EventName = car.CarEvent.EventName diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index 66bd500485..dc42c41e63 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -3,11 +3,10 @@ from collections import namedtuple from cereal import car from openpilot.common.numpy_fast import clip, interp from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import DT_CTRL +from openpilot.selfdrive.car import DT_CTRL, rate_limit from openpilot.selfdrive.car.honda import hondacan from openpilot.selfdrive.car.honda.values import CruiseButtons, VISUAL_HUD, HONDA_BOSCH, HONDA_BOSCH_RADARLESS, HONDA_NIDEC_ALT_PCM_ACCEL, CarControllerParams from openpilot.selfdrive.car.interfaces import CarControllerBase -from openpilot.selfdrive.controls.lib.drive_helpers import rate_limit VisualAlert = car.CarControl.HUDControl.VisualAlert LongCtrlState = car.CarControl.Actuators.LongControlState diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 9f1b650158..d37e171da7 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -13,9 +13,9 @@ from openpilot.common.basedir import BASEDIR from openpilot.common.conversions import Conversions as CV from openpilot.common.simple_kalman import KF1D, get_kalman_gain from openpilot.common.numpy_fast import clip -from openpilot.selfdrive.car import DT_CTRL, apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, STD_CARGO_KG +from openpilot.selfdrive.car import DT_CTRL, apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, get_friction, STD_CARGO_KG from openpilot.selfdrive.car.values import PLATFORMS -from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, get_friction +from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX from openpilot.selfdrive.controls.lib.events import Events from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index bd74051374..4c111a4fd1 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -2,7 +2,7 @@ import math from cereal import car, log from openpilot.common.conversions import Conversions as CV -from openpilot.common.numpy_fast import clip, interp +from openpilot.common.numpy_fast import clip from openpilot.common.realtime import DT_CTRL # WARNING: this value was determined based on the model's training distribution, @@ -141,16 +141,6 @@ class VCruiseHelper: self.v_cruise_cluster_kph = self.v_cruise_kph -def apply_center_deadzone(error, deadzone): - if (error > - deadzone) and (error < deadzone): - error = 0. - return error - - -def rate_limit(new_value, last_value, dw_step, up_step): - return clip(new_value, last_value + dw_step, last_value + up_step) - - def clip_curvature(v_ego, prev_curvature, new_curvature): v_ego = max(MIN_SPEED, v_ego) max_curvature_rate = MAX_LATERAL_JERK / (v_ego**2) # inexact calculation, check https://github.com/commaai/openpilot/pull/24755 @@ -161,17 +151,6 @@ def clip_curvature(v_ego, prev_curvature, new_curvature): return safe_desired_curvature -def get_friction(lateral_accel_error: float, lateral_accel_deadzone: float, friction_threshold: float, - torque_params: car.CarParams.LateralTorqueTuning, friction_compensation: bool) -> float: - friction_interp = interp( - apply_center_deadzone(lateral_accel_error, lateral_accel_deadzone), - [-friction_threshold, friction_threshold], - [-torque_params.friction, torque_params.friction] - ) - friction = float(friction_interp) if friction_compensation else 0.0 - return friction - - def get_speed_error(modelV2: log.ModelDataV2, v_ego: float) -> float: # ToDo: Try relative error, and absolute speed if len(modelV2.temporalPose.trans): From 76fd5b00f1f169013334e06031e6b063c16cf5a5 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 30 Jul 2024 14:29:48 -0700 Subject: [PATCH 170/229] CI: increase shm size to 2G --- .github/workflows/badges.yaml | 2 +- .github/workflows/selfdrive_tests.yaml | 2 +- .github/workflows/tools_tests.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/badges.yaml b/.github/workflows/badges.yaml index cf8bdc7109..f8d2fc3cf1 100644 --- a/.github/workflows/badges.yaml +++ b/.github/workflows/badges.yaml @@ -7,7 +7,7 @@ on: env: BASE_IMAGE: openpilot-base DOCKER_REGISTRY: ghcr.io/commaai - RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $DOCKER_REGISTRY/$BASE_IMAGE:latest /bin/bash -c + RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $DOCKER_REGISTRY/$BASE_IMAGE:latest /bin/bash -c jobs: badges: diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index a178634321..bfad6e1e7d 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -25,7 +25,7 @@ env: DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} BUILD: selfdrive/test/docker_build.sh base - RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PRE_COMMIT_HOME=/tmp/pre-commit -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/pre-commit:/tmp/pre-commit -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c + RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PRE_COMMIT_HOME=/tmp/pre-commit -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/pre-commit:/tmp/pre-commit -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c PYTEST: pytest --continue-on-collection-errors --cov --cov-report=xml --cov-append --durations=0 --durations-min=5 --hypothesis-seed 0 -n logical diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index 9085556392..271e4bda17 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -21,7 +21,7 @@ env: BUILD: selfdrive/test/docker_build.sh base - RUN: docker run --shm-size 1G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c + RUN: docker run --shm-size 2G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c jobs: From 661ef03a24171addba79b69bb14867425f5a9474 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 30 Jul 2024 15:18:26 -0700 Subject: [PATCH 171/229] Ford: add long controls todo --- selfdrive/car/ford/carcontroller.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index 36589f34e5..09bba46565 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -92,6 +92,7 @@ class CarController(CarControllerBase): if not CC.longActive or gas < CarControllerParams.MIN_GAS: gas = CarControllerParams.INACTIVE_GAS stopping = CC.actuators.longControlState == LongCtrlState.stopping + # TODO: look into using the actuators packet to send the desired speed can_sends.append(fordcan.create_acc_msg(self.packer, self.CAN, CC.longActive, gas, accel, stopping, v_ego_kph=V_CRUISE_MAX)) ### ui ### From b6d124d268ec705585e49d4ba84a316810e3b2b8 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 30 Jul 2024 18:09:22 -0700 Subject: [PATCH 172/229] tester present msgs: use helper (#33147) use helper --- selfdrive/car/__init__.py | 11 +++++++++++ selfdrive/car/ecu_addrs.py | 13 ++----------- selfdrive/car/honda/carcontroller.py | 4 ++-- selfdrive/car/hyundai/carcontroller.py | 6 +++--- selfdrive/car/subaru/carcontroller.py | 4 ++-- selfdrive/car/toyota/carcontroller.py | 4 ++-- 6 files changed, 22 insertions(+), 20 deletions(-) diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index b685c6a435..87d43831e6 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -7,6 +7,7 @@ from dataclasses import replace import capnp from cereal import car +from panda.python.uds import SERVICE_TYPE from openpilot.common.numpy_fast import clip, interp from openpilot.common.utils import Freezable from openpilot.selfdrive.car.docs_definitions import CarDocs @@ -191,6 +192,16 @@ def make_can_msg(addr, dat, bus): return [addr, 0, dat, bus] +def make_tester_present_msg(addr, bus, subaddr=None, suppress_response=False): + dat = [0x02, SERVICE_TYPE.TESTER_PRESENT] + if subaddr is not None: + dat.insert(0, subaddr) + dat.append(0x80 if suppress_response else 0x0) # sub-function + + dat.extend([0x0] * (8 - len(dat))) + return make_can_msg(addr, bytes(dat), bus) + + def get_safety_config(safety_model, safety_param = None): ret = car.CarParams.SafetyConfig.new_message() ret.safetyModel = safety_model diff --git a/selfdrive/car/ecu_addrs.py b/selfdrive/car/ecu_addrs.py index 0fd4bbd0be..0ff827593e 100755 --- a/selfdrive/car/ecu_addrs.py +++ b/selfdrive/car/ecu_addrs.py @@ -4,21 +4,12 @@ import time import cereal.messaging as messaging from panda.python.uds import SERVICE_TYPE -from openpilot.selfdrive.car import make_can_msg +from openpilot.selfdrive.car import make_tester_present_msg from openpilot.selfdrive.car.fw_query_definitions import EcuAddrBusType from openpilot.selfdrive.pandad import can_list_to_can_capnp from openpilot.common.swaglog import cloudlog -def _make_tester_present_msg(addr, bus, subaddr=None): - dat = [0x02, SERVICE_TYPE.TESTER_PRESENT, 0x0] - if subaddr is not None: - dat.insert(0, subaddr) - - dat.extend([0x0] * (8 - len(dat))) - return make_can_msg(addr, bytes(dat), bus) - - def _is_tester_present_response(msg: capnp.lib.capnp._DynamicStructReader, subaddr: int = None) -> bool: # ISO-TP messages are always padded to 8 bytes # tester present response is always a single frame @@ -44,7 +35,7 @@ def get_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, que responses: set[EcuAddrBusType], timeout: float = 1, debug: bool = False) -> set[EcuAddrBusType]: ecu_responses: set[EcuAddrBusType] = set() # set((addr, subaddr, bus),) try: - msgs = [_make_tester_present_msg(addr, bus, subaddr) for addr, subaddr, bus in queries] + msgs = [make_tester_present_msg(addr, bus, subaddr) for addr, subaddr, bus in queries] messaging.drain_sock_raw(logcan) sendcan.send(can_list_to_can_capnp(msgs, msgtype='sendcan')) diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index dc42c41e63..84ccf29d18 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -3,7 +3,7 @@ from collections import namedtuple from cereal import car from openpilot.common.numpy_fast import clip, interp from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import DT_CTRL, rate_limit +from openpilot.selfdrive.car import DT_CTRL, rate_limit, make_tester_present_msg from openpilot.selfdrive.car.honda import hondacan from openpilot.selfdrive.car.honda.values import CruiseButtons, VISUAL_HUD, HONDA_BOSCH, HONDA_BOSCH_RADARLESS, HONDA_NIDEC_ALT_PCM_ACCEL, CarControllerParams from openpilot.selfdrive.car.interfaces import CarControllerBase @@ -164,7 +164,7 @@ class CarController(CarControllerBase): # tester present - w/ no response (keeps radar disabled) if self.CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS) and self.CP.openpilotLongitudinalControl: if self.frame % 10 == 0: - can_sends.append((0x18DAB0F1, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", 1)) + can_sends.append(make_tester_present_msg(0x18DAB0F1, 1, suppress_response=True)) # Send steering command. can_sends.append(hondacan.create_steering_control(self.packer, self.CAN, apply_steer, CC.latActive, self.CP.carFingerprint, diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 3d7768a83b..75aeb0efd6 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -2,7 +2,7 @@ from cereal import car from openpilot.common.conversions import Conversions as CV from openpilot.common.numpy_fast import clip from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits, common_fault_avoidance +from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits, common_fault_avoidance, make_tester_present_msg from openpilot.selfdrive.car.hyundai import hyundaicanfd, hyundaican from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR @@ -96,11 +96,11 @@ class CarController(CarControllerBase): addr, bus = 0x7d0, 0 if self.CP.flags & HyundaiFlags.CANFD_HDA2.value: addr, bus = 0x730, self.CAN.ECAN - can_sends.append([addr, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", bus]) + can_sends.append(make_tester_present_msg(addr, bus, suppress_response=True)) # for blinkers if self.CP.flags & HyundaiFlags.ENABLE_BLINKERS: - can_sends.append([0x7b1, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", self.CAN.ECAN]) + can_sends.append(make_tester_present_msg(0x7b1, self.CAN.ECAN, suppress_response=True)) # CAN-FD platforms if self.CP.carFingerprint in CANFD_CAR: diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index d89ae8c639..3e1b62c974 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -1,6 +1,6 @@ from openpilot.common.numpy_fast import clip, interp from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance +from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance, make_tester_present_msg from openpilot.selfdrive.car.interfaces import CarControllerBase from openpilot.selfdrive.car.subaru import subarucan from openpilot.selfdrive.car.subaru.values import DBC, GLOBAL_ES_ADDR, CanBus, CarControllerParams, SubaruFlags @@ -124,7 +124,7 @@ class CarController(CarControllerBase): if self.CP.flags & SubaruFlags.DISABLE_EYESIGHT: # Tester present (keeps eyesight disabled) if self.frame % 100 == 0: - can_sends.append([GLOBAL_ES_ADDR, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", CanBus.camera]) + can_sends.append(make_tester_present_msg(GLOBAL_ES_ADDR, CanBus.camera, suppress_response=True)) # Create all of the other eyesight messages to keep the rest of the car happy when eyesight is disabled if self.frame % 5 == 0: diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index f9b7a478e0..ea71dd536b 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -1,6 +1,6 @@ from cereal import car from openpilot.common.numpy_fast import clip -from openpilot.selfdrive.car import apply_meas_steer_torque_limits, apply_std_steer_angle_limits, common_fault_avoidance, make_can_msg +from openpilot.selfdrive.car import apply_meas_steer_torque_limits, apply_std_steer_angle_limits, common_fault_avoidance, make_can_msg, make_tester_present_msg from openpilot.selfdrive.car.interfaces import CarControllerBase from openpilot.selfdrive.car.toyota import toyotacan from openpilot.selfdrive.car.toyota.values import CAR, STATIC_DSU_MSGS, NO_STOP_TIMER_CAR, TSS2_CAR, \ @@ -166,7 +166,7 @@ class CarController(CarControllerBase): # keep radar disabled if self.frame % 20 == 0 and self.CP.flags & ToyotaFlags.DISABLE_RADAR.value: - can_sends.append([0x750, 0, b"\x0F\x02\x3E\x00\x00\x00\x00\x00", 0]) + can_sends.append(make_tester_present_msg(0x750, 0, 0xF)) new_actuators = actuators.as_builder() new_actuators.steer = apply_steer / self.params.STEER_MAX From 42f2601416bcb53c25e24b899131e66ee00177b8 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 30 Jul 2024 21:26:58 -0700 Subject: [PATCH 173/229] deprecate busTime (#33146) * deprecate busTime * bump * do car can + more * forgot some * bump opendbc * fix that too * bump --- cereal/log.capnp | 2 +- opendbc | 2 +- panda | 2 +- selfdrive/car/__init__.py | 2 +- selfdrive/car/ford/fordcan.py | 2 +- selfdrive/car/gm/gmcan.py | 2 +- selfdrive/car/hyundai/hyundaican.py | 6 +++--- selfdrive/car/isotp_parallel_query.py | 8 ++++---- selfdrive/car/nissan/nissancan.py | 2 +- selfdrive/car/subaru/subarucan.py | 2 +- selfdrive/car/tesla/teslacan.py | 6 +++--- selfdrive/car/tests/test_models.py | 2 +- selfdrive/controls/tests/test_startup.py | 4 ++-- selfdrive/pandad/__init__.py | 2 +- selfdrive/pandad/can_list_to_can_capnp.cc | 1 - selfdrive/pandad/panda.cc | 1 - selfdrive/pandad/panda.h | 1 - selfdrive/pandad/pandad.cc | 1 - selfdrive/pandad/pandad_api_impl.pyx | 6 ++---- system/webrtc/tests/test_stream_session.py | 2 +- tools/cabana/streams/pandastream.cc | 1 - 21 files changed, 25 insertions(+), 32 deletions(-) diff --git a/cereal/log.capnp b/cereal/log.capnp index d849f4840b..dcf9463ac8 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -336,9 +336,9 @@ enum LaneChangeDirection { struct CanData { address @0 :UInt32; - busTime @1 :UInt16; dat @2 :Data; src @3 :UInt8; + busTimeDEPRECATED @1 :UInt16; } struct DeviceState @0xa4d8b5af2aa492eb { diff --git a/opendbc b/opendbc index cff2af8ff8..8e9d368841 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit cff2af8ff8690466109f56be62129ebfb85cd5dc +Subproject commit 8e9d3688412405154a8189c421cfdc9d5feea715 diff --git a/panda b/panda index f6375848ca..8c3bb0151e 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit f6375848ca393a9483921665b6a2d131d7ec9b20 +Subproject commit 8c3bb0151e8907ade344ccb293d58cd543e28baa diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index 87d43831e6..28ec4ad187 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -189,7 +189,7 @@ def get_friction(lateral_accel_error: float, lateral_accel_deadzone: float, fric def make_can_msg(addr, dat, bus): - return [addr, 0, dat, bus] + return [addr, dat, bus] def make_tester_present_msg(addr, bus, subaddr=None, suppress_response=False): diff --git a/selfdrive/car/ford/fordcan.py b/selfdrive/car/ford/fordcan.py index 2cfd61a191..46d09ec22d 100644 --- a/selfdrive/car/ford/fordcan.py +++ b/selfdrive/car/ford/fordcan.py @@ -112,7 +112,7 @@ def create_lat_ctl2_msg(packer, CAN: CanBus, mode: int, path_offset: float, path } # calculate checksum - dat = packer.make_can_msg("LateralMotionControl2", 0, values)[2] + dat = packer.make_can_msg("LateralMotionControl2", 0, values)[1] values["LatCtlPath_No_Cs"] = calculate_lat_ctl2_checksum(mode, counter, dat) return packer.make_can_msg("LateralMotionControl2", CAN.main, values) diff --git a/selfdrive/car/gm/gmcan.py b/selfdrive/car/gm/gmcan.py index e833e77636..a70bcccd06 100644 --- a/selfdrive/car/gm/gmcan.py +++ b/selfdrive/car/gm/gmcan.py @@ -64,7 +64,7 @@ def create_gas_regen_command(packer, bus, throttle, idx, enabled, at_full_stop): "GasRegenAlwaysOne3": 1, } - dat = packer.make_can_msg("ASCMGasRegenCmd", bus, values)[2] + dat = packer.make_can_msg("ASCMGasRegenCmd", bus, values)[1] values["GasRegenChecksum"] = (((0xff - dat[1]) & 0xff) << 16) | \ (((0xff - dat[2]) & 0xff) << 8) | \ ((0x100 - dat[3] - idx) & 0xff) diff --git a/selfdrive/car/hyundai/hyundaican.py b/selfdrive/car/hyundai/hyundaican.py index b4b951f89e..d2002e23e0 100644 --- a/selfdrive/car/hyundai/hyundaican.py +++ b/selfdrive/car/hyundai/hyundaican.py @@ -77,7 +77,7 @@ def create_lkas11(packer, frame, CP, apply_steer, steer_req, # Genesis and Optima fault when forwarding while engaged values["CF_Lkas_LdwsActivemode"] = 2 - dat = packer.make_can_msg("LKAS11", 0, values)[2] + dat = packer.make_can_msg("LKAS11", 0, values)[1] if CP.flags & HyundaiFlags.CHECKSUM_CRC8: # CRC Checksum as seen on 2019 Hyundai Santa Fe @@ -156,7 +156,7 @@ def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, se scc12_values["CF_VSM_ConfMode"] = 1 scc12_values["AEB_Status"] = 1 # AEB disabled - scc12_dat = packer.make_can_msg("SCC12", 0, scc12_values)[2] + scc12_dat = packer.make_can_msg("SCC12", 0, scc12_values)[1] scc12_values["CR_VSM_ChkSum"] = 0x10 - sum(sum(divmod(i, 16)) for i in scc12_dat) % 0x10 commands.append(packer.make_can_msg("SCC12", 0, scc12_values)) @@ -181,7 +181,7 @@ def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, se "FCA_DrvSetStatus": 1, "FCA_Status": 1, # AEB disabled } - fca11_dat = packer.make_can_msg("FCA11", 0, fca11_values)[2] + fca11_dat = packer.make_can_msg("FCA11", 0, fca11_values)[1] fca11_values["CR_FCA_ChkSum"] = hyundai_checksum(fca11_dat[:7]) commands.append(packer.make_can_msg("FCA11", 0, fca11_values)) diff --git a/selfdrive/car/isotp_parallel_query.py b/selfdrive/car/isotp_parallel_query.py index 447c7093c5..b5158f2126 100644 --- a/selfdrive/car/isotp_parallel_query.py +++ b/selfdrive/car/isotp_parallel_query.py @@ -27,7 +27,7 @@ class IsoTpParallelQuery: assert tx_addr not in FUNCTIONAL_ADDRS, f"Functional address should be defined in functional_addrs: {hex(tx_addr)}" self.msg_addrs = {tx_addr: get_rx_addr_for_tx_addr(tx_addr[0], rx_offset=response_offset) for tx_addr in real_addrs} - self.msg_buffer: dict[int, list[tuple[int, int, bytes, int]]] = defaultdict(list) + self.msg_buffer: dict[int, list[tuple[int, bytes, int]]] = defaultdict(list) def rx(self): """Drain can socket and sort messages into buffers based on address""" @@ -36,11 +36,11 @@ class IsoTpParallelQuery: for packet in can_packets: for msg in packet.can: if msg.src == self.bus and msg.address in self.msg_addrs.values(): - self.msg_buffer[msg.address].append((msg.address, msg.busTime, msg.dat, msg.src)) + self.msg_buffer[msg.address].append((msg.address, msg.dat, msg.src)) def _can_tx(self, tx_addr, dat, bus): """Helper function to send single message""" - msg = [tx_addr, 0, dat, bus] + msg = [tx_addr, dat, bus] self.sendcan.send(can_list_to_can_capnp([msg], msgtype='sendcan')) def _can_rx(self, addr, sub_addr=None): @@ -53,7 +53,7 @@ class IsoTpParallelQuery: # Filter based on subadress msgs = [] for m in self.msg_buffer[addr]: - first_byte = m[2][0] + first_byte = m[1][0] if first_byte == sub_addr: msgs.append(m) else: diff --git a/selfdrive/car/nissan/nissancan.py b/selfdrive/car/nissan/nissancan.py index b9a1b4f843..28fb01d7e3 100644 --- a/selfdrive/car/nissan/nissancan.py +++ b/selfdrive/car/nissan/nissancan.py @@ -15,7 +15,7 @@ def create_steering_control(packer, apply_steer, frame, steer_on, lkas_max_torqu "LKA_ACTIVE": steer_on, } - dat = packer.make_can_msg("LKAS", 0, values)[2] + dat = packer.make_can_msg("LKAS", 0, values)[1] values["CHECKSUM"] = nissan_checksum(dat[:7]) return packer.make_can_msg("LKAS", 0, values) diff --git a/selfdrive/car/subaru/subarucan.py b/selfdrive/car/subaru/subarucan.py index 86d39ff885..41bd177ff2 100644 --- a/selfdrive/car/subaru/subarucan.py +++ b/selfdrive/car/subaru/subarucan.py @@ -279,7 +279,7 @@ def create_es_static_2(packer): # *** Subaru Pre-global *** def subaru_preglobal_checksum(packer, values, addr, checksum_byte=7): - dat = packer.make_can_msg(addr, 0, values)[2] + dat = packer.make_can_msg(addr, 0, values)[1] return (sum(dat[:checksum_byte]) + sum(dat[checksum_byte+1:])) % 256 diff --git a/selfdrive/car/tesla/teslacan.py b/selfdrive/car/tesla/teslacan.py index 6bb27b995f..f8cd138e77 100644 --- a/selfdrive/car/tesla/teslacan.py +++ b/selfdrive/car/tesla/teslacan.py @@ -25,7 +25,7 @@ class TeslaCAN: "DAS_steeringControlCounter": counter, } - data = self.packer.make_can_msg("DAS_steeringControl", CANBUS.chassis, values)[2] + data = self.packer.make_can_msg("DAS_steeringControl", CANBUS.chassis, values)[1] values["DAS_steeringControlChecksum"] = self.checksum(0x488, data[:3]) return self.packer.make_can_msg("DAS_steeringControl", CANBUS.chassis, values) @@ -69,7 +69,7 @@ class TeslaCAN: values["SpdCtrlLvr_Stat"] = 1 values["MC_STW_ACTN_RQ"] = counter - data = self.packer.make_can_msg("STW_ACTN_RQ", bus, values)[2] + data = self.packer.make_can_msg("STW_ACTN_RQ", bus, values)[1] values["CRC_STW_ACTN_RQ"] = self.crc(data[:7]) return self.packer.make_can_msg("STW_ACTN_RQ", bus, values) @@ -88,7 +88,7 @@ class TeslaCAN: } for packer, bus in [(self.packer, CANBUS.chassis), (self.pt_packer, CANBUS.powertrain)]: - data = packer.make_can_msg("DAS_control", bus, values)[2] + data = packer.make_can_msg("DAS_control", bus, values)[1] values["DAS_controlChecksum"] = self.checksum(0x2b9, data[:7]) messages.append(packer.make_can_msg("DAS_control", bus, values)) return messages diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index 02e99f0b82..1d05b7c731 100644 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -297,7 +297,7 @@ class TestCarModelBase(unittest.TestCase): now_nanos += DT_CTRL * 1e9 msgs_sent += len(sendcan) - for addr, _, dat, bus in sendcan: + for addr, dat, bus in sendcan: to_send = libpanda_py.make_CANPacket(addr, bus % 4, dat) self.assertTrue(self.safety.safety_tx_hook(to_send), (addr, dat, bus)) diff --git a/selfdrive/controls/tests/test_startup.py b/selfdrive/controls/tests/test_startup.py index 14b0788a3d..51b9887c96 100644 --- a/selfdrive/controls/tests/test_startup.py +++ b/selfdrive/controls/tests/test_startup.py @@ -90,7 +90,7 @@ def test_startup_alert(expected_event, car_model, fw_versions, brand): managed_processes['card'].start() assert pm.wait_for_readers_to_update('can', 5) - pm.send('can', can_list_to_can_capnp([[0, 0, b"", 0]])) + pm.send('can', can_list_to_can_capnp([[0, b"", 0]])) assert pm.wait_for_readers_to_update('pandaStates', 5) msg = messaging.new_message('pandaStates', 1) @@ -103,7 +103,7 @@ def test_startup_alert(expected_event, car_model, fw_versions, brand): else: finger = _FINGERPRINTS[car_model][0] - msgs = [[addr, 0, b'\x00'*length, 0] for addr, length in finger.items()] + msgs = [[addr, b'\x00'*length, 0] for addr, length in finger.items()] for _ in range(1000): # card waits for pandad to echo back that it has changed the multiplexing mode if not params.get_bool("ObdMultiplexingChanged"): diff --git a/selfdrive/pandad/__init__.py b/selfdrive/pandad/__init__.py index 8081a62dd0..2c80cd03c4 100644 --- a/selfdrive/pandad/__init__.py +++ b/selfdrive/pandad/__init__.py @@ -6,5 +6,5 @@ def can_capnp_to_can_list(can, src_filter=None): ret = [] for msg in can: if src_filter is None or msg.src in src_filter: - ret.append((msg.address, msg.busTime, msg.dat, msg.src)) + ret.append((msg.address, msg.dat, msg.src)) return ret diff --git a/selfdrive/pandad/can_list_to_can_capnp.cc b/selfdrive/pandad/can_list_to_can_capnp.cc index 9fc2648da2..d73541c17f 100644 --- a/selfdrive/pandad/can_list_to_can_capnp.cc +++ b/selfdrive/pandad/can_list_to_can_capnp.cc @@ -10,7 +10,6 @@ void can_list_to_can_capnp_cpp(const std::vector &can_list, std::stri for (auto it = can_list.begin(); it != can_list.end(); it++, j++) { auto c = canData[j]; c.setAddress(it->address); - c.setBusTime(it->busTime); c.setDat(kj::arrayPtr((uint8_t*)it->dat.data(), it->dat.size())); c.setSrc(it->src); } diff --git a/selfdrive/pandad/panda.cc b/selfdrive/pandad/panda.cc index fcb4ac67a4..ed5ee62501 100644 --- a/selfdrive/pandad/panda.cc +++ b/selfdrive/pandad/panda.cc @@ -257,7 +257,6 @@ bool Panda::unpack_can_buffer(uint8_t *data, uint32_t &size, std::vector pandas) { auto canData = evt.initCan(raw_can_data.size()); for (uint i = 0; i Date: Tue, 30 Jul 2024 23:28:49 -0700 Subject: [PATCH 174/229] bump --- opendbc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendbc b/opendbc index 8e9d368841..0a095bc1a4 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 8e9d3688412405154a8189c421cfdc9d5feea715 +Subproject commit 0a095bc1a487a8df669349cc923a9b3984219765 From 80f9278a734ad566d9484074d2f6834659ab1feb Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 30 Jul 2024 23:29:46 -0700 Subject: [PATCH 175/229] Revert "bump" This reverts commit 7824074aae74ff12bd56880a690234b582535748. --- opendbc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendbc b/opendbc index 0a095bc1a4..8e9d368841 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 0a095bc1a487a8df669349cc923a9b3984219765 +Subproject commit 8e9d3688412405154a8189c421cfdc9d5feea715 From 1b6ac2d876fe3170968944722df67ee815d8cb1b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 30 Jul 2024 23:55:23 -0700 Subject: [PATCH 176/229] CarController: call to super's init (#33148) * this should be common * super! * bump * and frame is common * bump --- selfdrive/car/body/carcontroller.py | 2 +- selfdrive/car/chrysler/carcontroller.py | 3 +-- selfdrive/car/chrysler/radar_interface.py | 1 - selfdrive/car/ford/carcontroller.py | 3 +-- selfdrive/car/gm/carcontroller.py | 3 +-- selfdrive/car/honda/carcontroller.py | 3 +-- selfdrive/car/hyundai/carcontroller.py | 3 +-- selfdrive/car/interfaces.py | 4 +++- selfdrive/car/mazda/carcontroller.py | 3 +-- selfdrive/car/nissan/carcontroller.py | 3 +-- selfdrive/car/subaru/carcontroller.py | 3 +-- selfdrive/car/tesla/carcontroller.py | 3 +-- selfdrive/car/tesla/radar_interface.py | 1 - selfdrive/car/toyota/carcontroller.py | 3 +-- selfdrive/car/volkswagen/carcontroller.py | 3 +-- 15 files changed, 15 insertions(+), 26 deletions(-) diff --git a/selfdrive/car/body/carcontroller.py b/selfdrive/car/body/carcontroller.py index c45dc7f0d2..0771d7a471 100644 --- a/selfdrive/car/body/carcontroller.py +++ b/selfdrive/car/body/carcontroller.py @@ -17,7 +17,7 @@ MAX_TURN_INTEGRATOR = 0.1 # meters class CarController(CarControllerBase): def __init__(self, dbc_name, CP, VM): - self.frame = 0 + super().__init__(dbc_name, CP, VM) self.packer = CANPacker(dbc_name) # PIDs diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index c9e7e2c9ed..c0c03e0e05 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -7,9 +7,8 @@ from openpilot.selfdrive.car.interfaces import CarControllerBase class CarController(CarControllerBase): def __init__(self, dbc_name, CP, VM): - self.CP = CP + super().__init__(dbc_name, CP, VM) self.apply_steer_last = 0 - self.frame = 0 self.hud_count = 0 self.last_lkas_falling_edge = 0 diff --git a/selfdrive/car/chrysler/radar_interface.py b/selfdrive/car/chrysler/radar_interface.py index d982958422..f1d863d1e1 100755 --- a/selfdrive/car/chrysler/radar_interface.py +++ b/selfdrive/car/chrysler/radar_interface.py @@ -39,7 +39,6 @@ def _address_to_track(address): class RadarInterface(RadarInterfaceBase): def __init__(self, CP): super().__init__(CP) - self.CP = CP self.rcp = _create_radar_can_parser(CP.carFingerprint) self.updated_messages = set() self.trigger_msg = LAST_MSG diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index 09bba46565..d090adf694 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -25,11 +25,10 @@ def apply_ford_curvature_limits(apply_curvature, apply_curvature_last, current_c class CarController(CarControllerBase): def __init__(self, dbc_name, CP, VM): - self.CP = CP + super().__init__(dbc_name, CP, VM) self.VM = VM self.packer = CANPacker(dbc_name) self.CAN = fordcan.CanBus(CP) - self.frame = 0 self.apply_curvature_last = 0 self.main_on_last = False diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index 013e72ad0b..cac4f13ed5 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -19,12 +19,11 @@ MIN_STEER_MSG_INTERVAL_MS = 15 class CarController(CarControllerBase): def __init__(self, dbc_name, CP, VM): - self.CP = CP + super().__init__(dbc_name, CP, VM) self.start_time = 0. self.apply_steer_last = 0 self.apply_gas = 0 self.apply_brake = 0 - self.frame = 0 self.last_steer_frame = 0 self.last_button_frame = 0 self.cancel_counter = 0 diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index 84ccf29d18..5748812648 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -105,11 +105,10 @@ def rate_limit_steer(new_steer, last_steer): class CarController(CarControllerBase): def __init__(self, dbc_name, CP, VM): - self.CP = CP + super().__init__(dbc_name, CP, VM) self.packer = CANPacker(dbc_name) self.params = CarControllerParams(CP) self.CAN = hondacan.CanBus(CP) - self.frame = 0 self.braking = False self.brake_steady = 0. diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 75aeb0efd6..84b565f0cd 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -44,12 +44,11 @@ def process_hud_alert(enabled, fingerprint, hud_control): class CarController(CarControllerBase): def __init__(self, dbc_name, CP, VM): - self.CP = CP + super().__init__(dbc_name, CP, VM) self.CAN = CanBus(CP) self.params = CarControllerParams(CP) self.packer = CANPacker(dbc_name) self.angle_limit_counter = 0 - self.frame = 0 self.accel_last = 0 self.apply_steer_last = 0 diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index d37e171da7..e491de3ed6 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -344,6 +344,7 @@ class CarInterfaceBase(ABC): class RadarInterfaceBase(ABC): def __init__(self, CP): + self.CP = CP self.rcp = None self.pts = {} self.delay = 0 @@ -466,7 +467,8 @@ SendCan = tuple[int, int, bytes, int] class CarControllerBase(ABC): def __init__(self, dbc_name: str, CP, VM): - pass + self.CP = CP + self.frame = 0 @abstractmethod def update(self, CC: car.CarControl.Actuators, CS: car.CarState, now_nanos: int) -> tuple[car.CarControl.Actuators, list[SendCan]]: diff --git a/selfdrive/car/mazda/carcontroller.py b/selfdrive/car/mazda/carcontroller.py index 3d41634879..23441a3a78 100644 --- a/selfdrive/car/mazda/carcontroller.py +++ b/selfdrive/car/mazda/carcontroller.py @@ -10,11 +10,10 @@ VisualAlert = car.CarControl.HUDControl.VisualAlert class CarController(CarControllerBase): def __init__(self, dbc_name, CP, VM): - self.CP = CP + super().__init__(dbc_name, CP, VM) self.apply_steer_last = 0 self.packer = CANPacker(dbc_name) self.brake_counter = 0 - self.frame = 0 def update(self, CC, CS, now_nanos): can_sends = [] diff --git a/selfdrive/car/nissan/carcontroller.py b/selfdrive/car/nissan/carcontroller.py index c7bd231398..473282edfc 100644 --- a/selfdrive/car/nissan/carcontroller.py +++ b/selfdrive/car/nissan/carcontroller.py @@ -10,9 +10,8 @@ VisualAlert = car.CarControl.HUDControl.VisualAlert class CarController(CarControllerBase): def __init__(self, dbc_name, CP, VM): - self.CP = CP + super().__init__(dbc_name, CP, VM) self.car_fingerprint = CP.carFingerprint - self.frame = 0 self.lkas_max_torque = 0 self.apply_angle_last = 0 diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index 3e1b62c974..6ce006df8b 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -13,9 +13,8 @@ MAX_STEER_RATE_FRAMES = 7 # tx control frames needed before torque can be cut class CarController(CarControllerBase): def __init__(self, dbc_name, CP, VM): - self.CP = CP + super().__init__(dbc_name, CP, VM) self.apply_steer_last = 0 - self.frame = 0 self.cruise_button_prev = 0 self.steer_rate_counter = 0 diff --git a/selfdrive/car/tesla/carcontroller.py b/selfdrive/car/tesla/carcontroller.py index e460111e32..8ee2a2165e 100644 --- a/selfdrive/car/tesla/carcontroller.py +++ b/selfdrive/car/tesla/carcontroller.py @@ -8,8 +8,7 @@ from openpilot.selfdrive.car.tesla.values import DBC, CANBUS, CarControllerParam class CarController(CarControllerBase): def __init__(self, dbc_name, CP, VM): - self.CP = CP - self.frame = 0 + super().__init__(dbc_name, CP, VM) self.apply_angle_last = 0 self.packer = CANPacker(dbc_name) self.pt_packer = CANPacker(DBC[CP.carFingerprint]['pt']) diff --git a/selfdrive/car/tesla/radar_interface.py b/selfdrive/car/tesla/radar_interface.py index ae5077824b..1684e42e7f 100755 --- a/selfdrive/car/tesla/radar_interface.py +++ b/selfdrive/car/tesla/radar_interface.py @@ -8,7 +8,6 @@ from openpilot.selfdrive.car.interfaces import RadarInterfaceBase class RadarInterface(RadarInterfaceBase): def __init__(self, CP): super().__init__(CP) - self.CP = CP if CP.carFingerprint == CAR.TESLA_MODELS_RAVEN: messages = [('RadarStatus', 16)] diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index ea71dd536b..f844b7dc44 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -27,9 +27,8 @@ MAX_LTA_DRIVER_TORQUE_ALLOWANCE = 150 # slightly above steering pressed allows class CarController(CarControllerBase): def __init__(self, dbc_name, CP, VM): - self.CP = CP + super().__init__(dbc_name, CP, VM) self.params = CarControllerParams(self.CP) - self.frame = 0 self.last_steer = 0 self.last_angle = 0 self.alert_active = False diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index 8e8652d3be..228900b6e9 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -13,7 +13,7 @@ LongCtrlState = car.CarControl.Actuators.LongControlState class CarController(CarControllerBase): def __init__(self, dbc_name, CP, VM): - self.CP = CP + super().__init__(dbc_name, CP, VM) self.CCP = CarControllerParams(CP) self.CCS = pqcan if CP.flags & VolkswagenFlags.PQ else mqbcan self.packer_pt = CANPacker(dbc_name) @@ -21,7 +21,6 @@ class CarController(CarControllerBase): self.apply_steer_last = 0 self.gra_acc_counter_last = None - self.frame = 0 self.eps_timer_soft_disable_alert = False self.hca_frame_timer_running = 0 self.hca_frame_same_torque = 0 From 0dddc97dca8bf4e023b29c35cb92fd3dd0a9a3a2 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 31 Jul 2024 15:24:46 +0800 Subject: [PATCH 177/229] update to new opendbc API (#32009) * use new opendbc api * export pandad_python * merge master * merge master * bump opendbc * bump opendbc * improve func * keep interface unchanged * fix test_car_interfaces * bump opendbc * bump opendbc * fix test_models * the interface now has to convert from can capnp to list, so we should include this time * goes from ~210 to ~240 mean ms real time * remoe busTime * lowercase sendcan * consistent msgtype * bump * bump * not used in lat_mpc * space * bump to master --------- Co-authored-by: Shane Smiskol --- opendbc | 2 +- selfdrive/car/interfaces.py | 4 ++- selfdrive/car/tests/test_car_interfaces.py | 3 +- selfdrive/car/tests/test_models.py | 3 +- .../lib/longitudinal_mpc_lib/SConscript | 4 +-- selfdrive/controls/radard.py | 4 +-- .../debug/check_can_parser_performance.py | 6 ++-- selfdrive/pandad/SConscript | 4 ++- selfdrive/pandad/__init__.py | 3 +- selfdrive/pandad/can_list_to_can_capnp.cc | 35 +++++++++++++++++-- selfdrive/pandad/pandad_api_impl.pyx | 29 ++++++++++++++- .../examples/subaru_long_accel.ipynb | 3 +- .../examples/subaru_steer_temp_fault.ipynb | 3 +- 13 files changed, 86 insertions(+), 17 deletions(-) diff --git a/opendbc b/opendbc index 8e9d368841..39a5345924 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 8e9d3688412405154a8189c421cfdc9d5feea715 +Subproject commit 39a5345924d2414f05c40d258d359eb8412a0b03 diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index e491de3ed6..6ecf6daab3 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -18,6 +18,7 @@ from openpilot.selfdrive.car.values import PLATFORMS from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX from openpilot.selfdrive.controls.lib.events import Events from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel +from openpilot.selfdrive.pandad import can_capnp_to_list ButtonType = car.CarState.ButtonEvent.Type GearShifter = car.CarState.GearShifter @@ -231,9 +232,10 @@ class CarInterfaceBase(ABC): def update(self, c: car.CarControl, can_strings: list[bytes]) -> car.CarState: # parse can + can_list = can_capnp_to_list(can_strings) for cp in self.can_parsers: if cp is not None: - cp.update_strings(can_strings) + cp.update_strings(can_list) # get CarState ret = self._update(c) diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index 4ca19f019e..9e3c7d157e 100644 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -15,6 +15,7 @@ from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque from openpilot.selfdrive.controls.lib.longcontrol import LongControl +from openpilot.selfdrive.pandad import can_capnp_to_list from openpilot.selfdrive.test.fuzzy_generation import DrawType, FuzzyGenerator ALL_ECUS = {ecu for ecus in FW_VERSIONS.values() for ecu in ecus.keys()} @@ -128,7 +129,7 @@ class TestCarInterfaces: # Test radar fault if not car_params.radarUnavailable and radar_interface.rcp is not None: - cans = [messaging.new_message('can', 1).to_bytes() for _ in range(5)] + cans = can_capnp_to_list([messaging.new_message('can', 1).to_bytes() for _ in range(5)]) rr = radar_interface.update(cans) assert rr is None or len(rr.errors) > 0 diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index 1d05b7c731..22a80f359a 100644 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -19,6 +19,7 @@ from openpilot.selfdrive.car.honda.values import CAR as HONDA, HondaFlags from openpilot.selfdrive.car.tests.routes import non_tested_cars, routes, CarTestRoute from openpilot.selfdrive.car.values import Platform from openpilot.selfdrive.car.card import Car +from openpilot.selfdrive.pandad import can_capnp_to_list from openpilot.selfdrive.test.helpers import read_segment_list from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT from openpilot.tools.lib.logreader import LogReader, internal_source, openpilotci_source @@ -237,7 +238,7 @@ class TestCarModelBase(unittest.TestCase): # start parsing CAN messages after we've left ELM mode and can expect CAN traffic error_cnt = 0 for i, msg in enumerate(self.can_msgs[self.elm_frame:]): - rr = RI.update((msg.as_builder().to_bytes(),)) + rr = RI.update(can_capnp_to_list((msg.as_builder().to_bytes(),))) if rr is not None and i > 50: error_cnt += car.RadarData.Error.canError in rr.errors self.assertEqual(error_cnt, 0) diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript index fc1e844d50..22342c0078 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript @@ -1,4 +1,4 @@ -Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python', 'np_version') +Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python', 'pandad_python', 'np_version') gen = "c_generated_code" @@ -66,7 +66,7 @@ lenv.Clean(generated_files, Dir(gen)) generated_long = lenv.Command(generated_files, source_list, f"cd {Dir('.').abspath} && python3 long_mpc.py") -lenv.Depends(generated_long, [msgq_python, common_python, opendbc_python]) +lenv.Depends(generated_long, [msgq_python, common_python, opendbc_python, pandad_python]) lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES") lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES") diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index c3fb60c61a..a7e3c0211d 100755 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -10,8 +10,8 @@ from openpilot.common.numpy_fast import interp from openpilot.common.params import Params from openpilot.common.realtime import DT_CTRL, Ratekeeper, Priority, config_realtime_process from openpilot.common.swaglog import cloudlog - from openpilot.common.simple_kalman import KF1D +from openpilot.selfdrive.pandad import can_capnp_to_list # Default lead acceleration decay set to 50% at 1s @@ -307,7 +307,7 @@ def main(): while 1: can_strings = messaging.drain_sock_raw(can_sock, wait_for_one=True) - rr = RI.update(can_strings) + rr = RI.update(can_capnp_to_list(can_strings)) sm.update(0) if rr is None: continue diff --git a/selfdrive/debug/check_can_parser_performance.py b/selfdrive/debug/check_can_parser_performance.py index 604a1df124..a5155f0126 100755 --- a/selfdrive/debug/check_can_parser_performance.py +++ b/selfdrive/debug/check_can_parser_performance.py @@ -6,6 +6,7 @@ from tqdm import tqdm from cereal import car from openpilot.selfdrive.car.tests.routes import CarTestRoute from openpilot.selfdrive.car.tests.test_models import TestCarModelBase +from openpilot.selfdrive.pandad import can_capnp_to_list from openpilot.tools.plotjuggler.juggle import DEMO_ROUTE N_RUNS = 10 @@ -25,12 +26,13 @@ if __name__ == '__main__': CC = car.CarControl.new_message() ets = [] for _ in tqdm(range(N_RUNS)): - msgs = [(m.as_builder().to_bytes(),) for m in tm.can_msgs] + msgs = [m.as_builder().to_bytes() for m in tm.can_msgs] start_t = time.process_time_ns() for msg in msgs: + can_list = can_capnp_to_list([msg]) for cp in tm.CI.can_parsers: if cp is not None: - cp.update_strings(msg) + cp.update_strings(can_list) ets.append((time.process_time_ns() - start_t) * 1e-6) print(f'{len(tm.can_msgs)} CAN packets, {N_RUNS} runs') diff --git a/selfdrive/pandad/SConscript b/selfdrive/pandad/SConscript index 63a2c1e650..dcc1f9811e 100644 --- a/selfdrive/pandad/SConscript +++ b/selfdrive/pandad/SConscript @@ -6,6 +6,8 @@ panda = env.Library('panda', ['panda.cc', 'panda_comms.cc', 'spi.cc']) env.Program('pandad', ['main.cc', 'pandad.cc'], LIBS=[panda] + libs) env.Library('libcan_list_to_can_capnp', ['can_list_to_can_capnp.cc']) -envCython.Program('pandad_api_impl.so', 'pandad_api_impl.pyx', LIBS=["can_list_to_can_capnp", 'capnp', 'kj'] + envCython["LIBS"]) +pandad_python = envCython.Program('pandad_api_impl.so', 'pandad_api_impl.pyx', LIBS=["can_list_to_can_capnp", 'capnp', 'kj'] + envCython["LIBS"]) +Export('pandad_python') + if GetOption('extras'): env.Program('tests/test_pandad_usbprotocol', ['tests/test_pandad_usbprotocol.cc'], LIBS=[panda] + libs) diff --git a/selfdrive/pandad/__init__.py b/selfdrive/pandad/__init__.py index 2c80cd03c4..b72c8ccb57 100644 --- a/selfdrive/pandad/__init__.py +++ b/selfdrive/pandad/__init__.py @@ -1,6 +1,7 @@ # Cython, now uses scons to build -from openpilot.selfdrive.pandad.pandad_api_impl import can_list_to_can_capnp +from openpilot.selfdrive.pandad.pandad_api_impl import can_list_to_can_capnp, can_capnp_to_list assert can_list_to_can_capnp +assert can_capnp_to_list def can_capnp_to_can_list(can, src_filter=None): ret = [] diff --git a/selfdrive/pandad/can_list_to_can_capnp.cc b/selfdrive/pandad/can_list_to_can_capnp.cc index d73541c17f..ad2393b986 100644 --- a/selfdrive/pandad/can_list_to_can_capnp.cc +++ b/selfdrive/pandad/can_list_to_can_capnp.cc @@ -1,11 +1,12 @@ #include "cereal/messaging/messaging.h" #include "selfdrive/pandad/panda.h" +#include "opendbc/can/common.h" -void can_list_to_can_capnp_cpp(const std::vector &can_list, std::string &out, bool sendCan, bool valid) { +void can_list_to_can_capnp_cpp(const std::vector &can_list, std::string &out, bool sendcan, bool valid) { MessageBuilder msg; auto event = msg.initEvent(valid); - auto canData = sendCan ? event.initSendcan(can_list.size()) : event.initCan(can_list.size()); + auto canData = sendcan ? event.initSendcan(can_list.size()) : event.initCan(can_list.size()); int j = 0; for (auto it = can_list.begin(); it != can_list.end(); it++, j++) { auto c = canData[j]; @@ -18,3 +19,33 @@ void can_list_to_can_capnp_cpp(const std::vector &can_list, std::stri kj::ArrayOutputStream output_stream(kj::ArrayPtr((unsigned char *)out.data(), msg_size)); capnp::writeMessage(output_stream, msg); } + +// Converts a vector of Cap'n Proto serialized can strings into a vector of CanData structures. +void can_capnp_to_can_list_cpp(const std::vector &strings, std::vector &can_list, bool sendcan) { + AlignedBuffer aligned_buf; + can_list.reserve(strings.size()); + + for (const auto &str : strings) { + // extract the messages + capnp::FlatArrayMessageReader reader(aligned_buf.align(str.data(), str.size())); + cereal::Event::Reader event = reader.getRoot(); + + auto frames = sendcan ? event.getSendcan() : event.getCan(); + + // Add new CanData entry + CanData &can_data = can_list.emplace_back(); + can_data.nanos = event.getLogMonoTime(); + can_data.frames.reserve(frames.size()); + + // Populate CAN frames + for (const auto &frame : frames) { + CanFrame &can_frame = can_data.frames.emplace_back(); + can_frame.src = frame.getSrc(); + can_frame.address = frame.getAddress(); + + // Copy CAN data + auto dat = frame.getDat(); + can_frame.dat.assign(dat.begin(), dat.end()); + } + } +} diff --git a/selfdrive/pandad/pandad_api_impl.pyx b/selfdrive/pandad/pandad_api_impl.pyx index dd3f3d702f..8a12e1c433 100644 --- a/selfdrive/pandad/pandad_api_impl.pyx +++ b/selfdrive/pandad/pandad_api_impl.pyx @@ -1,8 +1,10 @@ # distutils: language = c++ # cython: language_level=3 +from cython.operator cimport dereference as deref, preincrement as preinc from libcpp.vector cimport vector from libcpp.string cimport string from libcpp cimport bool +from libc.stdint cimport uint8_t, uint32_t, uint64_t cdef extern from "panda.h": cdef struct can_frame: @@ -10,8 +12,19 @@ cdef extern from "panda.h": string dat long src +cdef extern from "opendbc/can/common.h": + cdef struct CanFrame: + long src + uint32_t address + vector[uint8_t] dat + + cdef struct CanData: + uint64_t nanos + vector[CanFrame] frames + cdef extern from "can_list_to_can_capnp.cc": - void can_list_to_can_capnp_cpp(const vector[can_frame] &can_list, string &out, bool sendCan, bool valid) + void can_list_to_can_capnp_cpp(const vector[can_frame] &can_list, string &out, bool sendcan, bool valid) + void can_capnp_to_can_list_cpp(const vector[string] &strings, vector[CanData] &can_data, bool sendcan) def can_list_to_can_capnp(can_msgs, msgtype='can', valid=True): cdef can_frame *f @@ -27,3 +40,17 @@ def can_list_to_can_capnp(can_msgs, msgtype='can', valid=True): cdef string out can_list_to_can_capnp_cpp(can_list, out, msgtype == 'sendcan', valid) return out + +def can_capnp_to_list(strings, msgtype='can'): + cdef vector[CanData] data + can_capnp_to_can_list_cpp(strings, data, msgtype == 'sendcan') + + result = [] + cdef CanData *d + cdef vector[CanData].iterator it = data.begin() + while it != data.end(): + d = &deref(it) + frames = [[f.address, (&f.dat[0])[:f.dat.size()], f.src] for f in d.frames] + result.append([d.nanos, frames]) + preinc(it) + return result diff --git a/tools/car_porting/examples/subaru_long_accel.ipynb b/tools/car_porting/examples/subaru_long_accel.ipynb index 9d18a114df..35b92702a7 100644 --- a/tools/car_porting/examples/subaru_long_accel.ipynb +++ b/tools/car_porting/examples/subaru_long_accel.ipynb @@ -24,6 +24,7 @@ "from opendbc.can.parser import CANParser\n", "\n", "from openpilot.selfdrive.car.subaru.values import DBC\n", + "from openpilot.selfdrive.pandad import can_capnp_to_list\n", "from openpilot.tools.lib.logreader import LogReader\n", "\n", "\"\"\"\n", @@ -50,7 +51,7 @@ "\n", " for msg in lr:\n", " if msg.which() == \"can\":\n", - " cp.update_strings([msg.as_builder().to_bytes()])\n", + " cp.update_strings(can_capnp_to_list([msg.as_builder().to_bytes()]))\n", " es_distance_history.append(copy.copy(cp.vl[\"ES_Distance\"]))\n", " es_brake_history.append(copy.copy(cp.vl[\"ES_Brake\"]))\n", " es_status_history.append(copy.copy(cp.vl[\"ES_Status\"]))\n", diff --git a/tools/car_porting/examples/subaru_steer_temp_fault.ipynb b/tools/car_porting/examples/subaru_steer_temp_fault.ipynb index 3d5055cbc2..8b762fecb8 100644 --- a/tools/car_porting/examples/subaru_steer_temp_fault.ipynb +++ b/tools/car_porting/examples/subaru_steer_temp_fault.ipynb @@ -27,6 +27,7 @@ "from opendbc.can.parser import CANParser\n", "\n", "from openpilot.selfdrive.car.subaru.values import CanBus, DBC\n", + "from openpilot.selfdrive.pandad import can_capnp_to_list\n", "from openpilot.tools.lib.logreader import LogReader\n", "\n", "\"\"\"\n", @@ -50,7 +51,7 @@ " examples = []\n", "\n", " for msg in can_msgs:\n", - " cp.update_strings([msg.as_builder().to_bytes()])\n", + " cp.update_strings(can_capnp_to_list([msg.as_builder().to_bytes()]))\n", " steering_torque_history.append(copy.copy(cp.vl[\"Steering_Torque\"]))\n", "\n", " steer_warning_last = False\n", From ac130001cc83734118524f59a83a96a2065dd56e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 31 Jul 2024 02:38:44 -0700 Subject: [PATCH 178/229] Revert "update to new opendbc API (#32009)" This reverts commit 0dddc97dca8bf4e023b29c35cb92fd3dd0a9a3a2. --- opendbc | 2 +- selfdrive/car/interfaces.py | 4 +-- selfdrive/car/tests/test_car_interfaces.py | 3 +- selfdrive/car/tests/test_models.py | 3 +- .../lib/longitudinal_mpc_lib/SConscript | 4 +-- selfdrive/controls/radard.py | 4 +-- .../debug/check_can_parser_performance.py | 6 ++-- selfdrive/pandad/SConscript | 4 +-- selfdrive/pandad/__init__.py | 3 +- selfdrive/pandad/can_list_to_can_capnp.cc | 35 ++----------------- selfdrive/pandad/pandad_api_impl.pyx | 29 +-------------- .../examples/subaru_long_accel.ipynb | 3 +- .../examples/subaru_steer_temp_fault.ipynb | 3 +- 13 files changed, 17 insertions(+), 86 deletions(-) diff --git a/opendbc b/opendbc index 39a5345924..8e9d368841 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 39a5345924d2414f05c40d258d359eb8412a0b03 +Subproject commit 8e9d3688412405154a8189c421cfdc9d5feea715 diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 6ecf6daab3..e491de3ed6 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -18,7 +18,6 @@ from openpilot.selfdrive.car.values import PLATFORMS from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX from openpilot.selfdrive.controls.lib.events import Events from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel -from openpilot.selfdrive.pandad import can_capnp_to_list ButtonType = car.CarState.ButtonEvent.Type GearShifter = car.CarState.GearShifter @@ -232,10 +231,9 @@ class CarInterfaceBase(ABC): def update(self, c: car.CarControl, can_strings: list[bytes]) -> car.CarState: # parse can - can_list = can_capnp_to_list(can_strings) for cp in self.can_parsers: if cp is not None: - cp.update_strings(can_list) + cp.update_strings(can_strings) # get CarState ret = self._update(c) diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index 9e3c7d157e..4ca19f019e 100644 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -15,7 +15,6 @@ from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque from openpilot.selfdrive.controls.lib.longcontrol import LongControl -from openpilot.selfdrive.pandad import can_capnp_to_list from openpilot.selfdrive.test.fuzzy_generation import DrawType, FuzzyGenerator ALL_ECUS = {ecu for ecus in FW_VERSIONS.values() for ecu in ecus.keys()} @@ -129,7 +128,7 @@ class TestCarInterfaces: # Test radar fault if not car_params.radarUnavailable and radar_interface.rcp is not None: - cans = can_capnp_to_list([messaging.new_message('can', 1).to_bytes() for _ in range(5)]) + cans = [messaging.new_message('can', 1).to_bytes() for _ in range(5)] rr = radar_interface.update(cans) assert rr is None or len(rr.errors) > 0 diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index 22a80f359a..1d05b7c731 100644 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -19,7 +19,6 @@ from openpilot.selfdrive.car.honda.values import CAR as HONDA, HondaFlags from openpilot.selfdrive.car.tests.routes import non_tested_cars, routes, CarTestRoute from openpilot.selfdrive.car.values import Platform from openpilot.selfdrive.car.card import Car -from openpilot.selfdrive.pandad import can_capnp_to_list from openpilot.selfdrive.test.helpers import read_segment_list from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT from openpilot.tools.lib.logreader import LogReader, internal_source, openpilotci_source @@ -238,7 +237,7 @@ class TestCarModelBase(unittest.TestCase): # start parsing CAN messages after we've left ELM mode and can expect CAN traffic error_cnt = 0 for i, msg in enumerate(self.can_msgs[self.elm_frame:]): - rr = RI.update(can_capnp_to_list((msg.as_builder().to_bytes(),))) + rr = RI.update((msg.as_builder().to_bytes(),)) if rr is not None and i > 50: error_cnt += car.RadarData.Error.canError in rr.errors self.assertEqual(error_cnt, 0) diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript index 22342c0078..fc1e844d50 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript @@ -1,4 +1,4 @@ -Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python', 'pandad_python', 'np_version') +Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python', 'np_version') gen = "c_generated_code" @@ -66,7 +66,7 @@ lenv.Clean(generated_files, Dir(gen)) generated_long = lenv.Command(generated_files, source_list, f"cd {Dir('.').abspath} && python3 long_mpc.py") -lenv.Depends(generated_long, [msgq_python, common_python, opendbc_python, pandad_python]) +lenv.Depends(generated_long, [msgq_python, common_python, opendbc_python]) lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES") lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES") diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index a7e3c0211d..c3fb60c61a 100755 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -10,8 +10,8 @@ from openpilot.common.numpy_fast import interp from openpilot.common.params import Params from openpilot.common.realtime import DT_CTRL, Ratekeeper, Priority, config_realtime_process from openpilot.common.swaglog import cloudlog + from openpilot.common.simple_kalman import KF1D -from openpilot.selfdrive.pandad import can_capnp_to_list # Default lead acceleration decay set to 50% at 1s @@ -307,7 +307,7 @@ def main(): while 1: can_strings = messaging.drain_sock_raw(can_sock, wait_for_one=True) - rr = RI.update(can_capnp_to_list(can_strings)) + rr = RI.update(can_strings) sm.update(0) if rr is None: continue diff --git a/selfdrive/debug/check_can_parser_performance.py b/selfdrive/debug/check_can_parser_performance.py index a5155f0126..604a1df124 100755 --- a/selfdrive/debug/check_can_parser_performance.py +++ b/selfdrive/debug/check_can_parser_performance.py @@ -6,7 +6,6 @@ from tqdm import tqdm from cereal import car from openpilot.selfdrive.car.tests.routes import CarTestRoute from openpilot.selfdrive.car.tests.test_models import TestCarModelBase -from openpilot.selfdrive.pandad import can_capnp_to_list from openpilot.tools.plotjuggler.juggle import DEMO_ROUTE N_RUNS = 10 @@ -26,13 +25,12 @@ if __name__ == '__main__': CC = car.CarControl.new_message() ets = [] for _ in tqdm(range(N_RUNS)): - msgs = [m.as_builder().to_bytes() for m in tm.can_msgs] + msgs = [(m.as_builder().to_bytes(),) for m in tm.can_msgs] start_t = time.process_time_ns() for msg in msgs: - can_list = can_capnp_to_list([msg]) for cp in tm.CI.can_parsers: if cp is not None: - cp.update_strings(can_list) + cp.update_strings(msg) ets.append((time.process_time_ns() - start_t) * 1e-6) print(f'{len(tm.can_msgs)} CAN packets, {N_RUNS} runs') diff --git a/selfdrive/pandad/SConscript b/selfdrive/pandad/SConscript index dcc1f9811e..63a2c1e650 100644 --- a/selfdrive/pandad/SConscript +++ b/selfdrive/pandad/SConscript @@ -6,8 +6,6 @@ panda = env.Library('panda', ['panda.cc', 'panda_comms.cc', 'spi.cc']) env.Program('pandad', ['main.cc', 'pandad.cc'], LIBS=[panda] + libs) env.Library('libcan_list_to_can_capnp', ['can_list_to_can_capnp.cc']) -pandad_python = envCython.Program('pandad_api_impl.so', 'pandad_api_impl.pyx', LIBS=["can_list_to_can_capnp", 'capnp', 'kj'] + envCython["LIBS"]) -Export('pandad_python') - +envCython.Program('pandad_api_impl.so', 'pandad_api_impl.pyx', LIBS=["can_list_to_can_capnp", 'capnp', 'kj'] + envCython["LIBS"]) if GetOption('extras'): env.Program('tests/test_pandad_usbprotocol', ['tests/test_pandad_usbprotocol.cc'], LIBS=[panda] + libs) diff --git a/selfdrive/pandad/__init__.py b/selfdrive/pandad/__init__.py index b72c8ccb57..2c80cd03c4 100644 --- a/selfdrive/pandad/__init__.py +++ b/selfdrive/pandad/__init__.py @@ -1,7 +1,6 @@ # Cython, now uses scons to build -from openpilot.selfdrive.pandad.pandad_api_impl import can_list_to_can_capnp, can_capnp_to_list +from openpilot.selfdrive.pandad.pandad_api_impl import can_list_to_can_capnp assert can_list_to_can_capnp -assert can_capnp_to_list def can_capnp_to_can_list(can, src_filter=None): ret = [] diff --git a/selfdrive/pandad/can_list_to_can_capnp.cc b/selfdrive/pandad/can_list_to_can_capnp.cc index ad2393b986..d73541c17f 100644 --- a/selfdrive/pandad/can_list_to_can_capnp.cc +++ b/selfdrive/pandad/can_list_to_can_capnp.cc @@ -1,12 +1,11 @@ #include "cereal/messaging/messaging.h" #include "selfdrive/pandad/panda.h" -#include "opendbc/can/common.h" -void can_list_to_can_capnp_cpp(const std::vector &can_list, std::string &out, bool sendcan, bool valid) { +void can_list_to_can_capnp_cpp(const std::vector &can_list, std::string &out, bool sendCan, bool valid) { MessageBuilder msg; auto event = msg.initEvent(valid); - auto canData = sendcan ? event.initSendcan(can_list.size()) : event.initCan(can_list.size()); + auto canData = sendCan ? event.initSendcan(can_list.size()) : event.initCan(can_list.size()); int j = 0; for (auto it = can_list.begin(); it != can_list.end(); it++, j++) { auto c = canData[j]; @@ -19,33 +18,3 @@ void can_list_to_can_capnp_cpp(const std::vector &can_list, std::stri kj::ArrayOutputStream output_stream(kj::ArrayPtr((unsigned char *)out.data(), msg_size)); capnp::writeMessage(output_stream, msg); } - -// Converts a vector of Cap'n Proto serialized can strings into a vector of CanData structures. -void can_capnp_to_can_list_cpp(const std::vector &strings, std::vector &can_list, bool sendcan) { - AlignedBuffer aligned_buf; - can_list.reserve(strings.size()); - - for (const auto &str : strings) { - // extract the messages - capnp::FlatArrayMessageReader reader(aligned_buf.align(str.data(), str.size())); - cereal::Event::Reader event = reader.getRoot(); - - auto frames = sendcan ? event.getSendcan() : event.getCan(); - - // Add new CanData entry - CanData &can_data = can_list.emplace_back(); - can_data.nanos = event.getLogMonoTime(); - can_data.frames.reserve(frames.size()); - - // Populate CAN frames - for (const auto &frame : frames) { - CanFrame &can_frame = can_data.frames.emplace_back(); - can_frame.src = frame.getSrc(); - can_frame.address = frame.getAddress(); - - // Copy CAN data - auto dat = frame.getDat(); - can_frame.dat.assign(dat.begin(), dat.end()); - } - } -} diff --git a/selfdrive/pandad/pandad_api_impl.pyx b/selfdrive/pandad/pandad_api_impl.pyx index 8a12e1c433..dd3f3d702f 100644 --- a/selfdrive/pandad/pandad_api_impl.pyx +++ b/selfdrive/pandad/pandad_api_impl.pyx @@ -1,10 +1,8 @@ # distutils: language = c++ # cython: language_level=3 -from cython.operator cimport dereference as deref, preincrement as preinc from libcpp.vector cimport vector from libcpp.string cimport string from libcpp cimport bool -from libc.stdint cimport uint8_t, uint32_t, uint64_t cdef extern from "panda.h": cdef struct can_frame: @@ -12,19 +10,8 @@ cdef extern from "panda.h": string dat long src -cdef extern from "opendbc/can/common.h": - cdef struct CanFrame: - long src - uint32_t address - vector[uint8_t] dat - - cdef struct CanData: - uint64_t nanos - vector[CanFrame] frames - cdef extern from "can_list_to_can_capnp.cc": - void can_list_to_can_capnp_cpp(const vector[can_frame] &can_list, string &out, bool sendcan, bool valid) - void can_capnp_to_can_list_cpp(const vector[string] &strings, vector[CanData] &can_data, bool sendcan) + void can_list_to_can_capnp_cpp(const vector[can_frame] &can_list, string &out, bool sendCan, bool valid) def can_list_to_can_capnp(can_msgs, msgtype='can', valid=True): cdef can_frame *f @@ -40,17 +27,3 @@ def can_list_to_can_capnp(can_msgs, msgtype='can', valid=True): cdef string out can_list_to_can_capnp_cpp(can_list, out, msgtype == 'sendcan', valid) return out - -def can_capnp_to_list(strings, msgtype='can'): - cdef vector[CanData] data - can_capnp_to_can_list_cpp(strings, data, msgtype == 'sendcan') - - result = [] - cdef CanData *d - cdef vector[CanData].iterator it = data.begin() - while it != data.end(): - d = &deref(it) - frames = [[f.address, (&f.dat[0])[:f.dat.size()], f.src] for f in d.frames] - result.append([d.nanos, frames]) - preinc(it) - return result diff --git a/tools/car_porting/examples/subaru_long_accel.ipynb b/tools/car_porting/examples/subaru_long_accel.ipynb index 35b92702a7..9d18a114df 100644 --- a/tools/car_porting/examples/subaru_long_accel.ipynb +++ b/tools/car_porting/examples/subaru_long_accel.ipynb @@ -24,7 +24,6 @@ "from opendbc.can.parser import CANParser\n", "\n", "from openpilot.selfdrive.car.subaru.values import DBC\n", - "from openpilot.selfdrive.pandad import can_capnp_to_list\n", "from openpilot.tools.lib.logreader import LogReader\n", "\n", "\"\"\"\n", @@ -51,7 +50,7 @@ "\n", " for msg in lr:\n", " if msg.which() == \"can\":\n", - " cp.update_strings(can_capnp_to_list([msg.as_builder().to_bytes()]))\n", + " cp.update_strings([msg.as_builder().to_bytes()])\n", " es_distance_history.append(copy.copy(cp.vl[\"ES_Distance\"]))\n", " es_brake_history.append(copy.copy(cp.vl[\"ES_Brake\"]))\n", " es_status_history.append(copy.copy(cp.vl[\"ES_Status\"]))\n", diff --git a/tools/car_porting/examples/subaru_steer_temp_fault.ipynb b/tools/car_porting/examples/subaru_steer_temp_fault.ipynb index 8b762fecb8..3d5055cbc2 100644 --- a/tools/car_porting/examples/subaru_steer_temp_fault.ipynb +++ b/tools/car_porting/examples/subaru_steer_temp_fault.ipynb @@ -27,7 +27,6 @@ "from opendbc.can.parser import CANParser\n", "\n", "from openpilot.selfdrive.car.subaru.values import CanBus, DBC\n", - "from openpilot.selfdrive.pandad import can_capnp_to_list\n", "from openpilot.tools.lib.logreader import LogReader\n", "\n", "\"\"\"\n", @@ -51,7 +50,7 @@ " examples = []\n", "\n", " for msg in can_msgs:\n", - " cp.update_strings(can_capnp_to_list([msg.as_builder().to_bytes()]))\n", + " cp.update_strings([msg.as_builder().to_bytes()])\n", " steering_torque_history.append(copy.copy(cp.vl[\"Steering_Torque\"]))\n", "\n", " steer_warning_last = False\n", From 9810b10c49d66a163f0e3ce082dcfc086b877d8f Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Wed, 31 Jul 2024 16:31:51 +0200 Subject: [PATCH 179/229] [SL] Enable sunnylink by default (#366) Enable Sunnylink by default Sunnylink was previously conditionally enabled based on build metadata. This change ensures that Sunnylink is enabled by default, facilitating immediate access for all builds. --- system/manager/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/manager/manager.py b/system/manager/manager.py index 0f34a5e57f..8169617302 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -111,7 +111,7 @@ def manager_init() -> None: ("OsmDownloadedDate", "0"), ("OSMDownloadProgress", "{}"), ("SidebarTemperatureOptions", "0"), - ("SunnylinkEnabled", "0" if (build_metadata.release_channel or build_metadata.release_sp_channel) else "1"), + ("SunnylinkEnabled", "1"), ("SunnylinkDongleId", f"{UNREGISTERED_SUNNYLINK_DONGLE_ID}"), ("CustomDrivingModel", "0"), ("DrivingModelGeneration", "4"), From bf003f297239afd75889814da0aa9d53ab0101a1 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Wed, 31 Jul 2024 10:42:08 -0700 Subject: [PATCH 180/229] setup.sh: retry + timing (#33145) * improve * update readme * stdin * better * allow non interactive * specify dir --- README.md | 2 +- tools/op.sh | 16 +++++--- tools/setup.sh | 102 ++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 104 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 9772ad646f..8316e52261 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Try it on a comma 3X

-Quick start: `curl -fsSL openpilot.comma.ai | bash` +Quick start: `bash <(curl -fsSL openpilot.comma.ai)` ![openpilot tests](https://github.com/commaai/openpilot/actions/workflows/selfdrive_tests.yaml/badge.svg) [![codecov](https://codecov.io/gh/commaai/openpilot/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/openpilot) diff --git a/tools/op.sh b/tools/op.sh index 8533017d8e..3ebd413a79 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -181,20 +181,26 @@ function op_setup() { op_check_python echo "Installing dependencies..." + st="$(date +%s)" if [[ "$OSTYPE" == "linux-gnu"* ]]; then op_run_command $OPENPILOT_ROOT/tools/ubuntu_setup.sh elif [[ "$OSTYPE" == "darwin"* ]]; then op_run_command $OPENPILOT_ROOT/tools/mac_setup.sh fi - echo -e " ↳ [${GREEN}✔${NC}] Dependencies installed successfully.\n" + et="$(date +%s)" + echo -e " ↳ [${GREEN}✔${NC}] Dependencies installed successfully in $((et - st)) seconds.\n" echo "Getting git submodules..." - op_run_command git submodule update --jobs 4 --init --recursive - echo -e " ↳ [${GREEN}✔${NC}] Submodules installed successfully.\n" + st="$(date +%s)" + op_run_command git submodule update --filter=blob:none --jobs 4 --init --recursive + et="$(date +%s)" + echo -e " ↳ [${GREEN}✔${NC}] Submodules installed successfully in $((et - st)) seconds.\n" echo "Pulling git lfs files..." + st="$(date +%s)" op_run_command git lfs pull - echo -e " ↳ [${GREEN}✔${NC}] Files pulled successfully.\n" + et="$(date +%s)" + echo -e " ↳ [${GREEN}✔${NC}] Files pulled successfully in $((et - st)) seconds.\n" op_check @@ -360,7 +366,7 @@ function _op() { -d | --dir ) shift 1; OPENPILOT_ROOT="$1"; shift 1 ;; --dry ) shift 1; DRY="1" ;; -n | --no-verify ) shift 1; NO_VERIFY="1" ;; - -v | --verbose ) shift 1; VERBOSE="1" ;; + -v | --verbose ) shift 1; VERBOSE="1" ;; esac # parse Commands diff --git a/tools/setup.sh b/tools/setup.sh index 9b1ee9c0c1..e770ba48aa 100755 --- a/tools/setup.sh +++ b/tools/setup.sh @@ -1,7 +1,10 @@ #!/usr/bin/env bash +set -e + RED='\033[0;31m' GREEN='\033[0;32m' +BOLD='\033[1m' NC='\033[0m' if [ -z "$OPENPILOT_ROOT" ]; then @@ -9,11 +12,84 @@ if [ -z "$OPENPILOT_ROOT" ]; then OPENPILOT_ROOT="$(pwd)/openpilot" fi +function show_motd() { +cat << 'EOF' + + .~ssos+. + +8888888888i, + {888888888888o. + h8888888888888k + t888888888s888k + `t88888d/ h88k + ``` h88l + ,88k` + .d8h` + +d8h + _+d8h` + ;y8h+` + |-` + + openpilot installer + +EOF +} + +function check_stdin() { + if [ -t 0 ]; then + INTERACTIVE=1 + else + echo "Checking for valid invocation..." + echo -e " ↳ [${RED}✗${NC}] stdin not found! Running in non-interactive mode." + echo -e " Run ${BOLD}'bash <(curl -fsSL openpilot.comma.ai)'${NC} to run in interactive mode.\n" + fi +} + +function ask_dir() { + echo -n "Enter directory in which to install openpilot (default $OPENPILOT_ROOT): " + + if [[ -z $INTERACTIVE ]]; then + echo -e "\nBecause your are running in non-interactive mode, the installation" + echo -e "will default to $OPENPILOT_ROOT\n" + return 0 + fi + + read + if [[ ! -z "$REPLY" ]]; then + mkdir -p $REPLY + OPENPILOT_ROOT="$(realpath $REPLY/openpilot)" + fi +} + function check_dir() { echo "Checking for installation directory..." if [ -d "$OPENPILOT_ROOT" ]; then - echo -e " ↳ [${RED}✗${NC}] can't install openpilot in $OPENPILOT_ROOT !" - return 1 + echo -e " ↳ [${RED}✗${NC}] Installation destination $OPENPILOT_ROOT already exists!" + + # not a valid clone, can't continue + if [[ ! -z "$(ls -A $OPENPILOT_ROOT)" && ! -f "$OPENPILOT_ROOT/launch_openpilot.sh" ]]; then + echo -e " $OPENPILOT_ROOT already contains files but does not seems" + echo -e " to be a valid openpilot git clone. Choose another location for" + echo -e " installing openpilot!\n" + return 1 + fi + + # by default, don't try installing in already existing directory + if [[ -z $INTERACTIVE ]]; then + return 1 + fi + + read -p " Would you like to attempt installation anyway? [Y/n] " -n 1 -r + echo -e "\n" + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + return 1 + fi + + # already a "valid" openpilot clone, skip cloning again + if [[ ! -z "$(ls -A $OPENPILOT_ROOT)" ]]; then + SKIP_GIT_CLONE=1 + fi + + return 0 fi echo -e " ↳ [${GREEN}✔${NC}] Successfully chosen $OPENPILOT_ROOT as installation directory\n" @@ -30,10 +106,12 @@ function check_git() { } function git_clone() { + st="$(date +%s)" echo "Cloning openpilot..." if $(git clone --filter=blob:none https://github.com/commaai/openpilot.git "$OPENPILOT_ROOT"); then if [[ -f $OPENPILOT_ROOT/launch_openpilot.sh ]]; then - echo -e " ↳ [${GREEN}✔${NC}] Successfully cloned openpilot.\n" + et="$(date +%s)" + echo -e " ↳ [${GREEN}✔${NC}] Successfully cloned openpilot in $((et - st)) seconds.\n" return 0 fi fi @@ -47,13 +125,17 @@ function install_with_op() { $OPENPILOT_ROOT/tools/op.sh install $OPENPILOT_ROOT/tools/op.sh setup - # make op usable right now - alias op="source $OPENPILOT_ROOT/tools/op.sh \"\$@\"" + echo -e "\n----------------------------------------------------------------------" + echo -e "openpilot was successfully installed into ${BOLD}$OPENPILOT_ROOT${NC}" + echo -e "Checkout the docs at https://docs.comma.ai" + echo -e "Checkout how to contribute at https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md" } -check_dir && check_git && git_clone && install_with_op +show_motd -unset OPENPILOT_ROOT -unset RED -unset GREEN -unset NC +check_stdin +ask_dir +check_dir +check_git +[ -z $SKIP_GIT_CLONE ] && git_clone +install_with_op From 1dd8bdc7912bef693c112816a5ac5066b036337b Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Wed, 31 Jul 2024 13:34:14 -0700 Subject: [PATCH 181/229] Remove hexdump package (#33155) * remove hexdump * uv lock * cleanup --- pyproject.toml | 1 - selfdrive/debug/dump.py | 13 +- uv.lock | 1275 ++++++++++++++++++++------------------- 3 files changed, 652 insertions(+), 637 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1473cf5707..b486df3870 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -111,7 +111,6 @@ dev = [ "tabulate", "types-requests", "types-tabulate", - "hexdump", # this is only pinned since 5.15.11 is broken "pyqt5 ==5.15.2; platform_machine == 'x86_64'", # no aarch64 wheels for macOS/linux diff --git a/selfdrive/debug/dump.py b/selfdrive/debug/dump.py index 787e9bc738..78cf51e3db 100755 --- a/selfdrive/debug/dump.py +++ b/selfdrive/debug/dump.py @@ -4,7 +4,6 @@ import argparse import json import codecs -from hexdump import hexdump from cereal import log from cereal.services import SERVICE_LIST from openpilot.tools.lib.live_logreader import raw_live_logreader @@ -12,6 +11,18 @@ from openpilot.tools.lib.live_logreader import raw_live_logreader codecs.register_error("strict", codecs.backslashreplace_errors) +def hexdump(msg): + m = str.upper(msg.hex()) + m = [m[i:i+2] for i in range(0,len(m),2)] + m = [m[i:i+16] for i in range(0,len(m),16)] + for row,dump in enumerate(m): + addr = '%08X:' % (row*16) + raw = ' '.join(dump[:8]) + ' ' + ' '.join(dump[8:]) + space = ' ' * (48 - len(raw)) + asci = ''.join(chr(int(x,16)) if 0x20 <= int(x,16) <= 0x7E else '.' for x in dump) + print(f'{addr} {raw} {space} {asci}') + + if __name__ == "__main__": parser = argparse.ArgumentParser(description='Dump communication sockets. See cereal/services.py for a complete list of available sockets.') diff --git a/uv.lock b/uv.lock index ded3ddec7c..7afdbb3c65 100644 --- a/uv.lock +++ b/uv.lock @@ -1,16 +1,21 @@ version = 1 requires-python = ">=3.11" +environment-markers = [ + "python_version == '3.12' and platform_machine == 'aarch64'", + "python_version == '3.12' and platform_machine == 'aarch64' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64')", + "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'", +] [[distribution]] name = "aiohttp" version = "3.9.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "aiosignal" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "yarl" }, + { name = "aiosignal", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "attrs", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "frozenlist", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "multidict", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "yarl", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/04/a4/e3679773ea7eb5b37a2c998e25b017cc5349edf6ba2739d1f32855cfb11b/aiohttp-3.9.5.tar.gz", hash = "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551", size = 7504841 } wheels = [ @@ -51,8 +56,8 @@ name = "aioice" version = "0.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "dnspython" }, - { name = "ifaddr" }, + { name = "dnspython", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "ifaddr", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/33/b6/e2b0e48ccb5b04fe29265e93f14a0915f416e359c897ae87d570566c430b/aioice-0.9.0.tar.gz", hash = "sha256:fc2401b1c4b6e19372eaaeaa28fd1bd9cbf6b0e412e48625297c53b495eebd1e", size = 40324 } wheels = [ @@ -64,14 +69,14 @@ name = "aiortc" version = "1.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "aioice" }, - { name = "av" }, - { name = "cffi" }, - { name = "cryptography" }, - { name = "google-crc32c" }, - { name = "pyee" }, - { name = "pylibsrtp" }, - { name = "pyopenssl" }, + { name = "aioice", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "av", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "cffi", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "cryptography", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "google-crc32c", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyee", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pylibsrtp", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyopenssl", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/71/32/e9b01e2271124643e5dc15c273f2bb8155efebf5bc2115407441ac62f4c5/aiortc-1.9.0.tar.gz", hash = "sha256:03faa76d76ef0e5989ac10386898b029369756102217230e2fcd4b029c50b303", size = 1168973 } wheels = [ @@ -89,7 +94,7 @@ name = "aiosignal" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "frozenlist" }, + { name = "frozenlist", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ae/67/0952ed97a9793b4958e5736f6d2b346b414a2cd63e82d05940032f45b32f/aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", size = 19422 } wheels = [ @@ -130,9 +135,9 @@ name = "azure-core" version = "1.30.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "requests" }, - { name = "six" }, - { name = "typing-extensions" }, + { name = "requests", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "six", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "typing-extensions", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/99/d4/1f469fa246f554b86fb5cebc30eef1b2a38b7af7a2c2791bce0a4c6e4604/azure-core-1.30.2.tar.gz", hash = "sha256:a14dc210efcd608821aa472d9fb8e8d035d29b68993819147bc290a8ac224472", size = 271104 } wheels = [ @@ -144,11 +149,11 @@ name = "azure-identity" version = "1.17.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "azure-core" }, - { name = "cryptography" }, - { name = "msal" }, - { name = "msal-extensions" }, - { name = "typing-extensions" }, + { name = "azure-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "cryptography", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "msal", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "msal-extensions", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "typing-extensions", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/51/c9/f7e3926686a89670ce641b360bd2da9a2d7a12b3e532403462d99f81e9d5/azure-identity-1.17.1.tar.gz", hash = "sha256:32ecc67cc73f4bd0595e4f64b1ca65cd05186f4fe6f98ed2ae9f1aa32646efea", size = 246652 } wheels = [ @@ -160,10 +165,10 @@ name = "azure-storage-blob" version = "12.21.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "azure-core" }, - { name = "cryptography" }, - { name = "isodate" }, - { name = "typing-extensions" }, + { name = "azure-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "cryptography", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "isodate", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "typing-extensions", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/97/c9/0e1e864eef8071102de2d6b11dfcf8d35410735145b2fbc2e0a5f58d1490/azure-storage-blob-12.21.0.tar.gz", hash = "sha256:b9722725072f5b7373c0f4dd6d78fbae2bb37bffc5c3e01731ab8c750ee8dd7e", size = 557430 } wheels = [ @@ -174,8 +179,11 @@ wheels = [ name = "casadi" version = "3.6.5" source = { registry = "https://pypi.org/simple" } +environment-markers = [ + "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'", +] dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5a/97/ca40c4d7d36162ddfd0bb96a89206469a95b925faf67046ba6e4b5b78283/casadi-3.6.5.tar.gz", hash = "sha256:409a5f6725eadea40fddfb8ba2321139b5252edac8bc115a72f68e648631d56a", size = 5070590 } wheels = [ @@ -200,8 +208,11 @@ wheels = [ name = "casadi" version = "3.6.6" source = { url = "https://github.com/commaai/casadi/releases/download/nightly-release-3.6.6/casadi-3.6.6-cp312-none-manylinux2014_aarch64.whl" } +environment-markers = [ + "python_version == '3.12' and platform_machine == 'aarch64'", +] dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "python_version == '3.12' and platform_machine == 'aarch64'" }, ] wheels = [ { url = "https://github.com/commaai/casadi/releases/download/nightly-release-3.6.6/casadi-3.6.6-cp312-none-manylinux2014_aarch64.whl", hash = "sha256:06a15e0099657b960620a2491e565c7f126030018da80c39f6bd33439160c669" }, @@ -221,7 +232,7 @@ name = "cffi" version = "1.16.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pycparser" }, + { name = "pycparser", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/68/ce/95b0bae7968c65473e1298efb042e10cafc7bafc14d9e4f154008241c91d/cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", size = 512873 } wheels = [ @@ -331,7 +342,7 @@ name = "coloredlogs" version = "15.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "humanfriendly" }, + { name = "humanfriendly", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cc/c7/eed8f27100517e8c0e6b923d5f0845d0cb99763da6fdee00478f91db7325/coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0", size = 278520 } wheels = [ @@ -343,7 +354,7 @@ name = "contourpy" version = "1.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8d/9e/e4786569b319847ffd98a8326802d5cf8a5500860dbfc2df1f0f4883ed99/contourpy-1.2.1.tar.gz", hash = "sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c", size = 13457196 } wheels = [ @@ -499,7 +510,7 @@ version = "0.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "python-xlib", marker = "sys_platform == 'linux'" }, - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/2f/3a/46ca34abf0725a754bc44ef474ad34aedcc3ea23b052d97b18b76715a6a9/EWMHlib-0.2-py3-none-any.whl", hash = "sha256:f5b07d8cfd4c7734462ee744c32d490f2f3233fa7ab354240069344208d2f6f5", size = 46657 }, @@ -628,12 +639,12 @@ name = "geopandas" version = "1.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, - { name = "packaging" }, - { name = "pandas" }, - { name = "pyogrio" }, - { name = "pyproj" }, - { name = "shapely" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "packaging", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "pandas", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "pyogrio", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "pyproj", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "shapely", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/39/08/2cf5d85356e45b10b8d066cf4c3ba1e9e3185423c48104eed87e8afd0455/geopandas-1.0.1.tar.gz", hash = "sha256:b8bf70a5534588205b7a56646e2082fb1de9a03599651b3d80c99ea4c2ca08ab", size = 317736 } wheels = [ @@ -645,7 +656,7 @@ name = "ghp-import" version = "2.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "python-dateutil" }, + { name = "python-dateutil", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943 } wheels = [ @@ -675,7 +686,7 @@ name = "grimp" version = "3.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/94/6c/6b071cc23c6c643b333af6f54147b59687e79b3a49bba80b4a0627bc5d90/grimp-3.4.1.tar.gz", hash = "sha256:c743c989ea49582171a93ac5aa0d22ecf04fd57143f956b3e35b6a1c7cddafec", size = 833762 } wheels = [ @@ -716,22 +727,16 @@ name = "gymnasium" version = "0.29.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cloudpickle" }, - { name = "farama-notifications" }, - { name = "numpy" }, - { name = "typing-extensions" }, + { name = "cloudpickle", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "farama-notifications", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "typing-extensions", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0d/f8/5699ddb3e1c4f6d97b8930e573074849b921da8374fccd141f0f3a9bd713/gymnasium-0.29.1.tar.gz", hash = "sha256:1a532752efcb7590478b1cc7aa04f608eb7a2fdad5570cd217b66b6a35274bb1", size = 820485 } wheels = [ { url = "https://files.pythonhosted.org/packages/a8/4d/3cbfd81ed84db450dbe73a89afcd8bc405273918415649ac6683356afe92/gymnasium-0.29.1-py3-none-any.whl", hash = "sha256:61c3384b5575985bb7f85e43213bcb40f36fcdff388cae6bc229304c71f2843e", size = 953939 }, ] -[[distribution]] -name = "hexdump" -version = "3.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/55/b3/279b1d57fa3681725d0db8820405cdcb4e62a9239c205e4ceac4391c78e4/hexdump-3.3.zip", hash = "sha256:d781a43b0c16ace3f9366aade73e8ad3a7bd5137d58f0b45ab2d3f54876f20db", size = 12658 } - [[distribution]] name = "humanfriendly" version = "10.0" @@ -749,8 +754,8 @@ name = "hypothesis" version = "6.47.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "attrs" }, - { name = "sortedcontainers" }, + { name = "attrs", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "sortedcontainers", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/45/f2/f77da8271b1abb630cb2090ead2f5aa4acc9639d632e8e68187f52527e4b/hypothesis-6.47.5.tar.gz", hash = "sha256:e0c1e253fc97e7ecdb9e2bbff2cf815d8739e0d1d3d093d67c3af5bb6a7211b0", size = 326641 } wheels = [ @@ -789,9 +794,9 @@ name = "import-linter" version = "2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click" }, - { name = "grimp" }, - { name = "typing-extensions" }, + { name = "click", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "grimp", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "typing-extensions", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d4/3a/6b433eace42d2f92cb96667f326b11582004b74acd045bf10a277761eed4/import-linter-2.0.tar.gz", hash = "sha256:b067cf0cdbf11c4f87524e32c2e3eaa62d46572e9e06511e6b453198b15b1c9a", size = 28678 } wheels = [ @@ -803,7 +808,7 @@ name = "importlib-metadata" version = "8.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "zipp" }, + { name = "zipp", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f6/a1/db39a513aa99ab3442010a994eef1cb977a436aded53042e69bee6959f74/importlib_metadata-8.2.0.tar.gz", hash = "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d", size = 53907 } wheels = [ @@ -833,7 +838,7 @@ name = "isodate" version = "0.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six" }, + { name = "six", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/db/7a/c0a56c7d56c7fa723988f122fa1f1ccf8c5c4ccc48efad0d214b49e5b1af/isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9", size = 28443 } wheels = [ @@ -845,7 +850,7 @@ name = "jinja2" version = "3.1.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markupsafe" }, + { name = "markupsafe", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ed/55/39036716d19cab0747a5020fc7e907f362fbf48c984b14e62127f7e68e5d/jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", size = 240245 } wheels = [ @@ -1036,15 +1041,15 @@ name = "matplotlib" version = "3.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "contourpy" }, - { name = "cycler" }, - { name = "fonttools" }, - { name = "kiwisolver" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pillow" }, - { name = "pyparsing" }, - { name = "python-dateutil" }, + { name = "contourpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "cycler", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "fonttools", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "kiwisolver", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "packaging", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pillow", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyparsing", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "python-dateutil", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/22/06/9e8ba6ec8b716a215404a5d1938b61f5a28001be493cf35344dda9a4072a/matplotlib-3.9.1.tar.gz", hash = "sha256:de06b19b8db95dd33d0dc17c926c7c9ebed9f572074b6fac4f65068a6814d010", size = 36084124 } wheels = [ @@ -1076,28 +1081,28 @@ name = "metadrive-simulator" version = "0.4.2.3" source = { git = "https://github.com/commaai/metadrive?rev=opencv_headless#9b6ddb791919249effa0573883076681514787e4" } dependencies = [ - { name = "filelock" }, - { name = "geopandas" }, - { name = "gymnasium" }, - { name = "lxml" }, - { name = "matplotlib" }, - { name = "numpy" }, - { name = "opencv-python-headless" }, - { name = "panda3d" }, - { name = "panda3d-gltf" }, - { name = "pandas" }, - { name = "pillow" }, - { name = "progressbar" }, - { name = "psutil" }, - { name = "pygame" }, - { name = "pygments" }, - { name = "pytest" }, - { name = "requests" }, - { name = "scipy" }, - { name = "seaborn" }, - { name = "shapely" }, - { name = "tqdm" }, - { name = "yapf" }, + { name = "filelock", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "geopandas", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "gymnasium", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "lxml", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "matplotlib", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "opencv-python-headless", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "panda3d", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "panda3d-gltf", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "pandas", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "pillow", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "progressbar", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "psutil", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "pygame", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "pygments", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "pytest", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "requests", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "scipy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "seaborn", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "shapely", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "tqdm", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "yapf", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] [[distribution]] @@ -1105,19 +1110,19 @@ name = "mkdocs" version = "1.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click" }, + { name = "click", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "colorama", marker = "platform_system == 'Windows'" }, - { name = "ghp-import" }, - { name = "jinja2" }, - { name = "markdown" }, - { name = "markupsafe" }, - { name = "mergedeep" }, - { name = "mkdocs-get-deps" }, - { name = "packaging" }, - { name = "pathspec" }, - { name = "pyyaml" }, - { name = "pyyaml-env-tag" }, - { name = "watchdog" }, + { name = "ghp-import", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "jinja2", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "markdown", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "markupsafe", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "mergedeep", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "mkdocs-get-deps", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "packaging", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pathspec", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyyaml", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyyaml-env-tag", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "watchdog", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cc/6b/26b33cc8ad54e8bc0345cddc061c2c5c23e364de0ecd97969df23f95a673/mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512", size = 3888392 } wheels = [ @@ -1129,9 +1134,9 @@ name = "mkdocs-get-deps" version = "0.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "mergedeep" }, - { name = "platformdirs" }, - { name = "pyyaml" }, + { name = "mergedeep", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "platformdirs", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyyaml", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239 } wheels = [ @@ -1143,7 +1148,7 @@ name = "mouseinfo" version = "0.1.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyperclip" }, + { name = "pyperclip", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "python3-xlib", marker = "platform_system == 'Linux'" }, { name = "rubicon-objc", marker = "platform_system == 'Darwin'" }, ] @@ -1163,9 +1168,10 @@ name = "msal" version = "1.30.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cryptography" }, + { name = "cryptography", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyjwt", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyjwt", extra = ["crypto"] }, - { name = "requests" }, + { name = "requests", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/03/ce/45b9af8f43fbbf34d15162e1e39ce34b675c234c56638277cc05562b6dbf/msal-1.30.0.tar.gz", hash = "sha256:b4bf00850092e465157d814efa24a18f788284c9a479491024d62903085ea2fb", size = 142510 } wheels = [ @@ -1177,8 +1183,8 @@ name = "msal-extensions" version = "1.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "msal" }, - { name = "portalocker" }, + { name = "msal", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "portalocker", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2d/38/ad49272d0a5af95f7a0cb64a79bbd75c9c187f3b789385a143d8d537a5eb/msal_extensions-1.2.0.tar.gz", hash = "sha256:6f41b320bfd2933d631a215c91ca0dd3e67d84bd1a2f50ce917d5874ec646bef", size = 22391 } wheels = [ @@ -1229,8 +1235,8 @@ name = "mypy" version = "1.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "mypy-extensions" }, - { name = "typing-extensions" }, + { name = "mypy-extensions", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "typing-extensions", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b1/95/a6dbb4fef19402c488b001ff4bd9f1a770e44049ce049b904dcffc65356c/mypy-1.11.0.tar.gz", hash = "sha256:93743608c7348772fdc717af4aeee1997293a1ad04bc0ea6efa15bf65385c538", size = 3078260 } wheels = [ @@ -1303,8 +1309,8 @@ name = "onnx" version = "1.16.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, - { name = "protobuf" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "protobuf", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/74/be/242d02ebf7fe115bd695166eeea58b2206c9fa62de22cf9cbf8986fa8d27/onnx-1.16.1.tar.gz", hash = "sha256:8299193f0f2a3849bfc069641aa8e4f93696602da8d165632af8ee48ec7556b6", size = 12306956 } wheels = [ @@ -1325,12 +1331,12 @@ name = "onnxruntime" version = "1.18.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "coloredlogs" }, - { name = "flatbuffers" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "protobuf" }, - { name = "sympy" }, + { name = "coloredlogs", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "flatbuffers", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "packaging", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "protobuf", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "sympy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/d7/ae/e257a5ffa4ef84e51255a38b62b4fdb538d92455e1f0f0ad056074f89c94/onnxruntime-1.18.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:f26582882f2dc581b809cfa41a125ba71ad9e715738ec6402418df356969774a", size = 15892594 }, @@ -1350,12 +1356,12 @@ name = "onnxruntime-gpu" version = "1.18.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "coloredlogs" }, - { name = "flatbuffers" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "protobuf" }, - { name = "sympy" }, + { name = "coloredlogs", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "flatbuffers", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "packaging", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "protobuf", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "sympy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/92/2e/5c6a3c94a8e4794a0ad1ba00f5b86c89673f271f43c77f537a90db4472c0/onnxruntime_gpu-1.18.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:af2d3ee6fba72b57abf6f379b8aca30ee773959d4346271e7d92557dd5cf2901", size = 200794895 }, @@ -1369,7 +1375,7 @@ name = "opencv-python-headless" version = "4.10.0.84" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2f/7e/d20f68a5f1487adf19d74378d349932a386b1ece3be9be9915e5986db468/opencv-python-headless-4.10.0.84.tar.gz", hash = "sha256:f2017c6101d7c2ef8d7bc3b414c37ff7f54d64413a1847d89970b6b7069b4e1a", size = 95117755 } wheels = [ @@ -1398,8 +1404,8 @@ dependencies = [ { name = "libusb1", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "onnx", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "onnxruntime", marker = "(python_version == '3.12' and platform_machine == 'aarch64' and platform_system == 'Linux') or (python_version == '3.12' and platform_machine == 'aarch64' and platform_system == 'Linux' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64')) or (platform_machine == 'aarch64' and platform_system == 'Linux' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'))" }, - { name = "onnxruntime-gpu", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64')" }, + { name = "onnxruntime", marker = "platform_machine == 'aarch64' and platform_system == 'Linux'" }, + { name = "onnxruntime-gpu", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, { name = "psutil", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyaudio", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pycapnp", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, @@ -1413,7 +1419,7 @@ dependencies = [ { name = "setuptools", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "smbus2", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "sounddevice", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "spidev", marker = "(python_version == '3.12' and platform_machine == 'aarch64' and platform_system == 'Linux') or (python_version == '3.12' and platform_machine == 'aarch64' and platform_system == 'Linux' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64')) or (platform_system == 'Linux' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'))" }, + { name = "spidev", marker = "platform_system == 'Linux'" }, { name = "sympy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "tqdm", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "websocket-client", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, @@ -1422,50 +1428,49 @@ dependencies = [ [distribution.optional-dependencies] dev = [ - { name = "av" }, - { name = "azure-identity" }, - { name = "azure-storage-blob" }, - { name = "dictdiffer" }, - { name = "flaky" }, - { name = "hexdump" }, - { name = "inputs" }, - { name = "lru-dict" }, - { name = "matplotlib" }, + { name = "av", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "azure-identity", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "azure-storage-blob", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "dictdiffer", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "flaky", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "inputs", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "lru-dict", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "matplotlib", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "metadrive-simulator", marker = "platform_machine != 'aarch64'" }, - { name = "parameterized" }, - { name = "pyautogui" }, + { name = "parameterized", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyautogui", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyopencl", marker = "platform_machine != 'aarch64'" }, - { name = "pyprof2calltree" }, + { name = "pyprof2calltree", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyqt5", marker = "platform_machine == 'x86_64'" }, { name = "pytools", marker = "platform_machine != 'aarch64'" }, - { name = "pywinctl" }, - { name = "rerun-sdk" }, - { name = "tabulate" }, - { name = "types-requests" }, - { name = "types-tabulate" }, + { name = "pywinctl", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "rerun-sdk", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "tabulate", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "types-requests", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "types-tabulate", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] docs = [ - { name = "jinja2" }, - { name = "mkdocs" }, - { name = "natsort" }, + { name = "jinja2", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "mkdocs", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "natsort", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] testing = [ - { name = "coverage" }, - { name = "hypothesis" }, - { name = "import-linter" }, - { name = "mypy" }, - { name = "pre-commit" }, - { name = "pytest" }, - { name = "pytest-asyncio" }, - { name = "pytest-cov" }, - { name = "pytest-cpp" }, - { name = "pytest-mock" }, - { name = "pytest-randomly" }, - { name = "pytest-repeat" }, - { name = "pytest-subtests" }, - { name = "pytest-timeout" }, - { name = "pytest-xdist" }, - { name = "ruff" }, + { name = "coverage", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "hypothesis", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "import-linter", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "mypy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pre-commit", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pytest", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pytest-asyncio", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pytest-cov", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pytest-cpp", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pytest-mock", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pytest-randomly", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pytest-repeat", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pytest-subtests", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pytest-timeout", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pytest-xdist", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "ruff", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] [[distribution]] @@ -1500,8 +1505,8 @@ name = "panda3d-gltf" version = "0.13" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "panda3d" }, - { name = "panda3d-simplepbr" }, + { name = "panda3d", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "panda3d-simplepbr", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/07/7f/9f18fc3fa843a080acb891af6bcc12262e7bdf1d194a530f7042bebfc81f/panda3d-gltf-0.13.tar.gz", hash = "sha256:d06d373bdd91cf530909b669f43080e599463bbf6d3ef00c3558bad6c6b19675", size = 25573 } wheels = [ @@ -1513,8 +1518,8 @@ name = "panda3d-simplepbr" version = "0.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "panda3d" }, - { name = "typing-extensions" }, + { name = "panda3d", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "typing-extensions", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b1/af/505608eef09d7f9b822e69dc7631cd14102650b8fe1b6f60d9562d2788d9/panda3d-simplepbr-0.12.0.tar.gz", hash = "sha256:c71d490afeeb3a90455dcfde1d30c41f321a38742a97d18834e5c31016331ed5", size = 1929980 } wheels = [ @@ -1643,11 +1648,11 @@ name = "pre-commit" version = "3.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cfgv" }, - { name = "identify" }, - { name = "nodeenv" }, - { name = "pyyaml" }, - { name = "virtualenv" }, + { name = "cfgv", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "identify", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "nodeenv", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyyaml", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "virtualenv", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/64/10/97ee2fa54dff1e9da9badbc5e35d0bbaef0776271ea5907eccf64140f72f/pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af", size = 177815 } wheels = [ @@ -1696,7 +1701,7 @@ name = "pyarrow" version = "17.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/27/4e/ea6d43f324169f8aec0e57569443a38bab4b398d09769ca64f7b4d467de3/pyarrow-17.0.0.tar.gz", hash = "sha256:4beca9521ed2c0921c1023e68d097d0299b62c362639ea315572a58f3f50fd28", size = 1112479 } wheels = [ @@ -1733,14 +1738,14 @@ name = "pyautogui" version = "0.9.54" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "mouseinfo" }, - { name = "pygetwindow" }, - { name = "pymsgbox" }, + { name = "mouseinfo", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pygetwindow", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pymsgbox", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-core", marker = "platform_system == 'Darwin'" }, { name = "pyobjc-framework-quartz", marker = "platform_system == 'Darwin'" }, - { name = "pyscreeze" }, + { name = "pyscreeze", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "python3-xlib", marker = "platform_system == 'Linux'" }, - { name = "pytweening" }, + { name = "pytweening", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/65/ff/cdae0a8c2118a0de74b6cf4cbcdcaf8fd25857e6c3f205ce4b1794b27814/PyAutoGUI-0.9.54.tar.gz", hash = "sha256:dd1d29e8fd118941cb193f74df57e5c6ff8e9253b99c7b04f39cfc69f3ae04b2", size = 61236 } @@ -1814,7 +1819,7 @@ name = "pyee" version = "11.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f7/22/b4c7f3d9579204a014c4eda0e019e6bfe56af52a96cacc82004b60eec079/pyee-11.1.0.tar.gz", hash = "sha256:b53af98f6990c810edd9b56b87791021a8f54fd13db4edd1142438d44ba2263f", size = 29806 } wheels = [ @@ -1848,7 +1853,7 @@ name = "pygetwindow" version = "0.0.9" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyrect" }, + { name = "pyrect", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e1/70/c7a4f46dbf06048c6d57d9489b8e0f9c4c3d36b7479f03c5ca97eaa2541d/PyGetWindow-0.0.9.tar.gz", hash = "sha256:17894355e7d2b305cd832d717708384017c1698a90ce24f6f7fbf0242dd0a688", size = 9699 } @@ -1872,7 +1877,7 @@ wheels = [ [distribution.optional-dependencies] crypto = [ - { name = "cryptography" }, + { name = "cryptography", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] [[distribution]] @@ -1880,7 +1885,7 @@ name = "pylibsrtp" version = "0.10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cffi" }, + { name = "cffi", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6b/ae/c95199144eed954976223bdce3f94564eb6c43567111aff8048a26a429bd/pylibsrtp-0.10.0.tar.gz", hash = "sha256:d8001912d7f51bd05b4ea3551747930631777fd37892cf3bfe0e541a742e699f", size = 10557 } wheels = [ @@ -1902,7 +1907,7 @@ dependencies = [ { name = "pyobjc", marker = "sys_platform == 'darwin'" }, { name = "python-xlib", marker = "sys_platform == 'linux'" }, { name = "pywin32", marker = "sys_platform == 'win32'" }, - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/2d/13/076a20da28b82be281f7e43e16d9da0f545090f5d14b2125699232b9feba/PyMonCtl-0.92-py3-none-any.whl", hash = "sha256:2495d8dab78f9a7dbce37e74543e60b8bd404a35c3108935697dda7768611b5a", size = 45945 }, @@ -1919,20 +1924,20 @@ name = "pyobjc" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-accessibility", marker = "platform_release >= '20.0'" }, { name = "pyobjc-framework-accounts", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-addressbook" }, + { name = "pyobjc-framework-addressbook", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-adservices", marker = "platform_release >= '20.0'" }, { name = "pyobjc-framework-adsupport", marker = "platform_release >= '18.0'" }, - { name = "pyobjc-framework-applescriptkit" }, + { name = "pyobjc-framework-applescriptkit", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-applescriptobjc", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-applicationservices" }, + { name = "pyobjc-framework-applicationservices", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-apptrackingtransparency", marker = "platform_release >= '20.0'" }, { name = "pyobjc-framework-audiovideobridging", marker = "platform_release >= '12.0'" }, { name = "pyobjc-framework-authenticationservices", marker = "platform_release >= '19.0'" }, { name = "pyobjc-framework-automaticassessmentconfiguration", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-automator" }, + { name = "pyobjc-framework-automator", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-avfoundation", marker = "platform_release >= '11.0'" }, { name = "pyobjc-framework-avkit", marker = "platform_release >= '13.0'" }, { name = "pyobjc-framework-avrouting", marker = "platform_release >= '22.0'" }, @@ -1941,40 +1946,40 @@ dependencies = [ { name = "pyobjc-framework-businesschat", marker = "platform_release >= '18.0'" }, { name = "pyobjc-framework-calendarstore", marker = "platform_release >= '9.0'" }, { name = "pyobjc-framework-callkit", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-cfnetwork" }, + { name = "pyobjc-framework-cfnetwork", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-cinematic", marker = "platform_release >= '23.0'" }, { name = "pyobjc-framework-classkit", marker = "platform_release >= '20.0'" }, { name = "pyobjc-framework-cloudkit", marker = "platform_release >= '14.0'" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-collaboration", marker = "platform_release >= '9.0'" }, { name = "pyobjc-framework-colorsync", marker = "platform_release >= '17.0'" }, { name = "pyobjc-framework-contacts", marker = "platform_release >= '15.0'" }, { name = "pyobjc-framework-contactsui", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-coreaudio" }, - { name = "pyobjc-framework-coreaudiokit" }, + { name = "pyobjc-framework-coreaudio", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coreaudiokit", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-corebluetooth", marker = "platform_release >= '14.0'" }, - { name = "pyobjc-framework-coredata" }, + { name = "pyobjc-framework-coredata", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-corehaptics", marker = "platform_release >= '19.0'" }, { name = "pyobjc-framework-corelocation", marker = "platform_release >= '10.0'" }, { name = "pyobjc-framework-coremedia", marker = "platform_release >= '11.0'" }, { name = "pyobjc-framework-coremediaio", marker = "platform_release >= '11.0'" }, - { name = "pyobjc-framework-coremidi" }, + { name = "pyobjc-framework-coremidi", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-coreml", marker = "platform_release >= '17.0'" }, { name = "pyobjc-framework-coremotion", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-coreservices" }, + { name = "pyobjc-framework-coreservices", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-corespotlight", marker = "platform_release >= '17.0'" }, - { name = "pyobjc-framework-coretext" }, + { name = "pyobjc-framework-coretext", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-corewlan", marker = "platform_release >= '10.0'" }, { name = "pyobjc-framework-cryptotokenkit", marker = "platform_release >= '14.0'" }, { name = "pyobjc-framework-datadetection", marker = "platform_release >= '21.0'" }, { name = "pyobjc-framework-devicecheck", marker = "platform_release >= '19.0'" }, { name = "pyobjc-framework-dictionaryservices", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-discrecording" }, - { name = "pyobjc-framework-discrecordingui" }, - { name = "pyobjc-framework-diskarbitration" }, - { name = "pyobjc-framework-dvdplayback" }, + { name = "pyobjc-framework-discrecording", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-discrecordingui", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-diskarbitration", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-dvdplayback", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-eventkit", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-exceptionhandling" }, + { name = "pyobjc-framework-exceptionhandling", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-executionpolicy", marker = "platform_release >= '19.0'" }, { name = "pyobjc-framework-extensionkit", marker = "platform_release >= '22.0'" }, { name = "pyobjc-framework-externalaccessory", marker = "platform_release >= '17.0'" }, @@ -1989,17 +1994,17 @@ dependencies = [ { name = "pyobjc-framework-healthkit", marker = "platform_release >= '22.0'" }, { name = "pyobjc-framework-imagecapturecore", marker = "platform_release >= '10.0'" }, { name = "pyobjc-framework-inputmethodkit", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-installerplugins" }, + { name = "pyobjc-framework-installerplugins", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-instantmessage", marker = "platform_release >= '9.0'" }, { name = "pyobjc-framework-intents", marker = "platform_release >= '16.0'" }, { name = "pyobjc-framework-intentsui", marker = "platform_release >= '21.0'" }, - { name = "pyobjc-framework-iobluetooth" }, - { name = "pyobjc-framework-iobluetoothui" }, + { name = "pyobjc-framework-iobluetooth", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-iobluetoothui", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-iosurface", marker = "platform_release >= '10.0'" }, { name = "pyobjc-framework-ituneslibrary", marker = "platform_release >= '10.0'" }, { name = "pyobjc-framework-kernelmanagement", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-latentsemanticmapping" }, - { name = "pyobjc-framework-launchservices" }, + { name = "pyobjc-framework-latentsemanticmapping", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-launchservices", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-libdispatch", marker = "platform_release >= '12.0'" }, { name = "pyobjc-framework-libxpc", marker = "platform_release >= '12.0'" }, { name = "pyobjc-framework-linkpresentation", marker = "platform_release >= '19.0'" }, @@ -2026,30 +2031,30 @@ dependencies = [ { name = "pyobjc-framework-networkextension", marker = "platform_release >= '15.0'" }, { name = "pyobjc-framework-notificationcenter", marker = "platform_release >= '14.0'" }, { name = "pyobjc-framework-opendirectory", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-osakit" }, + { name = "pyobjc-framework-osakit", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-oslog", marker = "platform_release >= '19.0'" }, { name = "pyobjc-framework-passkit", marker = "platform_release >= '20.0'" }, { name = "pyobjc-framework-pencilkit", marker = "platform_release >= '19.0'" }, { name = "pyobjc-framework-phase", marker = "platform_release >= '21.0'" }, { name = "pyobjc-framework-photos", marker = "platform_release >= '15.0'" }, { name = "pyobjc-framework-photosui", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-preferencepanes" }, + { name = "pyobjc-framework-preferencepanes", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-pubsub", marker = "platform_release >= '9.0' and platform_release < '18.0'" }, { name = "pyobjc-framework-pushkit", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-quicklookthumbnailing", marker = "platform_release >= '19.0'" }, { name = "pyobjc-framework-replaykit", marker = "platform_release >= '20.0'" }, { name = "pyobjc-framework-safariservices", marker = "platform_release >= '16.0'" }, { name = "pyobjc-framework-safetykit", marker = "platform_release >= '22.0'" }, { name = "pyobjc-framework-scenekit", marker = "platform_release >= '11.0'" }, { name = "pyobjc-framework-screencapturekit", marker = "platform_release >= '21.4'" }, - { name = "pyobjc-framework-screensaver" }, + { name = "pyobjc-framework-screensaver", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-screentime", marker = "platform_release >= '20.0'" }, { name = "pyobjc-framework-scriptingbridge", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-searchkit" }, - { name = "pyobjc-framework-security" }, - { name = "pyobjc-framework-securityfoundation" }, - { name = "pyobjc-framework-securityinterface" }, + { name = "pyobjc-framework-searchkit", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-security", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-securityfoundation", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-securityinterface", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-sensitivecontentanalysis", marker = "platform_release >= '23.0'" }, { name = "pyobjc-framework-servicemanagement", marker = "platform_release >= '10.0'" }, { name = "pyobjc-framework-sharedwithyou", marker = "platform_release >= '22.0'" }, @@ -2061,8 +2066,8 @@ dependencies = [ { name = "pyobjc-framework-spritekit", marker = "platform_release >= '13.0'" }, { name = "pyobjc-framework-storekit", marker = "platform_release >= '11.0'" }, { name = "pyobjc-framework-symbols", marker = "platform_release >= '23.0'" }, - { name = "pyobjc-framework-syncservices" }, - { name = "pyobjc-framework-systemconfiguration" }, + { name = "pyobjc-framework-syncservices", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-systemconfiguration", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc-framework-systemextensions", marker = "platform_release >= '19.0'" }, { name = "pyobjc-framework-threadnetwork", marker = "platform_release >= '22.0'" }, { name = "pyobjc-framework-uniformtypeidentifiers", marker = "platform_release >= '20.0'" }, @@ -2072,7 +2077,7 @@ dependencies = [ { name = "pyobjc-framework-videotoolbox", marker = "platform_release >= '12.0'" }, { name = "pyobjc-framework-virtualization", marker = "platform_release >= '20.0'" }, { name = "pyobjc-framework-vision", marker = "platform_release >= '17.0'" }, - { name = "pyobjc-framework-webkit" }, + { name = "pyobjc-framework-webkit", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e0/20/722e33f62631370c1475d773cadf4290d3c6f3a0e9d025fa6e2528270eaa/pyobjc-10.3.1.tar.gz", hash = "sha256:476dd5c72394e4cfcdac6dfd756839011a0159353247f45e3e07cc0b3536c9d4", size = 10975 } wheels = [ @@ -2095,9 +2100,9 @@ name = "pyobjc-framework-accessibility" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/24/20/18a45998ae8bf9ce532a29f8eaebdaa7f15a7f77b3c34a8304714b393166/pyobjc_framework_accessibility-10.3.1.tar.gz", hash = "sha256:c973306417441e6bed5f9be6154e6399aa7f38fa9b6bcf3368fa42d92ef3030b", size = 29349 } wheels = [ @@ -2112,8 +2117,8 @@ name = "pyobjc-framework-accounts" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cf/be/a4e4eeebfa140f0e00fe2fb882802cc4a5fa7f12c7fea01e35314fcf276c/pyobjc_framework_accounts-10.3.1.tar.gz", hash = "sha256:3d55738e7b3290af8cd4993fd2b670242a952deb995a69911be2a1be4c509a86", size = 16180 } wheels = [ @@ -2125,8 +2130,8 @@ name = "pyobjc-framework-addressbook" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/21/0a/68769f71cbf9f46070059def94a5c7b0b218626652d7aa589e15f4e8b876/pyobjc_framework_addressbook-10.3.1.tar.gz", hash = "sha256:cde99b855c39b56ca52479b0a1e2daa3ef5de12cebfe780c3c802a5f59a484cc", size = 84696 } wheels = [ @@ -2141,8 +2146,8 @@ name = "pyobjc-framework-adservices" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ab/9b/eaeb7c8f30899979113b91d8317efd30743d335bdaaa8fb88434e7bf7616/pyobjc_framework_adservices-10.3.1.tar.gz", hash = "sha256:28123eb111d023f708e1d86f5f3f76bd4f6bb0d932466863f84b3e322b11537a", size = 11838 } wheels = [ @@ -2154,8 +2159,8 @@ name = "pyobjc-framework-adsupport" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/87/cf/9b40ef87f1315858e3dce9f807b359e43a6183616a6a8d2caab533d49a3e/pyobjc_framework_adsupport-10.3.1.tar.gz", hash = "sha256:ba85a00cf20c42501d8083092f7ca0fcd1e616b1725e6512e75bcb60a6d58528", size = 11991 } wheels = [ @@ -2167,8 +2172,8 @@ name = "pyobjc-framework-applescriptkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5c/c4/42e37476f31dddecb3d7b83b076d5e94b754837e2326b0218227b20f96ec/pyobjc_framework_applescriptkit-10.3.1.tar.gz", hash = "sha256:add2e63598b699666bcf00ac59f6f1046266df1665bec71b142cd21b89037064", size = 11779 } wheels = [ @@ -2180,8 +2185,8 @@ name = "pyobjc-framework-applescriptobjc" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/80/9e/db9d93764db336ed53da548cd7b52b6fbd7d493101b801b164f5c1f5fce8/pyobjc_framework_applescriptobjc-10.3.1.tar.gz", hash = "sha256:a87101d86b08e06e2c0e51630ac76d4c70f01cf1ed7af281f3138e63146e279b", size = 11797 } wheels = [ @@ -2193,10 +2198,10 @@ name = "pyobjc-framework-applicationservices" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coretext" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coretext", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/66/a6/3704b63c6e844739e3b7e324d1268fb6f7cb485550267719660779266c60/pyobjc_framework_applicationservices-10.3.1.tar.gz", hash = "sha256:f27cb64aa4d129ce671fd42638c985eb2a56d544214a95fe3214a007eacc4790", size = 182738 } wheels = [ @@ -2210,8 +2215,8 @@ name = "pyobjc-framework-apptrackingtransparency" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/75/63/b7039473d92211938645c44069b2e8bc65eefc229a3aac1ff8ccf0f13415/pyobjc_framework_apptrackingtransparency-10.3.1.tar.gz", hash = "sha256:2e381db5f7d3985207b5ff2975e41bf0f9147080345b2e1b4b242f8799290d04", size = 12547 } wheels = [ @@ -2223,8 +2228,8 @@ name = "pyobjc-framework-audiovideobridging" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f9/f8/437666f24f295986ad9ea77a694f7db98889a8367fad46d93b84ae028e28/pyobjc_framework_audiovideobridging-10.3.1.tar.gz", hash = "sha256:b2c1d5977a92915f6af2203e3b4c9b8a8392bc51e0fc13ccb393589419387119", size = 59209 } wheels = [ @@ -2238,8 +2243,8 @@ name = "pyobjc-framework-authenticationservices" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/35/3b/12082a13266fed356222a5c6c3eaf6ddcf21099f7a5b76b3fff58568042a/pyobjc_framework_authenticationservices-10.3.1.tar.gz", hash = "sha256:0ac834f4a5cbe3cf20acd4f6a96df77bc643a1ae248e394d06964db9fe0d6310", size = 86405 } wheels = [ @@ -2254,8 +2259,8 @@ name = "pyobjc-framework-automaticassessmentconfiguration" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/67/0d/19f8aee86e91da5a9f6954870f21d839b835a20e84eb2221b839797be705/pyobjc_framework_automaticassessmentconfiguration-10.3.1.tar.gz", hash = "sha256:f7846d04493e90eddbacfb7cffebc11b3f76f0800d3dc2bec39441732a20ac56", size = 22477 } wheels = [ @@ -2270,8 +2275,8 @@ name = "pyobjc-framework-automator" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/88/ca/fe39648043bf7ab2e5f09707cca9254277555c1a09973ade71fc029f7dff/pyobjc_framework_automator-10.3.1.tar.gz", hash = "sha256:330042475479f054ac98abd568b523fc0165c39eeefffc23bd65d35780939316", size = 195097 } wheels = [ @@ -2286,11 +2291,11 @@ name = "pyobjc-framework-avfoundation" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coreaudio" }, - { name = "pyobjc-framework-coremedia" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coreaudio", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coremedia", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5b/4f/0f509c925c28d4b0ea709ccb9fd9a229c6552187f7506aa1e583d66cf658/pyobjc_framework_avfoundation-10.3.1.tar.gz", hash = "sha256:2f94bee3a4217b46d9416cad066e4f357bf0f344079c328736114451ae19ae94", size = 695146 } wheels = [ @@ -2305,9 +2310,9 @@ name = "pyobjc-framework-avkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b5/de/7de605cea8176d69a41503dd544c0af02760c4518be3049b877563cc0c36/pyobjc_framework_avkit-10.3.1.tar.gz", hash = "sha256:97ca35b5f0cec98f5c8521fedb8537bb23d82739b7102e4ac732d3c3944c8ccc", size = 38986 } wheels = [ @@ -2322,8 +2327,8 @@ name = "pyobjc-framework-avrouting" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/66/d5/b3012c90b18722b9d8e27f6a570ac534da89e4902bf5805f0bb39e340891/pyobjc_framework_avrouting-10.3.1.tar.gz", hash = "sha256:7026059b24daf8e1da05d7867f450e82abe412fe5c438faf9344f46e3b83da39", size = 18663 } wheels = [ @@ -2338,8 +2343,8 @@ name = "pyobjc-framework-backgroundassets" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bb/be/6a0039ac75e7d9b84f7250d2301e0fe6529c0db6c137e398e31d04f65629/pyobjc_framework_backgroundassets-10.3.1.tar.gz", hash = "sha256:5e1198f81db6f30ead2a55e8ea39264f9fce83dcf8e31a68e5f0ea08c5cfe9b5", size = 21762 } wheels = [ @@ -2354,11 +2359,11 @@ name = "pyobjc-framework-browserenginekit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coreaudio" }, - { name = "pyobjc-framework-coremedia" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coreaudio", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coremedia", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/48/09/61f1688824a500f74e4fee94cec3ec3bef87e58a5205026761e4d292f027/pyobjc_framework_browserenginekit-10.3.1.tar.gz", hash = "sha256:0f6ea100bcf06f2b3f915dab27cf2f038698b39510fb47d3769f72ff62c1e80b", size = 21016 } wheels = [ @@ -2373,8 +2378,8 @@ name = "pyobjc-framework-businesschat" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a5/19/7414a07489dbeef3b1bd40845cb9bd0e035062da3879ca20fb01a7901302/pyobjc_framework_businesschat-10.3.1.tar.gz", hash = "sha256:53e52981f9da336fcaf6783e82509e06faf8868931213ac70e6bd7395a5859a4", size = 12088 } wheels = [ @@ -2386,8 +2391,8 @@ name = "pyobjc-framework-calendarstore" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/10/85/c4bb713e7e4d3f197ac975f5425ecf5469c1ea91d7b80d32eb4437b004f4/pyobjc_framework_calendarstore-10.3.1.tar.gz", hash = "sha256:21f627b0afb9a667794b451dd3a03f12ea3f74358dc5977c33b8ecc8b9736c27", size = 62920 } wheels = [ @@ -2399,8 +2404,8 @@ name = "pyobjc-framework-callkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d3/b2/be5cf42e2b288073fa5d693d869ac2fbfb091a34e8edd5aa67f50fa6982f/pyobjc_framework_callkit-10.3.1.tar.gz", hash = "sha256:350390023e9ac98ff6c91b1f51da2489eef2e23aa649d0f63c13cf1d8be1e0df", size = 31907 } wheels = [ @@ -2412,8 +2417,8 @@ name = "pyobjc-framework-cfnetwork" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fb/e6/e1d6b0d0b21ba5241712389aea46dba4ee9d5c955738076f5ec9d75b5f29/pyobjc_framework_cfnetwork-10.3.1.tar.gz", hash = "sha256:0e4c51a75dbf4e2b1c0d4ee60a363f9d31d682d2dd2f6b74aded769d2d883aa8", size = 66882 } wheels = [ @@ -2428,11 +2433,11 @@ name = "pyobjc-framework-cinematic" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-avfoundation" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coremedia" }, - { name = "pyobjc-framework-metal" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-avfoundation", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coremedia", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-metal", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2a/83/90a5f31fd89bfa030c812c869ab69cf0e333e13ee2e3c1e4877ed883d6d3/pyobjc_framework_cinematic-10.3.1.tar.gz", hash = "sha256:7edaaa7e325aeb39cd0c33329c25783dd54af294229884556daad36d1d1b9d72", size = 19342 } wheels = [ @@ -2444,8 +2449,8 @@ name = "pyobjc-framework-classkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a9/b8/cc33b734656f6617394b410a9805d05511aecdb665591936acfd66060dfd/pyobjc_framework_classkit-10.3.1.tar.gz", hash = "sha256:e15700d32007bf77c5c740bc9931c864bb7739cdfcd2b0595377c3ed35ecfe25", size = 32503 } wheels = [ @@ -2460,11 +2465,11 @@ name = "pyobjc-framework-cloudkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-accounts" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coredata" }, - { name = "pyobjc-framework-corelocation" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-accounts", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coredata", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-corelocation", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/84/2d/22c51450dddeb9d851529f90ebd4f15fc12a4f3c9b2ceae4df8841fde64e/pyobjc_framework_cloudkit-10.3.1.tar.gz", hash = "sha256:4c7db72c2bb2fcf63365df91bf2eefa83cee4004606b901e1da89b75da652309", size = 98916 } wheels = [ @@ -2476,7 +2481,7 @@ name = "pyobjc-framework-cocoa" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a7/6c/b62e31e6e00f24e70b62f680e35a0d663ba14ff7601ae591b5d20e251161/pyobjc_framework_cocoa-10.3.1.tar.gz", hash = "sha256:1cf20714daaa986b488fb62d69713049f635c9d41a60c8da97d835710445281a", size = 4941542 } wheels = [ @@ -2490,8 +2495,8 @@ name = "pyobjc-framework-collaboration" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0d/cd/8bc8e3c4cf93b1044d5e582904ec5c55656f4385bd25f86f924b4ed25ae3/pyobjc_framework_collaboration-10.3.1.tar.gz", hash = "sha256:bbca3de3679b058cbb89ad911e3bdfe491a02b4fa219d5f9219c022774ba237a", size = 15830 } wheels = [ @@ -2503,8 +2508,8 @@ name = "pyobjc-framework-colorsync" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/43/16/b5cf65d3cdae2127a868e06b21e9c59e2ef531e65c4ee58afcaef2c4fe69/pyobjc_framework_colorsync-10.3.1.tar.gz", hash = "sha256:180960ed6f76084b35073eff49fcca41a8fa883c3236949a40f75daa28ee8f94", size = 31940 } wheels = [ @@ -2516,8 +2521,8 @@ name = "pyobjc-framework-contacts" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/eb/a9/112ee53259220322f6729c446fd7b779d3bae7b24804bd342f51764dc6bc/pyobjc_framework_contacts-10.3.1.tar.gz", hash = "sha256:7120b5593a20e936cb5589b93ef7fd5558c86bd6ec8003f427afb87c04bbea20", size = 68431 } wheels = [ @@ -2532,9 +2537,9 @@ name = "pyobjc-framework-contactsui" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-contacts" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-contacts", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ad/17/ce9b512e29ca92eb519328d0fc1e12b6b048ac379447c7f4f2be4266599e/pyobjc_framework_contactsui-10.3.1.tar.gz", hash = "sha256:51601501d5bc94c59ad458c7bb1d1994c497b373307dad8bd2ea2aa348f66c4a", size = 17921 } wheels = [ @@ -2549,8 +2554,8 @@ name = "pyobjc-framework-coreaudio" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c5/fe/39351e6a58f4a9b1fce5a5e982830612277233084fe72b1d84b4de890f3b/pyobjc_framework_coreaudio-10.3.1.tar.gz", hash = "sha256:c81c709bf955aea474a4de380b187f3c2e56c864ca7de520b08362b73070c795", size = 125676 } wheels = [ @@ -2564,9 +2569,9 @@ name = "pyobjc-framework-coreaudiokit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coreaudio" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coreaudio", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1f/4e/79a20d1ab459467de5695f96057e034d6457b061da68951b41af211b1fe3/pyobjc_framework_coreaudiokit-10.3.1.tar.gz", hash = "sha256:81f35d5dc45cda043e01f0ca045311f4aebc36c51cb71e859b30ea0edf90b3db", size = 19761 } wheels = [ @@ -2581,8 +2586,8 @@ name = "pyobjc-framework-corebluetooth" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f7/69/89afd7747f42d2eb1e8f4b7f2ba2739d98ccf36f6b5c72474802962494de/pyobjc_framework_corebluetooth-10.3.1.tar.gz", hash = "sha256:dc5d326ab5541b8b68e7e920aa8363851e779cb8c33842f6cfeef4674cc62f94", size = 50210 } wheels = [ @@ -2597,8 +2602,8 @@ name = "pyobjc-framework-coredata" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cc/17/1929fabc88d265373ce2b5e5c3136aae03c30ee42df66bd0810fa71328da/pyobjc_framework_coredata-10.3.1.tar.gz", hash = "sha256:8a75094942c8f3ddc1bcbde920c87658d7bb4c7534a4652e60db42d17f4b4a4a", size = 229850 } wheels = [ @@ -2613,8 +2618,8 @@ name = "pyobjc-framework-corehaptics" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6b/04/ef530d0c30cf81a772ddee64cbfeb7cafd9428d87df96bbc6eb41b77d80f/pyobjc_framework_corehaptics-10.3.1.tar.gz", hash = "sha256:5a7cc117c0b64428e1f08dc9c8b76dbc5d8f61f80dc41e911d11ddee4e0e2059", size = 36854 } wheels = [ @@ -2626,8 +2631,8 @@ name = "pyobjc-framework-corelocation" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/35/8cf7ab8f9b7be5b81deac4d74fdc89607a3eeb901f785cc7d50332eaa275/pyobjc_framework_corelocation-10.3.1.tar.gz", hash = "sha256:8ae54e5bd4c07f7224639d815f7a6537fadee17c11cb35dd99c2804bac1825ab", size = 89219 } wheels = [ @@ -2642,8 +2647,8 @@ name = "pyobjc-framework-coremedia" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/68/9f/5e500c16472053db65dc917b7ea9cdc0fa8fde140ea4c38500a4c341b0a4/pyobjc_framework_coremedia-10.3.1.tar.gz", hash = "sha256:bc3e0cddf5f546b5d8407d8f46b203f1bd4396ad5dbfdc0d064a560b3fe31221", size = 180773 } wheels = [ @@ -2657,8 +2662,8 @@ name = "pyobjc-framework-coremediaio" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/08/67/1c22ff55baf5018d3ca4979f8c319e055ecff8b51ea91d53b8654503cc35/pyobjc_framework_coremediaio-10.3.1.tar.gz", hash = "sha256:5da3ed78475223dd3400fdb55fb97d543a248086f5cf8b77bf4aceac3df1513c", size = 88655 } wheels = [ @@ -2673,8 +2678,8 @@ name = "pyobjc-framework-coremidi" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bf/9f/38d8668499e0c590e51b3f3091d972e09a1f45e4efba94373c22d23d2b88/pyobjc_framework_coremidi-10.3.1.tar.gz", hash = "sha256:818454b56edae082a3a4b4366a7e93b8bb54856be01ee21bb8527a22a4732efc", size = 78441 } wheels = [ @@ -2689,8 +2694,8 @@ name = "pyobjc-framework-coreml" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5b/a2/08a73df17f344700f48444e3000ebdf0ca78765bf0816387de7392380255/pyobjc_framework_coreml-10.3.1.tar.gz", hash = "sha256:6b7091142cfaafee76f1a804329e7a4e3aeca921eea8644e9ceba4cc2751f705", size = 66750 } wheels = [ @@ -2705,8 +2710,8 @@ name = "pyobjc-framework-coremotion" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6c/77/cef3cee6010e926754cc80faa455b5a7530d740f9b5a83a94fd4bd34484a/pyobjc_framework_coremotion-10.3.1.tar.gz", hash = "sha256:6ba61ffd360473b018702b9ae025eb16b8aaa45c6e533121522f26eef93a9f71", size = 54459 } wheels = [ @@ -2720,9 +2725,9 @@ name = "pyobjc-framework-coreservices" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-fsevents" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-fsevents", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/18/c6/9214c4e64a22e92233f67f6518dc60269b30b317a169861f8cb8150adaef/pyobjc_framework_coreservices-10.3.1.tar.gz", hash = "sha256:2e46d008ee4ff586420175888c45f8eb0f002ed5b840c8f7893c560af01b2d72", size = 859909 } wheels = [ @@ -2737,8 +2742,8 @@ name = "pyobjc-framework-corespotlight" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9f/fa/e0ef8d255265a2aaa575244df3d629c46a4eda6c64a210a9faf62fd70772/pyobjc_framework_corespotlight-10.3.1.tar.gz", hash = "sha256:6b8ad243a65943d631434a9ff4696458cdd3d0cb631cfeb501a967fe29445c30", size = 69476 } wheels = [ @@ -2753,9 +2758,9 @@ name = "pyobjc-framework-coretext" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9e/9f/d363cb1548808f538d7ae267a9fcb999dfb5693056fdaa5bc93de089cfef/pyobjc_framework_coretext-10.3.1.tar.gz", hash = "sha256:b8fa2d5078ed774431ae64ba886156e319aec0b8c6cc23dabfd86778265b416f", size = 233428 } wheels = [ @@ -2769,8 +2774,8 @@ name = "pyobjc-framework-corewlan" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9f/b0/6e708d931e85db91de439c080d3af77422d7935b7527ce81888f8ff6ed8b/pyobjc_framework_corewlan-10.3.1.tar.gz", hash = "sha256:d340d976b5d072b917c6d3de130cb4e7a944ee0fdf4e1335b2aa6b1d4d6b4e14", size = 57781 } wheels = [ @@ -2785,8 +2790,8 @@ name = "pyobjc-framework-cryptotokenkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/07/15/49981d93f8402c655cbda9181a55e0f5879715d3f6c344070ba41d2511f1/pyobjc_framework_cryptotokenkit-10.3.1.tar.gz", hash = "sha256:ef1c4a3b9bc5429eceda59724279428e1f8740df2c5a511d061b244113b6fd97", size = 48548 } wheels = [ @@ -2801,8 +2806,8 @@ name = "pyobjc-framework-datadetection" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/28/9b/8b3a633ef4a215095bf1e008f4921bb9647a61a1f5b24e8ab94e89473df9/pyobjc_framework_datadetection-10.3.1.tar.gz", hash = "sha256:5394350cd7e7f40562dc0777f26dd9ddf4a595d20cb6e3cd601938e9490c963e", size = 12682 } wheels = [ @@ -2814,8 +2819,8 @@ name = "pyobjc-framework-devicecheck" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/23/40/51f5e655f4d003227df3077151d20e8490e17e28043e0c4152cec9fcdfac/pyobjc_framework_devicecheck-10.3.1.tar.gz", hash = "sha256:7f6f95c84dc3d1f62aa07061f79b47d19463390d977e5afb444ef9fdd9177a9d", size = 13134 } wheels = [ @@ -2827,8 +2832,8 @@ name = "pyobjc-framework-dictionaryservices" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-coreservices" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coreservices", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a9/ee/ecf4fc40acfdc71a42f6efb7de6cd12b43ee73b3a2397872145584157aef/pyobjc_framework_dictionaryservices-10.3.1.tar.gz", hash = "sha256:c9fb8ed1b92f63c6f568bcdbadf628baab1cb8bb4cd01dbd65424d59c236a552", size = 10131 } wheels = [ @@ -2840,8 +2845,8 @@ name = "pyobjc-framework-discrecording" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e3/0a/07b7871e9bbfb59676be857046c8285549edaf285e8c1508b67db62ddf9c/pyobjc_framework_discrecording-10.3.1.tar.gz", hash = "sha256:47865c9a0d24366b6ede01d326d57404346c3d01e249f417bd2b0b3de00d6c54", size = 101624 } wheels = [ @@ -2856,9 +2861,9 @@ name = "pyobjc-framework-discrecordingui" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-discrecording" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-discrecording", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e6/5e/12669a09410b9707bd27ba93274cd9e817acc6d43ff358299974a52fa624/pyobjc_framework_discrecordingui-10.3.1.tar.gz", hash = "sha256:4b9c804a97c89001feddb58106cdc3e099e241314f7c4de062842d27b1318b68", size = 18181 } wheels = [ @@ -2870,8 +2875,8 @@ name = "pyobjc-framework-diskarbitration" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4e/e8/9f1929c51bcfd78bde9763cc08200eb498528534664701730077beea31d3/pyobjc_framework_diskarbitration-10.3.1.tar.gz", hash = "sha256:0776318cb56f8e095066a880812c4fc5db2071687846e23a000a947a079f6c6c", size = 18667 } wheels = [ @@ -2883,8 +2888,8 @@ name = "pyobjc-framework-dvdplayback" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/72/b6/7f7d140ce091b9813e11f1b980956e607b552ead399abed5a70662f721c0/pyobjc_framework_dvdplayback-10.3.1.tar.gz", hash = "sha256:1f7c22624dee9b1b54def15f12a3f7cacb28052cd864a845eb24b7f59de12257", size = 53047 } wheels = [ @@ -2896,8 +2901,8 @@ name = "pyobjc-framework-eventkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ac/c4/995108bba1fb40eac108501038ae44c57099310982d1a6339b6a5fa47d82/pyobjc_framework_eventkit-10.3.1.tar.gz", hash = "sha256:3eef14ba439be1c5bc47da561ccea3941daba663577efac7a58e3031d27e056b", size = 64043 } wheels = [ @@ -2909,8 +2914,8 @@ name = "pyobjc-framework-exceptionhandling" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/00/88/1328bdac98aa75de421ffea4e16f0b894e39b4ea6569b3a109b531798d20/pyobjc_framework_exceptionhandling-10.3.1.tar.gz", hash = "sha256:ff6208777739f8a886d0cbfe20692b41cc4e5e0607419c47d2c5d405b6b4c6ee", size = 17129 } wheels = [ @@ -2922,8 +2927,8 @@ name = "pyobjc-framework-executionpolicy" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/54/8e/e5a3c06123a4ec3b845dac82450f4f1b4e5b80c0863881fb538f900762b0/pyobjc_framework_executionpolicy-10.3.1.tar.gz", hash = "sha256:cc066dc8378fc2a1a4e6129c4d09e2076dc9a5b09925f8dd959aad591cbf9a44", size = 12825 } wheels = [ @@ -2935,8 +2940,8 @@ name = "pyobjc-framework-extensionkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e7/6a/2803c373283c66eb0d38f139aa1bfa7eb9dc909bc470856ae2308f064e39/pyobjc_framework_extensionkit-10.3.1.tar.gz", hash = "sha256:91946030195fa17c5248655b10786ea60b9aee7d83a4627ba56768600b4e7674", size = 17592 } wheels = [ @@ -2951,8 +2956,8 @@ name = "pyobjc-framework-externalaccessory" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/db/51/61ed6de7d4950f3810e0b5f95cad1a225a1fff8eef13223ebcbc659a4888/pyobjc_framework_externalaccessory-10.3.1.tar.gz", hash = "sha256:3ba1a7242448126b4af0fb93963790d0066766bcba2770d935111093e87b7b83", size = 20735 } wheels = [ @@ -2967,8 +2972,8 @@ name = "pyobjc-framework-fileprovider" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2e/69/c4ebc6738e8a3f5e0c9394791434813fa2656dbe2356fdf4c611a57e7391/pyobjc_framework_fileprovider-10.3.1.tar.gz", hash = "sha256:63a4160e6cbede0f682145f4303ed889bd9f3c9fccfecdc32636a8d95aeceeab", size = 63649 } wheels = [ @@ -2982,8 +2987,8 @@ name = "pyobjc-framework-fileproviderui" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-fileprovider" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-fileprovider", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bf/5c/b130db2b86ff41da6422cd9ed54959202052c0b7401992b467c6cc29ec16/pyobjc_framework_fileproviderui-10.3.1.tar.gz", hash = "sha256:2a3f3b9b81aff216df76bc72c8e8730d7ba7f3b2412720f68b722bae58f82797", size = 12546 } wheels = [ @@ -2995,8 +3000,8 @@ name = "pyobjc-framework-findersync" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/67/70/0a2d490c88541912cab2d245093460190ddeed3bcde9faa3bc5e987c2247/pyobjc_framework_findersync-10.3.1.tar.gz", hash = "sha256:b4a08e0a87c54f62623038de1929fab018fe44fca5372a455bb524b9f90e9196", size = 14228 } wheels = [ @@ -3008,8 +3013,8 @@ name = "pyobjc-framework-fsevents" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a6/fe/53eb4883293b4920544570feb1d8290e937df706ee063a26061f3aebfa72/pyobjc_framework_fsevents-10.3.1.tar.gz", hash = "sha256:6269fd8aa3f62d8a6312e316043aca6d7d792812bff09b617bbd6ca9f0f6e440", size = 27274 } wheels = [ @@ -3024,8 +3029,8 @@ name = "pyobjc-framework-gamecenter" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/46/2f/82cea539bd5a3c764c7acb065face9d1176011f58643323fde30f05997cd/pyobjc_framework_gamecenter-10.3.1.tar.gz", hash = "sha256:221ae88ee69816b95861b1a0dc781c1c17775d38fcf0388327620535479b6a07", size = 30111 } wheels = [ @@ -3040,8 +3045,8 @@ name = "pyobjc-framework-gamecontroller" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/49/6e/1ee46fe9870ce020529ce883c04291a7c7f43adad2b6fbc9b0c44d2549c0/pyobjc_framework_gamecontroller-10.3.1.tar.gz", hash = "sha256:f9f252b5fed5de2a8c7fdd2e302b6ed6e0b82015d7da75b28984c5ea5909345e", size = 94100 } wheels = [ @@ -3056,9 +3061,9 @@ name = "pyobjc-framework-gamekit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/84/aa/897e74e41c80f0eaec994c4b0852e680e5eb22868d3a4681b46f06cf4032/pyobjc_framework_gamekit-10.3.1.tar.gz", hash = "sha256:7d21a8f45c32ac94ce0e70b6c6fe72928fe75cb1a6bd6d7715e2bf39b291b70b", size = 137591 } wheels = [ @@ -3073,9 +3078,9 @@ name = "pyobjc-framework-gameplaykit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-spritekit" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-spritekit", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/02/df/3a6e19a496dec873d26f255458a3e557f6e3aa004f04ca83f9de4e85e9e8/pyobjc_framework_gameplaykit-10.3.1.tar.gz", hash = "sha256:2035b81f7bc34b93636753cc3f9b06cd08171afc5c95bb2327a82fd3195f3c36", size = 55768 } wheels = [ @@ -3090,8 +3095,8 @@ name = "pyobjc-framework-healthkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c0/68/fdda86963c5b3f86941623176acc2d7df03183ea9d3bbfff9088283d2bd2/pyobjc_framework_healthkit-10.3.1.tar.gz", hash = "sha256:45622fedb42bbd95dcc096248bbc41dacd857d9db120ff7310f74f3bad4b23e1", size = 113769 } wheels = [ @@ -3106,8 +3111,8 @@ name = "pyobjc-framework-imagecapturecore" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2f/32/36b2b34e2ae902552854c1e5d24cb4d587875f4400791a30740213f57178/pyobjc_framework_imagecapturecore-10.3.1.tar.gz", hash = "sha256:9ce83c38b8ccee6b022faadb9cd7b8716119092cd41b6c2cabce3670101119bf", size = 81896 } wheels = [ @@ -3122,8 +3127,8 @@ name = "pyobjc-framework-inputmethodkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3b/1b/28c9e10640e0b73dcd7b4693c9ee1fb5519443bd8fd5debb0066261a0abd/pyobjc_framework_inputmethodkit-10.3.1.tar.gz", hash = "sha256:637ba2da38da5f558443b4529b33bab276380336e977807347ee9dad81d42109", size = 24489 } wheels = [ @@ -3138,8 +3143,8 @@ name = "pyobjc-framework-installerplugins" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a2/cd/a9594b8200b1460630d21af18c9fc38741ff748c5457bf5958c5599795c7/pyobjc_framework_installerplugins-10.3.1.tar.gz", hash = "sha256:280808bbce36090b59197756fdb56c19838845a5fc25966a435dbc5fc4ddbbf0", size = 26514 } wheels = [ @@ -3151,9 +3156,9 @@ name = "pyobjc-framework-instantmessage" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c7/fc/51a0707b48507ca4963333452fd17119cc325bbbefdac460bd960f6a935e/pyobjc_framework_instantmessage-10.3.1.tar.gz", hash = "sha256:bb1560a2f92a2def179b6381c17d406331b7818fa0fd1ba98f09ed94415f8a7b", size = 32767 } wheels = [ @@ -3165,8 +3170,8 @@ name = "pyobjc-framework-intents" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/64/dc/120a1891de4ea2c4c5fa382100ac9706dda75a64dd6185367ddc8d89710e/pyobjc_framework_intents-10.3.1.tar.gz", hash = "sha256:89f0ed49c515b75c8811d9f6771ac635e799dfaf11921172729f8e0857c8c0e9", size = 361884 } wheels = [ @@ -3181,8 +3186,8 @@ name = "pyobjc-framework-intentsui" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-intents" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-intents", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/df/51/3cff5de2db25fb516eba66480e90ceea293fc12d715d51a16ebb242c0893/pyobjc_framework_intentsui-10.3.1.tar.gz", hash = "sha256:68f42cabbd36889060d07b21f156f1dae78243d42b34c652448c687d07cbca62", size = 18822 } wheels = [ @@ -3196,8 +3201,8 @@ name = "pyobjc-framework-iobluetooth" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e9/98/b6aade04f7e07de0e81f0312c19bbd21ea61986ab8158a0986aec6c5efd5/pyobjc_framework_iobluetooth-10.3.1.tar.gz", hash = "sha256:bca424889d7fdd5bcb728d312e91ee681e73c0c2ac16ba37068603d699043d39", size = 226060 } wheels = [ @@ -3212,8 +3217,8 @@ name = "pyobjc-framework-iobluetoothui" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-iobluetooth" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-iobluetooth", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d4/e2/3793269efe06505b1b4224ea395912c697896054bdc0bddcc3889796ceac/pyobjc_framework_iobluetoothui-10.3.1.tar.gz", hash = "sha256:6db82aeb360641b878f8ed73c2074db0425664d9411317b2e01962e0929fa29c", size = 19226 } wheels = [ @@ -3225,8 +3230,8 @@ name = "pyobjc-framework-iosurface" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b1/45/8cc7def9b73ec0c3423b7c4878ee3e02fd27e72085574f4c5b7b284bebc5/pyobjc_framework_iosurface-10.3.1.tar.gz", hash = "sha256:94e4a109a94f0e365bd60ce68aab6ff166fef6f30a40f7682c76902f5fc3aa34", size = 19262 } wheels = [ @@ -3238,8 +3243,8 @@ name = "pyobjc-framework-ituneslibrary" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/53/a8/63766d37cc93e2a92a53bb3b5dc769fed0ac27509bfb251cb94878792432/pyobjc_framework_ituneslibrary-10.3.1.tar.gz", hash = "sha256:3899f8555ae02f6441a711892cdc6537404215b3d5f8a7ea4594f7460c58c9b2", size = 40017 } wheels = [ @@ -3251,8 +3256,8 @@ name = "pyobjc-framework-kernelmanagement" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2a/b2/0c894451b949023e00b76e17e46ce65dfa30e5005c5500958d6f90a20fcd/pyobjc_framework_kernelmanagement-10.3.1.tar.gz", hash = "sha256:04c41bc0d0ce014318acf9e333aba302092d2698ec408cbf0b022f3a507ecfa1", size = 11933 } wheels = [ @@ -3264,8 +3269,8 @@ name = "pyobjc-framework-latentsemanticmapping" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6e/17/435b483033f21fa1d95132e93c0cedbf93567f00e6ffb579989e0c070f9c/pyobjc_framework_latentsemanticmapping-10.3.1.tar.gz", hash = "sha256:0bca94fd00f59f49874c8266bfacb09a7c56ad13b4d405c241421cef201f8943", size = 16630 } wheels = [ @@ -3277,8 +3282,8 @@ name = "pyobjc-framework-launchservices" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-coreservices" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coreservices", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/34/dd/53ff73cc0fbf1ad21d3acdd387830f793541dd023150866853e4f00d8dc1/pyobjc_framework_launchservices-10.3.1.tar.gz", hash = "sha256:7f16af2acabca0c2953eb7333bfe652bf853bb9d9e59b771f9d228468bccdea3", size = 20012 } wheels = [ @@ -3290,8 +3295,8 @@ name = "pyobjc-framework-libdispatch" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b7/37/1a7d9e5a04ab42aa8186f3493478c055601503ac7f8d58b8501d23db8b21/pyobjc_framework_libdispatch-10.3.1.tar.gz", hash = "sha256:f5c3475498cb32f54d75e21952670e4a32c8517fb2db2e90869f634edc942446", size = 44771 } wheels = [ @@ -3305,8 +3310,8 @@ name = "pyobjc-framework-libxpc" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8e/9d/8a7eb8d3570f2f41fd265513655fbf28e2ab93155a0053f46277fd61b097/pyobjc_framework_libxpc-10.3.1.tar.gz", hash = "sha256:b3c9e9fd281b5610e3bef486e91570b0afa8ab8eb0c01c0baa5e2ec49ccb7329", size = 39868 } wheels = [ @@ -3320,9 +3325,9 @@ name = "pyobjc-framework-linkpresentation" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b3/f2/8317cff954187875cc82dd8a08de69adbd1efb48451cd2b6836f347392db/pyobjc_framework_linkpresentation-10.3.1.tar.gz", hash = "sha256:535d452cc33d61074ba9bad7707d6c0a23d474fb045ed4322e5f87bfb0b7e865", size = 14174 } wheels = [ @@ -3334,9 +3339,9 @@ name = "pyobjc-framework-localauthentication" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-security" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-security", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d7/a9/bb2c2c3171a600dad5c7db509cdeef5a1a3cd7a22266a515145ebd5497b0/pyobjc_framework_localauthentication-10.3.1.tar.gz", hash = "sha256:ad85411f1899a2ba89349df6a92db99fcaa80a4232a4934a1a176c60698d46b1", size = 26240 } wheels = [ @@ -3348,9 +3353,9 @@ name = "pyobjc-framework-localauthenticationembeddedui" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-localauthentication" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-localauthentication", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/00/36/ba89365d6bdbed5db435e0b4e2dc310a977dab5a306453c4f7ef8de745f2/pyobjc_framework_localauthenticationembeddedui-10.3.1.tar.gz", hash = "sha256:f915190f6106b9f9234750abf48f87445c364ccbca8f8dd565bba1b66ddd55a3", size = 13305 } wheels = [ @@ -3362,8 +3367,8 @@ name = "pyobjc-framework-mailkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d3/1a/683f99e9af1966de9173c1696946ec52b7d45d346aee8a638d1104eade95/pyobjc_framework_mailkit-10.3.1.tar.gz", hash = "sha256:90ad82786ae01a275aeec842e73b1fef12d9f91a67edcde8ff6a145859dc9f92", size = 26043 } wheels = [ @@ -3375,10 +3380,10 @@ name = "pyobjc-framework-mapkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-corelocation" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-corelocation", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/53/f3/1f711e0311ddf3a838d1fe2ec1ab7c52cdb52d4a6144edcd2bd49becbe6c/pyobjc_framework_mapkit-10.3.1.tar.gz", hash = "sha256:f433228c404b9ef4a66e808995daccc1306f7123296317651078a6a734ac1ab0", size = 135465 } wheels = [ @@ -3393,8 +3398,8 @@ name = "pyobjc-framework-mediaaccessibility" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c1/d9/e82531ed727311b54bbbeb9da0bec5c098b8cf8017d541fc77175f4bf322/pyobjc_framework_mediaaccessibility-10.3.1.tar.gz", hash = "sha256:c249e1eee636e77b5f00db3bf85174cb3e0cb53ca991a17e53a1f200377f4289", size = 16607 } wheels = [ @@ -3406,9 +3411,9 @@ name = "pyobjc-framework-medialibrary" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/01/1c/c8355ad906e2051a3d73bef221ce559f417cd58e94dc5af1163bd3669c09/pyobjc_framework_medialibrary-10.3.1.tar.gz", hash = "sha256:703ffd0904fc86d4fbfbbd4952be43e91a6d477c53ce2868e4c18c3eb295f5c6", size = 17661 } wheels = [ @@ -3420,8 +3425,8 @@ name = "pyobjc-framework-mediaplayer" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-avfoundation" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-avfoundation", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/10/00/6d991d13624e8e9288ee289945737bd7e48cce6df7497ee25f2c39c4d173/pyobjc_framework_mediaplayer-10.3.1.tar.gz", hash = "sha256:97043df5ef89d4fbe217813e8f4ee1e226d8a43dee4eac00fff95e6b8a7772be", size = 77337 } wheels = [ @@ -3433,8 +3438,8 @@ name = "pyobjc-framework-mediatoolbox" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a6/8e/a4abb578ad0207ef723fac1255738ea2a3fab3c5b0b0c49a3bb30463257f/pyobjc_framework_mediatoolbox-10.3.1.tar.gz", hash = "sha256:f141056dce0dc16ec21be596fea58acb4a668045f53e12a0f250990d936b44f2", size = 21516 } wheels = [ @@ -3449,8 +3454,8 @@ name = "pyobjc-framework-metal" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8c/5e/2df5fdb85a5753ebe6e1a1b1905da565a408a4f090f7c1d89f3a3143d18b/pyobjc_framework_metal-10.3.1.tar.gz", hash = "sha256:495307db0bfd2063f28b7c8fa350af71afcfbf5f5f2186a6a751b4cb2ef46a1a", size = 299751 } wheels = [ @@ -3465,8 +3470,8 @@ name = "pyobjc-framework-metalfx" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-metal" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-metal", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5f/b0/a479ef7219d4176806e6f49718da59feb1dc222605f45f5e06777a6c6a3c/pyobjc_framework_metalfx-10.3.1.tar.gz", hash = "sha256:3ea0f259397523a84a320b3925dcaaa5c039494accc3cb412b63e6f7f66f9513", size = 21547 } wheels = [ @@ -3481,9 +3486,9 @@ name = "pyobjc-framework-metalkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-metal" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-metal", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f0/6d/c5a782ee9def0feda16cf41c7326680f306293f4446185f3b0040e3e956c/pyobjc_framework_metalkit-10.3.1.tar.gz", hash = "sha256:905eaad9dce29082efd5cc56195337d2e8bff86ccfad36ec5127f818155ec038", size = 38269 } wheels = [ @@ -3498,8 +3503,8 @@ name = "pyobjc-framework-metalperformanceshaders" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-metal" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-metal", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4a/f5/d6b25e063691ab304ed39b3d8121262f661b2e56630bf3b07476134e08a4/pyobjc_framework_metalperformanceshaders-10.3.1.tar.gz", hash = "sha256:1a9e91dc9e748834c95b7a596b943203761f6533352631c7abe612f804b23d50", size = 215419 } wheels = [ @@ -3514,8 +3519,8 @@ name = "pyobjc-framework-metalperformanceshadersgraph" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-metalperformanceshaders" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-metalperformanceshaders", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e6/0c/c00edcdc19f692d0d261d2a0c43f296f240c236704666e287e60dea23edd/pyobjc_framework_metalperformanceshadersgraph-10.3.1.tar.gz", hash = "sha256:4bf2045036f97dcaabbf16ee8527f1787c7e9366611b9b9ed4bfabc81c19343f", size = 81585 } wheels = [ @@ -3527,8 +3532,8 @@ name = "pyobjc-framework-metrickit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b2/71/82f14e24708d44eb0c53b4fc57224bf5db8fa268c0632974abd6ea4b2e7f/pyobjc_framework_metrickit-10.3.1.tar.gz", hash = "sha256:f0b96fe9da0e26759f38d9e4cdf7d9c8be9c6ba35403bc8e675183a6f81dd0b3", size = 31749 } wheels = [ @@ -3542,8 +3547,8 @@ name = "pyobjc-framework-mlcompute" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/db/9a/405b3091a514670d36d21a9f1a9441555ae3b6cc0e6913765484af1cf52f/pyobjc_framework_mlcompute-10.3.1.tar.gz", hash = "sha256:9ac94b0a9511fedceacda846865daa05358eec5a4bf62be534b69eb4d7aced9b", size = 68347 } wheels = [ @@ -3555,9 +3560,9 @@ name = "pyobjc-framework-modelio" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/98/d1/3020a89e0e1145b831351b1e0b34b89b3af7055843384c2a138d3ef4979a/pyobjc_framework_modelio-10.3.1.tar.gz", hash = "sha256:b1da37d10c38c63006d5173b49d18891b2db2c9acdbb6dbd21c73f17c0ccab7e", size = 93075 } wheels = [ @@ -3572,8 +3577,8 @@ name = "pyobjc-framework-multipeerconnectivity" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a6/bf/14b2e58b3462ab15fba8fb07fa493da6531d6c8da07382ef2b63e429be4a/pyobjc_framework_multipeerconnectivity-10.3.1.tar.gz", hash = "sha256:eb801d44194eb7eafcb0a21094c4ce78bcf41ed727125b048755838b59de3271", size = 23441 } wheels = [ @@ -3588,8 +3593,8 @@ name = "pyobjc-framework-naturallanguage" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1f/37/a0af80f8bb4ce27b5d6ab5d6bb8a71ea950cbdf81ec73c03b03388d8c572/pyobjc_framework_naturallanguage-10.3.1.tar.gz", hash = "sha256:49f19d0dba34802696a270d690db310ff03f1c85d6fb411734cb13667db90dd9", size = 39154 } wheels = [ @@ -3601,8 +3606,8 @@ name = "pyobjc-framework-netfs" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/90/94/d467f7bc9efdf633f6cb40b83357f1cb91308efea2738f37b7c682e6619a/pyobjc_framework_netfs-10.3.1.tar.gz", hash = "sha256:46466917f7b0aca3772bf4dfd586b583992c60ecd71c39f7d28ff7665d057637", size = 15212 } wheels = [ @@ -3614,8 +3619,8 @@ name = "pyobjc-framework-network" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b7/a2/547e786e3ff87e4facf038b0375d8fd4a48a8f6c69762efc7aac87b2d379/pyobjc_framework_network-10.3.1.tar.gz", hash = "sha256:87a5839d4ab2ae452b4e563bd7a00569557ede4b8cd1eb77c973cdf45fb8f5ab", size = 104030 } wheels = [ @@ -3630,8 +3635,8 @@ name = "pyobjc-framework-networkextension" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/dc/46/1af5ad27f16af7ef97cced31dc70d92cf85c08d1e15a32997f9e40496601/pyobjc_framework_networkextension-10.3.1.tar.gz", hash = "sha256:c5a094862061565ca6d37457db42f55f344ec24dd7604ddf5d72e20ae7f63fdd", size = 130653 } wheels = [ @@ -3646,8 +3651,8 @@ name = "pyobjc-framework-notificationcenter" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/11/a4/105abbec54e815ab9de653bba08db37524589c369badab6e1a5e3bd598a3/pyobjc_framework_notificationcenter-10.3.1.tar.gz", hash = "sha256:3e6efe0fe6389601bb87086f5585fa7e74b2143236b7d5afd02b617a73656419", size = 21039 } wheels = [ @@ -3662,8 +3667,8 @@ name = "pyobjc-framework-opendirectory" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/32/1e/85e8d9ea9ee43a111a6d278c5006a3a58c4573af60ba7932402cb3ca5e84/pyobjc_framework_opendirectory-10.3.1.tar.gz", hash = "sha256:cddc25632eebeb6bf0d886ae0fc919d574e458c597691226ba15bbf134ab51a6", size = 159659 } wheels = [ @@ -3675,8 +3680,8 @@ name = "pyobjc-framework-osakit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ce/db/2ee141472cb30079b8881d4839f4d46d38bed2e78e04d5ecf44885d05cd7/pyobjc_framework_osakit-10.3.1.tar.gz", hash = "sha256:0af326b831fa29fca11ffe2b641807ad3c233be9eb403e62328fa784528da4ab", size = 18286 } wheels = [ @@ -3688,10 +3693,10 @@ name = "pyobjc-framework-oslog" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coremedia" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coremedia", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/11/ba/45a84a9a26608c8dd2d909f8ad8183434c17b1d4071ce910388c80a07637/pyobjc_framework_oslog-10.3.1.tar.gz", hash = "sha256:592c3e50cf824c2c07779771aa0065de2dbb4c615de43e8949b39d19ba04d744", size = 22288 } wheels = [ @@ -3706,8 +3711,8 @@ name = "pyobjc-framework-passkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a5/5a/8336d8fe6371e7696235d131d042572156299d6a0c566a5854f127270adc/pyobjc_framework_passkit-10.3.1.tar.gz", hash = "sha256:4c3eea19c1ae3edf6e7858ab815bcd8ecf517a146928ce6a843910729372f010", size = 94853 } wheels = [ @@ -3722,8 +3727,8 @@ name = "pyobjc-framework-pencilkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d2/8e/9152ecf82135f5f6ec94f4b407948cdee9b8f01ead2896613422dbfe8ef1/pyobjc_framework_pencilkit-10.3.1.tar.gz", hash = "sha256:4dfd8e0179be5ecf67b768317a88d86d93df1c8674d422afa14957cf80e6e01f", size = 18784 } wheels = [ @@ -3735,8 +3740,8 @@ name = "pyobjc-framework-phase" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-avfoundation" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-avfoundation", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f8/7c/57e7a130932027f11ce8bfb68e8a6a910b9ec11c8bd4647605d0c6ff1ade/pyobjc_framework_phase-10.3.1.tar.gz", hash = "sha256:5be2ea5d36ea9620f5278f5ad3b02cc243511be3b137aa28b1523e8f6da54f99", size = 43938 } wheels = [ @@ -3748,8 +3753,8 @@ name = "pyobjc-framework-photos" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4f/e3/764707657dc2ee986510ac137dfcb98ca3498fa21ed7c79e711df3b85736/pyobjc_framework_photos-10.3.1.tar.gz", hash = "sha256:8d538c399720062523694f7669aa82dcb75a7b192fb4aca93cf782d04e4c39be", size = 74176 } wheels = [ @@ -3764,8 +3769,8 @@ name = "pyobjc-framework-photosui" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/aa/34/6ee322114383d37c4921fc15e41ba4595347f0b108e14d6232e540d77c5e/pyobjc_framework_photosui-10.3.1.tar.gz", hash = "sha256:e9eb961c6be1f3e00d76cc0a8ec15b50ac0692bd5b5c86268ad08f6d09cf390d", size = 38914 } wheels = [ @@ -3780,8 +3785,8 @@ name = "pyobjc-framework-preferencepanes" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8a/56/da2d75cf4900a62cafde27d875bbe0dc0e9c3624b6d4c08adc69d9336033/pyobjc_framework_preferencepanes-10.3.1.tar.gz", hash = "sha256:eef150416a39a0109a8a37e9978ac4a55ad0b125ef6053a7431524ede5c69783", size = 25330 } wheels = [ @@ -3793,8 +3798,8 @@ name = "pyobjc-framework-pubsub" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ad/94/7126b622790d16a422589938b97f8c7c13a0724d9b9c8bed7badd8016d01/pyobjc_framework_pubsub-10.3.1.tar.gz", hash = "sha256:d123e75288c2f9d785ed1c4d92a96e5118c4b6f1cd9c55605eb4b4a74c2e36f4", size = 15716 } wheels = [ @@ -3806,8 +3811,8 @@ name = "pyobjc-framework-pushkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/30/d6/2fec9c42a76466902b14afeea7a9c8cc2c90aeafd3f3dbe72af474681dc5/pyobjc_framework_pushkit-10.3.1.tar.gz", hash = "sha256:cc4da5382cf48c29637af1c633490203358a6ab0c76f0c006079cf144eeb9568", size = 19167 } wheels = [ @@ -3822,8 +3827,8 @@ name = "pyobjc-framework-quartz" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f7/a2/f488d801197b9b4d28d0b8d85947f9e2c8a6e89c5e6d4a828fc7cccfb57a/pyobjc_framework_quartz-10.3.1.tar.gz", hash = "sha256:b6d7e346d735c9a7f147cd78e6da79eeae416a0b7d3874644c83a23786c6f886", size = 3775947 } wheels = [ @@ -3837,9 +3842,9 @@ name = "pyobjc-framework-quicklookthumbnailing" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/29/04/ef2db0a73af5b2530de728529f5d637bbe5f09bf4165493db0ab3df2018b/pyobjc_framework_quicklookthumbnailing-10.3.1.tar.gz", hash = "sha256:ee26be78df9ce46ffa6f971f4ce167a0e98f38167aeb86cfc1b41270f15c96a3", size = 15534 } wheels = [ @@ -3851,8 +3856,8 @@ name = "pyobjc-framework-replaykit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5b/37/dbadcb487150f4ea1a691c83d09f1ed58463bed6b4fa54dca6aeb1584d06/pyobjc_framework_replaykit-10.3.1.tar.gz", hash = "sha256:21762c8674b629fb670c3cbd515c593f1b5f98ee24ee4834a09055cb08849068", size = 23417 } wheels = [ @@ -3867,8 +3872,8 @@ name = "pyobjc-framework-safariservices" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/69/63/c12192ed8b5a08cc5313aef6d4e6d86d9d17171d4325a7f6e2f8c0da7a19/pyobjc_framework_safariservices-10.3.1.tar.gz", hash = "sha256:9c5278576e7c28c3d93e74ebe5d39d07c5c91572ddf03ea01cc45d9a06dc8d0a", size = 29436 } wheels = [ @@ -3883,9 +3888,9 @@ name = "pyobjc-framework-safetykit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d8/db/1d099ed2b3655caacad70315a6789b47277f9939f73d4f13810bf27f9e29/pyobjc_framework_safetykit-10.3.1.tar.gz", hash = "sha256:8421be801ce29053e67a2c91673913562c3ad9d4bb1fbaa934a3a365d8bff12d", size = 19035 } wheels = [ @@ -3900,9 +3905,9 @@ name = "pyobjc-framework-scenekit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/23/cb/0451b9463cc1d19eef523dfc6098c5d774cbd5f4cae9fbc6884b17cd5cd9/pyobjc_framework_scenekit-10.3.1.tar.gz", hash = "sha256:99cf0db3055d9bae0a8643400e528a8c012235db8ee6a1864ea0b03a0854c9d0", size = 155276 } wheels = [ @@ -3917,9 +3922,9 @@ name = "pyobjc-framework-screencapturekit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coremedia" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coremedia", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d4/20/51dbb697dc5d3bc522771afa375e05370e6357b49dacf1bafe7dae37908f/pyobjc_framework_screencapturekit-10.3.1.tar.gz", hash = "sha256:cb1a2e746e0f98ea14a11ea35d059d38587340beeeb905812085e2c7ceb14e0c", size = 34829 } wheels = [ @@ -3933,8 +3938,8 @@ name = "pyobjc-framework-screensaver" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/dc/7c/55374bae0be8632e2c76b911af3bcdfd5b5ea417c125d8268f8207c77516/pyobjc_framework_screensaver-10.3.1.tar.gz", hash = "sha256:0bbc5b574f12e95f6f6e48ced40b601e46e560ef6786845c15c57d78e6cd083e", size = 22037 } wheels = [ @@ -3949,8 +3954,8 @@ name = "pyobjc-framework-screentime" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/38/a5/b2b9c57eb364ccc1074442ce956b0052f71e903b7b944a93bc4888deb94d/pyobjc_framework_screentime-10.3.1.tar.gz", hash = "sha256:351179d5bf951aa754c72f50ba8785212adf1b26abe10149c750fafd0a3108ae", size = 13365 } wheels = [ @@ -3962,8 +3967,8 @@ name = "pyobjc-framework-scriptingbridge" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/10/45/ef1ae83f84555c3cf7ba18e53be9ace9f4225e56b852d7f5d79b5c516d4f/pyobjc_framework_scriptingbridge-10.3.1.tar.gz", hash = "sha256:6bfb45efd0a1cda38a37154afe69f86ea086d5cbdfbc33b3e31c0bda97537fe9", size = 20828 } wheels = [ @@ -3978,8 +3983,8 @@ name = "pyobjc-framework-searchkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-coreservices" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coreservices", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/85/74/1ee0012987c203f6776b7ca3da12b68623d9861c96ddc9575809c38864bc/pyobjc_framework_searchkit-10.3.1.tar.gz", hash = "sha256:7efb76b7af9d8f0f08efb91543f4dba0b00261ed41abb121ada80175cc82d65d", size = 30449 } wheels = [ @@ -3991,8 +3996,8 @@ name = "pyobjc-framework-security" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/20/db/3fa2a151c53f2d87d9da725948d33f8bb4c7f36d6cb468411ae4b46ad474/pyobjc_framework_security-10.3.1.tar.gz", hash = "sha256:0d4e679a8aebaef9b54bd24e2fe2794ad5c28d601b6d140ed38370594bcb6fa0", size = 252496 } wheels = [ @@ -4006,9 +4011,9 @@ name = "pyobjc-framework-securityfoundation" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-security" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-security", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/40/d6/908dcceb7cd5dcfa3ff265dfcb945a8707256f7ab09ee709d86cb26ae1d4/pyobjc_framework_securityfoundation-10.3.1.tar.gz", hash = "sha256:414b13acabfae584729cd614e27247d250ec225d31140e8d971aa08536d6150c", size = 12595 } wheels = [ @@ -4020,9 +4025,9 @@ name = "pyobjc-framework-securityinterface" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-security" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-security", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b6/8b/d2dfd658f279fe6d3416b45c5030a65342ded0150ba56e028f6dcc9b38e1/pyobjc_framework_securityinterface-10.3.1.tar.gz", hash = "sha256:cd25f342a2b53cbffd134443506d5e75c96ba7145135debb8932c1252d57269a", size = 31921 } wheels = [ @@ -4037,9 +4042,9 @@ name = "pyobjc-framework-sensitivecontentanalysis" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ef/3d/7b50fb510374640c7562fc3cc83a75d91bd23f3f53a15579bd0061ffc3bd/pyobjc_framework_sensitivecontentanalysis-10.3.1.tar.gz", hash = "sha256:ac8dd18d77ccc0bb4eb24839cf39da9981db64e53f52b09636e47bd7b3066f84", size = 12006 } wheels = [ @@ -4051,8 +4056,8 @@ name = "pyobjc-framework-servicemanagement" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ec/de/f60506eef312ea3cbd5eacd1308bfb7e68f8d1a032573840f46b7de3a122/pyobjc_framework_servicemanagement-10.3.1.tar.gz", hash = "sha256:d048a803ad34c997dcc99ba778fca9d91cc5adfa1d115202e4bf22d9b04fd92c", size = 15746 } wheels = [ @@ -4064,8 +4069,8 @@ name = "pyobjc-framework-sharedwithyou" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-sharedwithyoucore" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-sharedwithyoucore", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a2/c8/261b3ae7063550b157fd33e9931c53007e4b7ff209a6d5a393b301af67c3/pyobjc_framework_sharedwithyou-10.3.1.tar.gz", hash = "sha256:7e35b631bc77b040151515e4fee9c8f47bc313924fc3e5970e940f1343db039b", size = 27924 } wheels = [ @@ -4080,8 +4085,8 @@ name = "pyobjc-framework-sharedwithyoucore" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/58/ba/09d6cfb51167b14711d2a2526d69994566eec101578af0e39b84a4794e5b/pyobjc_framework_sharedwithyoucore-10.3.1.tar.gz", hash = "sha256:e4768b7fdb18730e225bbebc9c9f9acfa7e44e648875816aff8c7e7f0e82afbf", size = 24331 } wheels = [ @@ -4096,8 +4101,8 @@ name = "pyobjc-framework-shazamkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/07/d7/5cf2157fd163084d75d1cf9cf2de774d373387162a7b03c19cbcd193f22f/pyobjc_framework_shazamkit-10.3.1.tar.gz", hash = "sha256:deef11a43e773b876df31eeadbfc447892fda0607e314ca2afb2c012284cfa32", size = 22923 } wheels = [ @@ -4111,8 +4116,8 @@ name = "pyobjc-framework-social" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/94/a8/c5a8ea9eea5ec096e03fcda22f3bf5077710a988dbcdbc543afed7478d34/pyobjc_framework_social-10.3.1.tar.gz", hash = "sha256:d1303cf3860ad02a8795c099e17888923505a9c45be407da50721a9a8a5b2efd", size = 13749 } wheels = [ @@ -4124,8 +4129,8 @@ name = "pyobjc-framework-soundanalysis" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cc/23/bb9bc28f3d96e1316ac257b6b0605bcefb4b38879b9594272bbc9505e341/pyobjc_framework_soundanalysis-10.3.1.tar.gz", hash = "sha256:faa533644231f99dbdc2fcc3ecb9181c5df4f4dc68d42856729214021c83c881", size = 15578 } wheels = [ @@ -4137,8 +4142,8 @@ name = "pyobjc-framework-speech" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e6/8c/cc25b4267f884139b9677ea3fed8a8b99c423ef3f72dcc35eae6a01e4007/pyobjc_framework_speech-10.3.1.tar.gz", hash = "sha256:5b77b1d1ced0d1ad7244037b865dda2b83e8f9562d76d1e9fa4fea3b89e437b8", size = 29979 } wheels = [ @@ -4153,9 +4158,9 @@ name = "pyobjc-framework-spritekit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fc/a3/037c63ce21d3a01d1d3c891b17979c5c1ce13a0893c97848bf2eb3e30442/pyobjc_framework_spritekit-10.3.1.tar.gz", hash = "sha256:2c11f35f48302f487c51ba8030f5cf79493a9dc0993dd901016ae4b8d8047c8b", size = 95557 } wheels = [ @@ -4169,8 +4174,8 @@ name = "pyobjc-framework-storekit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bb/42/e0ebe600ca0572fea164c2308bdd8866cb09167ef1617ed66d5c9a9a6026/pyobjc_framework_storekit-10.3.1.tar.gz", hash = "sha256:913b4aad7dc31df7d8011c54a695da65cc57819f4b48c98abaed4e6d9ff7d323", size = 63667 } wheels = [ @@ -4185,8 +4190,8 @@ name = "pyobjc-framework-symbols" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d7/2b/e32921c7f2e00ba41fdd6befc0f7aabf17bc4c136f2b6a0cf4f44939940e/pyobjc_framework_symbols-10.3.1.tar.gz", hash = "sha256:3e3f35ef3646b5f9c0653d9dbf5693cf87de3df04420cb2679dad74c75965d18", size = 11785 } wheels = [ @@ -4198,9 +4203,9 @@ name = "pyobjc-framework-syncservices" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coredata" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coredata", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/77/eb/6b73844bc7a4f964128cde7fffbe4243b62c691626b4b101337b6ac7caff/pyobjc_framework_syncservices-10.3.1.tar.gz", hash = "sha256:1cd5e3eaf85a11996184afad1da47037cd921e302ccb35fe388b19f91a685669", size = 49572 } wheels = [ @@ -4215,8 +4220,8 @@ name = "pyobjc-framework-systemconfiguration" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1f/34/4a8a79ae382296533cf0aa51377f53d9157aa41484c83a506d9dc43fc9e1/pyobjc_framework_systemconfiguration-10.3.1.tar.gz", hash = "sha256:1bf6ffe98faa4e208bf594c857ba23cd56fe404bc579188ff53b704844d9c402", size = 124143 } wheels = [ @@ -4231,8 +4236,8 @@ name = "pyobjc-framework-systemextensions" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/dd/d2/eab93a69f95c757104112cb0bce3e1fc70de59ca47ff0c60d180f306819f/pyobjc_framework_systemextensions-10.3.1.tar.gz", hash = "sha256:34412e75c95a585d222ea23efc3eba436210ec0345cec6c7dc78d16e027d03e1", size = 19844 } wheels = [ @@ -4247,8 +4252,8 @@ name = "pyobjc-framework-threadnetwork" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/dc/6c/c502594ac550436bb8d989b18734eeabd5ce189c2ebb1f4895e3e00d424d/pyobjc_framework_threadnetwork-10.3.1.tar.gz", hash = "sha256:1038210a8e5dfa86aefd10894563913e767e95d1c1bd4333ae5f9c6cabbb3ce9", size = 12639 } wheels = [ @@ -4260,8 +4265,8 @@ name = "pyobjc-framework-uniformtypeidentifiers" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1f/54/10c56c741e7c95ee4dd8db06afac5e59722e5372e35f3c5a3e7c2954c746/pyobjc_framework_uniformtypeidentifiers-10.3.1.tar.gz", hash = "sha256:1985fee7e1f1157db36f3c19ee0ad273677eeff10467f575086246bbeffcdf50", size = 18476 } wheels = [ @@ -4273,8 +4278,8 @@ name = "pyobjc-framework-usernotifications" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/12/d2/32432d2b579ca393f65f7ae7b53cf887f2efda861c4e1b372428f65dd4bf/pyobjc_framework_usernotifications-10.3.1.tar.gz", hash = "sha256:ddb5de88fb659c2241429b6408ddcabbfc0c2c9e4a7f5f543a6fab1c4953403b", size = 45987 } wheels = [ @@ -4289,9 +4294,9 @@ name = "pyobjc-framework-usernotificationsui" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-usernotifications" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-usernotifications", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/df/10/a525f13919955d653fd431f527974e2604b0b8727c886de1ec7e2bf34189/pyobjc_framework_usernotificationsui-10.3.1.tar.gz", hash = "sha256:80390b5361bb6014dc32d0afbf581280e7762a4f67460a736f461f613d397094", size = 13288 } wheels = [ @@ -4303,8 +4308,8 @@ name = "pyobjc-framework-videosubscriberaccount" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c8/a6/41d6afaa800bf8839c45642b60d7fa13a0e292d477762c33ce22ba1c0aa6/pyobjc_framework_videosubscriberaccount-10.3.1.tar.gz", hash = "sha256:f62509e976b805bc76ff5928444677ac542b52dd9f7781ac0731d7c4b22bed96", size = 23793 } wheels = [ @@ -4316,10 +4321,10 @@ name = "pyobjc-framework-videotoolbox" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coremedia" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coremedia", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/65/e4/435561672801cb29a398b208e75e6823e6c369027cd51f0774f3b24f2baf/pyobjc_framework_videotoolbox-10.3.1.tar.gz", hash = "sha256:7ebc281523b2b37aff17ce6eabd0c81081864b3e3e4a83ae72b18fd70c57c521", size = 66253 } wheels = [ @@ -4334,8 +4339,8 @@ name = "pyobjc-framework-virtualization" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2e/d1/427065aab5570855228fe0bc3d387fcc4c76e18538c28c5fc2497b0f75f2/pyobjc_framework_virtualization-10.3.1.tar.gz", hash = "sha256:8348ddef18eb943d151e5b5977e4d410012ee2e3f6048c16f7cfe0c1a73536cb", size = 61591 } wheels = [ @@ -4350,10 +4355,10 @@ name = "pyobjc-framework-vision" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coreml" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-coreml", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-quartz", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7c/55/ff278351cb47f939a932dc5d9d80a8a0d51a427e27e0419833d49219e757/pyobjc_framework_vision-10.3.1.tar.gz", hash = "sha256:aa071656d395afc2d624600a9f30d6a3344aa747bf37f613ff3972158c40881c", size = 108532 } wheels = [ @@ -4368,8 +4373,8 @@ name = "pyobjc-framework-webkit" version = "10.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyobjc-framework-cocoa", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/15/6b/50c1000354e9de966a150b4a41c291c83517eec9bd162f43ea4e55444d64/pyobjc_framework_webkit-10.3.1.tar.gz", hash = "sha256:7ad9f4eb91a6dff39848d9c2ab71f170aeab4b6396bcec8e5a780739f9be4222", size = 610874 } wheels = [ @@ -4384,9 +4389,9 @@ name = "pyogrio" version = "0.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "certifi" }, - { name = "numpy" }, - { name = "packaging" }, + { name = "certifi", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "packaging", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4e/09/a13ffa71f617f3c76f31984bc4fc237aede9988d89056b278efcb97f6fb0/pyogrio-0.9.0.tar.gz", hash = "sha256:6a6fa2e8cf95b3d4a7c0fac48bce6e5037579e28d3eb33b53349d6e11f15e5a8", size = 352526 } wheels = [ @@ -4407,9 +4412,9 @@ name = "pyopencl" version = "2024.2.7" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, - { name = "platformdirs" }, - { name = "pytools" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "platformdirs", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "pytools", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/92/68/a26269be1ba101b740a7b47d81032cf71c50a8700cc71ab2c49f0fcccec9/pyopencl-2024.2.7.tar.gz", hash = "sha256:6ae4458a959b6ad9c138fb711a52c4d57c2c2f798eb3aecc4c26830cb2726140", size = 470964 } wheels = [ @@ -4430,7 +4435,7 @@ name = "pyopenssl" version = "24.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cryptography" }, + { name = "cryptography", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5d/70/ff56a63248562e77c0c8ee4aefc3224258f1856977e0c1472672b62dadb8/pyopenssl-24.2.1.tar.gz", hash = "sha256:4247f0dbe3748d560dcbb2ff3ea01af0f9a1a001ef5f7c4c647956ed8cbf0e95", size = 184323 } wheels = [ @@ -4463,7 +4468,7 @@ name = "pyproj" version = "3.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "certifi" }, + { name = "certifi", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7d/84/2b39bbf888c753ea48b40d47511548c77aa03445465c35cc4c4e9649b643/pyproj-3.6.1.tar.gz", hash = "sha256:44aa7c704c2b7d8fb3d483bbf75af6cb2350d30a63b144279a09b75fead501bf", size = 225131 } wheels = [ @@ -4486,7 +4491,7 @@ name = "pyqt5" version = "5.15.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyqt5-sip" }, + { name = "pyqt5-sip", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/28/6c/640e3f5c734c296a7193079a86842a789edb7988dca39eab44579088a1d1/PyQt5-5.15.2.tar.gz", hash = "sha256:372b08dc9321d1201e4690182697c5e7ffb2e0770e6b4a45519025134b12e4fc", size = 3265445 } wheels = [ @@ -4549,9 +4554,9 @@ version = "8.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "iniconfig" }, - { name = "packaging" }, - { name = "pluggy" }, + { name = "iniconfig", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "packaging", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pluggy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b4/8c/9862305bdcd6020bc7b45b1b5e7397a6caf1a33d3025b9a003b39075ffb2/pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce", size = 1439314 } wheels = [ @@ -4563,7 +4568,7 @@ name = "pytest-asyncio" version = "0.23.8" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pytest" }, + { name = "pytest", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/de/b4/0b378b7bf26a8ae161c3890c0b48a91a04106c5713ce81b4b080ea2f4f18/pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3", size = 46920 } wheels = [ @@ -4575,8 +4580,8 @@ name = "pytest-cov" version = "5.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "coverage" }, - { name = "pytest" }, + { name = "coverage", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pytest", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/74/67/00efc8d11b630c56f15f4ad9c7f9223f1e5ec275aaae3fa9118c6a223ad2/pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857", size = 63042 } wheels = [ @@ -4588,8 +4593,8 @@ name = "pytest-cpp" version = "2.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama" }, - { name = "pytest" }, + { name = "colorama", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pytest", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0f/72/6da4fd6ea5afd44e10dbed76ef666c0732e27317a753099bc163f3330a91/pytest-cpp-2.5.0.tar.gz", hash = "sha256:695604baa21bc95291bb4ea7263a7aa960753de57c2d17d224c4652fbcf65cdc", size = 465039 } wheels = [ @@ -4601,7 +4606,7 @@ name = "pytest-mock" version = "3.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pytest" }, + { name = "pytest", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c6/90/a955c3ab35ccd41ad4de556596fa86685bf4fc5ffcc62d22d856cfd4e29a/pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0", size = 32814 } wheels = [ @@ -4613,7 +4618,7 @@ name = "pytest-randomly" version = "3.15.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pytest" }, + { name = "pytest", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c9/d4/6e924a0b2855736d942703dec88dfc98b4fe0881c8fa849b6b0fbb9182fa/pytest_randomly-3.15.0.tar.gz", hash = "sha256:b908529648667ba5e54723088edd6f82252f540cc340d748d1fa985539687047", size = 21743 } wheels = [ @@ -4625,7 +4630,7 @@ name = "pytest-repeat" version = "0.9.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pytest" }, + { name = "pytest", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/86/5e/99365eb229efff0b1bd475886150fc6db9937ab7e1bd21f6f65c1279e0eb/pytest_repeat-0.9.3.tar.gz", hash = "sha256:ffd3836dfcd67bb270bec648b330e20be37d2966448c4148c4092d1e8aba8185", size = 6272 } wheels = [ @@ -4637,8 +4642,8 @@ name = "pytest-subtests" version = "0.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "attrs" }, - { name = "pytest" }, + { name = "attrs", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pytest", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/67/fe/e691d2f4ce061a475f488cad1ef58431556affea323dde5c764fd7515a70/pytest_subtests-0.13.1.tar.gz", hash = "sha256:989e38f0f1c01bc7c6b2e04db7d9fd859db35d77c2c1a430c831a70cbf3fde2d", size = 15936 } wheels = [ @@ -4650,7 +4655,7 @@ name = "pytest-timeout" version = "2.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pytest" }, + { name = "pytest", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/93/0d/04719abc7a4bdb3a7a1f968f24b0f5253d698c9cc94975330e9d3145befb/pytest-timeout-2.3.1.tar.gz", hash = "sha256:12397729125c6ecbdaca01035b9e5239d4db97352320af155b3f5de1ba5165d9", size = 17697 } wheels = [ @@ -4662,8 +4667,8 @@ name = "pytest-xdist" version = "3.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "execnet" }, - { name = "pytest" }, + { name = "execnet", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pytest", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/41/c4/3c310a19bc1f1e9ef50075582652673ef2bfc8cd62afef9585683821902f/pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d", size = 84060 } wheels = [ @@ -4675,7 +4680,7 @@ name = "python-dateutil" version = "2.9.0.post0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six" }, + { name = "six", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } wheels = [ @@ -4687,7 +4692,7 @@ name = "python-xlib" version = "0.33" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six" }, + { name = "six", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/86/f5/8c0653e5bb54e0cbdfe27bf32d41f27bc4e12faa8742778c17f2a71be2c0/python-xlib-0.33.tar.gz", hash = "sha256:55af7906a2c75ce6cb280a584776080602444f75815a7aff4d287bb2d7018b32", size = 269068 } wheels = [ @@ -4705,8 +4710,8 @@ name = "pytools" version = "2024.1.10" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "platformdirs" }, - { name = "siphash24" }, + { name = "platformdirs", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "siphash24", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, { name = "typing-extensions", marker = "python_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ee/0f/56e109c0307f831b5d598ad73976aaaa84b4d0e98da29a642e797eaa940c/pytools-2024.1.10.tar.gz", hash = "sha256:9af6f4b045212c49be32bb31fe19606c478ee4b09631886d05a32459f4ce0a12", size = 81741 } @@ -4751,7 +4756,7 @@ dependencies = [ { name = "pyobjc", marker = "sys_platform == 'darwin'" }, { name = "python-xlib", marker = "sys_platform == 'linux'" }, { name = "pywin32", marker = "sys_platform == 'win32'" }, - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/b1/37/d59397221e15d2a7f38afaa4e8e6b8c244d818044f7daa0bdc5988df0a69/PyWinBox-0.7-py3-none-any.whl", hash = "sha256:8b2506a8dd7afa0a910b368762adfac885274132ef9151b0c81b0d2c6ffd6f83", size = 12274 }, @@ -4763,12 +4768,12 @@ version = "0.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ewmhlib", marker = "sys_platform == 'linux'" }, - { name = "pymonctl" }, + { name = "pymonctl", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyobjc", marker = "sys_platform == 'darwin'" }, { name = "python-xlib", marker = "sys_platform == 'linux'" }, { name = "pywin32", marker = "sys_platform == 'win32'" }, - { name = "pywinbox" }, - { name = "typing-extensions" }, + { name = "pywinbox", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "typing-extensions", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/ff/53/a7234a6b6d0c5cf295950166498623046422a333d8af79a26552ab40b9a6/PyWinCtl-0.4-py3-none-any.whl", hash = "sha256:8c4a92bd57e35fd280c5c04f048cc822e236abffe2fa17351096b0e28907172d", size = 60338 }, @@ -4802,7 +4807,7 @@ name = "pyyaml-env-tag" version = "0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyyaml" }, + { name = "pyyaml", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fb/8e/da1c6c58f751b70f8ceb1eb25bc25d524e8f14fe16edcce3f4e3ba08629c/pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", size = 5631 } wheels = [ @@ -4849,10 +4854,10 @@ name = "requests" version = "2.32.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, + { name = "certifi", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "charset-normalizer", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "idna", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "urllib3", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } wheels = [ @@ -4864,11 +4869,11 @@ name = "rerun-sdk" version = "0.17.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "attrs" }, - { name = "numpy" }, - { name = "pillow" }, - { name = "pyarrow" }, - { name = "typing-extensions" }, + { name = "attrs", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pillow", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyarrow", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "typing-extensions", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/30/5f/ce02381b9d7e1e14f60c421c76dce12b7d823690181784780b30266017b1/rerun_sdk-0.17.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:abd34f746eada83b8bb0bc50007183151981d7ccf18306f3d42165819a3f6fcb", size = 33166544 }, @@ -4917,7 +4922,7 @@ name = "scipy" version = "1.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4e/e5/0230da034a2e1b1feb32621d7cd57c59484091d6dccc9e6b855b0d309fc9/scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b", size = 58618870 } wheels = [ @@ -4953,9 +4958,9 @@ name = "seaborn" version = "0.13.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "matplotlib" }, - { name = "numpy" }, - { name = "pandas" }, + { name = "matplotlib", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "pandas", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696 } wheels = [ @@ -4967,8 +4972,8 @@ name = "sentry-sdk" version = "2.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "certifi" }, - { name = "urllib3" }, + { name = "certifi", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "urllib3", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6d/b3/39e4cd04b75a1ada788342d0d30a781cf65b5e43da806d5bf2bad4846ea3/sentry_sdk-2.11.0.tar.gz", hash = "sha256:4ca16e9f5c7c6bc2fb2d5c956219f4926b148e511fffdbbde711dc94f1e0468f", size = 276242 } wheels = [ @@ -4989,7 +4994,7 @@ name = "shapely" version = "2.0.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ad/99/c47247f4d688bbb5346df5ff1de5d9792b6d95cbbb2fd7b71f45901c1878/shapely-2.0.5.tar.gz", hash = "sha256:bff2366bc786bfa6cb353d6b47d0443c570c32776612e527ee47b6df63fcfe32", size = 282188 } wheels = [ @@ -5059,7 +5064,7 @@ name = "sounddevice" version = "0.4.7" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cffi" }, + { name = "cffi", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0d/88/5832219fa90595932d5f6d1b5125bfd8a55e95b19ad866e265c9bbb7cde4/sounddevice-0.4.7.tar.gz", hash = "sha256:69b386818d50a2d518607d4b973442e8d524760c7cd6c8b8be03d8c98fc4bce7", size = 52244 } wheels = [ @@ -5080,7 +5085,7 @@ name = "sympy" version = "1.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "mpmath" }, + { name = "mpmath", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ca/99/5a5b6f19ff9f083671ddf7b9632028436167cd3d33e11015754e41b249a4/sympy-1.13.1.tar.gz", hash = "sha256:9cebf7e04ff162015ce31c9c6c9144daa34a93bd082f54fd8f12deca4f47515f", size = 7533040 } wheels = [ @@ -5122,7 +5127,7 @@ name = "types-requests" version = "2.32.0.20240712" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "urllib3" }, + { name = "urllib3", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5e/9e/7663eb27c33568b8fc20ccdaf2a1ce53a9530c42a7cceb9f552a6ff4a1d8/types-requests-2.32.0.20240712.tar.gz", hash = "sha256:90c079ff05e549f6bf50e02e910210b98b8ff1ebdd18e19c873cd237737c1358", size = 17896 } wheels = [ @@ -5170,9 +5175,9 @@ name = "virtualenv" version = "20.26.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "distlib" }, - { name = "filelock" }, - { name = "platformdirs" }, + { name = "distlib", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "filelock", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "platformdirs", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/68/60/db9f95e6ad456f1872486769c55628c7901fb4de5a72c2f7bdd912abf0c1/virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a", size = 9057588 } wheels = [ @@ -5217,9 +5222,9 @@ name = "yapf" version = "0.40.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "importlib-metadata" }, - { name = "platformdirs" }, - { name = "tomli" }, + { name = "importlib-metadata", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "platformdirs", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "tomli", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/14/c1f0ebd083fddd38a7c832d5ffde343150bd465689d12c549c303fbcd0f5/yapf-0.40.2.tar.gz", hash = "sha256:4dab8a5ed7134e26d57c1647c7483afb3f136878b579062b786c9ba16b94637b", size = 252068 } wheels = [ @@ -5231,8 +5236,8 @@ name = "yarl" version = "1.9.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "idna" }, - { name = "multidict" }, + { name = "idna", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "multidict", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e0/ad/bedcdccbcbf91363fd425a948994f3340924145c2bc8ccb296f4a1e52c28/yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf", size = 141869 } wheels = [ From ebff7cab1ab897526800e229e30b01ec4cf1114c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 31 Jul 2024 14:53:13 -0700 Subject: [PATCH 182/229] get_fw_versions: test the full stack (#33156) * add the test fix * bump * not sure why mypy didn't catch this --- panda | 2 +- selfdrive/car/interfaces.py | 6 ++---- selfdrive/car/tests/test_fw_fingerprint.py | 20 +++++++++++++++++++- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/panda b/panda index 8c3bb0151e..daa739efb7 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 8c3bb0151e8907ade344ccb293d58cd543e28baa +Subproject commit daa739efb76e2908bf1b2ee064be9034a8e299c3 diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index e491de3ed6..6c6e544f75 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -52,6 +52,7 @@ class LatControlInputs(NamedTuple): aego: float +SendCan = tuple[int, bytes, int] TorqueFromLateralAccelCallbackType = Callable[[LatControlInputs, car.CarParams.LateralTorqueTuning, float, float, bool, bool], float] @@ -109,7 +110,7 @@ class CarInterfaceBase(ABC): dbc_name = "" if self.cp is None else self.cp.dbc_name self.CC: CarControllerBase = CarController(dbc_name, CP, self.VM) - def apply(self, c: car.CarControl, now_nanos: int) -> tuple[car.CarControl.Actuators, list[tuple[int, int, bytes, int]]]: + def apply(self, c: car.CarControl, now_nanos: int) -> tuple[car.CarControl.Actuators, list[SendCan]]: return self.CC.update(c, self.CS, now_nanos) @staticmethod @@ -462,9 +463,6 @@ class CarStateBase(ABC): return None -SendCan = tuple[int, int, bytes, int] - - class CarControllerBase(ABC): def __init__(self, dbc_name: str, CP, VM): self.CP = CP diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py index f872972542..f6f6ed86d7 100644 --- a/selfdrive/car/tests/test_fw_fingerprint.py +++ b/selfdrive/car/tests/test_fw_fingerprint.py @@ -5,11 +5,13 @@ from collections import defaultdict from parameterized import parameterized from cereal import car +from openpilot.selfdrive.car import make_can_msg from openpilot.selfdrive.car.car_helpers import interfaces from openpilot.selfdrive.car.fingerprints import FW_VERSIONS from openpilot.selfdrive.car.fw_versions import ESSENTIAL_ECUS, FW_QUERY_CONFIGS, FUZZY_EXCLUDE_ECUS, VERSIONS, build_fw_dict, \ match_fw_to_car, get_brand_ecu_matches, get_fw_versions, get_present_ecus from openpilot.selfdrive.car.vin import get_vin +from openpilot.selfdrive.pandad import can_list_to_can_capnp CarFw = car.CarParams.CarFw Ecu = car.CarParams.Ecu @@ -19,7 +21,8 @@ ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} class FakeSocket: def receive(self, non_blocking=False): - pass + return (can_list_to_can_capnp([make_can_msg(random.randint(0x600, 0x800), b'\x00' * 8, 0)]) + if random.uniform(0, 1) > 0.5 else None) def send(self, msg): pass @@ -313,3 +316,18 @@ class TestFwFingerprintTiming: total_time = round(total_times[num_pandas], 2) self._assert_timing(total_time, total_ref_time[num_pandas]) print(f'all brands, total FW query time={total_time} seconds') + + def test_get_fw_versions(self, subtests, mocker): + # some coverage on IsoTpParallelQuery and panda UDS library + # TODO: replace this with full fingerprint simulation testing + # https://github.com/commaai/panda/pull/1329 + + def fake_cloudlog_exception(*args, **kwargs): + raise + + mocker.patch("openpilot.selfdrive.car.fw_versions.set_obd_multiplexing", lambda *args: None) + mocker.patch("openpilot.common.swaglog.cloudlog.exception", fake_cloudlog_exception) + fake_socket = FakeSocket() + for brand in FW_QUERY_CONFIGS.keys(): + with subtests.test(brand=brand): + get_fw_versions(fake_socket, fake_socket, brand, num_pandas=1) From 7c112341c358b57ee9d0209cb2b2c53383adcca9 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 31 Jul 2024 15:37:39 -0700 Subject: [PATCH 183/229] Reapply "update to new opendbc API (#32009)" (#33151) This reverts commit ac130001cc83734118524f59a83a96a2065dd56e. --- opendbc | 2 +- selfdrive/car/interfaces.py | 4 ++- selfdrive/car/tests/test_car_interfaces.py | 3 +- selfdrive/car/tests/test_models.py | 3 +- .../lib/longitudinal_mpc_lib/SConscript | 4 +-- selfdrive/controls/radard.py | 4 +-- .../debug/check_can_parser_performance.py | 6 ++-- selfdrive/pandad/SConscript | 4 ++- selfdrive/pandad/__init__.py | 3 +- selfdrive/pandad/can_list_to_can_capnp.cc | 35 +++++++++++++++++-- selfdrive/pandad/pandad_api_impl.pyx | 29 ++++++++++++++- .../examples/subaru_long_accel.ipynb | 3 +- .../examples/subaru_steer_temp_fault.ipynb | 3 +- 13 files changed, 86 insertions(+), 17 deletions(-) diff --git a/opendbc b/opendbc index 8e9d368841..39a5345924 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 8e9d3688412405154a8189c421cfdc9d5feea715 +Subproject commit 39a5345924d2414f05c40d258d359eb8412a0b03 diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 6c6e544f75..2121f433b7 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -18,6 +18,7 @@ from openpilot.selfdrive.car.values import PLATFORMS from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX from openpilot.selfdrive.controls.lib.events import Events from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel +from openpilot.selfdrive.pandad import can_capnp_to_list ButtonType = car.CarState.ButtonEvent.Type GearShifter = car.CarState.GearShifter @@ -232,9 +233,10 @@ class CarInterfaceBase(ABC): def update(self, c: car.CarControl, can_strings: list[bytes]) -> car.CarState: # parse can + can_list = can_capnp_to_list(can_strings) for cp in self.can_parsers: if cp is not None: - cp.update_strings(can_strings) + cp.update_strings(can_list) # get CarState ret = self._update(c) diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index 4ca19f019e..9e3c7d157e 100644 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -15,6 +15,7 @@ from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque from openpilot.selfdrive.controls.lib.longcontrol import LongControl +from openpilot.selfdrive.pandad import can_capnp_to_list from openpilot.selfdrive.test.fuzzy_generation import DrawType, FuzzyGenerator ALL_ECUS = {ecu for ecus in FW_VERSIONS.values() for ecu in ecus.keys()} @@ -128,7 +129,7 @@ class TestCarInterfaces: # Test radar fault if not car_params.radarUnavailable and radar_interface.rcp is not None: - cans = [messaging.new_message('can', 1).to_bytes() for _ in range(5)] + cans = can_capnp_to_list([messaging.new_message('can', 1).to_bytes() for _ in range(5)]) rr = radar_interface.update(cans) assert rr is None or len(rr.errors) > 0 diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index 1d05b7c731..22a80f359a 100644 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -19,6 +19,7 @@ from openpilot.selfdrive.car.honda.values import CAR as HONDA, HondaFlags from openpilot.selfdrive.car.tests.routes import non_tested_cars, routes, CarTestRoute from openpilot.selfdrive.car.values import Platform from openpilot.selfdrive.car.card import Car +from openpilot.selfdrive.pandad import can_capnp_to_list from openpilot.selfdrive.test.helpers import read_segment_list from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT from openpilot.tools.lib.logreader import LogReader, internal_source, openpilotci_source @@ -237,7 +238,7 @@ class TestCarModelBase(unittest.TestCase): # start parsing CAN messages after we've left ELM mode and can expect CAN traffic error_cnt = 0 for i, msg in enumerate(self.can_msgs[self.elm_frame:]): - rr = RI.update((msg.as_builder().to_bytes(),)) + rr = RI.update(can_capnp_to_list((msg.as_builder().to_bytes(),))) if rr is not None and i > 50: error_cnt += car.RadarData.Error.canError in rr.errors self.assertEqual(error_cnt, 0) diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript index fc1e844d50..22342c0078 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript @@ -1,4 +1,4 @@ -Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python', 'np_version') +Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python', 'pandad_python', 'np_version') gen = "c_generated_code" @@ -66,7 +66,7 @@ lenv.Clean(generated_files, Dir(gen)) generated_long = lenv.Command(generated_files, source_list, f"cd {Dir('.').abspath} && python3 long_mpc.py") -lenv.Depends(generated_long, [msgq_python, common_python, opendbc_python]) +lenv.Depends(generated_long, [msgq_python, common_python, opendbc_python, pandad_python]) lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES") lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES") diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index c3fb60c61a..a7e3c0211d 100755 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -10,8 +10,8 @@ from openpilot.common.numpy_fast import interp from openpilot.common.params import Params from openpilot.common.realtime import DT_CTRL, Ratekeeper, Priority, config_realtime_process from openpilot.common.swaglog import cloudlog - from openpilot.common.simple_kalman import KF1D +from openpilot.selfdrive.pandad import can_capnp_to_list # Default lead acceleration decay set to 50% at 1s @@ -307,7 +307,7 @@ def main(): while 1: can_strings = messaging.drain_sock_raw(can_sock, wait_for_one=True) - rr = RI.update(can_strings) + rr = RI.update(can_capnp_to_list(can_strings)) sm.update(0) if rr is None: continue diff --git a/selfdrive/debug/check_can_parser_performance.py b/selfdrive/debug/check_can_parser_performance.py index 604a1df124..a5155f0126 100755 --- a/selfdrive/debug/check_can_parser_performance.py +++ b/selfdrive/debug/check_can_parser_performance.py @@ -6,6 +6,7 @@ from tqdm import tqdm from cereal import car from openpilot.selfdrive.car.tests.routes import CarTestRoute from openpilot.selfdrive.car.tests.test_models import TestCarModelBase +from openpilot.selfdrive.pandad import can_capnp_to_list from openpilot.tools.plotjuggler.juggle import DEMO_ROUTE N_RUNS = 10 @@ -25,12 +26,13 @@ if __name__ == '__main__': CC = car.CarControl.new_message() ets = [] for _ in tqdm(range(N_RUNS)): - msgs = [(m.as_builder().to_bytes(),) for m in tm.can_msgs] + msgs = [m.as_builder().to_bytes() for m in tm.can_msgs] start_t = time.process_time_ns() for msg in msgs: + can_list = can_capnp_to_list([msg]) for cp in tm.CI.can_parsers: if cp is not None: - cp.update_strings(msg) + cp.update_strings(can_list) ets.append((time.process_time_ns() - start_t) * 1e-6) print(f'{len(tm.can_msgs)} CAN packets, {N_RUNS} runs') diff --git a/selfdrive/pandad/SConscript b/selfdrive/pandad/SConscript index 63a2c1e650..dcc1f9811e 100644 --- a/selfdrive/pandad/SConscript +++ b/selfdrive/pandad/SConscript @@ -6,6 +6,8 @@ panda = env.Library('panda', ['panda.cc', 'panda_comms.cc', 'spi.cc']) env.Program('pandad', ['main.cc', 'pandad.cc'], LIBS=[panda] + libs) env.Library('libcan_list_to_can_capnp', ['can_list_to_can_capnp.cc']) -envCython.Program('pandad_api_impl.so', 'pandad_api_impl.pyx', LIBS=["can_list_to_can_capnp", 'capnp', 'kj'] + envCython["LIBS"]) +pandad_python = envCython.Program('pandad_api_impl.so', 'pandad_api_impl.pyx', LIBS=["can_list_to_can_capnp", 'capnp', 'kj'] + envCython["LIBS"]) +Export('pandad_python') + if GetOption('extras'): env.Program('tests/test_pandad_usbprotocol', ['tests/test_pandad_usbprotocol.cc'], LIBS=[panda] + libs) diff --git a/selfdrive/pandad/__init__.py b/selfdrive/pandad/__init__.py index 2c80cd03c4..b72c8ccb57 100644 --- a/selfdrive/pandad/__init__.py +++ b/selfdrive/pandad/__init__.py @@ -1,6 +1,7 @@ # Cython, now uses scons to build -from openpilot.selfdrive.pandad.pandad_api_impl import can_list_to_can_capnp +from openpilot.selfdrive.pandad.pandad_api_impl import can_list_to_can_capnp, can_capnp_to_list assert can_list_to_can_capnp +assert can_capnp_to_list def can_capnp_to_can_list(can, src_filter=None): ret = [] diff --git a/selfdrive/pandad/can_list_to_can_capnp.cc b/selfdrive/pandad/can_list_to_can_capnp.cc index d73541c17f..ad2393b986 100644 --- a/selfdrive/pandad/can_list_to_can_capnp.cc +++ b/selfdrive/pandad/can_list_to_can_capnp.cc @@ -1,11 +1,12 @@ #include "cereal/messaging/messaging.h" #include "selfdrive/pandad/panda.h" +#include "opendbc/can/common.h" -void can_list_to_can_capnp_cpp(const std::vector &can_list, std::string &out, bool sendCan, bool valid) { +void can_list_to_can_capnp_cpp(const std::vector &can_list, std::string &out, bool sendcan, bool valid) { MessageBuilder msg; auto event = msg.initEvent(valid); - auto canData = sendCan ? event.initSendcan(can_list.size()) : event.initCan(can_list.size()); + auto canData = sendcan ? event.initSendcan(can_list.size()) : event.initCan(can_list.size()); int j = 0; for (auto it = can_list.begin(); it != can_list.end(); it++, j++) { auto c = canData[j]; @@ -18,3 +19,33 @@ void can_list_to_can_capnp_cpp(const std::vector &can_list, std::stri kj::ArrayOutputStream output_stream(kj::ArrayPtr((unsigned char *)out.data(), msg_size)); capnp::writeMessage(output_stream, msg); } + +// Converts a vector of Cap'n Proto serialized can strings into a vector of CanData structures. +void can_capnp_to_can_list_cpp(const std::vector &strings, std::vector &can_list, bool sendcan) { + AlignedBuffer aligned_buf; + can_list.reserve(strings.size()); + + for (const auto &str : strings) { + // extract the messages + capnp::FlatArrayMessageReader reader(aligned_buf.align(str.data(), str.size())); + cereal::Event::Reader event = reader.getRoot(); + + auto frames = sendcan ? event.getSendcan() : event.getCan(); + + // Add new CanData entry + CanData &can_data = can_list.emplace_back(); + can_data.nanos = event.getLogMonoTime(); + can_data.frames.reserve(frames.size()); + + // Populate CAN frames + for (const auto &frame : frames) { + CanFrame &can_frame = can_data.frames.emplace_back(); + can_frame.src = frame.getSrc(); + can_frame.address = frame.getAddress(); + + // Copy CAN data + auto dat = frame.getDat(); + can_frame.dat.assign(dat.begin(), dat.end()); + } + } +} diff --git a/selfdrive/pandad/pandad_api_impl.pyx b/selfdrive/pandad/pandad_api_impl.pyx index dd3f3d702f..8a12e1c433 100644 --- a/selfdrive/pandad/pandad_api_impl.pyx +++ b/selfdrive/pandad/pandad_api_impl.pyx @@ -1,8 +1,10 @@ # distutils: language = c++ # cython: language_level=3 +from cython.operator cimport dereference as deref, preincrement as preinc from libcpp.vector cimport vector from libcpp.string cimport string from libcpp cimport bool +from libc.stdint cimport uint8_t, uint32_t, uint64_t cdef extern from "panda.h": cdef struct can_frame: @@ -10,8 +12,19 @@ cdef extern from "panda.h": string dat long src +cdef extern from "opendbc/can/common.h": + cdef struct CanFrame: + long src + uint32_t address + vector[uint8_t] dat + + cdef struct CanData: + uint64_t nanos + vector[CanFrame] frames + cdef extern from "can_list_to_can_capnp.cc": - void can_list_to_can_capnp_cpp(const vector[can_frame] &can_list, string &out, bool sendCan, bool valid) + void can_list_to_can_capnp_cpp(const vector[can_frame] &can_list, string &out, bool sendcan, bool valid) + void can_capnp_to_can_list_cpp(const vector[string] &strings, vector[CanData] &can_data, bool sendcan) def can_list_to_can_capnp(can_msgs, msgtype='can', valid=True): cdef can_frame *f @@ -27,3 +40,17 @@ def can_list_to_can_capnp(can_msgs, msgtype='can', valid=True): cdef string out can_list_to_can_capnp_cpp(can_list, out, msgtype == 'sendcan', valid) return out + +def can_capnp_to_list(strings, msgtype='can'): + cdef vector[CanData] data + can_capnp_to_can_list_cpp(strings, data, msgtype == 'sendcan') + + result = [] + cdef CanData *d + cdef vector[CanData].iterator it = data.begin() + while it != data.end(): + d = &deref(it) + frames = [[f.address, (&f.dat[0])[:f.dat.size()], f.src] for f in d.frames] + result.append([d.nanos, frames]) + preinc(it) + return result diff --git a/tools/car_porting/examples/subaru_long_accel.ipynb b/tools/car_porting/examples/subaru_long_accel.ipynb index 9d18a114df..35b92702a7 100644 --- a/tools/car_porting/examples/subaru_long_accel.ipynb +++ b/tools/car_porting/examples/subaru_long_accel.ipynb @@ -24,6 +24,7 @@ "from opendbc.can.parser import CANParser\n", "\n", "from openpilot.selfdrive.car.subaru.values import DBC\n", + "from openpilot.selfdrive.pandad import can_capnp_to_list\n", "from openpilot.tools.lib.logreader import LogReader\n", "\n", "\"\"\"\n", @@ -50,7 +51,7 @@ "\n", " for msg in lr:\n", " if msg.which() == \"can\":\n", - " cp.update_strings([msg.as_builder().to_bytes()])\n", + " cp.update_strings(can_capnp_to_list([msg.as_builder().to_bytes()]))\n", " es_distance_history.append(copy.copy(cp.vl[\"ES_Distance\"]))\n", " es_brake_history.append(copy.copy(cp.vl[\"ES_Brake\"]))\n", " es_status_history.append(copy.copy(cp.vl[\"ES_Status\"]))\n", diff --git a/tools/car_porting/examples/subaru_steer_temp_fault.ipynb b/tools/car_porting/examples/subaru_steer_temp_fault.ipynb index 3d5055cbc2..8b762fecb8 100644 --- a/tools/car_porting/examples/subaru_steer_temp_fault.ipynb +++ b/tools/car_porting/examples/subaru_steer_temp_fault.ipynb @@ -27,6 +27,7 @@ "from opendbc.can.parser import CANParser\n", "\n", "from openpilot.selfdrive.car.subaru.values import CanBus, DBC\n", + "from openpilot.selfdrive.pandad import can_capnp_to_list\n", "from openpilot.tools.lib.logreader import LogReader\n", "\n", "\"\"\"\n", @@ -50,7 +51,7 @@ " examples = []\n", "\n", " for msg in can_msgs:\n", - " cp.update_strings([msg.as_builder().to_bytes()])\n", + " cp.update_strings(can_capnp_to_list([msg.as_builder().to_bytes()]))\n", " steering_torque_history.append(copy.copy(cp.vl[\"Steering_Torque\"]))\n", "\n", " steer_warning_last = False\n", From b3926faebb00a8c571338aedec081191a8e28cfb Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Wed, 31 Jul 2024 14:41:17 -0800 Subject: [PATCH 184/229] Revert "MADS: Map cruise main and lateral buttons to button events" (#372) Revert "MADS: Map cruise main and lateral buttons to button events (#361)" This reverts commit 4d7afe3a7bbcd4f31ee309a6aa2f5db93367daae. --- selfdrive/car/chrysler/interface.py | 3 +-- selfdrive/car/ford/interface.py | 3 +-- selfdrive/car/gm/interface.py | 4 +--- selfdrive/car/honda/interface.py | 2 +- selfdrive/car/hyundai/interface.py | 14 ++++++++------ selfdrive/car/mazda/interface.py | 8 +++++--- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index f4881dd363..d4911375e7 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -94,7 +94,6 @@ class CarInterface(CarInterfaceBase): self.sp_update_params() self.CS.button_events.extend(create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})) - self.CS.button_events.extend(create_button_events(self.CS.lkas_enabled, self.CS.prev_lkas_enabled, {1: ButtonType.altButton1})) self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) @@ -109,7 +108,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): + if self.CS.prev_lkas_enabled != 1 and self.CS.lkas_enabled == 1: self.CS.madsEnabled = not self.CS.madsEnabled self.CS.lkas_disabled = not self.CS.lkas_disabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index b0a1c15f34..18dd7b4fa3 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -75,7 +75,6 @@ class CarInterface(CarInterfaceBase): self.sp_update_params() self.CS.button_events.extend(create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})) - self.CS.button_events.extend(create_button_events(self.CS.lkas_enabled, self.CS.prev_lkas_enabled, {1: ButtonType.altButton1})) self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) @@ -86,7 +85,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): + if not self.CS.prev_lkas_enabled and self.CS.lkas_enabled: self.CS.madsEnabled = not self.CS.madsEnabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) else: diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 4a1e459722..0e428bc13b 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -218,8 +218,6 @@ class CarInterface(CarInterfaceBase): ] distance_button = self.CS.distance_button - self.CS.button_events.extend(create_button_events(self.CS.lkas_enabled, self.CS.prev_lkas_enabled, {1: ButtonType.altButton1})) - self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) if not self.CP.pcmCruise: @@ -233,7 +231,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): + if self.CS.prev_lkas_enabled != 1 and self.CS.lkas_enabled == 1: self.CS.madsEnabled = not self.CS.madsEnabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) else: diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index af294a63a7..72ab68647f 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -282,7 +282,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): + if self.CS.prev_cruise_setting != 1 and self.CS.cruise_setting == 1: self.CS.madsEnabled = not self.CS.madsEnabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) else: diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 72a12b0ba8..dbe0b62895 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -205,9 +205,7 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_cam) self.sp_update_params() - self.CS.button_events.extend(create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT)) - self.CS.button_events.extend(create_button_events(self.CS.lfa_enabled, self.CS.prev_lfa_enabled, {1: ButtonType.altButton1})) - self.CS.button_events.extend(create_button_events(self.CS.main_buttons[-1], self.CS.prev_main_buttons, {1: ButtonType.altButton3})) + self.CS.button_events = create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT) self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled, self.CS.button_events, c.vCruise) @@ -216,12 +214,16 @@ class CarInterface(CarInterfaceBase): if ret.cruiseState.available: if not self.CP.pcmCruiseSpeed: - if any(b.type in (ButtonType.altButton3, ButtonType.cancel) and not b.pressed for b in self.CS.button_events): - self.CS.accEnabled = True + if self.CS.prev_main_buttons == 1: + if self.CS.main_buttons[-1] != 1: + self.CS.accEnabled = True + elif self.CS.prev_cruise_buttons == 4: + if self.CS.cruise_buttons[-1] != 4: + self.accEnabled = True if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): + if self.CS.prev_lfa_enabled != 1 and self.CS.lfa_enabled == 1: self.CS.madsEnabled = not self.CS.madsEnabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) else: diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py index 2bd4f71c78..9447803ae6 100755 --- a/selfdrive/car/mazda/interface.py +++ b/selfdrive/car/mazda/interface.py @@ -40,8 +40,10 @@ class CarInterface(CarInterfaceBase): self.sp_update_params() # TODO: add button types for inc and dec - self.CS.button_events.extend(create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})) - self.CS.button_events.extend(create_button_events(self.CS.lkas_enabled, self.CS.prev_lkas_enabled, {1: ButtonType.altButton1})) + self.CS.button_events = [ + *self.CS.button_events, + *create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}) + ] self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) @@ -52,7 +54,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): + if self.CS.prev_lkas_enabled != self.CS.lkas_enabled: self.CS.madsEnabled = not self.CS.madsEnabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) else: From 7de618a5cf38a759d3986d775f7d7f7a35167050 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 31 Jul 2024 16:12:37 -0700 Subject: [PATCH 185/229] ensure alerts_generated.h is built (#33157) don't build alerts_generated.h in test, and ensure scons builds it more reliably + clean up support --- selfdrive/ui/SConscript | 2 +- selfdrive/ui/update_translations.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index c6b4860bf7..509f2aebd1 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -40,7 +40,7 @@ translation_sources = [f"#selfdrive/ui/translations/{l}.ts" for l in languages.v translation_targets = [src.replace(".ts", ".qm") for src in translation_sources] lrelease_bin = 'third_party/qt5/larch64/bin/lrelease' if arch == 'larch64' else 'lrelease' -lupdate = qt_env.Command(translation_sources, qt_src + widgets_src, "selfdrive/ui/update_translations.py") +lupdate = qt_env.Command(translation_sources + ["translations/alerts_generated.h"], qt_src + widgets_src, "selfdrive/ui/update_translations.py") lrelease = qt_env.Command(translation_targets, translation_sources, f"{lrelease_bin} $SOURCES") qt_env.Depends(lrelease, lupdate) qt_env.NoClean(translation_sources) diff --git a/selfdrive/ui/update_translations.py b/selfdrive/ui/update_translations.py index 0fe0f05ac4..f13c65fdae 100755 --- a/selfdrive/ui/update_translations.py +++ b/selfdrive/ui/update_translations.py @@ -25,8 +25,6 @@ def generate_translations_include(): def update_translations(vanish: bool = False, translation_files: None | list[str] = None, translations_dir: str = TRANSLATIONS_DIR): - generate_translations_include() - if translation_files is None: with open(LANGUAGES_FILE) as f: translation_files = json.load(f).values() @@ -48,4 +46,5 @@ if __name__ == "__main__": parser.add_argument("--vanish", action="store_true", help="Remove translations with source text no longer found") args = parser.parse_args() + generate_translations_include() update_translations(args.vanish) From fa3a0ba747041b1b2a6d43fa61bdeef1ba9ba5df Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Wed, 31 Jul 2024 15:47:34 -0800 Subject: [PATCH 186/229] CI: Update prebuilt repository URL (#374) --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2704a7bb28..f1fe0226cc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -202,7 +202,7 @@ check no source code sent: publish to private gitlab prebuilt: extends: ".publish_base" variables: - GIT_ORIGIN: git@gitlab.com:sunnypilot/public/sunnypilot.git + GIT_ORIGIN: git@gitlab.com:sunnypilot/public/sunnypilot-prebuilts.git rules: - if: $NEW_BRANCH when: on_success From 3ccc63deec85f454521d465c4e0e3438e76cb547 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Wed, 31 Jul 2024 19:10:44 -0700 Subject: [PATCH 187/229] camerad: use os binning (#33161) * all * right sz * what is this * Revert "what is this" This reverts commit 3ff771926f109452a055dfb61cee06b34e498164. * ok * big * update intrs * fl * more specifuc * fish * revert * revert --------- Co-authored-by: Comma Device --- common/transformations/camera.py | 4 +-- system/camerad/cameras/camera_common.cc | 2 +- system/camerad/sensors/os04c10.cc | 6 ++-- system/camerad/sensors/os04c10_registers.h | 42 +++++++++++----------- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/common/transformations/camera.py b/common/transformations/camera.py index dc3ca5f388..2e68b5e37c 100644 --- a/common/transformations/camera.py +++ b/common/transformations/camera.py @@ -47,9 +47,9 @@ class DeviceCameraConfig: yield cam, getattr(self, cam) _ar_ox_fisheye = CameraConfig(1928, 1208, 567.0) # focal length probably wrong? magnification is not consistent across frame -_os_fisheye = CameraConfig(2688, 1520, 567.0 / 2 * 3) +_os_fisheye = CameraConfig(2688 // 2, 1520 // 2, 567.0 / 4 * 3) _ar_ox_config = DeviceCameraConfig(CameraConfig(1928, 1208, 2648.0), _ar_ox_fisheye, _ar_ox_fisheye) -_os_config = DeviceCameraConfig(CameraConfig(2688, 1520, 2648.0 * 2 / 3), _os_fisheye, _os_fisheye) +_os_config = DeviceCameraConfig(CameraConfig(2688 // 2, 1520 // 2, 1522.0 * 3 / 4), _os_fisheye, _os_fisheye) _neo_config = DeviceCameraConfig(CameraConfig(1164, 874, 910.0), CameraConfig(816, 612, 650.0), _NoneCameraConfig()) DEVICE_CAMERAS = { diff --git a/system/camerad/cameras/camera_common.cc b/system/camerad/cameras/camera_common.cc index 542be29d80..06ef2bd378 100644 --- a/system/camerad/cameras/camera_common.cc +++ b/system/camerad/cameras/camera_common.cc @@ -84,7 +84,7 @@ void CameraBuf::init(cl_device_id device_id, cl_context context, CameraState *s, // the encoder HW tells us the size it wants after setting it up. // TODO: VENUS_BUFFER_SIZE should give the size, but it's too small. dependent on encoder settings? - size_t nv12_size = (rgb_width >= 2688 ? 2900 : 2346)*nv12_width; + size_t nv12_size = (rgb_width <= 1344 ? 2900 : 2346)*nv12_width; vipc_server->create_buffers_with_sizes(stream_type, YUV_BUFFER_COUNT, false, rgb_width, rgb_height, nv12_size, nv12_width, nv12_uv_offset); LOGD("created %d YUV vipc buffers with size %dx%d", YUV_BUFFER_COUNT, nv12_width, nv12_height); diff --git a/system/camerad/sensors/os04c10.cc b/system/camerad/sensors/os04c10.cc index 97a317407a..e651d6ff7a 100644 --- a/system/camerad/sensors/os04c10.cc +++ b/system/camerad/sensors/os04c10.cc @@ -20,12 +20,12 @@ const uint32_t os04c10_analog_gains_reg[] = { OS04C10::OS04C10() { image_sensor = cereal::FrameData::ImageSensor::OS04C10; - pixel_size_mm = 0.002; + pixel_size_mm = 0.004; data_word = false; hdr_offset = 64 * 2 + 8; // stagger - frame_width = 2688; - frame_height = 1520 * 2 + hdr_offset; + frame_width = 1344; + frame_height = 760 * 2 + hdr_offset; frame_stride = (frame_width * 10 / 8); // no alignment extra_height = 0; diff --git a/system/camerad/sensors/os04c10_registers.h b/system/camerad/sensors/os04c10_registers.h index 91eb48b24f..d698b1311f 100644 --- a/system/camerad/sensors/os04c10_registers.h +++ b/system/camerad/sensors/os04c10_registers.h @@ -95,7 +95,7 @@ const struct i2c_random_wr_payload init_array_os04c10[] = { {0x388b, 0x00}, {0x3c80, 0x10}, {0x3c86, 0x00}, - // {0x3c8c, 0x20}, + {0x3c8c, 0x20}, {0x3c9f, 0x01}, {0x3d85, 0x1b}, {0x3d8c, 0x71}, @@ -199,7 +199,7 @@ const struct i2c_random_wr_payload init_array_os04c10[] = { {0x370b, 0xa2}, {0x370c, 0x01}, {0x370f, 0x00}, - {0x3714, 0x24}, + {0x3714, 0x28}, {0x3716, 0x04}, {0x3719, 0x11}, {0x371a, 0x1e}, @@ -231,24 +231,24 @@ const struct i2c_random_wr_payload init_array_os04c10[] = { {0x37bd, 0x01}, {0x37bf, 0x26}, {0x37c0, 0x11}, - {0x37c2, 0x04}, + {0x37c2, 0x14}, {0x37cd, 0x19}, - // {0x37e0, 0x08}, - // {0x37e6, 0x04}, + {0x37e0, 0x08}, + {0x37e6, 0x04}, {0x37e5, 0x02}, - // {0x37e1, 0x0c}, - // {0x3737, 0x04}, + {0x37e1, 0x0c}, + {0x3737, 0x04}, {0x37d8, 0x02}, - // {0x37e2, 0x10}, + {0x37e2, 0x10}, {0x3739, 0x10}, - {0x3662, 0x10}, - // {0x37e4, 0x20}, - // {0x37e3, 0x08}, - {0x37d9, 0x08}, + {0x3662, 0x08}, + {0x37e4, 0x20}, + {0x37e3, 0x08}, + {0x37d9, 0x04}, {0x4040, 0x00}, - {0x4041, 0x07}, - {0x4008, 0x02}, - {0x4009, 0x0d}, + {0x4041, 0x03}, + {0x4008, 0x01}, + {0x4009, 0x06}, // FSIN {0x3002, 0x22}, @@ -269,20 +269,20 @@ const struct i2c_random_wr_payload init_array_os04c10[] = { {0x3802, 0x00}, {0x3803, 0x00}, {0x3804, 0x0a}, {0x3805, 0x8f}, {0x3806, 0x05}, {0x3807, 0xff}, - {0x3808, 0x0a}, {0x3809, 0x80}, - {0x380a, 0x05}, {0x380b, 0xf0}, + {0x3808, 0x05}, {0x3809, 0x40}, + {0x380a, 0x02}, {0x380b, 0xf8}, {0x3811, 0x08}, {0x3813, 0x08}, - {0x3814, 0x01}, + {0x3814, 0x03}, {0x3815, 0x01}, - {0x3816, 0x01}, + {0x3816, 0x03}, {0x3817, 0x01}, {0x380c, 0x04}, {0x380d, 0x2e}, // HTS {0x380e, 0x09}, {0x380f, 0xdb}, // VTS - {0x3820, 0xb0}, - {0x3821, 0x04}, + {0x3820, 0xb3}, + {0x3821, 0x05}, {0x3880, 0x00}, {0x3882, 0x20}, {0x3c91, 0x0b}, From 16ea2ff270165e027370ddff67952b46404d01fb Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Wed, 31 Jul 2024 19:37:06 -0700 Subject: [PATCH 188/229] op.sh: call directly instead of sourcing (#33160) no source --- tools/op.sh | 114 ++++------------------------------------------------ 1 file changed, 8 insertions(+), 106 deletions(-) diff --git a/tools/op.sh b/tools/op.sh index 3ebd413a79..ec4728ddf1 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -1,24 +1,22 @@ #!/usr/bin/env bash +set -e + RED='\033[0;31m' GREEN='\033[0;32m' UNDERLINE='\033[4m' BOLD='\033[1m' NC='\033[0m' +RC_FILE="${HOME}/.$(basename ${SHELL})rc" +if [ "$(uname)" == "Darwin" ] && [ $SHELL == "/bin/bash" ]; then + RC_FILE="$HOME/.bash_profile" +fi function op_install() { - (set -e - echo "Installing op system-wide..." - RC_FILE="${HOME}/.$(basename ${SHELL})rc" - if [ "$(uname)" == "Darwin" ] && [ $SHELL == "/bin/bash" ]; then - RC_FILE="$HOME/.bash_profile" - fi - CMD="\nalias op='source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/op.sh" \"\$@\"'\n" + CMD="\nalias op='"$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/op.sh" \"\$@\"'\n" grep "alias op=" "$RC_FILE" &> /dev/null || printf "$CMD" >> $RC_FILE echo -e " ↳ [${GREEN}✔${NC}] op installed successfully. Open a new shell to use it.\n" - - ) } function op_run_command() { @@ -55,8 +53,6 @@ function op_check_openpilot_dir() { } function op_check_git() { - (set -e - echo "Checking for git..." if ! command -v "git" > /dev/null 2>&1; then echo -e " ↳ [${RED}✗${NC}] git not found on your system!" @@ -81,13 +77,9 @@ function op_check_git() { fi done echo -e " ↳ [${GREEN}✔${NC}] git submodules found." - - ) } function op_check_os() { - (set -e - echo "Checking for compatible os version..." if [[ "$OSTYPE" == "linux-gnu"* ]]; then @@ -113,13 +105,9 @@ function op_check_os() { echo -e " ↳ [${RED}✗${NC}] OS type $OSTYPE not supported!" return 1 fi - - ) } function op_check_python() { - (set -e - echo "Checking for compatible python version..." REQUIRED_PYTHON_VERSION=$(grep "requires-python" $OPENPILOT_ROOT/pyproject.toml) INSTALLED_PYTHON_VERSION=$(python3 --version 2> /dev/null || true) @@ -133,8 +121,6 @@ function op_check_python() { echo -e " ↳ [${RED}✗${NC}] You need python version at least $(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9.]') to continue!" return 1 fi - - ) } function op_check_venv() { @@ -171,8 +157,6 @@ function op_before_cmd() { } function op_setup() { - (set -e - op_get_openpilot_dir cd $OPENPILOT_ROOT @@ -203,8 +187,6 @@ function op_setup() { echo -e " ↳ [${GREEN}✔${NC}] Files pulled successfully in $((et - st)) seconds.\n" op_check - - ) } function op_activate_venv() { @@ -212,99 +194,52 @@ function op_activate_venv() { } function op_venv() { - ( set -e - op_before_cmd - - ) - - if [[ "$?" -eq 0 ]]; then - - if [[ "${BASH_SOURCE[0]}" = "${0}" ]]; then - echo "Run 'op venv' or 'source op.sh venv' to activate your venv!" - return 1 - fi - - # this must be run in the same shell as the user calling "op" - op_get_openpilot_dir - op_run_command source $OPENPILOT_ROOT/.venv/bin/activate - fi + bash --rcfile <(echo "source $RC_FILE; source $OPENPILOT_ROOT/.venv/bin/activate") } function op_check() { - (set -e - VERBOSE=1 op_before_cmd unset VERBOSE - - ) } function op_build() { - (set -e - CDIR=$(pwd) op_before_cmd cd "$CDIR" op_run_command scons $@ - - ) } function op_juggle() { - (set -e - op_before_cmd op_run_command tools/plotjuggler/juggle.py $@ - - ) } function op_lint() { - (set -e - op_before_cmd op_run_command pre-commit run --all $@ - - ) } function op_test() { - (set -e - op_before_cmd op_run_command pytest $@ - - ) } function op_replay() { - (set -e - op_before_cmd op_run_command tools/replay/replay $@ - - ) } function op_cabana() { - (set -e - op_before_cmd op_run_command tools/cabana/cabana $@ - - ) } function op_sim() { - (set -e - op_before_cmd op_run_command exec tools/sim/run_bridge.py & op_run_command exec tools/sim/launch_openpilot.sh - - ) } function op_default() { @@ -387,36 +322,3 @@ function _op() { } _op $@ - -# remove from env -unset -f _op -unset -f op_check -unset -f op_setup -unset -f op_build -unset -f op_juggle -unset -f op_venv -unset -f op_check_openpilot_dir -unset -f op_check_git -unset -f op_check_python -unset -f op_check_os -unset -f op_install -unset -f op_default -unset -f op_run_command -unset -f op_lint -unset -f op_replay -unset -f op_cabana -unset -f op_check_venv -unset -f op_before_cmd -unset -f op_sim -unset -f op_activate_venv -unset -f op_get_openpilot_dir -unset -f op_test -unset DRY -unset NC -unset RED -unset GREEN -unset UNDERLINE -unset BOLD -unset OPENPILOT_ROOT -unset NO_VERIFY -unset VERBOSE From 3e66827a8501c792fde66f16c65e5297ab51fa2d Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Wed, 31 Jul 2024 20:32:41 -0700 Subject: [PATCH 189/229] setup.sh: work in non interactive mode (#33162) * work without terminal * failure message * no if --- tools/install_ubuntu_dependencies.sh | 7 ++++++- tools/setup.sh | 16 ++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/tools/install_ubuntu_dependencies.sh b/tools/install_ubuntu_dependencies.sh index 67b28fa280..a7cf0e75c3 100755 --- a/tools/install_ubuntu_dependencies.sh +++ b/tools/install_ubuntu_dependencies.sh @@ -12,6 +12,11 @@ if [[ ! $(id -u) -eq 0 ]]; then SUDO="sudo" fi +# Check if stdin is open +if [ -t 0 ]; then + INTERACTIVE=1 +fi + # Install common packages function install_ubuntu_common_requirements() { $SUDO apt-get update @@ -133,7 +138,7 @@ if [ -f "/etc/os-release" ]; then esac # Install extra packages - if [[ -z "$INSTALL_EXTRA_PACKAGES" ]]; then + if [[ -z "$INSTALL_EXTRA_PACKAGES" && -n "$INTERACTIVE" ]]; then read -p "Base setup done. Do you want to install extra development packages? [Y/n]: " -n 1 -r echo "" if [[ $REPLY =~ ^[Yy]$ ]]; then diff --git a/tools/setup.sh b/tools/setup.sh index e770ba48aa..b2b9563d30 100755 --- a/tools/setup.sh +++ b/tools/setup.sh @@ -73,9 +73,14 @@ function check_dir() { return 1 fi + # already a "valid" openpilot clone, skip cloning again + if [[ ! -z "$(ls -A $OPENPILOT_ROOT)" ]]; then + SKIP_GIT_CLONE=1 + fi + # by default, don't try installing in already existing directory if [[ -z $INTERACTIVE ]]; then - return 1 + return 0 fi read -p " Would you like to attempt installation anyway? [Y/n] " -n 1 -r @@ -84,11 +89,6 @@ function check_dir() { return 1 fi - # already a "valid" openpilot clone, skip cloning again - if [[ ! -z "$(ls -A $OPENPILOT_ROOT)" ]]; then - SKIP_GIT_CLONE=1 - fi - return 0 fi @@ -123,10 +123,10 @@ function git_clone() { function install_with_op() { cd $OPENPILOT_ROOT $OPENPILOT_ROOT/tools/op.sh install - $OPENPILOT_ROOT/tools/op.sh setup + $OPENPILOT_ROOT/tools/op.sh setup || (echo -e "\n[${RED}✗${NC}] failed to install openpilot!" && return 1) echo -e "\n----------------------------------------------------------------------" - echo -e "openpilot was successfully installed into ${BOLD}$OPENPILOT_ROOT${NC}" + echo -e "[${GREEN}✔${NC}] openpilot was successfully installed into ${BOLD}$OPENPILOT_ROOT${NC}" echo -e "Checkout the docs at https://docs.comma.ai" echo -e "Checkout how to contribute at https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md" } From 7bf912f40740b4cca62ddc65bd82700615636550 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Wed, 31 Jul 2024 21:40:48 -0700 Subject: [PATCH 190/229] op.sh: fix python version check (#33163) fix check --- tools/op.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/op.sh b/tools/op.sh index ec4728ddf1..1715aaab63 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -115,7 +115,7 @@ function op_check_python() { if [[ -z $INSTALLED_PYTHON_VERSION ]]; then echo -e " ↳ [${RED}✗${NC}] python3 not found on your system. You need python version at least $(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9.]') to continue!" return 1 - elif [[ $(echo $INSTALLED_PYTHON_VERSION | tr -d -c '[0-9]') -ge $(($(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9]') * 10)) ]]; then + elif [[ $(echo $INSTALLED_PYTHON_VERSION | grep -o '[0-9]\+\.[0-9]\+' | tr -d -c '[0-9]') -ge $(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9]') ]]; then echo -e " ↳ [${GREEN}✔${NC}] $INSTALLED_PYTHON_VERSION detected." else echo -e " ↳ [${RED}✗${NC}] You need python version at least $(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9.]') to continue!" From 7ee9d2d1b93abb3ccba53f9552b716d3a11c2b6d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 31 Jul 2024 23:17:40 -0700 Subject: [PATCH 191/229] opendbc is a package (#33159) * bump * rename to opendbc_repo add symlink * bump * fix cabana fix cabana * bump * fix whitelist paths bump * bump to master * remove trailing slash --- .gitmodules | 2 +- opendbc | 2 +- opendbc_repo | 1 + release/release_files.py | 102 +++++++++++++++++++-------------------- tools/cabana/SConscript | 2 +- 5 files changed, 55 insertions(+), 54 deletions(-) mode change 160000 => 120000 opendbc create mode 160000 opendbc_repo diff --git a/.gitmodules b/.gitmodules index 1d5d04577e..ad6530de9a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,7 +2,7 @@ path = panda url = ../../commaai/panda.git [submodule "opendbc"] - path = opendbc + path = opendbc_repo url = ../../commaai/opendbc.git [submodule "msgq"] path = msgq_repo diff --git a/opendbc b/opendbc deleted file mode 160000 index 39a5345924..0000000000 --- a/opendbc +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 39a5345924d2414f05c40d258d359eb8412a0b03 diff --git a/opendbc b/opendbc new file mode 120000 index 0000000000..7cd9a5bd1e --- /dev/null +++ b/opendbc @@ -0,0 +1 @@ +opendbc_repo/opendbc \ No newline at end of file diff --git a/opendbc_repo b/opendbc_repo new file mode 160000 index 0000000000..a40652d341 --- /dev/null +++ b/opendbc_repo @@ -0,0 +1 @@ +Subproject commit a40652d341ea3161a6a10001fa74284d9d650f8c diff --git a/release/release_files.py b/release/release_files.py index 1590807435..be9ad75ed5 100755 --- a/release/release_files.py +++ b/release/release_files.py @@ -14,8 +14,8 @@ blacklist = [ "panda/examples/", "panda/tests/safety/", - "opendbc/.*.dbc$", - "opendbc/generator/", + "opendbc_repo/dbc/.*.dbc$", + "opendbc_repo/dbc/generator/", "cereal/.*test.*", "^common/tests/", @@ -74,55 +74,55 @@ whitelist = [ "tinygrad_repo/tinygrad/.*.py", # TODO: do this automatically - "opendbc/comma_body.dbc", - "opendbc/chrysler_ram_hd_generated.dbc", - "opendbc/chrysler_ram_dt_generated.dbc", - "opendbc/chrysler_pacifica_2017_hybrid_generated.dbc", - "opendbc/chrysler_pacifica_2017_hybrid_private_fusion.dbc", - "opendbc/gm_global_a_powertrain_generated.dbc", - "opendbc/gm_global_a_object.dbc", - "opendbc/gm_global_a_chassis.dbc", - "opendbc/FORD_CADS.dbc", - "opendbc/ford_fusion_2018_adas.dbc", - "opendbc/ford_lincoln_base_pt.dbc", - "opendbc/honda_accord_2018_can_generated.dbc", - "opendbc/acura_ilx_2016_can_generated.dbc", - "opendbc/acura_rdx_2018_can_generated.dbc", - "opendbc/acura_rdx_2020_can_generated.dbc", - "opendbc/honda_civic_touring_2016_can_generated.dbc", - "opendbc/honda_civic_hatchback_ex_2017_can_generated.dbc", - "opendbc/honda_crv_touring_2016_can_generated.dbc", - "opendbc/honda_crv_ex_2017_can_generated.dbc", - "opendbc/honda_crv_ex_2017_body_generated.dbc", - "opendbc/honda_crv_executive_2016_can_generated.dbc", - "opendbc/honda_fit_ex_2018_can_generated.dbc", - "opendbc/honda_odyssey_exl_2018_generated.dbc", - "opendbc/honda_odyssey_extreme_edition_2018_china_can_generated.dbc", - "opendbc/honda_insight_ex_2019_can_generated.dbc", - "opendbc/acura_ilx_2016_nidec.dbc", - "opendbc/honda_civic_ex_2022_can_generated.dbc", - "opendbc/hyundai_canfd.dbc", - "opendbc/hyundai_kia_generic.dbc", - "opendbc/hyundai_kia_mando_front_radar_generated.dbc", - "opendbc/mazda_2017.dbc", - "opendbc/nissan_x_trail_2017_generated.dbc", - "opendbc/nissan_leaf_2018_generated.dbc", - "opendbc/subaru_global_2017_generated.dbc", - "opendbc/subaru_global_2020_hybrid_generated.dbc", - "opendbc/subaru_outback_2015_generated.dbc", - "opendbc/subaru_outback_2019_generated.dbc", - "opendbc/subaru_forester_2017_generated.dbc", - "opendbc/toyota_tnga_k_pt_generated.dbc", - "opendbc/toyota_new_mc_pt_generated.dbc", - "opendbc/toyota_nodsu_pt_generated.dbc", - "opendbc/toyota_adas.dbc", - "opendbc/toyota_tss2_adas.dbc", - "opendbc/vw_golf_mk4.dbc", - "opendbc/vw_mqb_2010.dbc", - "opendbc/tesla_can.dbc", - "opendbc/tesla_radar_bosch_generated.dbc", - "opendbc/tesla_radar_continental_generated.dbc", - "opendbc/tesla_powertrain.dbc", + "opendbc_repo/dbc/comma_body.dbc", + "opendbc_repo/dbc/chrysler_ram_hd_generated.dbc", + "opendbc_repo/dbc/chrysler_ram_dt_generated.dbc", + "opendbc_repo/dbc/chrysler_pacifica_2017_hybrid_generated.dbc", + "opendbc_repo/dbc/chrysler_pacifica_2017_hybrid_private_fusion.dbc", + "opendbc_repo/dbc/gm_global_a_powertrain_generated.dbc", + "opendbc_repo/dbc/gm_global_a_object.dbc", + "opendbc_repo/dbc/gm_global_a_chassis.dbc", + "opendbc_repo/dbc/FORD_CADS.dbc", + "opendbc_repo/dbc/ford_fusion_2018_adas.dbc", + "opendbc_repo/dbc/ford_lincoln_base_pt.dbc", + "opendbc_repo/dbc/honda_accord_2018_can_generated.dbc", + "opendbc_repo/dbc/acura_ilx_2016_can_generated.dbc", + "opendbc_repo/dbc/acura_rdx_2018_can_generated.dbc", + "opendbc_repo/dbc/acura_rdx_2020_can_generated.dbc", + "opendbc_repo/dbc/honda_civic_touring_2016_can_generated.dbc", + "opendbc_repo/dbc/honda_civic_hatchback_ex_2017_can_generated.dbc", + "opendbc_repo/dbc/honda_crv_touring_2016_can_generated.dbc", + "opendbc_repo/dbc/honda_crv_ex_2017_can_generated.dbc", + "opendbc_repo/dbc/honda_crv_ex_2017_body_generated.dbc", + "opendbc_repo/dbc/honda_crv_executive_2016_can_generated.dbc", + "opendbc_repo/dbc/honda_fit_ex_2018_can_generated.dbc", + "opendbc_repo/dbc/honda_odyssey_exl_2018_generated.dbc", + "opendbc_repo/dbc/honda_odyssey_extreme_edition_2018_china_can_generated.dbc", + "opendbc_repo/dbc/honda_insight_ex_2019_can_generated.dbc", + "opendbc_repo/dbc/acura_ilx_2016_nidec.dbc", + "opendbc_repo/dbc/honda_civic_ex_2022_can_generated.dbc", + "opendbc_repo/dbc/hyundai_canfd.dbc", + "opendbc_repo/dbc/hyundai_kia_generic.dbc", + "opendbc_repo/dbc/hyundai_kia_mando_front_radar_generated.dbc", + "opendbc_repo/dbc/mazda_2017.dbc", + "opendbc_repo/dbc/nissan_x_trail_2017_generated.dbc", + "opendbc_repo/dbc/nissan_leaf_2018_generated.dbc", + "opendbc_repo/dbc/subaru_global_2017_generated.dbc", + "opendbc_repo/dbc/subaru_global_2020_hybrid_generated.dbc", + "opendbc_repo/dbc/subaru_outback_2015_generated.dbc", + "opendbc_repo/dbc/subaru_outback_2019_generated.dbc", + "opendbc_repo/dbc/subaru_forester_2017_generated.dbc", + "opendbc_repo/dbc/toyota_tnga_k_pt_generated.dbc", + "opendbc_repo/dbc/toyota_new_mc_pt_generated.dbc", + "opendbc_repo/dbc/toyota_nodsu_pt_generated.dbc", + "opendbc_repo/dbc/toyota_adas.dbc", + "opendbc_repo/dbc/toyota_tss2_adas.dbc", + "opendbc_repo/dbc/vw_golf_mk4.dbc", + "opendbc_repo/dbc/vw_mqb_2010.dbc", + "opendbc_repo/dbc/tesla_can.dbc", + "opendbc_repo/dbc/tesla_radar_bosch_generated.dbc", + "opendbc_repo/dbc/tesla_radar_continental_generated.dbc", + "opendbc_repo/dbc/tesla_powertrain.dbc", ] diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 04b768dc69..911ac9324c 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -16,7 +16,7 @@ qt_libs = ['qt_util'] + base_libs cabana_env = qt_env.Clone() cabana_libs = [widgets, cereal, messaging, visionipc, replay_lib, 'panda', 'avutil', 'avcodec', 'avformat', 'bz2', 'zstd', 'curl', 'yuv', 'usb-1.0'] + qt_libs -opendbc_path = '-DOPENDBC_FILE_PATH=\'"%s"\'' % (cabana_env.Dir("../../opendbc").abspath) +opendbc_path = '-DOPENDBC_FILE_PATH=\'"%s"\'' % (cabana_env.Dir("../../opendbc/dbc").abspath) cabana_env['CXXFLAGS'] += [opendbc_path] # build assets From 54d52810642af9eea69e640360ea64993b395c05 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Thu, 1 Aug 2024 06:26:27 -0800 Subject: [PATCH 192/229] MADS: Map cruise main and lateral buttons to button events (#373) * MADS: Map cruise main and lateral buttons to button events * MADS: Map cruise main and lateral buttons to button events * different style * nah (cherry picked from commit 4d7afe3a7bbcd4f31ee309a6aa2f5db93367daae) * reimplement --- selfdrive/car/chrysler/interface.py | 8 ++++++-- selfdrive/car/ford/interface.py | 8 ++++++-- selfdrive/car/gm/interface.py | 7 ++++++- selfdrive/car/honda/interface.py | 2 +- selfdrive/car/hyundai/interface.py | 16 ++++++++-------- selfdrive/car/mazda/interface.py | 5 +++-- 6 files changed, 30 insertions(+), 16 deletions(-) diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index d4911375e7..38d7cf0828 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -93,7 +93,11 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_cam) self.sp_update_params() - self.CS.button_events.extend(create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})) + self.CS.button_events = [ + *self.CS.button_events, + *create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}), + *create_button_events(self.CS.lkas_enabled, self.CS.prev_lkas_enabled, {1: ButtonType.altButton1}), + ] self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) @@ -108,7 +112,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if self.CS.prev_lkas_enabled != 1 and self.CS.lkas_enabled == 1: + if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): self.CS.madsEnabled = not self.CS.madsEnabled self.CS.lkas_disabled = not self.CS.lkas_disabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 18dd7b4fa3..080663c9cf 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -74,7 +74,11 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_cam) self.sp_update_params() - self.CS.button_events.extend(create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})) + self.CS.button_events = [ + *self.CS.button_events, + *create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}), + *create_button_events(self.CS.lkas_enabled, self.CS.prev_lkas_enabled, {1: ButtonType.altButton1}), + ] self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) @@ -85,7 +89,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if not self.CS.prev_lkas_enabled and self.CS.lkas_enabled: + if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): self.CS.madsEnabled = not self.CS.madsEnabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) else: diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 0e428bc13b..726af2afac 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -218,6 +218,11 @@ class CarInterface(CarInterfaceBase): ] distance_button = self.CS.distance_button + self.CS.button_events = [ + *self.CS.button_events, + *create_button_events(self.CS.lkas_enabled, self.CS.prev_lkas_enabled, {1: ButtonType.altButton1}), + ] + self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) if not self.CP.pcmCruise: @@ -231,7 +236,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if self.CS.prev_lkas_enabled != 1 and self.CS.lkas_enabled == 1: + if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): self.CS.madsEnabled = not self.CS.madsEnabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) else: diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 72ab68647f..af294a63a7 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -282,7 +282,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if self.CS.prev_cruise_setting != 1 and self.CS.cruise_setting == 1: + if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): self.CS.madsEnabled = not self.CS.madsEnabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) else: diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index dbe0b62895..e2ad23a7b6 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -205,7 +205,11 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_cam) self.sp_update_params() - self.CS.button_events = create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT) + self.CS.button_events = [ + *create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT), + *create_button_events(self.CS.lfa_enabled, self.CS.prev_lfa_enabled, {1: ButtonType.altButton1}), + *create_button_events(self.CS.main_buttons[-1], self.CS.prev_main_buttons, {1: ButtonType.altButton3}), + ] self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled, self.CS.button_events, c.vCruise) @@ -214,16 +218,12 @@ class CarInterface(CarInterfaceBase): if ret.cruiseState.available: if not self.CP.pcmCruiseSpeed: - if self.CS.prev_main_buttons == 1: - if self.CS.main_buttons[-1] != 1: - self.CS.accEnabled = True - elif self.CS.prev_cruise_buttons == 4: - if self.CS.cruise_buttons[-1] != 4: - self.accEnabled = True + if any(b.type in (ButtonType.altButton3, ButtonType.cancel) and not b.pressed for b in self.CS.button_events): + self.CS.accEnabled = True if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if self.CS.prev_lfa_enabled != 1 and self.CS.lfa_enabled == 1: + if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): self.CS.madsEnabled = not self.CS.madsEnabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) else: diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py index 9447803ae6..8b113cf4db 100755 --- a/selfdrive/car/mazda/interface.py +++ b/selfdrive/car/mazda/interface.py @@ -42,7 +42,8 @@ class CarInterface(CarInterfaceBase): # TODO: add button types for inc and dec self.CS.button_events = [ *self.CS.button_events, - *create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}) + *create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}), + *create_button_events(self.CS.lkas_enabled, self.CS.prev_lkas_enabled, {1: ButtonType.altButton1}), ] self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) @@ -54,7 +55,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if self.CS.prev_lkas_enabled != self.CS.lkas_enabled: + if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): self.CS.madsEnabled = not self.CS.madsEnabled self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) else: From f7ab369d476ec2729b3aceb19ccc336ce4b04adf Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Thu, 1 Aug 2024 17:22:43 +0200 Subject: [PATCH 193/229] First attempt at mirroring to gitlab --- .github/workflows/mirror_to_gitlab.yaml | 55 +++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 .github/workflows/mirror_to_gitlab.yaml diff --git a/.github/workflows/mirror_to_gitlab.yaml b/.github/workflows/mirror_to_gitlab.yaml new file mode 100644 index 0000000000..bbb731759d --- /dev/null +++ b/.github/workflows/mirror_to_gitlab.yaml @@ -0,0 +1,55 @@ +name: Mirror to GitLab + +on: + push: + delete: + workflow_dispatch: # This enables manual triggering + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - name: Wait for other instances of this workflow to conclude + uses: softprops/turnstyle@8db075d65b19bf94e6e8687b504db69938dc3c65 + with: + same-branch-only: 'true' + abort-after-seconds: 300 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Checkout Repository + uses: actions/checkout@v3 + with: + ref: ${{ github.ref }} + fetch-depth: 0 # Fetch full history + + - name: Set up Git + run: | + git config --global user.name 'GitHub Action' + git config --global user.email 'action@github.com' + + - name: Set up SSH + uses: webfactory/ssh-agent@v0.5.3 + with: + ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + + - name: Add GitLab public keys + run: | + ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts + + - name: Sync and commit changes + id: sync-and-commit + run: | + git lfs pull + + # Add GitLab remote + git remote add gitlab git@gitlab.com:sunnypilot/public/sunnypilot.git + + # Fetch from GitLab and check if the branch exists + if git fetch gitlab ${{ github.ref }}; then + # Merge changes from GitLab if the branch exists + git merge gitlab/${{ github.ref_name }} --allow-unrelated-histories --strategy-option=theirs + else + echo "Branch does not exist on GitLab, skipping merge." + fi + git push -u gitlab ${{ github.ref }} # If you have issues with "push rejected missing LFS" or something. Make sure you disabled LFS on the GITLAB repo if you intend to use a different LFS repo other than the target repo \ No newline at end of file From cd0ee087634802a18ee1f9ab3ba974de19f24d20 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Thu, 1 Aug 2024 18:10:59 +0200 Subject: [PATCH 194/229] Allow auto publishing of public prebuilts --- .gitlab-ci.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f1fe0226cc..6ea0c3b70b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,6 +47,7 @@ workflow: # If running on any branch other than main. variables: EXTRA_VERSION_IDENTIFIER: "-${CI_PIPELINE_IID}" NEW_BRANCH: "dev-c3" + AUTO_PUBLISH: true when: always #commit made to main (master) - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH @@ -54,6 +55,7 @@ workflow: # If running on any branch other than main. NEW_BRANCH: "staging-c3" VERSION: 'cat common/version.h | grep COMMA_VERSION | sed -e "s/[^0-9|.]//g"' EXTRA_VERSION_IDENTIFIER: "-staging" + AUTO_PUBLISH: true when: always # if tag - if: $CI_COMMIT_TAG @@ -61,6 +63,7 @@ workflow: # If running on any branch other than main. NEW_BRANCH: "release-c3" VERSION: 'cat common/version.h | grep COMMA_VERSION | sed -e "s/[^0-9|.]//g"' EXTRA_VERSION_IDENTIFIER: "-release" + AUTO_PUBLISH: true - when: always @@ -92,7 +95,7 @@ build: - sed -i '/from .board.jungle import PandaJungle, PandaJungleDFU/s/^/#/' panda/__init__.py # comment panda jungle when prebuilt - scons -j$(nproc) cache_dir=${CI_DIR}/scons_cache --minimal - touch ${BUILD_DIR}/prebuilt - - sudo rm -rf ${OUTPUT_DIR} + - sudo rm -rf ${OUTPUT_DIR} - mkdir -p ${OUTPUT_DIR} # We first include the paths we want to keep, even if we later will be excluding the other things on those paths - rsync -avm @@ -135,7 +138,7 @@ build: --chown=comma:comma ${BUILD_DIR}/ ${OUTPUT_DIR}/ after_script: - # cleanup build dir after doing work + # cleanup build dir after doing work - find $BUILD_DIR/ -mindepth 1 -delete artifacts: paths: @@ -146,7 +149,7 @@ build: when: manual - if: $NEW_BRANCH when: always - + check no source code sent: image: alpine stage: sanity @@ -215,6 +218,8 @@ publish to public github prebuilt: GIT_CONFIG_USER_EMAIL: "jason.wen@sunnypilot.ai" GIT_CONFIG_USER_NAME: "Jason Wen" rules: + - if: $AUTO_PUBLISH + when: on_success - if: $NEW_BRANCH when: manual - when: never From fb7076a042f44389c65499d38b8832b018260648 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Thu, 1 Aug 2024 18:28:15 +0200 Subject: [PATCH 195/229] Change remote --- .github/workflows/mirror_to_gitlab.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mirror_to_gitlab.yaml b/.github/workflows/mirror_to_gitlab.yaml index bbb731759d..e605458ad9 100644 --- a/.github/workflows/mirror_to_gitlab.yaml +++ b/.github/workflows/mirror_to_gitlab.yaml @@ -43,7 +43,7 @@ jobs: git lfs pull # Add GitLab remote - git remote add gitlab git@gitlab.com:sunnypilot/public/sunnypilot.git + git remote add gitlab git@gitlab.com:sunnypilot/sunnyhaibin/sunnypilot-github-mirror.git # Fetch from GitLab and check if the branch exists if git fetch gitlab ${{ github.ref }}; then From f311c8b1d7f6de46b25c10a2a8dbb64d002e8d60 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Thu, 1 Aug 2024 20:09:17 +0200 Subject: [PATCH 196/229] No auto publish for dev-c3 or release-c3 --- .gitlab-ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6ea0c3b70b..33d6289f63 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,7 +47,6 @@ workflow: # If running on any branch other than main. variables: EXTRA_VERSION_IDENTIFIER: "-${CI_PIPELINE_IID}" NEW_BRANCH: "dev-c3" - AUTO_PUBLISH: true when: always #commit made to main (master) - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH @@ -63,7 +62,6 @@ workflow: # If running on any branch other than main. NEW_BRANCH: "release-c3" VERSION: 'cat common/version.h | grep COMMA_VERSION | sed -e "s/[^0-9|.]//g"' EXTRA_VERSION_IDENTIFIER: "-release" - AUTO_PUBLISH: true - when: always From d0671bda6d2042bd2a4cebf0304cfeffcc90df2a Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Thu, 1 Aug 2024 13:44:57 -0700 Subject: [PATCH 197/229] op.sh: check for valid invocation (#33166) no source --- tools/op.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/op.sh b/tools/op.sh index 1715aaab63..a7ce7ef28b 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -1,5 +1,11 @@ #!/usr/bin/env bash +if [[ ! "${BASH_SOURCE[0]}" = "${0}" ]]; then + echo "Invalid invocation! This script must not be sourced." + echo "Run 'op.sh' directly or check your .bashrc for a valid alias" + return 0 +fi + set -e RED='\033[0;31m' From 08afbd7cb565d7a0485d420ae9d0c4fc33225d54 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Thu, 1 Aug 2024 14:12:27 -0800 Subject: [PATCH 198/229] car: Check params before car state is updated (#364) * car: Check params before car state is updated * read params in a thread instead * initialize list * Do this instead * type hint * ParamManager * make them internal --- selfdrive/car/card.py | 28 ++++++++++++++++++++---- selfdrive/car/chrysler/interface.py | 1 - selfdrive/car/ford/interface.py | 1 - selfdrive/car/gm/interface.py | 1 - selfdrive/car/honda/interface.py | 1 - selfdrive/car/hyundai/interface.py | 1 - selfdrive/car/interfaces.py | 31 ++++++++------------------- selfdrive/car/mazda/interface.py | 1 - selfdrive/car/nissan/interface.py | 1 - selfdrive/car/param_manager.py | 30 ++++++++++++++++++++++++++ selfdrive/car/subaru/interface.py | 1 - selfdrive/car/toyota/interface.py | 1 - selfdrive/car/volkswagen/interface.py | 1 - 13 files changed, 63 insertions(+), 36 deletions(-) create mode 100644 selfdrive/car/param_manager.py diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index 98be4bf82f..fe6f67296c 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 import os +import threading import time +from types import SimpleNamespace import cereal.messaging as messaging @@ -14,6 +16,7 @@ from openpilot.common.realtime import config_realtime_process, Priority, Ratekee from openpilot.selfdrive.pandad import can_list_to_can_capnp from openpilot.selfdrive.car.car_helpers import get_car, get_one_can from openpilot.selfdrive.car.interfaces import CarInterfaceBase +from openpilot.selfdrive.car.param_manager import ParamManager from openpilot.selfdrive.controls.lib.events import Events REPLAY = "REPLAY" in os.environ @@ -90,6 +93,10 @@ class Car: self.events = Events() + self.param_manager: ParamManager = ParamManager() + self.param_manager.update(self.params) + self._params_list: SimpleNamespace = self.param_manager.get_params() + # card is driven by can recv, expected at 100Hz self.rk = Ratekeeper(100, print_delay_threshold=None) @@ -98,7 +105,7 @@ class Car: # Update carState from CAN can_strs = messaging.drain_sock_raw(self.can_sock, wait_for_one=True) - CS = self.CI.update(self.CC_prev, can_strs) + CS = self.CI.update(self.CC_prev, can_strs, self._params_list) self.sm.update(0) @@ -186,10 +193,23 @@ class Car: self.initialized_prev = initialized self.CS_prev = CS.as_reader() + def sp_params_thread(self, event: threading.Event) -> None: + while not event.is_set(): + self.param_manager.update(self.params) + self._params_list = self.param_manager.get_params() + time.sleep(0.1) + def card_thread(self): - while True: - self.step() - self.rk.monitor_time() + event = threading.Event() + thread = threading.Thread(target=self.sp_params_thread, args=(event, )) + try: + thread.start() + while True: + self.step() + self.rk.monitor_time() + finally: + event.set() + thread.join() def main(): diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index 38d7cf0828..fbfce9d30d 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -91,7 +91,6 @@ class CarInterface(CarInterfaceBase): def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam) - self.sp_update_params() self.CS.button_events = [ *self.CS.button_events, diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 080663c9cf..a3bbd7ecf5 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -72,7 +72,6 @@ class CarInterface(CarInterfaceBase): def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam) - self.sp_update_params() self.CS.button_events = [ *self.CS.button_events, diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 726af2afac..e60039ec9a 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -204,7 +204,6 @@ class CarInterface(CarInterfaceBase): # returns a car.CarState def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam, self.cp_loopback) - self.sp_update_params() distance_button = 0 diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index af294a63a7..70124a8892 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -266,7 +266,6 @@ class CarInterface(CarInterfaceBase): # returns a car.CarState def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam, self.cp_body) - self.sp_update_params() self.CS.button_events = [ *create_button_events(self.CS.cruise_buttons, self.CS.prev_cruise_buttons, BUTTONS_DICT), diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index e2ad23a7b6..02897f9765 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -203,7 +203,6 @@ class CarInterface(CarInterfaceBase): def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam) - self.sp_update_params() self.CS.button_events = [ *create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT), diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index b8ca13ec86..bda574f54d 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -7,6 +7,7 @@ import tomllib from abc import abstractmethod, ABC from difflib import SequenceMatcher from enum import StrEnum +from types import SimpleNamespace from typing import Any, NamedTuple from collections.abc import Callable from functools import cache @@ -19,6 +20,7 @@ from openpilot.common.numpy_fast import clip from openpilot.common.params import Params from openpilot.common.realtime import DT_CTRL from openpilot.selfdrive.car import apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, STD_CARGO_KG, ButtonEvents +from openpilot.selfdrive.car.param_manager import ParamManager from openpilot.selfdrive.car.values import PLATFORMS from openpilot.selfdrive.controls.lib.desire_helper import get_min_lateral_speed from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, V_CRUISE_UNSET, get_friction @@ -239,16 +241,10 @@ class CarInterfaceBase(ABC): self.gear_warning = 0 self.cruise_cancelled_btn = True self.acc_mads_combo = self.param_s.get_bool("AccMadsCombo") - self.is_metric = self.param_s.get_bool("IsMetric") - self.below_speed_pause = self.param_s.get_bool("BelowSpeedPause") - self.pause_lateral_speed = int(self.param_s.get("PauseLateralSpeed", encoding="utf8")) self.prev_acc_mads_combo = False self.mads_event_lock = True self.gap_button_counter = 0 self.experimental_mode_hold = False - self.experimental_mode = self.param_s.get_bool("ExperimentalMode") - self._frame = 0 - self.reverse_dm_cam = self.param_s.get_bool("ReverseDmCam") self.mads_main_toggle = self.param_s.get_bool("MadsCruiseMain") self.lkas_toggle = self.param_s.get_bool("LkasToggle") self.last_mads_init = 0. @@ -421,13 +417,14 @@ class CarInterfaceBase(ABC): def _update(self, c: car.CarControl) -> car.CarState: pass - def update(self, c: car.CarControl, can_strings: list[bytes]) -> car.CarState: + def update(self, c: car.CarControl, can_strings: list[bytes], params_list: SimpleNamespace) -> car.CarState: # parse can for cp in self.can_parsers: if cp is not None: cp.update_strings(can_strings) self.CS.button_events = [] + self.CS.params_list = params_list # get CarState ret = self._update(c) @@ -472,7 +469,7 @@ class CarInterfaceBase(ABC): else: events.add(EventName.wrongGear) if cs_out.gearShifter == GearShifter.reverse: - if not self.reverse_dm_cam and cs_out.vEgo < 5: + if not self.CS.params_list.reverse_dm_cam and cs_out.vEgo < 5: events.add(EventName.spReverseGear) elif cs_out.vEgo >= 5: events.add(EventName.reverseGear) @@ -634,9 +631,9 @@ class CarInterfaceBase(ABC): if self.CP.openpilotLongitudinalControl: self.toggle_exp_mode(gap_button) - lane_change_speed_min = get_min_lateral_speed(self.pause_lateral_speed, self.is_metric) + lane_change_speed_min = get_min_lateral_speed(self.CS.params_list.pause_lateral_speed, self.CS.params_list.is_metric) - cs_out.belowLaneChangeSpeed = cs_out.vEgo < lane_change_speed_min and self.below_speed_pause + cs_out.belowLaneChangeSpeed = cs_out.vEgo < lane_change_speed_min and self.CS.params_list.below_speed_pause if cs_out.gearShifter in [GearShifter.park, GearShifter.reverse] or cs_out.doorOpen or \ (cs_out.seatbeltUnlatched and cs_out.gearShifter != GearShifter.park): @@ -669,7 +666,7 @@ class CarInterfaceBase(ABC): if self.gap_button_counter > 50: self.gap_button_counter = 0 self.experimental_mode_hold = True - self.param_s.put_bool_nonblocking("ExperimentalMode", not self.experimental_mode) + self.param_s.put_bool_nonblocking("ExperimentalMode", not self.CS.params_list.experimental_mode) else: self.gap_button_counter = 0 self.experimental_mode_hold = False @@ -735,17 +732,6 @@ class CarInterfaceBase(ABC): return events, cs_out - def sp_update_params(self): - self.experimental_mode = self.param_s.get_bool("ExperimentalMode") - self._frame += 1 - if self._frame % 100 == 0: - self.is_metric = self.param_s.get_bool("IsMetric") - self.below_speed_pause = self.param_s.get_bool("BelowSpeedPause") - self.pause_lateral_speed = int(self.param_s.get("PauseLateralSpeed", encoding="utf8")) - if self._frame % 300 == 0: - self._frame = 0 - self.reverse_dm_cam = self.param_s.get_bool("ReverseDmCam") - class RadarInterfaceBase(ABC): def __init__(self, CP): self.rcp = None @@ -785,6 +771,7 @@ class CarStateBase(ABC): self.control_initialized = False self.button_events: list[capnp.lib.capnp._DynamicStructBuilder] = [] + self.params_list: SimpleNamespace = ParamManager().get_params() Q = [[0.0, 0.0], [0.0, 100.0]] R = 0.3 diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py index 8b113cf4db..4c26a18a57 100755 --- a/selfdrive/car/mazda/interface.py +++ b/selfdrive/car/mazda/interface.py @@ -37,7 +37,6 @@ class CarInterface(CarInterfaceBase): # returns a car.CarState def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam) - self.sp_update_params() # TODO: add button types for inc and dec self.CS.button_events = [ diff --git a/selfdrive/car/nissan/interface.py b/selfdrive/car/nissan/interface.py index 4a9e5a9125..661ac668a5 100644 --- a/selfdrive/car/nissan/interface.py +++ b/selfdrive/car/nissan/interface.py @@ -32,7 +32,6 @@ class CarInterface(CarInterfaceBase): # returns a car.CarState def _update(self, c): ret = self.CS.update(self.cp, self.cp_adas, self.cp_cam) - self.sp_update_params() self.CS.button_events = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}) diff --git a/selfdrive/car/param_manager.py b/selfdrive/car/param_manager.py new file mode 100644 index 0000000000..85018aaa02 --- /dev/null +++ b/selfdrive/car/param_manager.py @@ -0,0 +1,30 @@ +from types import SimpleNamespace + +from openpilot.common.params import Params + + +class ParamManager: + def __init__(self): + self._params_list: SimpleNamespace = self._create_namespace({ + "below_speed_pause": False, + "experimental_mode": False, + "is_metric": False, + "pause_lateral_speed": 0, + "reverse_dm_cam": False, + }) + + @staticmethod + def _create_namespace(data: dict) -> SimpleNamespace: + return SimpleNamespace(**data) + + def get_params(self) -> SimpleNamespace: + return self._params_list + + def update(self, params: Params) -> None: + self._params_list = self._create_namespace({ + "below_speed_pause": params.get_bool("BelowSpeedPause"), + "experimental_mode": params.get_bool("ExperimentalMode"), + "is_metric": params.get_bool("IsMetric"), + "pause_lateral_speed": int(params.get("PauseLateralSpeed", encoding="utf8")), + "reverse_dm_cam": params.get_bool("ReverseDmCam"), + }) diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index 7eefeb66eb..185ee8e54d 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -116,7 +116,6 @@ class CarInterface(CarInterfaceBase): def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam, self.cp_body) - self.sp_update_params() self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 1b0528d12c..5214cc1265 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -207,7 +207,6 @@ class CarInterface(CarInterfaceBase): # returns a car.CarState def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam) - self.sp_update_params() distance_button = 0 diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index d965cf2e8b..0d57539a1b 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -113,7 +113,6 @@ class CarInterface(CarInterfaceBase): # returns a car.CarState def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam, self.cp_ext, self.CP.transmissionType) - self.sp_update_params() self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) From bfa8e0b2ec20727db070945e99549828c1f4bc0e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 1 Aug 2024 15:36:44 -0700 Subject: [PATCH 199/229] disable test_rotation until it's fixed --- system/loggerd/tests/test_loggerd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/loggerd/tests/test_loggerd.py b/system/loggerd/tests/test_loggerd.py index 6a24540acf..74fc42f5e2 100644 --- a/system/loggerd/tests/test_loggerd.py +++ b/system/loggerd/tests/test_loggerd.py @@ -136,7 +136,7 @@ class TestLoggerd: assert getattr(initData, initData_key) == v assert logged_params[param_key].decode() == v - @flaky(max_runs=3) + @pytest.skip("FIXME: encoderd sometimes crashes in CI when running with pytest-xdist") def test_rotation(self): os.environ["LOGGERD_TEST"] = "1" Params().put("RecordFront", "1") From 5b4b7a08fcabdc22bb52c2abeeda87772d7990d7 Mon Sep 17 00:00:00 2001 From: Hoang Bui <47828508+bongbui321@users.noreply.github.com> Date: Thu, 1 Aug 2024 19:28:26 -0400 Subject: [PATCH 200/229] CI: fix recent test_rotation skip (#33167) --- system/loggerd/tests/test_loggerd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/loggerd/tests/test_loggerd.py b/system/loggerd/tests/test_loggerd.py index 74fc42f5e2..cfd1247702 100644 --- a/system/loggerd/tests/test_loggerd.py +++ b/system/loggerd/tests/test_loggerd.py @@ -7,7 +7,7 @@ import subprocess import time from collections import defaultdict from pathlib import Path -from flaky import flaky +import pytest import cereal.messaging as messaging from cereal import log @@ -136,7 +136,7 @@ class TestLoggerd: assert getattr(initData, initData_key) == v assert logged_params[param_key].decode() == v - @pytest.skip("FIXME: encoderd sometimes crashes in CI when running with pytest-xdist") + @pytest.mark.skip("FIXME: encoderd sometimes crashes in CI when running with pytest-xdist") def test_rotation(self): os.environ["LOGGERD_TEST"] = "1" Params().put("RecordFront", "1") From 4b11c9e914707df9def598616995be2a5d355a6a Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Thu, 1 Aug 2024 16:44:10 -0700 Subject: [PATCH 201/229] ci: create ui report only on PR (#33168) only on pr --- .github/workflows/selfdrive_tests.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index bfad6e1e7d..80be72f26a 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -340,6 +340,7 @@ jobs: # This job name needs to be the same as UI_JOB_NAME in ui_preview.yaml name: Create UI Report runs-on: ubuntu-latest + if: github.event_name == 'pull_request' steps: - uses: actions/checkout@v4 with: From 22e0b4d597a2fe7fc8956afe06d8be4c990298b8 Mon Sep 17 00:00:00 2001 From: Mathew Locoteta <64510542+mlocoteta@users.noreply.github.com> Date: Thu, 1 Aug 2024 22:42:13 -0400 Subject: [PATCH 202/229] Honda Longitudinal: Remove tuning from 4-CYL 9th Gen Accord (#359) Remove ACC tuning from 9th Gen Accord Co-authored-by: Jason Wen --- selfdrive/car/honda/interface.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 70124a8892..3e32a35db6 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -174,11 +174,6 @@ class CarInterface(CarInterfaceBase): ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 239], [0, 239]] ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.,20], [0.,20]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.4,0.3], [0,0]] - tire_stiffness_factor = 0.8467 - ret.longitudinalTuning.kpBP = [0., 5., 35.] - ret.longitudinalTuning.kpV = [2.4, 1.6, 0.8] - ret.longitudinalTuning.kiBP = [0., 35.] - ret.longitudinalTuning.kiV = [0.2, 0.16] elif candidate in (CAR.HONDA_ODYSSEY, CAR.HONDA_ODYSSEY_CHN): ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]] From 8d760272c7691aa8899e5dddf98c75101e4c7960 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Thu, 1 Aug 2024 19:23:00 -0800 Subject: [PATCH 203/229] car: Move all live param checks to `ParamManger` (#378) car: Move all live param checks to ParamManger --- selfdrive/car/chrysler/carcontroller.py | 19 +++++---------- selfdrive/car/honda/carcontroller.py | 23 +++++++----------- selfdrive/car/hyundai/carcontroller.py | 23 +++++++----------- selfdrive/car/interfaces.py | 10 +++----- selfdrive/car/mazda/carcontroller.py | 23 +++++++----------- selfdrive/car/param_manager.py | 20 ++++++++++++++++ selfdrive/car/subaru/carcontroller.py | 9 +------ selfdrive/car/toyota/carcontroller.py | 24 +++++-------------- selfdrive/car/toyota/interface.py | 2 +- selfdrive/car/volkswagen/carcontroller.py | 19 +++++---------- .../settings/sunnypilot/mads_settings.cc | 4 ++-- 11 files changed, 69 insertions(+), 107 deletions(-) diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index 54bed40b51..9de0d4a547 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -30,9 +30,6 @@ class CarController(CarControllerBase): self.sm = messaging.SubMaster(['longitudinalPlanSP']) self.param_s = Params() - self.is_metric = self.param_s.get_bool("IsMetric") - self.speed_limit_control_enabled = False - self.last_speed_limit_sign_tap = False self.last_speed_limit_sign_tap_prev = False self.speed_limit = 0. self.speed_limit_offset = 0 @@ -72,23 +69,19 @@ class CarController(CarControllerBase): self.v_tsc = self.sm['longitudinalPlanSP'].visionTurnSpeed self.m_tsc = self.sm['longitudinalPlanSP'].turnSpeed - if self.frame % 200 == 0: - self.speed_limit_control_enabled = self.param_s.get_bool("EnableSlc") - self.is_metric = self.param_s.get_bool("IsMetric") - self.last_speed_limit_sign_tap = self.param_s.get_bool("LastSpeedLimitSignTap") - self.v_cruise_min = FCA_V_CRUISE_MIN[self.is_metric] * (CV.KPH_TO_MPH if not self.is_metric else 1) + self.v_cruise_min = FCA_V_CRUISE_MIN[CS.params_list.is_metric] * (CV.KPH_TO_MPH if not CS.params_list.is_metric else 1) can_sends = [] if not self.CP.pcmCruiseSpeed: - if not self.last_speed_limit_sign_tap_prev and self.last_speed_limit_sign_tap: + if not self.last_speed_limit_sign_tap_prev and CS.params_list.last_speed_limit_sign_tap: self.sl_force_active_timer = self.frame self.param_s.put_bool_nonblocking("LastSpeedLimitSignTap", False) - self.last_speed_limit_sign_tap_prev = self.last_speed_limit_sign_tap + self.last_speed_limit_sign_tap_prev = CS.params_list.last_speed_limit_sign_tap - sl_force_active = self.speed_limit_control_enabled and (self.frame < (self.sl_force_active_timer * DT_CTRL + 2.0)) - sl_inactive = not sl_force_active and (not self.speed_limit_control_enabled or (True if self.slc_state == 0 else False)) - sl_temp_inactive = not sl_force_active and (self.speed_limit_control_enabled and (True if self.slc_state == 1 else False)) + sl_force_active = CS.params_list.speed_limit_control_enabled and (self.frame < (self.sl_force_active_timer * DT_CTRL + 2.0)) + sl_inactive = not sl_force_active and (not CS.params_list.speed_limit_control_enabled or (True if self.slc_state == 0 else False)) + sl_temp_inactive = not sl_force_active and (CS.params_list.speed_limit_control_enabled and (True if self.slc_state == 1 else False)) slc_active = not sl_inactive and not sl_temp_inactive self.slc_active_stock = slc_active diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index dd40d07712..22c2eefe82 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -132,9 +132,6 @@ class CarController(CarControllerBase): self.sm = messaging.SubMaster(['longitudinalPlanSP']) self.param_s = Params() - self.is_metric = self.param_s.get_bool("IsMetric") - self.speed_limit_control_enabled = False - self.last_speed_limit_sign_tap = False self.last_speed_limit_sign_tap_prev = False self.speed_limit = 0. self.speed_limit_offset = 0 @@ -173,11 +170,7 @@ class CarController(CarControllerBase): self.v_tsc = self.sm['longitudinalPlanSP'].visionTurnSpeed self.m_tsc = self.sm['longitudinalPlanSP'].turnSpeed - if self.frame % 200 == 0: - self.speed_limit_control_enabled = self.param_s.get_bool("EnableSlc") - self.is_metric = self.param_s.get_bool("IsMetric") - self.last_speed_limit_sign_tap = self.param_s.get_bool("LastSpeedLimitSignTap") - self.v_cruise_min = HONDA_V_CRUISE_MIN[self.is_metric] * (CV.KPH_TO_MPH if not self.is_metric else 1) + self.v_cruise_min = HONDA_V_CRUISE_MIN[CS.params_list.is_metric] * (CV.KPH_TO_MPH if not CS.params_list.is_metric else 1) actuators = CC.actuators hud_control = CC.hudControl @@ -213,14 +206,14 @@ class CarController(CarControllerBase): self.params.STEER_LOOKUP_BP, self.params.STEER_LOOKUP_V)) if not self.CP.pcmCruiseSpeed: - if not self.last_speed_limit_sign_tap_prev and self.last_speed_limit_sign_tap: + if not self.last_speed_limit_sign_tap_prev and CS.params_list.last_speed_limit_sign_tap: self.sl_force_active_timer = self.frame self.param_s.put_bool_nonblocking("LastSpeedLimitSignTap", False) - self.last_speed_limit_sign_tap_prev = self.last_speed_limit_sign_tap + self.last_speed_limit_sign_tap_prev = CS.params_list.last_speed_limit_sign_tap - sl_force_active = self.speed_limit_control_enabled and (self.frame < (self.sl_force_active_timer * DT_CTRL + 2.0)) - sl_inactive = not sl_force_active and (not self.speed_limit_control_enabled or (True if self.slc_state == 0 else False)) - sl_temp_inactive = not sl_force_active and (self.speed_limit_control_enabled and (True if self.slc_state == 1 else False)) + sl_force_active = CS.params_list.speed_limit_control_enabled and (self.frame < (self.sl_force_active_timer * DT_CTRL + 2.0)) + sl_inactive = not sl_force_active and (not CS.params_list.speed_limit_control_enabled or (True if self.slc_state == 0 else False)) + sl_temp_inactive = not sl_force_active and (CS.params_list.speed_limit_control_enabled and (True if self.slc_state == 1 else False)) slc_active = not sl_inactive and not sl_temp_inactive self.slc_active_stock = slc_active @@ -432,8 +425,8 @@ class CarController(CarControllerBase): return min(target_speed_kph, curve_speed) def get_button_control(self, CS, final_speed, v_cruise_kph_prev): - self.init_speed = round(min(final_speed, v_cruise_kph_prev) * (CV.KPH_TO_MPH if not self.is_metric else 1)) - self.v_set_dis = round(CS.out.cruiseState.speed * (CV.MS_TO_MPH if not self.is_metric else CV.MS_TO_KPH)) + self.init_speed = round(min(final_speed, v_cruise_kph_prev) * (CV.KPH_TO_MPH if not CS.params_list.is_metric else 1)) + self.v_set_dis = round(CS.out.cruiseState.speed * (CV.MS_TO_MPH if not CS.params_list.is_metric else CV.MS_TO_KPH)) cruise_button = self.get_button_type(self.button_type) return cruise_button diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index f640f6529a..00e4cd919a 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -72,9 +72,6 @@ class CarController(CarControllerBase): self.sm = messaging.SubMaster(sub_services) self.param_s = Params() - self.is_metric = self.param_s.get_bool("IsMetric") - self.speed_limit_control_enabled = False - self.last_speed_limit_sign_tap = False self.last_speed_limit_sign_tap_prev = False self.speed_limit = 0. self.speed_limit_offset = 0 @@ -127,11 +124,7 @@ class CarController(CarControllerBase): self.v_tsc = self.sm['longitudinalPlanSP'].visionTurnSpeed self.m_tsc = self.sm['longitudinalPlanSP'].turnSpeed - if self.frame % 200 == 0: - self.speed_limit_control_enabled = self.param_s.get_bool("EnableSlc") - self.is_metric = self.param_s.get_bool("IsMetric") - self.last_speed_limit_sign_tap = self.param_s.get_bool("LastSpeedLimitSignTap") - self.v_cruise_min = HYUNDAI_V_CRUISE_MIN[self.is_metric] * (CV.KPH_TO_MPH if not self.is_metric else 1) + self.v_cruise_min = HYUNDAI_V_CRUISE_MIN[CS.params_list.is_metric] * (CV.KPH_TO_MPH if not CS.params_list.is_metric else 1) actuators = CC.actuators hud_control = CC.hudControl @@ -175,14 +168,14 @@ class CarController(CarControllerBase): blinking_icon = (self.frame - self.disengage_blink) * DT_CTRL < 1.0 if self.lat_disengage_init else False if not self.CP.pcmCruiseSpeed: - if not self.last_speed_limit_sign_tap_prev and self.last_speed_limit_sign_tap: + if not self.last_speed_limit_sign_tap_prev and CS.params_list.last_speed_limit_sign_tap: self.sl_force_active_timer = self.frame self.param_s.put_bool_nonblocking("LastSpeedLimitSignTap", False) - self.last_speed_limit_sign_tap_prev = self.last_speed_limit_sign_tap + self.last_speed_limit_sign_tap_prev = CS.params_list.last_speed_limit_sign_tap - sl_force_active = self.speed_limit_control_enabled and (self.frame < (self.sl_force_active_timer * DT_CTRL + 2.0)) - sl_inactive = not sl_force_active and (not self.speed_limit_control_enabled or (True if self.slc_state == 0 else False)) - sl_temp_inactive = not sl_force_active and (self.speed_limit_control_enabled and (True if self.slc_state == 1 else False)) + sl_force_active = CS.params_list.speed_limit_control_enabled and (self.frame < (self.sl_force_active_timer * DT_CTRL + 2.0)) + sl_inactive = not sl_force_active and (not CS.params_list.speed_limit_control_enabled or (True if self.slc_state == 0 else False)) + sl_temp_inactive = not sl_force_active and (CS.params_list.speed_limit_control_enabled and (True if self.slc_state == 1 else False)) slc_active = not sl_inactive and not sl_temp_inactive self.slc_active_stock = slc_active @@ -433,8 +426,8 @@ class CarController(CarControllerBase): return min(target_speed_kph, curve_speed) def get_button_control(self, CS, final_speed, v_cruise_kph_prev): - self.init_speed = round(min(final_speed, v_cruise_kph_prev) * (CV.KPH_TO_MPH if not self.is_metric else 1)) - self.v_set_dis = round(CS.out.cruiseState.speed * (CV.MS_TO_MPH if not self.is_metric else CV.MS_TO_KPH)) + self.init_speed = round(min(final_speed, v_cruise_kph_prev) * (CV.KPH_TO_MPH if not CS.params_list.is_metric else 1)) + self.v_set_dis = round(CS.out.cruiseState.speed * (CV.MS_TO_MPH if not CS.params_list.is_metric else CV.MS_TO_KPH)) cruise_button = self.get_button_type(self.button_type) return cruise_button diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index bda574f54d..ca4a508554 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -240,13 +240,10 @@ class CarInterfaceBase(ABC): self.mads_ndlob = self.enable_mads and not self.mads_disengage_lateral_on_brake self.gear_warning = 0 self.cruise_cancelled_btn = True - self.acc_mads_combo = self.param_s.get_bool("AccMadsCombo") self.prev_acc_mads_combo = False self.mads_event_lock = True self.gap_button_counter = 0 self.experimental_mode_hold = False - self.mads_main_toggle = self.param_s.get_bool("MadsCruiseMain") - self.lkas_toggle = self.param_s.get_bool("LkasToggle") self.last_mads_init = 0. self.madsEnabledInit = False self.madsEnabledInitPrev = False @@ -551,7 +548,7 @@ class CarInterfaceBase(ABC): return v_cruise != V_CRUISE_UNSET def get_acc_mads(self, cruiseState_enabled, acc_enabled, mads_enabled): - if self.acc_mads_combo: + if self.CS.params_list.acc_mads_combo: if not self.prev_acc_mads_combo and (cruiseState_enabled or acc_enabled): mads_enabled = True self.prev_acc_mads_combo = (cruiseState_enabled or acc_enabled) @@ -591,7 +588,7 @@ class CarInterfaceBase(ABC): def get_sp_cruise_main_state(self, cs_out, CS): if not CS.control_initialized: mads_enabled = False - elif not self.mads_main_toggle: + elif not self.CS.params_list.mads_main_toggle: mads_enabled = False else: mads_enabled = cs_out.cruiseState.available @@ -603,7 +600,7 @@ class CarInterfaceBase(ABC): self.madsEnabledInit = False self.madsEnabledInitPrev = False return False - if not self.mads_main_toggle or self.prev_acc_mads_combo: + if not self.CS.params_list.mads_main_toggle or self.prev_acc_mads_combo: return CS.madsEnabled if not self.madsEnabledInit and CS.madsEnabled: self.madsEnabledInit = True @@ -762,7 +759,6 @@ class CarStateBase(ABC): self.cluster_speed_hyst_gap = 0.0 self.cluster_min_speed = 0.0 # min speed before dropping to 0 - self.param_s = Params() self.accEnabled = False self.madsEnabled = False self.disengageByBrake = False diff --git a/selfdrive/car/mazda/carcontroller.py b/selfdrive/car/mazda/carcontroller.py index 368198e1c8..705dedc328 100644 --- a/selfdrive/car/mazda/carcontroller.py +++ b/selfdrive/car/mazda/carcontroller.py @@ -24,9 +24,6 @@ class CarController(CarControllerBase): self.sm = messaging.SubMaster(['longitudinalPlanSP']) self.param_s = Params() - self.is_metric = self.param_s.get_bool("IsMetric") - self.speed_limit_control_enabled = False - self.last_speed_limit_sign_tap = False self.last_speed_limit_sign_tap_prev = False self.speed_limit = 0. self.speed_limit_offset = 0 @@ -65,23 +62,19 @@ class CarController(CarControllerBase): self.v_tsc = self.sm['longitudinalPlanSP'].visionTurnSpeed self.m_tsc = self.sm['longitudinalPlanSP'].turnSpeed - if self.frame % 200 == 0: - self.speed_limit_control_enabled = self.param_s.get_bool("EnableSlc") - self.is_metric = self.param_s.get_bool("IsMetric") - self.last_speed_limit_sign_tap = self.param_s.get_bool("LastSpeedLimitSignTap") - self.v_cruise_min = MAZDA_V_CRUISE_MIN[self.is_metric] * (CV.KPH_TO_MPH if not self.is_metric else 1) + self.v_cruise_min = MAZDA_V_CRUISE_MIN[CS.params_list.is_metric] * (CV.KPH_TO_MPH if not CS.params_list.is_metric else 1) can_sends = [] if not self.CP.pcmCruiseSpeed: - if not self.last_speed_limit_sign_tap_prev and self.last_speed_limit_sign_tap: + if not self.last_speed_limit_sign_tap_prev and CS.params_list.last_speed_limit_sign_tap: self.sl_force_active_timer = self.frame self.param_s.put_bool_nonblocking("LastSpeedLimitSignTap", False) - self.last_speed_limit_sign_tap_prev = self.last_speed_limit_sign_tap + self.last_speed_limit_sign_tap_prev = CS.params_list.last_speed_limit_sign_tap - sl_force_active = self.speed_limit_control_enabled and (self.frame < (self.sl_force_active_timer * DT_CTRL + 2.0)) - sl_inactive = not sl_force_active and (not self.speed_limit_control_enabled or (True if self.slc_state == 0 else False)) - sl_temp_inactive = not sl_force_active and (self.speed_limit_control_enabled and (True if self.slc_state == 1 else False)) + sl_force_active = CS.params_list.speed_limit_control_enabled and (self.frame < (self.sl_force_active_timer * DT_CTRL + 2.0)) + sl_inactive = not sl_force_active and (not CS.params_list.speed_limit_control_enabled or (True if self.slc_state == 0 else False)) + sl_temp_inactive = not sl_force_active and (CS.params_list.speed_limit_control_enabled and (True if self.slc_state == 1 else False)) slc_active = not sl_inactive and not sl_temp_inactive self.slc_active_stock = slc_active @@ -229,8 +222,8 @@ class CarController(CarControllerBase): return min(target_speed_kph, curve_speed) def get_button_control(self, CS, final_speed, v_cruise_kph_prev): - self.init_speed = round(min(final_speed, v_cruise_kph_prev) * (CV.KPH_TO_MPH if not self.is_metric else 1)) - self.v_set_dis = round(CS.out.cruiseState.speed * (CV.MS_TO_MPH if not self.is_metric else CV.MS_TO_KPH)) + self.init_speed = round(min(final_speed, v_cruise_kph_prev) * (CV.KPH_TO_MPH if not CS.params_list.is_metric else 1)) + self.v_set_dis = round(CS.out.cruiseState.speed * (CV.MS_TO_MPH if not CS.params_list.is_metric else CV.MS_TO_KPH)) cruise_button = self.get_button_type(self.button_type) return cruise_button diff --git a/selfdrive/car/param_manager.py b/selfdrive/car/param_manager.py index 85018aaa02..c7df87b9b7 100644 --- a/selfdrive/car/param_manager.py +++ b/selfdrive/car/param_manager.py @@ -6,11 +6,21 @@ from openpilot.common.params import Params class ParamManager: def __init__(self): self._params_list: SimpleNamespace = self._create_namespace({ + "acc_mads_combo": False, "below_speed_pause": False, "experimental_mode": False, "is_metric": False, + "last_speed_limit_sign_tap": False, + "mads_main_toggle": False, "pause_lateral_speed": 0, + "reverse_acc_change": False, "reverse_dm_cam": False, + "speed_limit_control_enabled": False, + "subaru_manual_parking_brake": False, + "toyota_auto_lock_by_speed": False, + "toyota_auto_unlock_by_shifter": False, + "toyota_lkas_toggle": False, + "toyota_sng_hack": False, }) @staticmethod @@ -22,9 +32,19 @@ class ParamManager: def update(self, params: Params) -> None: self._params_list = self._create_namespace({ + "acc_mads_combo": params.get_bool("AccMadsCombo"), "below_speed_pause": params.get_bool("BelowSpeedPause"), "experimental_mode": params.get_bool("ExperimentalMode"), "is_metric": params.get_bool("IsMetric"), + "last_speed_limit_sign_tap": params.get_bool("LastSpeedLimitSignTap"), + "mads_main_toggle": params.get_bool("MadsCruiseMain"), "pause_lateral_speed": int(params.get("PauseLateralSpeed", encoding="utf8")), + "reverse_acc_change": params.get_bool("ReverseAccChange"), "reverse_dm_cam": params.get_bool("ReverseDmCam"), + "speed_limit_control_enabled": params.get_bool("EnableSlc"), + "subaru_manual_parking_brake": params.get_bool("SubaruManualParkingBrakeSng"), + "toyota_auto_lock_by_speed": params.get_bool("ToyotaAutoLockBySpeed"), + "toyota_auto_unlock_by_shifter": params.get_bool("ToyotaAutoUnlockByShifter"), + "toyota_lkas_toggle": params.get_bool("LkasToggle"), + "toyota_sng_hack": params.get_bool("ToyotaSnG"), }) diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index 198b17ace6..7574d33af8 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -1,6 +1,5 @@ from cereal import car from openpilot.common.numpy_fast import clip, interp -from openpilot.common.params import Params from opendbc.can.packer import CANPacker from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance from openpilot.selfdrive.car.interfaces import CarControllerBase @@ -25,12 +24,9 @@ class CarController(CarControllerBase): self.cruise_button_prev = 0 self.steer_rate_counter = 0 - self.param_s = Params() - self.subaru_sng = False if CP.spFlags & SubaruFlagsSP.SP_SUBARU_SNG: self.subaru_sng = True - self.manual_parking_brake = self.param_s.get_bool("SubaruManualParkingBrakeSng") self.prev_close_distance = 0 self.prev_standstill = False self.standstill_start = 0 @@ -47,9 +43,6 @@ class CarController(CarControllerBase): hud_control = CC.hudControl pcm_cancel_cmd = CC.cruiseControl.cancel - if self.frame % 250 == 0 and self.subaru_sng: - self.manual_parking_brake = self.param_s.get_bool("SubaruManualParkingBrakeSng") - can_sends = [] # *** steering *** @@ -191,7 +184,7 @@ class CarController(CarControllerBase): and CS.close_distance > self.prev_close_distance): # distance with lead car is increasing self.sng_acc_resume = True elif not (self.CP.flags & (SubaruFlags.GLOBAL_GEN2 | SubaruFlags.HYBRID)): - if self.manual_parking_brake: + if CS.params_list.subaru_manual_parking_brake and self.subaru_sng: # Send brake message with non-zero speed in standstill to avoid non-EPB ACC disengage if (CC.enabled # ACC active and CS.car_follow == 1 # lead car diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 89f5992961..b8185ee6ff 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -1,7 +1,6 @@ from cereal import car from common.conversions import Conversions as CV from openpilot.common.numpy_fast import clip, interp -from openpilot.common.params import Params from openpilot.selfdrive.car import apply_meas_steer_torque_limits, apply_std_steer_angle_limits, common_fault_avoidance, \ create_gas_interceptor_command, make_can_msg from openpilot.selfdrive.car.interfaces import CarControllerBase @@ -52,27 +51,16 @@ class CarController(CarControllerBase): self.gas = 0 self.accel = 0 - self.param_s = Params() - self._is_metric = self.param_s.get_bool("IsMetric") - self._reverse_acc_change = self.param_s.get_bool("ReverseAccChange") - self._sng_hack = self.param_s.get_bool("ToyotaSnG") - self.left_blindspot_debug_enabled = False self.right_blindspot_debug_enabled = False self.last_blindspot_frame = 0 - self._auto_lock_by_speed = self.param_s.get_bool("ToyotaAutoLockBySpeed") - self._auto_unlock_by_shifter = self.param_s.get_bool("ToyotaAutoUnlockByShifter") - self._auto_lock_speed = 10 * (CV.KPH_TO_MS if self._is_metric else CV.MPH_TO_MS) + self._auto_lock_speed = 0.0 self._auto_lock_once = False self._gear_prev = GearShifter.park def update(self, CC, CS, now_nanos): - if self.frame % 200 == 0: - self._is_metric = self.param_s.get_bool("IsMetric") - self._auto_lock_by_speed = self.param_s.get_bool("ToyotaAutoLockBySpeed") - self._auto_unlock_by_shifter = self.param_s.get_bool("ToyotaAutoUnlockByShifter") - self._auto_lock_speed = 10 * (CV.KPH_TO_MS if self._is_metric else CV.MPH_TO_MS) + self._auto_lock_speed = 10 * (CV.KPH_TO_MS if CS.params_list.is_metric else CV.MPH_TO_MS) actuators = CC.actuators hud_control = CC.hudControl @@ -88,11 +76,11 @@ class CarController(CarControllerBase): gear = CS.out.gearShifter if not CS.out.doorOpen: if gear == GearShifter.park and self._gear_prev != gear: - if self._auto_unlock_by_shifter: + if CS.params_list.toyota_auto_unlock_by_shifter: can_sends.append(make_can_msg(0x750, UNLOCK_CMD, 0)) self._auto_lock_once = False elif gear == GearShifter.drive and not self._auto_lock_once and CS.out.vEgo >= self._auto_lock_speed: - if self._auto_lock_by_speed: + if CS.params_list.toyota_auto_lock_by_speed: can_sends.append(make_can_msg(0x750, LOCK_CMD, 0)) self._auto_lock_once = True self._gear_prev = gear @@ -173,7 +161,7 @@ class CarController(CarControllerBase): # on entering standstill, send standstill request if CS.out.standstill and not self.last_standstill and (self.CP.carFingerprint not in NO_STOP_TIMER_CAR or self.CP.enableGasInterceptorDEPRECATED) and \ - not self._sng_hack: + not CS.params_list.toyota_sng_hack: self.standstill_req = True if CS.pcm_acc_status != 8: # pcm entered standstill or it's disabled @@ -188,7 +176,7 @@ class CarController(CarControllerBase): # we can spam can to cancel the system even if we are using lat only control if (self.frame % 3 == 0 and self.CP.openpilotLongitudinalControl) or pcm_cancel_cmd: lead = hud_control.leadVisible or CS.out.vEgo < 12. # at low speed we always assume the lead is present so ACC can be engaged - reverse_acc = 2 if self._reverse_acc_change else 1 + reverse_acc = 2 if CS.params_list.reverse_acc_change else 1 # Press distance button until we are at the correct bar length. Only change while enabled to avoid skipping startup popup if self.frame % 6 == 0 and self.CP.openpilotLongitudinalControl: diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 5214cc1265..f1bcfecb49 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -220,7 +220,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if self.lkas_toggle: + if self.CS.params_list.lkas_toggle: if self.CS.lta_status_active: if (self.CS.prev_lkas_enabled == 16 and self.CS.lkas_enabled == 0) or \ (self.CS.prev_lkas_enabled == 0 and self.CS.lkas_enabled == 16): diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index d690b7963d..4589805b5c 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -34,9 +34,6 @@ class CarController(CarControllerBase): self.sm = messaging.SubMaster(['longitudinalPlanSP']) self.param_s = Params() - self.is_metric = self.param_s.get_bool("IsMetric") - self.speed_limit_control_enabled = False - self.last_speed_limit_sign_tap = False self.last_speed_limit_sign_tap_prev = False self.speed_limit = 0. self.speed_limit_offset = 0 @@ -79,24 +76,20 @@ class CarController(CarControllerBase): self.v_tsc = self.sm['longitudinalPlanSP'].visionTurnSpeed self.m_tsc = self.sm['longitudinalPlanSP'].turnSpeed - if self.frame % 200 == 0: - self.speed_limit_control_enabled = self.param_s.get_bool("EnableSlc") - self.is_metric = self.param_s.get_bool("IsMetric") - self.last_speed_limit_sign_tap = self.param_s.get_bool("LastSpeedLimitSignTap") - self.v_cruise_min = VOLKSWAGEN_V_CRUISE_MIN[self.is_metric] * (CV.KPH_TO_MPH if not self.is_metric else 1) + self.v_cruise_min = VOLKSWAGEN_V_CRUISE_MIN[CS.params_list.is_metric] * (CV.KPH_TO_MPH if not CS.params_list.is_metric else 1) actuators = CC.actuators hud_control = CC.hudControl can_sends = [] if not self.CP.pcmCruiseSpeed: - if not self.last_speed_limit_sign_tap_prev and self.last_speed_limit_sign_tap: + if not self.last_speed_limit_sign_tap_prev and CS.params_list.last_speed_limit_sign_tap: self.sl_force_active_timer = self.frame self.param_s.put_bool_nonblocking("LastSpeedLimitSignTap", False) - self.last_speed_limit_sign_tap_prev = self.last_speed_limit_sign_tap + self.last_speed_limit_sign_tap_prev = CS.params_list.last_speed_limit_sign_tap - sl_force_active = self.speed_limit_control_enabled and (self.frame < (self.sl_force_active_timer * DT_CTRL + 2.0)) - sl_inactive = not sl_force_active and (not self.speed_limit_control_enabled or (True if self.slc_state == 0 else False)) - sl_temp_inactive = not sl_force_active and (self.speed_limit_control_enabled and (True if self.slc_state == 1 else False)) + sl_force_active = CS.params_list.speed_limit_control_enabled and (self.frame < (self.sl_force_active_timer * DT_CTRL + 2.0)) + sl_inactive = not sl_force_active and (not CS.params_list.speed_limit_control_enabled or (True if self.slc_state == 0 else False)) + sl_temp_inactive = not sl_force_active and (CS.params_list.speed_limit_control_enabled and (True if self.slc_state == 1 else False)) slc_active = not sl_inactive and not sl_temp_inactive self.slc_active_stock = slc_active diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/mads_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/mads_settings.cc index 610ee160bc..8dc11cbeac 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/mads_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/mads_settings.cc @@ -101,7 +101,7 @@ void MadsSettings::updateToggles() { const bool enable_mads = params.getBool("EnableMads"); const bool enabled = is_offroad && enable_mads; - toggles["AccMadsCombo"]->setEnabled(enabled); - toggles["MadsCruiseMain"]->setEnabled(enabled); + toggles["AccMadsCombo"]->setEnabled(enable_mads); + toggles["MadsCruiseMain"]->setEnabled(enable_mads); dlob_settings->setEnabled(enabled); } From 9be3925ee11030d1b24162088041dd382c2fccfd Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Thu, 1 Aug 2024 19:34:35 -0800 Subject: [PATCH 204/229] MADS: Hyundai: Independent control with LFA button (#362) * MADS: HKG CAN-FD: Disallow cruise buttons to engage when pcmCruiseSpeed is off * handle states properly * this is better * make sure main button is pressed * oops flipped main * same behavior * handle cruise main button universally * both * not needed * oops * wtf how did i miss --- selfdrive/car/hyundai/carcontroller.py | 2 +- selfdrive/car/hyundai/carstate.py | 17 ++++++++++------- selfdrive/car/hyundai/hyundaicanfd.py | 4 ++-- selfdrive/car/hyundai/interface.py | 21 ++++++++++++--------- selfdrive/car/interfaces.py | 2 +- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 00e4cd919a..7f07c08a0f 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -228,7 +228,7 @@ class CarController(CarControllerBase): if hda2: can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame)) if self.frame % 2 == 0: - can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled and CS.out.cruiseState.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override, + can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CS, CC.enabled and CS.out.cruiseState.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override, set_speed_in_units, hud_control)) self.accel_last = accel else: diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index d8329c5ba7..fcd44cc1cd 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -62,6 +62,11 @@ class CarState(CarStateBase): self.escc_aeb_dec_cmd = 0 self._speed_limit_clu = 0 + def get_main_enabled(self, ret) -> bool: + if self.prev_main_buttons != 1 and self.main_buttons[-1] == 1: + self.mainEnabled = not self.mainEnabled + return ret.cruiseState.available and self.mainEnabled + def update(self, cp, cp_cam): if self.CP.carFingerprint in CANFD_CAR: return self.update_canfd(cp, cp_cam) @@ -112,7 +117,7 @@ class CarState(CarStateBase): # cruise state if self.CP.openpilotLongitudinalControl: # These are not used for engage/disengage since openpilot keeps track of state using the buttons - ret.cruiseState.available = cp.vl["TCS13"]["ACCEnable"] == 0 and self.mainEnabled + ret.cruiseState.available = cp.vl["TCS13"]["ACCEnable"] == 0 ret.cruiseState.enabled = cp.vl["TCS13"]["ACC_REQ"] == 1 ret.cruiseState.standstill = False ret.cruiseState.nonAdaptive = False @@ -207,17 +212,12 @@ class CarState(CarStateBase): self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"]) self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"]) if self.CP.openpilotLongitudinalControl: - if self.prev_main_buttons != 1: - if self.main_buttons[-1] == 1: - self.mainEnabled = not self.mainEnabled - ret.cruiseState.available = ret.cruiseState.available and self.mainEnabled + ret.cruiseState.available = self.get_main_enabled(ret) self.prev_mads_enabled = self.mads_enabled self.prev_lfa_enabled = self.lfa_enabled if self.CP.spFlags & HyundaiFlagsSP.SP_CAN_LFA_BTN: self.lfa_enabled = cp.vl["BCM_PO_11"]["LFA_Pressed"] - self.mads_enabled = False if not self.control_initialized else ret.cruiseState.available - if self.CP.spFlags & HyundaiFlagsSP.SP_NAV_MSG or self.CP.spFlags & HyundaiFlagsSP.SP_LKAS12: self._update_traffic_signals(cp, cp_cam) ret.cruiseState.speedLimit = self._calculate_speed_limit() * speed_conv @@ -282,6 +282,7 @@ class CarState(CarStateBase): ret.cruiseState.standstill = False else: cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp + ret.cruiseState.available = cp_cruise_info.vl["SCC_CONTROL"]["MainMode_ACC"] == 1 ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2) ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1 ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor @@ -298,6 +299,8 @@ class CarState(CarStateBase): self.prev_main_buttons = self.main_buttons[-1] self.cruise_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"]) self.main_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"]) + if self.CP.openpilotLongitudinalControl: + ret.cruiseState.available = self.get_main_enabled(ret) self.prev_mads_enabled = self.mads_enabled self.prev_lfa_enabled = self.lfa_enabled self.lfa_enabled = cp.vl[self.cruise_btns_msg_canfd]["LFA_BTN"] diff --git a/selfdrive/car/hyundai/hyundaicanfd.py b/selfdrive/car/hyundai/hyundaicanfd.py index 8225166bfa..12b84ad0f6 100644 --- a/selfdrive/car/hyundai/hyundaicanfd.py +++ b/selfdrive/car/hyundai/hyundaicanfd.py @@ -121,7 +121,7 @@ def create_lfahda_cluster(packer, CAN, enabled, lat_active, lateral_paused, blin return packer.make_can_msg("LFAHDA_CLUSTER", CAN.ECAN, values) -def create_acc_control(packer, CAN, enabled, accel_last, accel, stopping, gas_override, set_speed, hud_control): +def create_acc_control(packer, CAN, CS, enabled, accel_last, accel, stopping, gas_override, set_speed, hud_control): jerk = 5 jn = jerk / 50 if not enabled or gas_override: @@ -132,7 +132,7 @@ def create_acc_control(packer, CAN, enabled, accel_last, accel, stopping, gas_ov values = { "ACCMode": 0 if not enabled else (2 if gas_override else 1), - "MainMode_ACC": 1, + "MainMode_ACC": 1 if CS.mainEnabled else 0, "StopReq": 1 if stopping else 0, "aReqValue": a_val, "aReqRaw": a_raw, diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 02897f9765..c2140d2925 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -210,22 +210,25 @@ class CarInterface(CarInterfaceBase): *create_button_events(self.CS.main_buttons[-1], self.CS.prev_main_buttons, {1: ButtonType.altButton3}), ] + self.CS.mads_enabled = self.get_sp_cruise_main_state(ret, self.CS) + self.CS.accEnabled = self.get_sp_v_cruise_non_pcm_state(ret, self.CS.accEnabled, self.CS.button_events, c.vCruise) - self.CS.mads_enabled = False if not self.mads_main_toggle else self.CS.mads_enabled - if ret.cruiseState.available: if not self.CP.pcmCruiseSpeed: if any(b.type in (ButtonType.altButton3, ButtonType.cancel) and not b.pressed for b in self.CS.button_events): self.CS.accEnabled = True - if self.enable_mads: - if not self.CS.prev_mads_enabled and self.CS.mads_enabled: - self.CS.madsEnabled = True - if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): - self.CS.madsEnabled = not self.CS.madsEnabled - self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) - else: + + if self.enable_mads: + if not self.CS.prev_mads_enabled and self.CS.mads_enabled and \ + any(b.type == ButtonType.altButton3 for b in self.CS.button_events): + self.CS.madsEnabled = True + if any(b.type == ButtonType.altButton1 and b.pressed for b in self.CS.button_events): + self.CS.madsEnabled = not self.CS.madsEnabled + self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) + + if not ret.cruiseState.available and self.CS.out.cruiseState.available: self.CS.madsEnabled = False if not self.CP.pcmCruise or not self.CP.pcmCruiseSpeed: diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index ca4a508554..53cca37458 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -470,7 +470,7 @@ class CarInterfaceBase(ABC): events.add(EventName.spReverseGear) elif cs_out.vEgo >= 5: events.add(EventName.reverseGear) - if not cs_out.cruiseState.available: + if not cs_out.cruiseState.available and cs_out.cruiseState.enabled: events.add(EventName.wrongCarMode) if cs_out.espDisabled: events.add(EventName.espDisabled) From 13511e383c1679d17843e8cbf1bcb0a926f74c35 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 1 Aug 2024 22:16:13 -0700 Subject: [PATCH 205/229] remove pre-commit (explorations) (#33172) * remove pre-commit (explorations) * lint.sh * remove rest * add to release files * no source * 1min is all you need --- .github/workflows/repo-maintenance.yaml | 8 +- .github/workflows/selfdrive_tests.yaml | 17 +- .../workflows/setup-pre-commit/action.yaml | 12 - .pre-commit-config.yaml | 105 --------- docs/WORKFLOW.md | 2 +- pyproject.toml | 11 +- release/release_files.py | 1 - scripts/lint.sh | 10 + scripts/pyupgrade.sh | 7 - tools/install_python_dependencies.sh | 6 - tools/op.sh | 4 +- uv.lock | 209 ++++++------------ 12 files changed, 101 insertions(+), 291 deletions(-) delete mode 100644 .github/workflows/setup-pre-commit/action.yaml delete mode 100644 .pre-commit-config.yaml create mode 100755 scripts/lint.sh delete mode 100755 scripts/pyupgrade.sh diff --git a/.github/workflows/repo-maintenance.yaml b/.github/workflows/repo-maintenance.yaml index cf35804492..3893c7fa5e 100644 --- a/.github/workflows/repo-maintenance.yaml +++ b/.github/workflows/repo-maintenance.yaml @@ -46,17 +46,13 @@ jobs: python3 -m ensurepip --upgrade pip3 install uv uv lock --upgrade - - name: pre-commit autoupdate - run: | - git config --global --add safe.directory '*' - pre-commit autoupdate - name: Create Pull Request uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83 with: author: Vehicle Researcher token: ${{ secrets.ACTIONS_CREATE_PR_PAT }} - commit-message: Update Python packages and pre-commit hooks - title: '[bot] Update Python packages and pre-commit hooks' + commit-message: Update Python packages + title: '[bot] Update Python packages' branch: auto-package-updates base: master delete-branch: true diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 80be72f26a..8c46e15c2f 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -25,7 +25,7 @@ env: DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} BUILD: selfdrive/test/docker_build.sh base - RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PRE_COMMIT_HOME=/tmp/pre-commit -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/pre-commit:/tmp/pre-commit -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c + RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c PYTEST: pytest --continue-on-collection-errors --cov --cov-report=xml --cov-append --durations=0 --durations-min=5 --hypothesis-seed 0 -n logical @@ -45,7 +45,6 @@ jobs: - name: Build devel timeout-minutes: 1 run: TARGET_DIR=$STRIPPED_DIR release/build_devel.sh - - uses: ./.github/workflows/setup-pre-commit - uses: ./.github/workflows/setup-with-retry - name: Check submodules if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' @@ -62,14 +61,13 @@ jobs: cd $STRIPPED_DIR ${{ env.RUN }} "release/check-dirty.sh && \ MAX_EXAMPLES=5 $PYTEST -m 'not slow' selfdrive/car" - - name: pre-commit - timeout-minutes: 3 + - name: static analysis + timeout-minutes: 1 run: | cd $GITHUB_WORKSPACE - cp .pre-commit-config.yaml $STRIPPED_DIR cp pyproject.toml $STRIPPED_DIR cd $STRIPPED_DIR - ${{ env.RUN }} "unset PYTHONWARNINGS && SKIP=check-added-large-files,check-hooks-apply,check-useless-excludes pre-commit run --all && chmod -R 777 /tmp/pre-commit" + ${{ env.RUN }} "scripts/lint.sh" build: strategy: @@ -146,13 +144,12 @@ jobs: - uses: actions/checkout@v4 with: submodules: true - - uses: ./.github/workflows/setup-pre-commit - uses: ./.github/workflows/setup-with-retry - name: Build openpilot run: ${{ env.RUN }} "scons -j$(nproc)" - - name: pre-commit - timeout-minutes: 4 - run: ${{ env.RUN }} "unset PYTHONWARNINGS && pre-commit run --all && chmod -R 777 /tmp/pre-commit" + - name: static analysis + timeout-minutes: 1 + run: ${{ env.RUN }} "scripts/lint.sh" unit_tests: name: unit tests diff --git a/.github/workflows/setup-pre-commit/action.yaml b/.github/workflows/setup-pre-commit/action.yaml deleted file mode 100644 index f07a106861..0000000000 --- a/.github/workflows/setup-pre-commit/action.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: 'set up pre-commit environment' - -runs: - using: "composite" - steps: - - uses: ./.github/workflows/auto-cache - with: - path: .ci_cache/pre-commit - key: pre-commit-${{ hashFiles('**/.pre-commit-config.yaml') }} - restore-keys: | - pre-commit- - save: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index a7a5379088..0000000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,105 +0,0 @@ -exclude: '^(tinygrad_repo)' -repos: -- repo: meta - hooks: - - id: check-hooks-apply - - id: check-useless-excludes -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 - hooks: - - id: check-ast - exclude: '^(third_party)/' - - id: check-json - exclude: '.devcontainer/devcontainer.json|.vscode/' # these support JSON with comments - - id: check-toml - - id: check-xml - - id: check-yaml - - id: check-merge-conflict - - id: check-symlinks - - id: check-executables-have-shebangs - - id: check-shebang-scripts-are-executable - - id: check-added-large-files - exclude: '(docs/CARS.md)|(uv.lock)|(third_party/acados/include/blasfeo/include/blasfeo_d_kernel.h)' - args: - - --maxkb=120 - - --enforce-all -- repo: https://github.com/codespell-project/codespell - rev: v2.3.0 - hooks: - - id: codespell - exclude: '^(third_party/)|(body/)|(msgq/)|(panda/)|(opendbc/)|(rednose/)|(rednose_repo/)|(teleoprtc/)|(teleoprtc_repo/)|(selfdrive/ui/translations/.*.ts)|(uv.lock)' - args: - # if you've got a short variable name that's getting flagged, add it here - - -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn - - --builtins clear,rare,informal,usage,code,names,en-GB_to_en-US -- repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.5 - hooks: - - id: ruff - exclude: '^(third_party/)|(msgq/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)' -- repo: local - hooks: - - id: mypy - name: mypy - entry: mypy - language: system - types: [python] - args: - - --local-partial-types - - --explicit-package-bases - exclude: '^(third_party/)|(body/)|(msgq/)|(opendbc/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)' -- repo: local - hooks: - - id: cppcheck - name: cppcheck - entry: cppcheck - language: system - types: [c++] - exclude: '^(third_party/)|(msgq/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(tools/)|(selfdrive/modeld/thneed/debug/)|(selfdrive/modeld/test/)|(selfdrive/camerad/test/)|(installer/)' - args: - - --error-exitcode=1 - - --language=c++ - - --quiet - - --force - - -j8 - - --library=qt - - --include=third_party/kaitai/kaitaistream.h -- repo: https://github.com/cpplint/cpplint - rev: 1.6.1 - hooks: - - id: cpplint - exclude: '^(third_party/)|(msgq/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(generated/)' - args: - - --quiet - - --counting=total - - --linelength=240 - # https://google.github.io/styleguide/cppguide.html - # relevant rules are whitelisted, see all options with: cpplint --filter= - - --filter=-build,-legal,-readability,-runtime,-whitespace,+build/include_subdir,+build/forward_decl,+build/include_what_you_use,+build/deprecated,+whitespace/comma,+whitespace/line_length,+whitespace/empty_if_body,+whitespace/empty_loop_body,+whitespace/empty_conditional_body,+whitespace/forcolon,+whitespace/parens,+whitespace/semicolon,+whitespace/tab,+readability/braces -- repo: https://github.com/MarcoGorelli/cython-lint - rev: v0.16.2 - hooks: - - id: cython-lint - exclude: '^(third_party/)|(msgq/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(generated/)' - args: - - --max-line-length=240 - - --ignore=E111, E302, E305 -- repo: local - hooks: - - id: test_translations - name: test translations - entry: pytest selfdrive/ui/tests/test_translations.py - language: system - pass_filenames: false - files: '^selfdrive/ui/translations/' -- repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.29.1 - hooks: - - id: check-github-workflows -- repo: local - hooks: - - id: import-linter - name: import linter - entry: lint-imports - language: system - pass_filenames: false diff --git a/docs/WORKFLOW.md b/docs/WORKFLOW.md index 10cf244fd6..477c7511ca 100644 --- a/docs/WORKFLOW.md +++ b/docs/WORKFLOW.md @@ -29,7 +29,7 @@ pytest cd system/loggerd && pytest . # run the linter -pre-commit run --all +op lint ``` ## Testing diff --git a/pyproject.toml b/pyproject.toml index b486df3870..90b6ecf983 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,7 +76,6 @@ testing = [ "hypothesis ==6.47.*", "import-linter", "mypy", - "pre-commit", "pytest", "pytest-cov", "pytest-cpp", @@ -87,7 +86,8 @@ testing = [ "pytest-asyncio", "pytest-mock", "pytest-repeat", - "ruff" + "ruff", + "codespell", ] dev = [ @@ -164,6 +164,13 @@ testpaths = [ "cereal/messaging/tests", ] +[tool.codespell] +count = true +quiet-level = 3 +# if you've got a short variable name that's getting flagged, add it here +ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn" +builtin = "clear,rare,informal,usage,code,names,en-GB_to_en-US" + [tool.mypy] python_version = "3.11" plugins = [ diff --git a/release/release_files.py b/release/release_files.py index be9ad75ed5..29d565a952 100755 --- a/release/release_files.py +++ b/release/release_files.py @@ -26,7 +26,6 @@ blacklist = [ "selfdrive/car/tests/test_models.*", "^tools/", - "^scripts/", "^tinygrad_repo/", "matlab.*.md", diff --git a/scripts/lint.sh b/scripts/lint.sh new file mode 100755 index 0000000000..3cf548f2bb --- /dev/null +++ b/scripts/lint.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -e + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +cd $DIR/../ + +# TODO: bring back rest of pre-commit checks: +# https://github.com/commaai/openpilot/blob/4b11c9e914707df9def598616995be2a5d355a6a/.pre-commit-config.yaml#L2 + +ruff check . diff --git a/scripts/pyupgrade.sh b/scripts/pyupgrade.sh deleted file mode 100755 index 19aac4b5e2..0000000000 --- a/scripts/pyupgrade.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -set -e - -pip install --upgrade pyupgrade - -git ls-files '*.py' | grep -v 'third_party/' | xargs pyupgrade --py311-plus diff --git a/tools/install_python_dependencies.sh b/tools/install_python_dependencies.sh index a90462888f..8d118525a5 100755 --- a/tools/install_python_dependencies.sh +++ b/tools/install_python_dependencies.sh @@ -43,9 +43,3 @@ if [[ "$(uname)" == 'Darwin' ]]; then echo "export ZMQ=1" >> $ROOT/.env echo "export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES" >> $ROOT/.env fi - -if [ "$(uname)" != "Darwin" ] && [ -e "$ROOT/.git" ]; then - echo "pre-commit hooks install..." - pre-commit install - git submodule foreach pre-commit install -fi diff --git a/tools/op.sh b/tools/op.sh index a7ce7ef28b..e578459ae0 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -224,7 +224,7 @@ function op_juggle() { function op_lint() { op_before_cmd - op_run_command pre-commit run --all $@ + op_run_command scripts/lint.sh $@ } function op_test() { @@ -272,7 +272,7 @@ function op_default() { echo -e " ${BOLD}juggle${NC} Run Plotjuggler" echo -e " ${BOLD}replay${NC} Run replay" echo -e " ${BOLD}cabana${NC} Run cabana" - echo -e " ${BOLD}lint${NC} Run all the pre-commit checks" + echo -e " ${BOLD}lint${NC} Run the linter" echo -e " ${BOLD}test${NC} Run all unit tests from pytest" echo -e " ${BOLD}help${NC} Show this message" echo -e " ${BOLD}install${NC} Install the 'op' tool system wide" diff --git a/uv.lock b/uv.lock index 7afdbb3c65..6876de533c 100644 --- a/uv.lock +++ b/uv.lock @@ -1,10 +1,5 @@ version = 1 requires-python = ">=3.11" -environment-markers = [ - "python_version == '3.12' and platform_machine == 'aarch64'", - "python_version == '3.12' and platform_machine == 'aarch64' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64')", - "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'", -] [[distribution]] name = "aiohttp" @@ -179,9 +174,6 @@ wheels = [ name = "casadi" version = "3.6.5" source = { registry = "https://pypi.org/simple" } -environment-markers = [ - "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'", -] dependencies = [ { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, ] @@ -208,11 +200,8 @@ wheels = [ name = "casadi" version = "3.6.6" source = { url = "https://github.com/commaai/casadi/releases/download/nightly-release-3.6.6/casadi-3.6.6-cp312-none-manylinux2014_aarch64.whl" } -environment-markers = [ - "python_version == '3.12' and platform_machine == 'aarch64'", -] dependencies = [ - { name = "numpy", marker = "python_version == '3.12' and platform_machine == 'aarch64'" }, + { name = "numpy" }, ] wheels = [ { url = "https://github.com/commaai/casadi/releases/download/nightly-release-3.6.6/casadi-3.6.6-cp312-none-manylinux2014_aarch64.whl", hash = "sha256:06a15e0099657b960620a2491e565c7f126030018da80c39f6bd33439160c669" }, @@ -259,15 +248,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/63/e285470a4880a4f36edabe4810057bd4b562c6ddcc165eacf9c3c7210b40/cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", size = 181956 }, ] -[[distribution]] -name = "cfgv" -version = "3.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249 }, -] - [[distribution]] name = "charset-normalizer" version = "3.3.2" @@ -328,6 +308,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/96/43/dae06432d0c4b1dc9e9149ad37b4ca8384cf6eb7700cd9215b177b914f0a/cloudpickle-3.0.0-py3-none-any.whl", hash = "sha256:246ee7d0c295602a036e86369c77fecda4ab17b506496730f2f576d9016fd9c7", size = 20088 }, ] +[[distribution]] +name = "codespell" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a0/a9/98353dfc7afcdf18cffd2dd3e959a25eaaf2728cf450caa59af89648a8e4/codespell-2.3.0.tar.gz", hash = "sha256:360c7d10f75e65f67bad720af7007e1060a5d395670ec11a7ed1fed9dd17471f", size = 329791 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/20/b6019add11e84f821184234cea0ad91442373489ef7ccfa3d73a71b908fa/codespell-2.3.0-py3-none-any.whl", hash = "sha256:a9c7cef2501c9cfede2110fd6d4e5e62296920efe9abfb84648df866e47f58d1", size = 329167 }, +] + [[distribution]] name = "colorama" version = "0.4.6" @@ -486,15 +475,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/47/ef/4cb333825d10317a36a1154341ba37e6e9c087bac99c1990ef07ffdb376f/dictdiffer-0.9.0-py2.py3-none-any.whl", hash = "sha256:442bfc693cfcadaf46674575d2eba1c53b42f5e404218ca2c2ff549f2df56595", size = 16754 }, ] -[[distribution]] -name = "distlib" -version = "0.3.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c4/91/e2df406fb4efacdf46871c25cde65d3c6ee5e173b7e5a4547a47bae91920/distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64", size = 609931 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/41/9307e4f5f9976bc8b7fea0b66367734e8faf3ec84bc0d412d8cfabbb66cd/distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784", size = 468850 }, -] - [[distribution]] name = "dnspython" version = "2.6.1" @@ -762,15 +742,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d3/a7/389bbaade2cbbb2534cb2715986041ed01c6d792152c527e71f7f68e93b5/hypothesis-6.47.5-py3-none-any.whl", hash = "sha256:87049b781ee11ec1c7948565b889ab02e428a1e32d427ab4de8fdb3649242d06", size = 387311 }, ] -[[distribution]] -name = "identify" -version = "2.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/32/f4/8e8f7db397a7ce20fbdeac5f25adaf567fc362472432938d25556008e03a/identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf", size = 99116 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/24/6c/a4f39abe7f19600b74528d0c717b52fff0b300bb0161081510d39c53cb00/identify-2.6.0-py2.py3-none-any.whl", hash = "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0", size = 98962 }, -] - [[distribution]] name = "idna" version = "3.7" @@ -1081,28 +1052,28 @@ name = "metadrive-simulator" version = "0.4.2.3" source = { git = "https://github.com/commaai/metadrive?rev=opencv_headless#9b6ddb791919249effa0573883076681514787e4" } dependencies = [ - { name = "filelock", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "geopandas", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "gymnasium", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "lxml", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "matplotlib", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "opencv-python-headless", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "panda3d", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "panda3d-gltf", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "pandas", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "pillow", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "progressbar", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "psutil", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "pygame", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "pygments", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "pytest", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "requests", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "scipy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "seaborn", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "shapely", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "tqdm", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, - { name = "yapf", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "filelock" }, + { name = "geopandas" }, + { name = "gymnasium" }, + { name = "lxml" }, + { name = "matplotlib" }, + { name = "numpy" }, + { name = "opencv-python-headless" }, + { name = "panda3d" }, + { name = "panda3d-gltf" }, + { name = "pandas" }, + { name = "pillow" }, + { name = "progressbar" }, + { name = "psutil" }, + { name = "pygame" }, + { name = "pygments" }, + { name = "pytest" }, + { name = "requests" }, + { name = "scipy" }, + { name = "seaborn" }, + { name = "shapely" }, + { name = "tqdm" }, + { name = "yapf" }, ] [[distribution]] @@ -1169,7 +1140,6 @@ version = "1.30.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "pyjwt", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyjwt", extra = ["crypto"] }, { name = "requests", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, ] @@ -1271,15 +1241,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ef/82/7a9d0550484a62c6da82858ee9419f3dd1ccc9aa1c26a1e43da3ecd20b0d/natsort-8.4.0-py3-none-any.whl", hash = "sha256:4732914fb471f56b5cce04d7bae6f164a592c7712e1c85f9ef585e197299521c", size = 38268 }, ] -[[distribution]] -name = "nodeenv" -version = "1.9.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314 }, -] - [[distribution]] name = "numpy" version = "1.26.4" @@ -1404,8 +1365,8 @@ dependencies = [ { name = "libusb1", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "numpy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "onnx", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "onnxruntime", marker = "platform_machine == 'aarch64' and platform_system == 'Linux'" }, - { name = "onnxruntime-gpu", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "onnxruntime", marker = "(python_version == '3.12' and platform_machine == 'aarch64' and platform_system == 'Linux') or (python_version == '3.12' and platform_machine == 'aarch64' and platform_system == 'Linux' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64')) or (platform_machine == 'aarch64' and platform_system == 'Linux' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'))" }, + { name = "onnxruntime-gpu", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64')" }, { name = "psutil", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pyaudio", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "pycapnp", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, @@ -1419,7 +1380,7 @@ dependencies = [ { name = "setuptools", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "smbus2", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "sounddevice", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "spidev", marker = "platform_system == 'Linux'" }, + { name = "spidev", marker = "(python_version == '3.12' and platform_machine == 'aarch64' and platform_system == 'Linux') or (python_version == '3.12' and platform_machine == 'aarch64' and platform_system == 'Linux' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64')) or (platform_system == 'Linux' and (python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'))" }, { name = "sympy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "tqdm", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, { name = "websocket-client", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, @@ -1428,49 +1389,49 @@ dependencies = [ [distribution.optional-dependencies] dev = [ - { name = "av", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "azure-identity", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "azure-storage-blob", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "dictdiffer", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "flaky", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "inputs", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "lru-dict", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "matplotlib", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "av" }, + { name = "azure-identity" }, + { name = "azure-storage-blob" }, + { name = "dictdiffer" }, + { name = "flaky" }, + { name = "inputs" }, + { name = "lru-dict" }, + { name = "matplotlib" }, { name = "metadrive-simulator", marker = "platform_machine != 'aarch64'" }, - { name = "parameterized", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "pyautogui", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "parameterized" }, + { name = "pyautogui" }, { name = "pyopencl", marker = "platform_machine != 'aarch64'" }, - { name = "pyprof2calltree", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pyprof2calltree" }, { name = "pyqt5", marker = "platform_machine == 'x86_64'" }, { name = "pytools", marker = "platform_machine != 'aarch64'" }, - { name = "pywinctl", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "rerun-sdk", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "tabulate", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "types-requests", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "types-tabulate", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "pywinctl" }, + { name = "rerun-sdk" }, + { name = "tabulate" }, + { name = "types-requests" }, + { name = "types-tabulate" }, ] docs = [ - { name = "jinja2", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "mkdocs", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "natsort", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "jinja2" }, + { name = "mkdocs" }, + { name = "natsort" }, ] testing = [ - { name = "coverage", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "hypothesis", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "import-linter", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "mypy", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "pre-commit", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "pytest", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "pytest-asyncio", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "pytest-cov", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "pytest-cpp", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "pytest-mock", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "pytest-randomly", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "pytest-repeat", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "pytest-subtests", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "pytest-timeout", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "pytest-xdist", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "ruff", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, + { name = "codespell" }, + { name = "coverage" }, + { name = "hypothesis" }, + { name = "import-linter" }, + { name = "mypy" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-cov" }, + { name = "pytest-cpp" }, + { name = "pytest-mock" }, + { name = "pytest-randomly" }, + { name = "pytest-repeat" }, + { name = "pytest-subtests" }, + { name = "pytest-timeout" }, + { name = "pytest-xdist" }, + { name = "ruff" }, ] [[distribution]] @@ -1643,22 +1604,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9b/fb/a70a4214956182e0d7a9099ab17d50bfcba1056188e9b14f35b9e2b62a0d/portalocker-2.10.1-py3-none-any.whl", hash = "sha256:53a5984ebc86a025552264b459b46a2086e269b21823cb572f8f28ee759e45bf", size = 18423 }, ] -[[distribution]] -name = "pre-commit" -version = "3.8.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cfgv", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "identify", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "nodeenv", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "pyyaml", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "virtualenv", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/64/10/97ee2fa54dff1e9da9badbc5e35d0bbaef0776271ea5907eccf64140f72f/pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af", size = 177815 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/92/caae8c86e94681b42c246f0bca35c059a2f0529e5b92619f6aba4cf7e7b6/pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f", size = 204643 }, -] - [[distribution]] name = "progressbar" version = "2.5" @@ -5170,20 +5115,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ca/1c/89ffc63a9605b583d5df2be791a27bc1a42b7c32bab68d3c8f2f73a98cd4/urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472", size = 121444 }, ] -[[distribution]] -name = "virtualenv" -version = "20.26.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "distlib", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "filelock", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, - { name = "platformdirs", marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64' or (python_version == '3.12' and platform_machine == 'aarch64')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/68/60/db9f95e6ad456f1872486769c55628c7901fb4de5a72c2f7bdd912abf0c1/virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a", size = 9057588 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/4d/410156100224c5e2f0011d435e477b57aed9576fc7fe137abcf14ec16e11/virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589", size = 5684792 }, -] - [[distribution]] name = "watchdog" version = "4.0.1" From ef2331b5df8089d1d65ebadf99e58f8e3725f0c5 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Fri, 2 Aug 2024 16:26:14 +0200 Subject: [PATCH 206/229] ci: Prebuilt public branches and update build number (#380) * fixing build number + forcing run to test * Cleaning up and changing the process for the auto builds * updating the logic for the extra verson identifier * Return to default master-dev-c3 * if this is MR on gitlab, we also publish prebuilt on private gitlab for internal testing * Silly formatting issue --- .gitlab-ci.yml | 64 ++++++++++++++++---------------------------------- 1 file changed, 20 insertions(+), 44 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 33d6289f63..13b30a6af2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,6 +9,10 @@ variables: GIT_CONFIG_USER_EMAIL: "gitlab@pipeline.com" GIT_CONFIG_USER_NAME: "Gitlab Pipeline" PUBLIC_REPO_URL: "https://github.com/sunnyhaibin/sunnypilot" + BASE_BUILD_NUMER: 3000 + + EXTRA_VERSION_IDENTIFIER: "${CI_PIPELINE_IID}" + NEW_BRANCH: ${CI_COMMIT_REF_NAME}-prebuilt stages: - build @@ -23,7 +27,8 @@ default: - x86 .default_before_script: &default_before_script - - 'export VERSION=$(eval $VERSION)${EXTRA_VERSION_IDENTIFIER}' + - 'if [ "$EXTRA_VERSION_IDENTIFIER" = "$CI_PIPELINE_IID" ]; then export EXTRA_VERSION_IDENTIFIER=$((CI_PIPELINE_IID + BASE_BUILD_NUMER)); fi' + - 'export VERSION=$(eval $VERSION)-${EXTRA_VERSION_IDENTIFIER}' - 'mkdir -p "${BUILD_DIR}/"' - 'git config --global user.email "${GIT_CONFIG_USER_EMAIL}"' - 'git config --global user.name "${GIT_CONFIG_USER_NAME}"' @@ -34,34 +39,31 @@ workflow: # If running on any branch other than main. # We are an MR, but it's a draft, we won't proceed with anything. - if: '$CI_MERGE_REQUEST_TITLE =~ /^wip:/i || $CI_MERGE_REQUEST_TITLE =~ /^draft:/i' when: never - # We are a merge request - - if: $CI_MERGE_REQUEST_IID - variables: - EXTRA_VERSION_IDENTIFIER: "-${CI_PIPELINE_IID}" - NEW_BRANCH: ${CI_COMMIT_REF_NAME}-prebuilt - when: always # Below are the rules when a commit is done (code has been added to the branch) # Commit to master-dev-c3 - if: $CI_COMMIT_REF_NAME == $DEV_C3_SOURCE_BRANCH variables: - EXTRA_VERSION_IDENTIFIER: "-${CI_PIPELINE_IID}" + EXTRA_VERSION_IDENTIFIER: "${CI_PIPELINE_IID}" NEW_BRANCH: "dev-c3" + AUTO_BUILD: true when: always #commit made to main (master) - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH variables: NEW_BRANCH: "staging-c3" VERSION: 'cat common/version.h | grep COMMA_VERSION | sed -e "s/[^0-9|.]//g"' - EXTRA_VERSION_IDENTIFIER: "-staging" + EXTRA_VERSION_IDENTIFIER: "staging" AUTO_PUBLISH: true + AUTO_BUILD: true when: always # if tag - if: $CI_COMMIT_TAG variables: NEW_BRANCH: "release-c3" VERSION: 'cat common/version.h | grep COMMA_VERSION | sed -e "s/[^0-9|.]//g"' - EXTRA_VERSION_IDENTIFIER: "-release" + EXTRA_VERSION_IDENTIFIER: "release" + AUTO_BUILD: true - when: always @@ -143,32 +145,9 @@ build: - ${OUTPUT_DIR}/ tags: [ 'sunnypilot', 'tici' ] rules: - - if: $CI_MERGE_REQUEST_IID - when: manual - - if: $NEW_BRANCH + - if: $AUTO_BUILD when: always - -check no source code sent: - image: alpine - stage: sanity - variables: - FORBIDDEN_FILE_EXTENSIONS: "*.a,*.o,*.os,*.pyc,moc_*,*.cc,Jenkinsfile,supercombo.onnx,.sconsign.dblite" - FORBIDDEN_DIR_PATTERNS: "*panda/certs,*panda/crypto,*release,*.github,*selfdrive/ui/replay,*__pycache__" - REQUIRED_FILE_EXTENSIONS: "*.py,*.json" - REQUIRED_DIR_PATTERNS: "*selfdrive/ui,*openpilot" - before_script: - - apk update && apk upgrade - - apk add bash findutils - script: - - cd ${OUTPUT_DIR} - - echo "Checking that we have properly cleaned up" - - ${CI_DIR}/sanity_check.sh "$FORBIDDEN_FILE_EXTENSIONS" "$FORBIDDEN_DIR_PATTERNS" true - - echo "Checking that our sanity check works and also checking that some required files are indeed found" - - ${CI_DIR}/sanity_check.sh "$REQUIRED_FILE_EXTENSIONS" "$REQUIRED_DIR_PATTERNS" false - rules: - - if: $NEW_BRANCH - when: on_success - - when: never + - when: manual .publish_base: &publish_base image: alpine @@ -178,9 +157,6 @@ check no source code sent: needs: - job: build artifacts: true - - job: "check no source code sent" - artifacts: false - optional: false before_script: - 'apk update && apk upgrade' - 'apk add git bash openssh' @@ -197,7 +173,7 @@ check no source code sent: - echo "${GIT_ORIGIN}" - echo "Calling to publish [${CI_DIR}/publish.sh ${CI_PROJECT_DIR} ${OUTPUT_DIR} ${NEW_BRANCH} ${VERSION} ${GIT_ORIGIN}]" - git config --global --add safe.directory ${OUTPUT_DIR} - - $CI_DIR/publish.sh "${CI_PROJECT_DIR}" "${OUTPUT_DIR}" "${NEW_BRANCH}" "${VERSION}" "${GIT_ORIGIN}" "${EXTRA_VERSION_IDENTIFIER}" + - $CI_DIR/publish.sh "${CI_PROJECT_DIR}" "${OUTPUT_DIR}" "${NEW_BRANCH}" "${VERSION}" "${GIT_ORIGIN}" "-${EXTRA_VERSION_IDENTIFIER}" allow_failure: false publish to private gitlab prebuilt: @@ -205,9 +181,11 @@ publish to private gitlab prebuilt: variables: GIT_ORIGIN: git@gitlab.com:sunnypilot/public/sunnypilot-prebuilts.git rules: - - if: $NEW_BRANCH + - if: $AUTO_BUILD when: on_success - - when: never + - if: $CI_MERGE_REQUEST_IID + when: on_success + - when: manual publish to public github prebuilt: extends: ".publish_base" @@ -218,9 +196,7 @@ publish to public github prebuilt: rules: - if: $AUTO_PUBLISH when: on_success - - if: $NEW_BRANCH - when: manual - - when: never + - when: manual .notify_discord: ¬ify_discord image: alpine From 4cb7263dd63e221e30a2ea40428bbacc2a5d6f20 Mon Sep 17 00:00:00 2001 From: John Belmonte Date: Fri, 2 Aug 2024 23:35:37 +0900 Subject: [PATCH 207/229] Docs: Fix indentation of feature list (#379) Fix indenting of feature list --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index c78052ad6b..72319c2dc2 100644 --- a/README.md +++ b/README.md @@ -170,16 +170,16 @@ After running the command to install the desired branch, your comma device shoul * Speed Limit Control (SLC) - Set speed limit based on map data or car interface (if applicable) * HKG only: Highway Driving Assist (HDA) status integration - Use cars native speed sign detection to set desired speed (on applicable HKG cars only) - [**Gap Adjust Cruise (GAC)**](#gap-adjust-cruise) - Allow `GAP`/`INTERVAL`/`DISTANCE` button on the steering wheel or on-screen button to adjust the follow distance from the lead car. See table below for options - - [**Quiet Drive 🤫**](#-quiet-drive) - Toggle to mute all notification sounds (excluding driver safety warnings) - - [**Auto Lane Change Timer**](#Auto-Lane-Change-Timer) - Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set - - [**Force Car Recognition (FCR)**](#Force-Car-Recognition-) - Use a selector to force your car to be recognized by sunnypilot - - [**Fix sunnypilot No Offroad**](#Fix-sunnypilot-No-Offroad) - Enforce sunnypilot to go offroad and turns off after shutting down the car. This feature fixes non-official devices running sunnypilot without comma power - - [**Enable ACC+MADS with RES+/SET-**](#Enable-ACC+MADS-with-RES+/SET-) - Engage both ACC and MADS with a single press of RES+ or SET- button - - [**Offline OSM Maps**](#Offline-OSM-Maps) - OSM database can now be downloaded locally for offline use[^2]. This enables offline SLC, V-TSC and M-TSC. Currently available for US South, US West, US Northeast, Florida, Taiwan, South Africa and New Zealand - - [**Various Live Tuning**](#Various-Live-Tuning) - Ability to tailor your driving experience on the fly: - * Enforce Torque Lateral Control - Use the newest [torque controller](https://blog.comma.ai/0815release/#torque-controller) for all vehicles. - * Torque Lateral Control Live Tune - Ability to adjust the torque controller’s `FRICTION` and `LAT_ACCEL_FACTOR` values to suit your vehicle. - * Torque Lateral Controller Self-Tune - Enable automatic turning for the Torque controller. +- [**Quiet Drive 🤫**](#-quiet-drive) - Toggle to mute all notification sounds (excluding driver safety warnings) +- [**Auto Lane Change Timer**](#Auto-Lane-Change-Timer) - Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set +- [**Force Car Recognition (FCR)**](#Force-Car-Recognition-) - Use a selector to force your car to be recognized by sunnypilot +- [**Fix sunnypilot No Offroad**](#Fix-sunnypilot-No-Offroad) - Enforce sunnypilot to go offroad and turns off after shutting down the car. This feature fixes non-official devices running sunnypilot without comma power +- [**Enable ACC+MADS with RES+/SET-**](#Enable-ACC+MADS-with-RES+/SET-) - Engage both ACC and MADS with a single press of RES+ or SET- button +- [**Offline OSM Maps**](#Offline-OSM-Maps) - OSM database can now be downloaded locally for offline use[^2]. This enables offline SLC, V-TSC and M-TSC. Currently available for US South, US West, US Northeast, Florida, Taiwan, South Africa and New Zealand +- [**Various Live Tuning**](#Various-Live-Tuning) - Ability to tailor your driving experience on the fly: + * Enforce Torque Lateral Control - Use the newest [torque controller](https://blog.comma.ai/0815release/#torque-controller) for all vehicles. + * Torque Lateral Control Live Tune - Ability to adjust the torque controller’s `FRICTION` and `LAT_ACCEL_FACTOR` values to suit your vehicle. + * Torque Lateral Controller Self-Tune - Enable automatic turning for the Torque controller. ### Visual Enhancements * **M.A.D.S Status Icon** - Dedicated icon to display M.A.D.S. engagement status From 61f7690265ab1a8c3827e3fcd9353cb6b64b3fb4 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Fri, 2 Aug 2024 07:38:25 -0800 Subject: [PATCH 208/229] ci: Update build number on dev builds with Discord notification (#381) --- .gitlab-ci.yml | 3 +++ release/ci/discord_template_notify_dev_public.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 13b30a6af2..23881001fe 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -230,6 +230,9 @@ notify new dev build: needs: ["publish to public github prebuilt"] # This notify shall only happen after a publish to github public variables: TEMPLATE: "discord_template_notify_dev_public.json" + before_script: + - !reference [".notify_discord", "before_script"] + - export EXTRA_VERSION_IDENTIFIER=$((CI_PIPELINE_IID + BASE_BUILD_NUMER)) rules: - if: $NEW_BRANCH == "dev-c3" variables: diff --git a/release/ci/discord_template_notify_dev_public.json b/release/ci/discord_template_notify_dev_public.json index d1a7b37f96..c933ea10b4 100644 --- a/release/ci/discord_template_notify_dev_public.json +++ b/release/ci/discord_template_notify_dev_public.json @@ -2,7 +2,7 @@ "embeds": [ { "title": "🎉 sunnypilot `${NEW_BRANCH}` New Update 🎉", - "description": "[sunnypilot](${PUBLIC_REPO_URL}): Build #${CI_PIPELINE_IID} of branch [${NEW_BRANCH}](${PUBLIC_REPO_URL}/tree/${NEW_BRANCH}) has been published.\n\nDrive safe! 🚗💨", + "description": "[sunnypilot](${PUBLIC_REPO_URL}): Build #${EXTRA_VERSION_IDENTIFIER} of branch [${NEW_BRANCH}](${PUBLIC_REPO_URL}/tree/${NEW_BRANCH}) has been published.\n\nDrive safe! 🚗💨", "color": 4321431 } ] From 09d1604b842f1490100fbcac664928bf07ca9506 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Fri, 2 Aug 2024 07:41:20 -0800 Subject: [PATCH 209/229] MADS: Honda: Fix PCM ACC disengage fault (#363) * MADS: Honda: Fix PCM ACC disengage fault * try this out * honda only --- selfdrive/car/honda/interface.py | 19 ++++++++++++------- selfdrive/car/interfaces.py | 5 ++--- selfdrive/controls/controlsd.py | 4 +++- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 3e32a35db6..1459b301a2 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -282,21 +282,26 @@ class CarInterface(CarInterfaceBase): else: self.CS.madsEnabled = False - if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0) or not self.CP.pcmCruiseSpeed: + min_enable_speed_pcm = self.CP.pcmCruise and self.CP.minEnableSpeed > 0 and self.CP.pcmCruiseSpeed + + if not self.CP.pcmCruise or min_enable_speed_pcm or not self.CP.pcmCruiseSpeed: if any(b.type == ButtonType.cancel for b in self.CS.button_events): self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled) if self.get_sp_pedal_disengage(ret): self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled) - ret.cruiseState.enabled = ret.cruiseState.enabled if not self.enable_mads else False if self.CP.pcmCruise else self.CS.accEnabled + ret.cruiseState.enabled = ret.cruiseState.enabled if not self.enable_mads or min_enable_speed_pcm \ + else False if self.CP.pcmCruise \ + else self.CS.accEnabled - if self.CP.pcmCruise and self.CP.minEnableSpeed > 0 and self.CP.pcmCruiseSpeed: + if min_enable_speed_pcm: if ret.gasPressed and not ret.cruiseState.enabled: self.CS.accEnabled = False - self.CS.accEnabled = ret.cruiseState.enabled or self.CS.accEnabled + if ret.cruiseState.enabled and not self.CS.out.cruiseState.enabled: + self.CS.accEnabled = True + elif not ret.cruiseState.enabled: + self.CS.accEnabled = False - ret, self.CS = self.get_sp_common_state(ret, self.CS, - min_enable_speed_pcm=(self.CP.pcmCruise and self.CP.minEnableSpeed > 0 and self.CP.pcmCruiseSpeed), - gap_button=(self.CS.cruise_setting == 3)) + ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=(self.CS.cruise_setting == 3)) ret.buttonEvents = [ *self.CS.button_events, diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 53cca37458..904fe4f45b 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -615,9 +615,8 @@ class CarInterfaceBase(ABC): else: return CS.madsEnabled - def get_sp_common_state(self, cs_out, CS, min_enable_speed_pcm=False, gear_allowed=True, gap_button=False): - cs_out.cruiseState.enabled = CS.accEnabled if not self.CP.pcmCruise or not self.CP.pcmCruiseSpeed or min_enable_speed_pcm else \ - cs_out.cruiseState.enabled + def get_sp_common_state(self, cs_out, CS, gear_allowed=True, gap_button=False): + cs_out.cruiseState.enabled = CS.accEnabled if not self.CP.pcmCruise or not self.CP.pcmCruiseSpeed else cs_out.cruiseState.enabled if not self.enable_mads: if cs_out.cruiseState.enabled and not CS.out.cruiseState.enabled: diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 2af32f8a0c..a8dcc3b5e4 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -739,7 +739,9 @@ class Controls: CC.angularVelocity = angular_rate_value CC.cruiseControl.override = self.enabled_long and not CC.longActive and self.CP.openpilotLongitudinalControl - CC.cruiseControl.cancel = CS.cruiseState.enabled and (not self.enabled_long or (CS.brakePressed and (not self.CS_prev.brakePressed or not CS.standstill))) + CC.cruiseControl.cancel = CS.cruiseState.enabled and \ + (not self.enabled_long or (CS.brakePressed and (not self.CS_prev.brakePressed or not CS.standstill)) or + (any(b.type == ButtonType.cancel for b in CS.buttonEvents) and self.CP.carName == "honda")) if self.joystick_mode and self.sm.recv_frame['testJoystick'] > 0 and self.sm['testJoystick'].buttons[0]: CC.cruiseControl.cancel = True From b63ef7b0bfed26db39366e2fc844e6ed2d8a187a Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Fri, 2 Aug 2024 18:35:44 +0200 Subject: [PATCH 210/229] Create codeql.yml --- .github/workflows/codeql.yml | 97 ++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..f352a6a416 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,97 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ "master", "*-c3", "master*" ] + pull_request: + branches: [ "master", "*-c3", "master*" ] + schedule: + - cron: '39 7 * * 2' + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: c-cpp + build-mode: autobuild + - language: javascript-typescript + build-mode: none + - language: python + build-mode: none + # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" From bdb733ddc9302b0051171eb81a255c19e2e2d89e Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Fri, 2 Aug 2024 08:36:49 -0800 Subject: [PATCH 211/229] car: Fix typo with `ParamManager` variable (#382) --- selfdrive/car/toyota/interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index f1bcfecb49..527964cead 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -220,7 +220,7 @@ class CarInterface(CarInterfaceBase): if self.enable_mads: if not self.CS.prev_mads_enabled and self.CS.mads_enabled: self.CS.madsEnabled = True - if self.CS.params_list.lkas_toggle: + if self.CS.params_list.toyota_lkas_toggle: if self.CS.lta_status_active: if (self.CS.prev_lkas_enabled == 16 and self.CS.lkas_enabled == 0) or \ (self.CS.prev_lkas_enabled == 0 and self.CS.lkas_enabled == 16): From 8f3fc699d4e06811fd29fbf64fe89032cce563b9 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 3 Aug 2024 03:01:56 +0800 Subject: [PATCH 212/229] loggerd: Initialize atomic variables to zero (#33130) Initialize atomic variables in LoggerdState to zero --- system/loggerd/loggerd.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/loggerd/loggerd.cc b/system/loggerd/loggerd.cc index a324479fb5..c9632c0dd6 100644 --- a/system/loggerd/loggerd.cc +++ b/system/loggerd/loggerd.cc @@ -15,8 +15,8 @@ ExitHandler do_exit; struct LoggerdState { LoggerState logger; - std::atomic last_camera_seen_tms; - std::atomic ready_to_rotate; // count of encoders ready to rotate + std::atomic last_camera_seen_tms{0.0}; + std::atomic ready_to_rotate{0}; // count of encoders ready to rotate int max_waiting = 0; double last_rotate_tms = 0.; // last rotate time in ms }; From 2189164d455aba0c72192881bef43a1cee8f3d3b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 3 Aug 2024 03:16:04 +0800 Subject: [PATCH 213/229] camerad: encapsulating event management within the ImgProc Class (#33119) Encapsulating Event Management Within the ImgProc Class --- system/camerad/cameras/camera_common.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/system/camerad/cameras/camera_common.cc b/system/camerad/cameras/camera_common.cc index 06ef2bd378..4032dad252 100644 --- a/system/camerad/cameras/camera_common.cc +++ b/system/camerad/cameras/camera_common.cc @@ -37,7 +37,7 @@ public: } - void queue(cl_command_queue q, cl_mem cam_buf_cl, cl_mem buf_cl, int width, int height, cl_event *imgproc_event, int expo_time) { + void runKernel(cl_command_queue q, cl_mem cam_buf_cl, cl_mem buf_cl, int width, int height, int expo_time) { CL_CHECK(clSetKernelArg(krnl_, 0, sizeof(cl_mem), &cam_buf_cl)); CL_CHECK(clSetKernelArg(krnl_, 1, sizeof(cl_mem), &buf_cl)); CL_CHECK(clSetKernelArg(krnl_, 2, sizeof(cl_int), &expo_time)); @@ -45,7 +45,11 @@ public: const size_t globalWorkSize[] = {size_t(width / 2), size_t(height / 2)}; const int imgproc_local_worksize = 16; const size_t localWorkSize[] = {imgproc_local_worksize, imgproc_local_worksize}; - CL_CHECK(clEnqueueNDRangeKernel(q, krnl_, 2, NULL, globalWorkSize, localWorkSize, 0, 0, imgproc_event)); + + cl_event event; + CL_CHECK(clEnqueueNDRangeKernel(q, krnl_, 2, NULL, globalWorkSize, localWorkSize, 0, 0, &event)); + clWaitForEvents(1, &event); + CL_CHECK(clReleaseEvent(event)); } ~ImgProc() { @@ -116,10 +120,7 @@ bool CameraBuf::acquire() { cur_camera_buf = &camera_bufs[cur_buf_idx]; double start_time = millis_since_boot(); - cl_event event; - imgproc->queue(q, camera_bufs[cur_buf_idx].buf_cl, cur_yuv_buf->buf_cl, rgb_width, rgb_height, &event, cur_frame_data.integ_lines); - clWaitForEvents(1, &event); - CL_CHECK(clReleaseEvent(event)); + imgproc->runKernel(q, camera_bufs[cur_buf_idx].buf_cl, cur_yuv_buf->buf_cl, rgb_width, rgb_height, cur_frame_data.integ_lines); cur_frame_data.processing_time = (millis_since_boot() - start_time) / 1000.0; VisionIpcBufExtra extra = { From ea5ee29ebddf0a17bd884f23de6b6a5a288ebd10 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 3 Aug 2024 03:16:24 +0800 Subject: [PATCH 214/229] params: wrap fsync and close in HANDLE_EINTR for robustness (#33154) Wrap fsync and close in HANDLE_EINTR for Robustness --- common/params.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/params.cc b/common/params.cc index 03a3cc31f1..615dd55abd 100644 --- a/common/params.cc +++ b/common/params.cc @@ -24,8 +24,8 @@ int fsync_dir(const std::string &path) { int result = -1; int fd = HANDLE_EINTR(open(path.c_str(), O_RDONLY, 0755)); if (fd >= 0) { - result = fsync(fd); - close(fd); + result = HANDLE_EINTR(fsync(fd)); + HANDLE_EINTR(close(fd)); } return result; } From 8ab587d30b461cf52844a351b912e3560b9dcbcd Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 3 Aug 2024 03:18:10 +0800 Subject: [PATCH 215/229] camerad: move `do_exit` to camera_qcom2.cc (#33086) move do_exit to camera_qcom2.cc --- system/camerad/cameras/camera_common.cc | 2 -- system/camerad/cameras/camera_qcom2.cc | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/system/camerad/cameras/camera_common.cc b/system/camerad/cameras/camera_common.cc index 4032dad252..6aec03eae1 100644 --- a/system/camerad/cameras/camera_common.cc +++ b/system/camerad/cameras/camera_common.cc @@ -15,8 +15,6 @@ #include "CL/cl_ext_qcom.h" #endif -ExitHandler do_exit; - class ImgProc { public: ImgProc(cl_device_id device_id, cl_context context, const CameraBuf *b, const CameraState *s, int buf_width, int uv_offset) { diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index 2729aa264c..6aebc88718 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -24,7 +24,7 @@ const int MIPI_SETTLE_CNT = 33; // Calculated by camera_freqs.py // For debugging: // echo "4294967295" > /sys/module/cam_debug_util/parameters/debug_mdl -extern ExitHandler do_exit; +ExitHandler do_exit; CameraState::CameraState(MultiCameraState *multi_camera_state, const CameraConfig &config) : multi_cam_state(multi_camera_state), From 19dec54f65459b619f9a726c7ca6ecb96f6067ea Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 2 Aug 2024 12:55:04 -0700 Subject: [PATCH 216/229] Update stale.yaml --- .github/workflows/stale.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml index a26691ea45..f7f92a0387 100644 --- a/.github/workflows/stale.yaml +++ b/.github/workflows/stale.yaml @@ -5,8 +5,8 @@ on: workflow_dispatch: env: - DAYS_BEFORE_PR_CLOSE: 3 - DAYS_BEFORE_PR_STALE: 14 + DAYS_BEFORE_PR_CLOSE: 2 + DAYS_BEFORE_PR_STALE: 9 jobs: stale: From c40d129f70338674302116cfdde129ba6511a920 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 3 Aug 2024 03:57:29 +0800 Subject: [PATCH 217/229] camerad: update frame msg related variable types to uint64_t for consistency (#33113) Update frame_msg related variable types to uint64_t for type safety --- system/camerad/cameras/camera_qcom2.cc | 14 +++++++------- system/camerad/cameras/camera_qcom2.h | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index 6aebc88718..0648ddf4de 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -345,7 +345,7 @@ void CameraState::config_isp(int io_mem_handle, int fence, int request_id, int b void CameraState::enqueue_buffer(int i, bool dp) { int ret; - int request_id = request_ids[i]; + uint64_t request_id = request_ids[i]; if (buf_handle[i] && sync_objs[i]) { // wait @@ -386,7 +386,7 @@ void CameraState::enqueue_buffer(int i, bool dp) { req_mgr_sched_request.req_id = request_id; ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_SCHED_REQ, &req_mgr_sched_request, sizeof(req_mgr_sched_request)); if (ret != 0) { - LOGE("failed to schedule cam mgr request: %d %d", ret, request_id); + LOGE("failed to schedule cam mgr request: %d %lu", ret, request_id); } // poke sensor, must happen after schedule @@ -396,8 +396,8 @@ void CameraState::enqueue_buffer(int i, bool dp) { config_isp(buf_handle[i], sync_objs[i], request_id, buf0_handle, 65632*(i+1)); } -void CameraState::enqueue_req_multi(int start, int n, bool dp) { - for (int i=start; iu.frame_msg.link_hdl == link_handle); uint64_t timestamp = event_data->u.frame_msg.timestamp; - int main_id = event_data->u.frame_msg.frame_id; - int real_id = event_data->u.frame_msg.request_id; + uint64_t main_id = event_data->u.frame_msg.frame_id; + uint64_t real_id = event_data->u.frame_msg.request_id; if (real_id != 0) { // next ready if (real_id == 1) {idx_offset = main_id;} @@ -799,7 +799,7 @@ void CameraState::handle_camera_event(void *evdat) { // check for dropped requests if (real_id > request_id_last + 1) { - LOGE("camera %d dropped requests %d %d", camera_num, real_id, request_id_last); + LOGE("camera %d dropped requests %ld %ld", camera_num, real_id, request_id_last); enqueue_req_multi(request_id_last + 1 + FRAME_BUF_COUNT, real_id - (request_id_last + 1), 0); } diff --git a/system/camerad/cameras/camera_qcom2.h b/system/camerad/cameras/camera_qcom2.h index 1b27fb18b8..02ebeb71f3 100644 --- a/system/camerad/cameras/camera_qcom2.h +++ b/system/camerad/cameras/camera_qcom2.h @@ -105,17 +105,17 @@ public: int buf0_handle = 0; int buf_handle[FRAME_BUF_COUNT] = {}; int sync_objs[FRAME_BUF_COUNT] = {}; - int request_ids[FRAME_BUF_COUNT] = {}; - int request_id_last = 0; - int frame_id_last = 0; - int idx_offset = 0; + uint64_t request_ids[FRAME_BUF_COUNT] = {}; + uint64_t request_id_last = 0; + uint64_t frame_id_last = 0; + uint64_t idx_offset = 0; bool skipped = true; CameraBuf buf; MemoryManager mm; void config_isp(int io_mem_handle, int fence, int request_id, int buf0_mem_handle, int buf0_offset); - void enqueue_req_multi(int start, int n, bool dp); + void enqueue_req_multi(uint64_t start, int n, bool dp); void enqueue_buffer(int i, bool dp); int clear_req_queue(); From 2cd9975e4fe31bf89cdbf41d3d5db02f519a2718 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 3 Aug 2024 04:40:33 +0800 Subject: [PATCH 218/229] modeld: remove redundant pred_mu assignment (#33152) remove redundant pred_mu assignment --- selfdrive/modeld/parse_model_outputs.py | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/modeld/parse_model_outputs.py b/selfdrive/modeld/parse_model_outputs.py index af57e11d03..03d03c5e1c 100644 --- a/selfdrive/modeld/parse_model_outputs.py +++ b/selfdrive/modeld/parse_model_outputs.py @@ -42,7 +42,6 @@ class Parser: raw = outs[name] raw = raw.reshape((raw.shape[0], max(in_N, 1), -1)) - pred_mu = raw[:,:,:(raw.shape[2] - out_N)//2] n_values = (raw.shape[2] - out_N)//2 pred_mu = raw[:,:,:n_values] pred_std = np.exp(raw[:,:,n_values: 2*n_values]) From cafca4f89176855585835ff7c67dea5a9b08ca23 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 3 Aug 2024 04:40:57 +0800 Subject: [PATCH 219/229] uploader.py: simplify clear_locks by using rglob (#32974) simplify clear_locks --- system/loggerd/uploader.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/system/loggerd/uploader.py b/system/loggerd/uploader.py index 965d74bef8..4a95997e60 100755 --- a/system/loggerd/uploader.py +++ b/system/loggerd/uploader.py @@ -19,6 +19,7 @@ from openpilot.common.realtime import set_core_affinity from openpilot.system.hardware.hw import Paths from openpilot.system.loggerd.xattr_cache import getxattr, setxattr from openpilot.common.swaglog import cloudlog +from pathlib import Path NetworkType = log.DeviceState.NetworkType UPLOAD_ATTR_NAME = 'user.upload' @@ -61,12 +62,9 @@ def listdir_by_creation(d: str) -> list[str]: return [] def clear_locks(root: str) -> None: - for logdir in os.listdir(root): - path = os.path.join(root, logdir) + for lock_file in Path(root).rglob('*.lock'): try: - for fname in os.listdir(path): - if fname.endswith(".lock"): - os.unlink(os.path.join(path, fname)) + lock_file.unlink() except OSError: cloudlog.exception("clear_locks failed") From 57daa151cb3e1cb144c5c74137540eea12736852 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Sat, 3 Aug 2024 16:14:43 +0200 Subject: [PATCH 220/229] Docs: Move HOW-TOS to `master` (#387) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * HOW-TOS.md: Instructions to enable radar tracks * HOW-TOS.md: Instructions to enable radar tracks and openpilot Longitudinal Control * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * README: Enable Radar Tracks (#17) * HOW-TOS: Update HKG enable radar tracks instructions (#24) * Update radar tracks instructions * Update HKG enable radar tracks instructions * Update HOW-TOS.md * Update HOW-TOS.md * HOW-TOS: Update enable openpilot Longitudinal Control instructions (#29) * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Update HOW-TOS.md * Added How-To for Enabling Mapbox Navigation (#78) * Readme 2.0 (#84) * Readme 2.0 • Add collapsible sections in an effort to make the readme page more digestible for first time readers. • Proposed rewording for the following sections: • Join our Discord • Safety Modifications • Prettify layout * Update README.md * Update README.md * Update README.md * Update README.md spelling corrections * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md Moved Prohibited Safety Modifications into it's own section * Update README.md Reduced clickable text for hyperlink branches. Added comma.ai link to safety policy. * Update README.md * Update README.md * Update README.md * Prettify • Make main headings expandable • Rework installation section (undecided yet) * Update README.md Make table of contents uniform * Update README.md * Update README.md Tidy up installation section * Update Driving Enhancements something is preventing self linking after [**Gap Adjust Cruise (GAC)**](#gap-adjust-cruise) * Quality of life Enhancements Added more to the list * Add e2e path colour * Fix How-To link * Add comma two recommended branch * Discrete discord badge * Update installation instructions * Make sections mobile friendly `h2` -> h3 * Update `Features:` reword and make use of footnotes * Less is more, updated branch with search query * 0.8.12 will work on comma three as well * Tweak OSM feature and add footnote * update menu reference * DLP footnote * Delete CHANGELOGS.md Not needed seen as README directs to live / updated changelog per branch * Delete FEATURES.md Double up / already exists in README * Update HOW-TOS.md Make styling consistent, no information changed * Difference format for installation block * Spelling * Update README.md Add VW/Audi/Skoda and reword what SP is for * Update README.md bounds -> parameters * Update README.md Update installation URL with shortened URL + reword. Include footnote * Update README.md Reword `GAC` * Update README.md * Update README.md Spacing * Update README.md less is more * Update README.md Remove DLP footnote, add NZ to Offline OSM * Update README.md Prettify change logs - link to a change log for `0.8.12-prod` branch instead of search * Update README.md Refactor QOL section. Focus more on "function of" vs "how-to". * Update README.md Refactor Visual Enhancements * Driving Enhancements rework * Additional -> Miscellaneous * Spelling + grammar check * Replace sirens with triangles * Always show donation, updated Special Thanks * 📡 * Update README.md Co-authored-by: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> * Update README.md Co-authored-by: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> * Fix how-to's * Update README.md * Discord badge to show total members * Update README.md * Small cleanup and additions Signed-off-by: Jason Wen * Don't miss this Signed-off-by: Jason Wen * someday Signed-off-by: Jason Wen * No longer needed Signed-off-by: Jason Wen * Take it out Signed-off-by: Jason Wen * Less sunny Signed-off-by: Jason Wen --------- Signed-off-by: Jason Wen Co-authored-by: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Co-authored-by: Jason Wen * Update HOW-TOS.md * Simplify README installation instructions Consolidated the installation command for the `release-c3` branch and removed redundant instructions for unsupported comma two. Also updated the How-To, removing the old branch that caused a huge size on the repo. * Remove comma two installation instructions This update cleans up the README by removing outdated installation instructions for the comma two device. It makes the documentation more concise and focused on current requirements and devices. --------- Signed-off-by: Jason Wen Co-authored-by: sunnyhaibin Co-authored-by: Brandon Bennett <56660362+bbennett80@users.noreply.github.com> Co-authored-by: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Co-authored-by: tango2590 <78666662+tango2590@users.noreply.github.com> Co-authored-by: Moodkiller --- HOW-TOS.md | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 33 ++--------------------- 2 files changed, 79 insertions(+), 31 deletions(-) create mode 100644 HOW-TOS.md diff --git a/HOW-TOS.md b/HOW-TOS.md new file mode 100644 index 0000000000..a66786c200 --- /dev/null +++ b/HOW-TOS.md @@ -0,0 +1,77 @@ +# How Tos +This page is a repository of useful how-tos as a supplement for additional information. + +Table of Contents +======================= + +* [Radar Tracks](#Radar-Tracks) + * [Enable Radar Tracks](#-Enable-Radar-Tracks) +* [Enable Mapbox Navigation](#-Enable-Mapbox-Navigation) + +--- + +

📡 Radar Tracks

+ +Radar tracks can now be enabled manually on applicable cars through SSH thanks to [@greghogan](https://github.com/greghogan) and [@pd0wm](https://github.com/pd0wm). + +Some Hyundai radars can be reconfigured to output (debug) radar points on bus 1. +Reconfiguration is done over UDS by reading/writing to 0x0142 using the Read/Write Data By Identifier +endpoints (0x22 & 0x2E). This script checks your radar firmware version against a list of known +firmware versions. If you want to try on a new radar, make sure to note the default config value +in case it is different from the other radars and you need to revert the changes. +After changing the config the car should not show any faults when openpilot is not running. +These config changes are persistent across car reboots. You need to run this script again +to go back to the default values. + +**USE AT YOUR OWN RISK!** Stock system safety features, like AEB and FCW, might be affected by these changes. + +**How radar points can be used along with vision:** +* Current OP long policy is identify with vision first, if vision sees a vehicle match it to a radar point. If vision sees nothing you get a false negative and no lead car detection. (Source: [Hubblesphere#7894 from comma.ai community Discord](https://discord.com/channels/469524606043160576/872899198738104330/872913890793635872)) + +### 🚨 Enable Radar Tracks + +***(EXPERIMENTAL, as of January 1st, 2022)*** + +***(Only applicable to some Hyundai, Kia, and Genesis cars, as of January 1st, 2022)*** + +*(Base on version 0.8.12 [`devel`](https://github.com/commaai/openpilot/tree/devel))* + +**USE AT YOUR OWN RISK!** Stock system safety features, like AEB and FCW, might be affected by these changes. + +1. Ensure the car is at the `OFF` ignition position. +2. Connect your compatible comma device (EON, C2, C3) to the car. comma device power should be ON. +3. Use a laptop or applicable device to connect to your comma device via SSH. (Tips: Instructions to SSH in [HERE](https://github.com/commaai/openpilot/wiki/SSH)) +4. In the SSH terminal after successfully connected to your comma device, execute the following commands: + 1. `pkill -f openpilot` + 2. `python /data/openpilot/selfdrive/debug/hyundai_enable_radar_points.py` + 3. Follow the instructions in the script: + * `Power on the vehicle keeping the engine off (press start button twice) then type OK to continue`. + * If successful, the following message should appear: `[DONE]. Restart your vehicle and ensure there are no faults`. + * If the script did not run successfully, reach out to the community in [Sunnyhaibin's Openpilot Discord Server](https://discord.gg/wRW3meAgtx) or `#hyundai-kia-genesis channel` on [commaai community Discord Server](https://discord.comma.ai) for assistance. + 4. Reboot your comma device: + 1. C3: `sudo reboot` + 2. C2 or EON: `reboot` +5. Once your comma device is rebooted, start your car with engine on (with or without comma device connected). Ensure that there are no faults from the car. If there are faults, reach out to the community in [Sunnyhaibin's Openpilot Discord Server](https://discord.gg/wRW3meAgtx) or `#hyundai-kia-genesis channel` on [commaai community Discord Server](https://discord.comma.ai) for assistance. +6. Go for a quick drive and drive behind a lead car with varied follow distance. Then, come back and allow the drive to upload its `rlogs` in [comma Connect](https://connect.comma.ai). +7. With all `rlogs` uploaded, open the drive in Cabana from [comma Connect](https://connect.comma.ai). Load DBC -> `hyundai_kia_mando_front_radar.dbc`, then search `RADAR_TRACK_50x` (`x` could be anything), open any of them, and look at `LONG_DIST`. +8. If the radar tracks data is relevant with the lead car you drove behind, you are done! Your car now have radar tracks enabled. +
+ +

🗺 Enable Mapbox Navigation

+ +1) Create a free mapbox account. Account will ask for a credit card for verification. You will not be charged for the free tier. +2) On the Dashboard, you will see a section called Access Tokens. Click `Create a Token`. Name it whatever you like. Set the scopes to allow everything for both Public and Secret. Copy both of these keys. **YOU WON'T BE ABLE TO ACCESS THE SECRET KEY AFTER THIS WINDOW.** +3) Once rebooted, connect your C3 to a network with internet access and find the C3’s IP address. +4) In a browser, navigate to that IP with **port 8082** (i.e 192.168.1.69:8082). You should be greeted with the Comma logo and a public key input field. +5) Paste your Public token (pk.xx), click enter, paste your Secret key (sk.xx), click enter. You can now search for places. This page will be available at your devices’s IP address/port 8082 to search for destinations. +6) To set Home and Work addresses, search for a place, select Home/Work from the dropdown and click Navigate. For non-Home/Work destinations, select Recent Places.
*At this time, it is not possible to search directly on the C3.* + +**TIPS:** +- If your C3 is showing a black screen that says “Map Loading”, performing a reboot via the UI should fix it. +- If your phone can create a Hotspot, you are able to connect the C3 to your phone hotspot and use your phone browser to search for places. +- In the Navigation panel on the C3, you can select Home, Work, and from a list of Recent Places you have navigated to without needing a browser (assuming the C3 is connected to the internet.) + +**IMPORTANT NOTE:** Your C3 will require an active internet connection to download map data, generate driving directions, and ETA. Once map data and directions are downloaded, it *is* possible to use it offline, however nothing will update (such as new driving direction after a missed turn, updated ETA, map data further into your drive etc.) + +***NAVIGATION NOTE:** At this time, mapbox does not support alphanumeric addresses (i.e W123N1234 Main St). There is currently no known workaround for this.* +
diff --git a/README.md b/README.md index 72319c2dc2..5986adbe33 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,6 @@ Join the official sunnypilot Discord server to stay up to date with all the late To use sunnypilot in a car, you need the following: * A supported device to run this software * a [comma three](https://comma.ai/shop/products/three), or - * a comma two (only with older versions below 0.8.13) * This software * One of [the 250+ supported cars](https://github.com/commaai/openpilot/blob/master/docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, Ford and more. If your car is not supported but has adaptive cruise control and lane-keeping assist, it's likely able to run sunnypilot. * A [car harness](https://comma.ai/shop/products/car-harness) to connect to your car @@ -115,40 +114,12 @@ Please refer to [Recommended Branches](#-recommended-branches) to find your pref Requires further assistance with software installation? Join the [sunnypilot Discord server](https://discord.sunnypilot.com) and message us in the `#installation-help` channel. -comma two ------- - -1. [Factory reset/uninstall](https://github.com/commaai/openpilot/wiki/FAQ#how-can-i-reset-the-device) the previous software if you have another software/fork installed. -2. After factory reset/uninstall and upon reboot, select `Custom Software` when given the option. -3. Input the installation URL per [Recommended Branches](#-recommended-branches). Example: ```https://smiskol.com/fork/sunnyhaibin/0.8.12-4-prod``` -4. Complete the rest of the installation following the onscreen instructions. - -Requires further assistance with software installation? Join the [sunnypilot Discord server](https://discord.sunnypilot.com) and message us in the `#installation-help` channel. - - - -
- SSH (More Versatile) -
- -Prerequisites: [How to SSH](https://github.com/commaai/openpilot/wiki/SSH) - -If you are looking to install sunnypilot via SSH, run the following command in an SSH terminal after connecting to your device: - comma three: ------ * [`release-c3`](https://github.com/sunnyhaibin/openpilot/tree/release-c3): ``` - cd /data; rm -rf ./openpilot; git clone -b release-c3 --recurse-submodules https://github.com/sunnyhaibin/sunnypilot.git openpilot; cd openpilot; sudo reboot - ``` - -comma two: ------- -* [`0.8.12-prod-personal-hkg`](https://github.com/sunnyhaibin/openpilot/tree/0.8.12-prod-personal-hkg): - - ``` - cd /data; rm -rf ./openpilot; git clone -b 0.8.12-prod-personal-hkg --recurse-submodules https://github.com/sunnyhaibin/sunnypilot.git openpilot; cd openpilot; sudo reboot + cd /data && rm -rf ./openpilot && git clone -b release-c3 --recurse-submodules https://github.com/sunnyhaibin/sunnypilot.git openpilot && cd openpilot && sudo reboot ``` After running the command to install the desired branch, your comma device should reboot. @@ -355,7 +326,7 @@ Example: --- -How-To instructions can be found in [HOW-TOS.md](https://github.com/sunnyhaibin/openpilot/blob/(!)README/HOW-TOS.md). +How-To instructions can be found in [HOW-TOS.md](HOW-TOS.md).
From 9474523addb78d3b16a72949c6d85c4059fffa92 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 3 Aug 2024 12:12:42 -0700 Subject: [PATCH 221/229] Revert "uploader.py: simplify clear_locks by using rglob (#32974)" This reverts commit cafca4f89176855585835ff7c67dea5a9b08ca23. --- system/loggerd/uploader.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/system/loggerd/uploader.py b/system/loggerd/uploader.py index 4a95997e60..965d74bef8 100755 --- a/system/loggerd/uploader.py +++ b/system/loggerd/uploader.py @@ -19,7 +19,6 @@ from openpilot.common.realtime import set_core_affinity from openpilot.system.hardware.hw import Paths from openpilot.system.loggerd.xattr_cache import getxattr, setxattr from openpilot.common.swaglog import cloudlog -from pathlib import Path NetworkType = log.DeviceState.NetworkType UPLOAD_ATTR_NAME = 'user.upload' @@ -62,9 +61,12 @@ def listdir_by_creation(d: str) -> list[str]: return [] def clear_locks(root: str) -> None: - for lock_file in Path(root).rglob('*.lock'): + for logdir in os.listdir(root): + path = os.path.join(root, logdir) try: - lock_file.unlink() + for fname in os.listdir(path): + if fname.endswith(".lock"): + os.unlink(os.path.join(path, fname)) except OSError: cloudlog.exception("clear_locks failed") From 8f9b165de8be31b8c68dfa31e7f6a036107aa2e4 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 4 Aug 2024 05:57:26 +0800 Subject: [PATCH 222/229] camerad: encapsulate cl_command_queue in ImgProc (#33178) move cl queue to imgproc --- system/camerad/cameras/camera_common.cc | 14 +++++++------- system/camerad/cameras/camera_common.h | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/system/camerad/cameras/camera_common.cc b/system/camerad/cameras/camera_common.cc index 6aec03eae1..6c745e1cde 100644 --- a/system/camerad/cameras/camera_common.cc +++ b/system/camerad/cameras/camera_common.cc @@ -33,9 +33,11 @@ public: krnl_ = CL_CHECK_ERR(clCreateKernel(prg_imgproc, "process_raw", &err)); CL_CHECK(clReleaseProgram(prg_imgproc)); + const cl_queue_properties props[] = {0}; //CL_QUEUE_PRIORITY_KHR, CL_QUEUE_PRIORITY_HIGH_KHR, 0}; + queue = CL_CHECK_ERR(clCreateCommandQueueWithProperties(context, device_id, props, &err)); } - void runKernel(cl_command_queue q, cl_mem cam_buf_cl, cl_mem buf_cl, int width, int height, int expo_time) { + void runKernel(cl_mem cam_buf_cl, cl_mem buf_cl, int width, int height, int expo_time) { CL_CHECK(clSetKernelArg(krnl_, 0, sizeof(cl_mem), &cam_buf_cl)); CL_CHECK(clSetKernelArg(krnl_, 1, sizeof(cl_mem), &buf_cl)); CL_CHECK(clSetKernelArg(krnl_, 2, sizeof(cl_int), &expo_time)); @@ -45,17 +47,19 @@ public: const size_t localWorkSize[] = {imgproc_local_worksize, imgproc_local_worksize}; cl_event event; - CL_CHECK(clEnqueueNDRangeKernel(q, krnl_, 2, NULL, globalWorkSize, localWorkSize, 0, 0, &event)); + CL_CHECK(clEnqueueNDRangeKernel(queue, krnl_, 2, NULL, globalWorkSize, localWorkSize, 0, 0, &event)); clWaitForEvents(1, &event); CL_CHECK(clReleaseEvent(event)); } ~ImgProc() { CL_CHECK(clReleaseKernel(krnl_)); + CL_CHECK(clReleaseCommandQueue(queue)); } private: cl_kernel krnl_; + cl_command_queue queue; }; void CameraBuf::init(cl_device_id device_id, cl_context context, CameraState *s, VisionIpcServer * v, int frame_cnt, VisionStreamType type) { @@ -92,9 +96,6 @@ void CameraBuf::init(cl_device_id device_id, cl_context context, CameraState *s, LOGD("created %d YUV vipc buffers with size %dx%d", YUV_BUFFER_COUNT, nv12_width, nv12_height); imgproc = new ImgProc(device_id, context, this, s, nv12_width, nv12_uv_offset); - - const cl_queue_properties props[] = {0}; //CL_QUEUE_PRIORITY_KHR, CL_QUEUE_PRIORITY_HIGH_KHR, 0}; - q = CL_CHECK_ERR(clCreateCommandQueueWithProperties(context, device_id, props, &err)); } CameraBuf::~CameraBuf() { @@ -102,7 +103,6 @@ CameraBuf::~CameraBuf() { camera_bufs[i].free(); } if (imgproc) delete imgproc; - if (q) CL_CHECK(clReleaseCommandQueue(q)); } bool CameraBuf::acquire() { @@ -118,7 +118,7 @@ bool CameraBuf::acquire() { cur_camera_buf = &camera_bufs[cur_buf_idx]; double start_time = millis_since_boot(); - imgproc->runKernel(q, camera_bufs[cur_buf_idx].buf_cl, cur_yuv_buf->buf_cl, rgb_width, rgb_height, cur_frame_data.integ_lines); + imgproc->runKernel(camera_bufs[cur_buf_idx].buf_cl, cur_yuv_buf->buf_cl, rgb_width, rgb_height, cur_frame_data.integ_lines); cur_frame_data.processing_time = (millis_since_boot() - start_time) / 1000.0; VisionIpcBufExtra extra = { diff --git a/system/camerad/cameras/camera_common.h b/system/camerad/cameras/camera_common.h index d58f4d3195..7c2fbaeec8 100644 --- a/system/camerad/cameras/camera_common.h +++ b/system/camerad/cameras/camera_common.h @@ -53,7 +53,6 @@ private: int frame_buf_count; public: - cl_command_queue q; FrameMetadata cur_frame_data; VisionBuf *cur_yuv_buf; VisionBuf *cur_camera_buf; From f3933df2f53fb48cdc8a98e7981e70042c6c8bc1 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Sat, 3 Aug 2024 21:24:49 -0400 Subject: [PATCH 223/229] Athenad: Add TODO-SP --- system/athena/athenad.py | 1 + 1 file changed, 1 insertion(+) diff --git a/system/athena/athenad.py b/system/athena/athenad.py index d07221bcb3..378098bf38 100755 --- a/system/athena/athenad.py +++ b/system/athena/athenad.py @@ -106,6 +106,7 @@ cancelled_uploads: set[str] = set() cur_upload_items: dict[int, UploadItem | None] = {} +# TODO-SP: adapt zst for sunnylink def strip_zst_extension(fn: str) -> str: if fn.endswith('.zst'): return fn[:-4] From 03f76199f3e03aaae82d42e0ec2ba8a418138ba3 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Sat, 3 Aug 2024 17:26:23 -0800 Subject: [PATCH 224/229] `ParamManager`: Convert missed params in cars (#390) --- selfdrive/car/chrysler/carcontroller.py | 4 ++-- selfdrive/car/volkswagen/carcontroller.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index 09068cec8a..8a805cd2a1 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -269,8 +269,8 @@ class CarController(CarControllerBase): return min(target_speed_kph, curve_speed) def get_button_control(self, CS, final_speed, v_cruise_kph_prev): - self.init_speed = round(min(final_speed, v_cruise_kph_prev) * (CV.KPH_TO_MPH if not self.is_metric else 1)) - self.v_set_dis = round(CS.out.cruiseState.speed * (CV.MS_TO_MPH if not self.is_metric else CV.MS_TO_KPH)) + self.init_speed = round(min(final_speed, v_cruise_kph_prev) * (CV.KPH_TO_MPH if not CS.params_list.is_metric else 1)) + self.v_set_dis = round(CS.out.cruiseState.speed * (CV.MS_TO_MPH if not CS.params_list.is_metric else CV.MS_TO_KPH)) cruise_button = self.get_button_type(self.button_type) return cruise_button diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index c3459f7676..28c48283a7 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -294,8 +294,8 @@ class CarController(CarControllerBase): return min(target_speed_kph, curve_speed) def get_button_control(self, CS, final_speed, v_cruise_kph_prev): - self.init_speed = round(min(final_speed, v_cruise_kph_prev) * (CV.KPH_TO_MPH if not self.is_metric else 1)) - self.v_set_dis = round(CS.out.cruiseState.speed * (CV.MS_TO_MPH if not self.is_metric else CV.MS_TO_KPH)) + self.init_speed = round(min(final_speed, v_cruise_kph_prev) * (CV.KPH_TO_MPH if not CS.params_list.is_metric else 1)) + self.v_set_dis = round(CS.out.cruiseState.speed * (CV.MS_TO_MPH if not CS.params_list.is_metric else CV.MS_TO_KPH)) cruise_button = self.get_button_type(self.button_type) return cruise_button From 963d356173f5a53651df957217201e53c4e9bc7a Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Sun, 4 Aug 2024 03:29:00 +0200 Subject: [PATCH 225/229] ci: Improvements on the mirror and prebuilt flow (#386) * Remove redundant git lfs pull command The `git lfs pull` command in the GitHub workflow is redundant and has been removed. Additionally, the `sync-lfs.sh` script has been updated to push all LFS objects to the origin repository. * using force push instead of trying to merge * Bumping ssh agent to 0.9.0 * Syntax --------- Co-authored-by: Jason Wen --- .github/workflows/mirror_to_gitlab.yaml | 15 +++------------ release/ci/sync-lfs.sh | 2 +- 2 files changed, 4 insertions(+), 13 deletions(-) mode change 100644 => 100755 release/ci/sync-lfs.sh diff --git a/.github/workflows/mirror_to_gitlab.yaml b/.github/workflows/mirror_to_gitlab.yaml index e605458ad9..38c95bac20 100644 --- a/.github/workflows/mirror_to_gitlab.yaml +++ b/.github/workflows/mirror_to_gitlab.yaml @@ -29,7 +29,7 @@ jobs: git config --global user.email 'action@github.com' - name: Set up SSH - uses: webfactory/ssh-agent@v0.5.3 + uses: webfactory/ssh-agent@v0.9.0 with: ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} @@ -37,19 +37,10 @@ jobs: run: | ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts + # Note: If you have issues with "push rejected missing LFS" or something make sure you disabled LFS on the GITLAB repo if you intend to use a different LFS repo other than the target repo. - name: Sync and commit changes id: sync-and-commit run: | - git lfs pull - # Add GitLab remote git remote add gitlab git@gitlab.com:sunnypilot/sunnyhaibin/sunnypilot-github-mirror.git - - # Fetch from GitLab and check if the branch exists - if git fetch gitlab ${{ github.ref }}; then - # Merge changes from GitLab if the branch exists - git merge gitlab/${{ github.ref_name }} --allow-unrelated-histories --strategy-option=theirs - else - echo "Branch does not exist on GitLab, skipping merge." - fi - git push -u gitlab ${{ github.ref }} # If you have issues with "push rejected missing LFS" or something. Make sure you disabled LFS on the GITLAB repo if you intend to use a different LFS repo other than the target repo \ No newline at end of file + git push -u --force gitlab ${{ github.ref }} diff --git a/release/ci/sync-lfs.sh b/release/ci/sync-lfs.sh old mode 100644 new mode 100755 index a328724351..778d310051 --- a/release/ci/sync-lfs.sh +++ b/release/ci/sync-lfs.sh @@ -4,4 +4,4 @@ mv .lfsconfig-comma .lfsconfig git lfs fetch --all; git lfs pull mv .lfsconfig .lfsconfig-comma mv .lfsconfig.bak .lfsconfig -git lfs fetch --all; git lfs push origin main +git lfs fetch --all; git lfs push --all origin From 0b7d3805ff98c60485a3cd959c1a2adc18f69a70 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Sat, 3 Aug 2024 17:29:22 -0800 Subject: [PATCH 226/229] ui: Network: Disable refresh button while scanning (#383) --- selfdrive/ui/sunnypilot/qt/network/networking.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/ui/sunnypilot/qt/network/networking.cc b/selfdrive/ui/sunnypilot/qt/network/networking.cc index bbe2cfb79c..0b26c2f8ba 100644 --- a/selfdrive/ui/sunnypilot/qt/network/networking.cc +++ b/selfdrive/ui/sunnypilot/qt/network/networking.cc @@ -107,6 +107,10 @@ NetworkingSP::NetworkingSP(QWidget* parent, bool show_advanced) : QFrame(parent) #back_btn:pressed, #advanced_btn:pressed, #scan_btn:pressed { background-color: #4a4a4a; } + #scan_btn:disabled { + background-color: #121212; + color: #33FFFFFF; + } )"); main_layout->setCurrentWidget(wifiScreen); } From c06a82f41bd3c4f8ed5265f07a8a3893b8faaa5a Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Sat, 3 Aug 2024 21:37:45 -0400 Subject: [PATCH 227/229] Submodules: Point back to sunnypilot --- .gitmodules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index ad1d1d9e91..a61bed1e2f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,10 +3,10 @@ url = https://github.com/sunnyhaibin/panda.git [submodule "opendbc"] path = opendbc_repo - url = https://github.com/commaai/opendbc.git + url = https://github.com/sunnypilot/opendbc.git [submodule "msgq"] path = msgq_repo - url = https://github.com/commaai/msgq.git + url = https://github.com/sunnypilot/msgq.git [submodule "rednose_repo"] path = rednose_repo url = https://github.com/commaai/rednose.git From 19afa83ce1e4a27535f3b55a709db37896c3e5ba Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Sun, 4 Aug 2024 07:25:09 -0400 Subject: [PATCH 228/229] Bump submodules --- opendbc_repo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendbc_repo b/opendbc_repo index d3cdde5f19..529474a50e 160000 --- a/opendbc_repo +++ b/opendbc_repo @@ -1 +1 @@ -Subproject commit d3cdde5f19d87a2853874b3fa1c5c5e277d9d7f8 +Subproject commit 529474a50e235db51085d8255b24092009107ccb From c70db1030c0b3d4df37f947adf36f6d5c6cb61e5 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Sun, 4 Aug 2024 08:09:00 -0800 Subject: [PATCH 229/229] Toyota: comma Pedal: Fix upstream merge conflicts (#393) --- selfdrive/car/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index ba3805b01f..a772d9c16a 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -218,7 +218,7 @@ def create_gas_interceptor_command(packer, gas_amount, idx): values["GAS_COMMAND"] = gas_amount * 255. values["GAS_COMMAND2"] = gas_amount * 255. - dat = packer.make_can_msg("GAS_COMMAND", 0, values)[2] + dat = packer.make_can_msg("GAS_COMMAND", 0, values)[1] checksum = crc8_pedal(dat[:-1]) values["CHECKSUM_PEDAL"] = checksum