mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-07-25 09:42:05 +08:00
Merge branch 'master' into sync-priv-20240220
# Conflicts: # CHANGELOGS.md # panda # selfdrive/car/toyota/interface.py # selfdrive/controls/controlsd.py # selfdrive/manager/manager.py # selfdrive/modeld/fill_model_msg.py # selfdrive/modeld/modeld.py
This commit is contained in:
@@ -44,7 +44,7 @@ repos:
|
||||
- --explicit-package-bases
|
||||
exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)|(xx/)'
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.2.1
|
||||
rev: v0.2.2
|
||||
hooks:
|
||||
- id: ruff
|
||||
exclude: '^(third_party/)|(cereal/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)'
|
||||
@@ -74,6 +74,14 @@ repos:
|
||||
# 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.0
|
||||
hooks:
|
||||
- id: cython-lint
|
||||
exclude: '^(third_party/)|(cereal/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(generated/)'
|
||||
args:
|
||||
- --max-line-length=240
|
||||
- --ignore=E111, E302, E305
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: test_translations
|
||||
|
||||
+24
-5
@@ -1,6 +1,25 @@
|
||||
sunnypilot - 0.9.6.0 (2024-xx-xx)
|
||||
sunnypilot - 0.9.6.1 (2024-02-22)
|
||||
========================
|
||||
* UPDATED: Synced with commaai's master commit 9acc558 (February 14, 2024)
|
||||
* New driving model
|
||||
* Vision model trained on more data
|
||||
* Improved driving performance
|
||||
* Directly outputs curvature for lateral control
|
||||
* New driver monitoring model
|
||||
* Trained on larger dataset
|
||||
* AGNOS 9
|
||||
* comma body streaming and controls over WebRTC
|
||||
* Improved fuzzy fingerprinting for many makes and models
|
||||
* Chevrolet Equinox 2019-22 support thanks to JasonJShuler and nworb-cire!
|
||||
* Dodge Duranago 2020-21 support
|
||||
* Hyundai Staria 2023 support thanks to sunnyhaibin!
|
||||
* Kia Niro Plug-in Hybrid 2022 support thanks to sunnyhaibin!
|
||||
* Lexus LC 2024 support thanks to nelsonjchen!
|
||||
* Toyota RAV4 2023-24 support
|
||||
* Toyota RAV4 Hybrid 2023-24 support
|
||||
************************
|
||||
* UPDATED: Synced with commaai's openpilot
|
||||
* master commit 9acc558 (February 14, 2024)
|
||||
* v0.9.6 release (February 22, 2024)
|
||||
* UPDATED: Dynamic Experimental Control (DEC)
|
||||
* Synced with dragonpilot-community/dragonpilot:beta3 commit f4ee52f
|
||||
* NEW❗: Default Driving Model: Los Angeles v2 (January 24, 2024)
|
||||
@@ -20,14 +39,14 @@ sunnypilot - 0.9.6.0 (2024-xx-xx)
|
||||
* Farmville (November 7, 2023) - FV
|
||||
* Night Strike (October 3, 2023) - NS
|
||||
* Certain features are deprecated with newer Driving Models
|
||||
* Dynamic Lane Profile
|
||||
* Dynamic Lane Profile (DLP)
|
||||
* Custom Offsets
|
||||
* UPDATED: Dynamic Lane Profile (DLP)
|
||||
* Continued support for Legacy Driving Models (e.g., ND, BDv2, BDv1, FV, NS)
|
||||
* Deprecate support for newer Driving Models (e.g., CHv2, CH, LAv2, LAv1)
|
||||
* Deprecated support for newer Driving Models (e.g., CHv2, CH, LAv2, LAv1)
|
||||
* UPDATED: Custom Offsets
|
||||
* Continued support for Legacy Driving Models (e.g., ND, BDv2, BDv1, FV, NS)
|
||||
* Deprecate support for newer Driving Models (e.g., CHv2, CH, LAv2, LAv1)
|
||||
* Deprecated support for newer Driving Models (e.g., CHv2, CH, LAv2, LAv1)
|
||||
* UPDATED: Hyundai/Kia/Genesis - ESCC Radar Interceptor
|
||||
* Message parsing improvements with the latest firmware update: https://github.com/sunnypilot/panda/tree/test-escc-smdps
|
||||
* UI Updates
|
||||
|
||||
@@ -27,7 +27,7 @@ Table of Contents
|
||||
---
|
||||
|
||||
Join the official sunnypilot Discord server to stay up to date with all the latest features and be a part of shaping the future of sunnypilot!
|
||||
* https://discord.sunnypilot.com
|
||||
* https://discord.gg/sunnypilot
|
||||
|
||||
 
|
||||
|
||||
|
||||
+7
-2
@@ -1,4 +1,8 @@
|
||||
Version 0.9.6 (2024-02-22)
|
||||
Version 0.9.7 (2024-XX-XX)
|
||||
========================
|
||||
* New driving model
|
||||
|
||||
Version 0.9.6 (2024-02-27)
|
||||
========================
|
||||
* New driving model
|
||||
* Vision model trained on more data
|
||||
@@ -9,8 +13,9 @@ Version 0.9.6 (2024-02-22)
|
||||
* AGNOS 9
|
||||
* comma body streaming and controls over WebRTC
|
||||
* Improved fuzzy fingerprinting for many makes and models
|
||||
* Alpha longitudinal support for new Toyota models
|
||||
* Chevrolet Equinox 2019-22 support thanks to JasonJShuler and nworb-cire!
|
||||
* Dodge Duranago 2020-21 support
|
||||
* Dodge Durango 2020-21 support
|
||||
* Hyundai Staria 2023 support thanks to sunnyhaibin!
|
||||
* Kia Niro Plug-in Hybrid 2022 support thanks to sunnyhaibin!
|
||||
* Lexus LC 2024 support thanks to nelsonjchen!
|
||||
|
||||
+1
-1
Submodule cereal updated: e86a48cf41...b891fcca7a
@@ -125,6 +125,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"ForcePowerDown", PERSISTENT},
|
||||
{"GitBranch", PERSISTENT},
|
||||
{"GitCommit", PERSISTENT},
|
||||
{"GitCommitDate", PERSISTENT},
|
||||
{"GitDiff", PERSISTENT},
|
||||
{"GithubSshKeys", PERSISTENT},
|
||||
{"GithubUsername", PERSISTENT},
|
||||
|
||||
@@ -29,7 +29,7 @@ cdef extern from "common/params.h":
|
||||
|
||||
|
||||
def ensure_bytes(v):
|
||||
return v.encode() if isinstance(v, str) else v;
|
||||
return v.encode() if isinstance(v, str) else v
|
||||
|
||||
class UnknownKeyName(Exception):
|
||||
pass
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#cython: language_level=3
|
||||
# cython: language_level=3
|
||||
from libcpp cimport bool
|
||||
|
||||
cdef extern from "orientation.cc":
|
||||
|
||||
@@ -17,7 +17,6 @@ from openpilot.common.transformations.transformations cimport ecef2geodetic as e
|
||||
from openpilot.common.transformations.transformations cimport LocalCoord_c
|
||||
|
||||
|
||||
import cython
|
||||
import numpy as np
|
||||
cimport numpy as np
|
||||
|
||||
@@ -34,14 +33,14 @@ cdef Matrix3 numpy2matrix(np.ndarray[double, ndim=2, mode="fortran"] m):
|
||||
return Matrix3(<double*>m.data)
|
||||
|
||||
cdef ECEF list2ecef(ecef):
|
||||
cdef ECEF e;
|
||||
cdef ECEF e
|
||||
e.x = ecef[0]
|
||||
e.y = ecef[1]
|
||||
e.z = ecef[2]
|
||||
return e
|
||||
|
||||
cdef NED list2ned(ned):
|
||||
cdef NED n;
|
||||
cdef NED n
|
||||
n.n = ned[0]
|
||||
n.e = ned[1]
|
||||
n.d = ned[2]
|
||||
@@ -61,7 +60,7 @@ def euler2quat_single(euler):
|
||||
|
||||
def quat2euler_single(quat):
|
||||
cdef Quaternion q = Quaternion(quat[0], quat[1], quat[2], quat[3])
|
||||
cdef Vector3 e = quat2euler_c(q);
|
||||
cdef Vector3 e = quat2euler_c(q)
|
||||
return [e(0), e(1), e(2)]
|
||||
|
||||
def quat2rot_single(quat):
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
#define COMMA_VERSION "0.9.6.0"
|
||||
#define COMMA_VERSION "0.9.6.1"
|
||||
|
||||
+27
-26
@@ -1,3 +1,4 @@
|
||||
import contextlib
|
||||
import gc
|
||||
import os
|
||||
import pytest
|
||||
@@ -25,42 +26,42 @@ def pytest_runtest_call(item):
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture(scope="function", autouse=True)
|
||||
def openpilot_function_fixture(request):
|
||||
@contextlib.contextmanager
|
||||
def clean_env():
|
||||
starting_env = dict(os.environ)
|
||||
|
||||
random.seed(0)
|
||||
|
||||
# setup a clean environment for each test
|
||||
with OpenpilotPrefix(shared_download_cache=request.node.get_closest_marker("shared_download_cache") is not None) as prefix:
|
||||
prefix = os.environ["OPENPILOT_PREFIX"]
|
||||
|
||||
yield
|
||||
|
||||
# ensure the test doesn't change the prefix
|
||||
assert "OPENPILOT_PREFIX" in os.environ and prefix == os.environ["OPENPILOT_PREFIX"]
|
||||
|
||||
yield
|
||||
os.environ.clear()
|
||||
os.environ.update(starting_env)
|
||||
|
||||
# cleanup any started processes
|
||||
manager.manager_cleanup()
|
||||
|
||||
# some processes disable gc for performance, re-enable here
|
||||
if not gc.isenabled():
|
||||
gc.enable()
|
||||
gc.collect()
|
||||
@pytest.fixture(scope="function", autouse=True)
|
||||
def openpilot_function_fixture(request):
|
||||
random.seed(0)
|
||||
|
||||
with clean_env():
|
||||
# setup a clean environment for each test
|
||||
with OpenpilotPrefix(shared_download_cache=request.node.get_closest_marker("shared_download_cache") is not None) as prefix:
|
||||
prefix = os.environ["OPENPILOT_PREFIX"]
|
||||
|
||||
yield
|
||||
|
||||
# ensure the test doesn't change the prefix
|
||||
assert "OPENPILOT_PREFIX" in os.environ and prefix == os.environ["OPENPILOT_PREFIX"]
|
||||
|
||||
# cleanup any started processes
|
||||
manager.manager_cleanup()
|
||||
|
||||
# some processes disable gc for performance, re-enable here
|
||||
if not gc.isenabled():
|
||||
gc.enable()
|
||||
gc.collect()
|
||||
|
||||
# If you use setUpClass, the environment variables won't be cleared properly,
|
||||
# so we need to hook both the function and class pytest fixtures
|
||||
@pytest.fixture(scope="class", autouse=True)
|
||||
def openpilot_class_fixture():
|
||||
starting_env = dict(os.environ)
|
||||
|
||||
yield
|
||||
|
||||
os.environ.clear()
|
||||
os.environ.update(starting_env)
|
||||
with clean_env():
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
|
||||
+6
-6
@@ -216,9 +216,9 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Toyota|Avalon Hybrid 2019-21|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon Hybrid 2019-21">Buy Here</a></sub></details>||
|
||||
|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon Hybrid 2022">Buy Here</a></sub></details>||
|
||||
|Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR 2017-20">Buy Here</a></sub></details>||
|
||||
|Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR 2021">Buy Here</a></sub></details>||
|
||||
|Toyota|C-HR 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR 2021">Buy Here</a></sub></details>||
|
||||
|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR Hybrid 2017-20">Buy Here</a></sub></details>||
|
||||
|Toyota|C-HR Hybrid 2021-22|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR Hybrid 2021-22">Buy Here</a></sub></details>||
|
||||
|Toyota|C-HR Hybrid 2021-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR Hybrid 2021-22">Buy Here</a></sub></details>||
|
||||
|Toyota|Camry 2018-20|All|Stock|0 mph[<sup>9</sup>](#footnotes)|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Camry 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=fkcjviZY9CM" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Camry 2021-24|All|openpilot|0 mph[<sup>9</sup>](#footnotes)|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Camry 2021-24">Buy Here</a></sub></details>||
|
||||
|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Camry Hybrid 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Q2DYY0AWKgk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
@@ -244,13 +244,13 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2016">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2017-18">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=wJxjDd42gGA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2022">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 2023-24|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2023-24">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2022">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 2023-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2023-24">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2016">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2019-21">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/U0nH9cnrFB0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 Hybrid 2023-24|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2023-24">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 Hybrid 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/U0nH9cnrFB0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 Hybrid 2023-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2023-24">Buy Here</a></sub></details>||
|
||||
|Toyota|Sienna 2018-20|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Sienna 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=q1UPOo4Sh68" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon eHybrid 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|
||||
@@ -15,6 +15,11 @@ function agnos_init {
|
||||
# set success flag for current boot slot
|
||||
sudo abctl --set_success
|
||||
|
||||
# TODO: do this without udev in AGNOS
|
||||
# udev does this, but sometimes we startup faster
|
||||
sudo chgrp gpu /dev/adsprpc-smd /dev/ion /dev/kgsl-3d0
|
||||
sudo chmod 660 /dev/adsprpc-smd /dev/ion /dev/kgsl-3d0
|
||||
|
||||
# Check if AGNOS update is required
|
||||
if [ $(< /VERSION) != "$AGNOS_VERSION" ]; then
|
||||
AGNOS_PY="$DIR/system/hardware/tici/agnos.py"
|
||||
|
||||
+1
-1
Submodule opendbc updated: a49eea191e...e8e8ed7222
+1
-1
Submodule panda updated: 53ad150cdf...ec91ad7f06
Generated
+210
-210
@@ -825,43 +825,43 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "42.0.2"
|
||||
version = "42.0.3"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "cryptography-42.0.2-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:701171f825dcab90969596ce2af253143b93b08f1a716d4b2a9d2db5084ef7be"},
|
||||
{file = "cryptography-42.0.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:61321672b3ac7aade25c40449ccedbc6db72c7f5f0fdf34def5e2f8b51ca530d"},
|
||||
{file = "cryptography-42.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea2c3ffb662fec8bbbfce5602e2c159ff097a4631d96235fcf0fb00e59e3ece4"},
|
||||
{file = "cryptography-42.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b15c678f27d66d247132cbf13df2f75255627bcc9b6a570f7d2fd08e8c081d2"},
|
||||
{file = "cryptography-42.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8e88bb9eafbf6a4014d55fb222e7360eef53e613215085e65a13290577394529"},
|
||||
{file = "cryptography-42.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a047682d324ba56e61b7ea7c7299d51e61fd3bca7dad2ccc39b72bd0118d60a1"},
|
||||
{file = "cryptography-42.0.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:36d4b7c4be6411f58f60d9ce555a73df8406d484ba12a63549c88bd64f7967f1"},
|
||||
{file = "cryptography-42.0.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a00aee5d1b6c20620161984f8ab2ab69134466c51f58c052c11b076715e72929"},
|
||||
{file = "cryptography-42.0.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b97fe7d7991c25e6a31e5d5e795986b18fbbb3107b873d5f3ae6dc9a103278e9"},
|
||||
{file = "cryptography-42.0.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5fa82a26f92871eca593b53359c12ad7949772462f887c35edaf36f87953c0e2"},
|
||||
{file = "cryptography-42.0.2-cp37-abi3-win32.whl", hash = "sha256:4b063d3413f853e056161eb0c7724822a9740ad3caa24b8424d776cebf98e7ee"},
|
||||
{file = "cryptography-42.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:841ec8af7a8491ac76ec5a9522226e287187a3107e12b7d686ad354bb78facee"},
|
||||
{file = "cryptography-42.0.2-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:55d1580e2d7e17f45d19d3b12098e352f3a37fe86d380bf45846ef257054b242"},
|
||||
{file = "cryptography-42.0.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28cb2c41f131a5758d6ba6a0504150d644054fd9f3203a1e8e8d7ac3aea7f73a"},
|
||||
{file = "cryptography-42.0.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9097a208875fc7bbeb1286d0125d90bdfed961f61f214d3f5be62cd4ed8a446"},
|
||||
{file = "cryptography-42.0.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:44c95c0e96b3cb628e8452ec060413a49002a247b2b9938989e23a2c8291fc90"},
|
||||
{file = "cryptography-42.0.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2f9f14185962e6a04ab32d1abe34eae8a9001569ee4edb64d2304bf0d65c53f3"},
|
||||
{file = "cryptography-42.0.2-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:09a77e5b2e8ca732a19a90c5bca2d124621a1edb5438c5daa2d2738bfeb02589"},
|
||||
{file = "cryptography-42.0.2-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad28cff53f60d99a928dfcf1e861e0b2ceb2bc1f08a074fdd601b314e1cc9e0a"},
|
||||
{file = "cryptography-42.0.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:130c0f77022b2b9c99d8cebcdd834d81705f61c68e91ddd614ce74c657f8b3ea"},
|
||||
{file = "cryptography-42.0.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:fa3dec4ba8fb6e662770b74f62f1a0c7d4e37e25b58b2bf2c1be4c95372b4a33"},
|
||||
{file = "cryptography-42.0.2-cp39-abi3-win32.whl", hash = "sha256:3dbd37e14ce795b4af61b89b037d4bc157f2cb23e676fa16932185a04dfbf635"},
|
||||
{file = "cryptography-42.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:8a06641fb07d4e8f6c7dda4fc3f8871d327803ab6542e33831c7ccfdcb4d0ad6"},
|
||||
{file = "cryptography-42.0.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:087887e55e0b9c8724cf05361357875adb5c20dec27e5816b653492980d20380"},
|
||||
{file = "cryptography-42.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a7ef8dd0bf2e1d0a27042b231a3baac6883cdd5557036f5e8df7139255feaac6"},
|
||||
{file = "cryptography-42.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4383b47f45b14459cab66048d384614019965ba6c1a1a141f11b5a551cace1b2"},
|
||||
{file = "cryptography-42.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:fbeb725c9dc799a574518109336acccaf1303c30d45c075c665c0793c2f79a7f"},
|
||||
{file = "cryptography-42.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:320948ab49883557a256eab46149df79435a22d2fefd6a66fe6946f1b9d9d008"},
|
||||
{file = "cryptography-42.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5ef9bc3d046ce83c4bbf4c25e1e0547b9c441c01d30922d812e887dc5f125c12"},
|
||||
{file = "cryptography-42.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:52ed9ebf8ac602385126c9a2fe951db36f2cb0c2538d22971487f89d0de4065a"},
|
||||
{file = "cryptography-42.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:141e2aa5ba100d3788c0ad7919b288f89d1fe015878b9659b307c9ef867d3a65"},
|
||||
{file = "cryptography-42.0.2.tar.gz", hash = "sha256:e0ec52ba3c7f1b7d813cd52649a5b3ef1fc0d433219dc8c93827c57eab6cf888"},
|
||||
{file = "cryptography-42.0.3-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:de5086cd475d67113ccb6f9fae6d8fe3ac54a4f9238fd08bfdb07b03d791ff0a"},
|
||||
{file = "cryptography-42.0.3-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:935cca25d35dda9e7bd46a24831dfd255307c55a07ff38fd1a92119cffc34857"},
|
||||
{file = "cryptography-42.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20100c22b298c9eaebe4f0b9032ea97186ac2555f426c3e70670f2517989543b"},
|
||||
{file = "cryptography-42.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eb6368d5327d6455f20327fb6159b97538820355ec00f8cc9464d617caecead"},
|
||||
{file = "cryptography-42.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:39d5c93e95bcbc4c06313fc6a500cee414ee39b616b55320c1904760ad686938"},
|
||||
{file = "cryptography-42.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3d96ea47ce6d0055d5b97e761d37b4e84195485cb5a38401be341fabf23bc32a"},
|
||||
{file = "cryptography-42.0.3-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d1998e545081da0ab276bcb4b33cce85f775adb86a516e8f55b3dac87f469548"},
|
||||
{file = "cryptography-42.0.3-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:93fbee08c48e63d5d1b39ab56fd3fdd02e6c2431c3da0f4edaf54954744c718f"},
|
||||
{file = "cryptography-42.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:90147dad8c22d64b2ff7331f8d4cddfdc3ee93e4879796f837bdbb2a0b141e0c"},
|
||||
{file = "cryptography-42.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4dcab7c25e48fc09a73c3e463d09ac902a932a0f8d0c568238b3696d06bf377b"},
|
||||
{file = "cryptography-42.0.3-cp37-abi3-win32.whl", hash = "sha256:1e935c2900fb53d31f491c0de04f41110351377be19d83d908c1fd502ae8daa5"},
|
||||
{file = "cryptography-42.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:762f3771ae40e111d78d77cbe9c1035e886ac04a234d3ee0856bf4ecb3749d54"},
|
||||
{file = "cryptography-42.0.3-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0d3ec384058b642f7fb7e7bff9664030011ed1af8f852540c76a1317a9dd0d20"},
|
||||
{file = "cryptography-42.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35772a6cffd1f59b85cb670f12faba05513446f80352fe811689b4e439b5d89e"},
|
||||
{file = "cryptography-42.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04859aa7f12c2b5f7e22d25198ddd537391f1695df7057c8700f71f26f47a129"},
|
||||
{file = "cryptography-42.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c3d1f5a1d403a8e640fa0887e9f7087331abb3f33b0f2207d2cc7f213e4a864c"},
|
||||
{file = "cryptography-42.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:df34312149b495d9d03492ce97471234fd9037aa5ba217c2a6ea890e9166f151"},
|
||||
{file = "cryptography-42.0.3-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:de4ae486041878dc46e571a4c70ba337ed5233a1344c14a0790c4c4be4bbb8b4"},
|
||||
{file = "cryptography-42.0.3-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:0fab2a5c479b360e5e0ea9f654bcebb535e3aa1e493a715b13244f4e07ea8eec"},
|
||||
{file = "cryptography-42.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:25b09b73db78facdfd7dd0fa77a3f19e94896197c86e9f6dc16bce7b37a96504"},
|
||||
{file = "cryptography-42.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d5cf11bc7f0b71fb71af26af396c83dfd3f6eed56d4b6ef95d57867bf1e4ba65"},
|
||||
{file = "cryptography-42.0.3-cp39-abi3-win32.whl", hash = "sha256:0fea01527d4fb22ffe38cd98951c9044400f6eff4788cf52ae116e27d30a1ba3"},
|
||||
{file = "cryptography-42.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:2619487f37da18d6826e27854a7f9d4d013c51eafb066c80d09c63cf24505306"},
|
||||
{file = "cryptography-42.0.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ead69ba488f806fe1b1b4050febafdbf206b81fa476126f3e16110c818bac396"},
|
||||
{file = "cryptography-42.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:20180da1b508f4aefc101cebc14c57043a02b355d1a652b6e8e537967f1e1b46"},
|
||||
{file = "cryptography-42.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:5fbf0f3f0fac7c089308bd771d2c6c7b7d53ae909dce1db52d8e921f6c19bb3a"},
|
||||
{file = "cryptography-42.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c23f03cfd7d9826cdcbad7850de67e18b4654179e01fe9bc623d37c2638eb4ef"},
|
||||
{file = "cryptography-42.0.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:db0480ffbfb1193ac4e1e88239f31314fe4c6cdcf9c0b8712b55414afbf80db4"},
|
||||
{file = "cryptography-42.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:6c25e1e9c2ce682d01fc5e2dde6598f7313027343bd14f4049b82ad0402e52cd"},
|
||||
{file = "cryptography-42.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9541c69c62d7446539f2c1c06d7046aef822940d248fa4b8962ff0302862cc1f"},
|
||||
{file = "cryptography-42.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1b797099d221df7cce5ff2a1d272761d1554ddf9a987d3e11f6459b38cd300fd"},
|
||||
{file = "cryptography-42.0.3.tar.gz", hash = "sha256:069d2ce9be5526a44093a0991c450fe9906cdf069e0e7cd67d9dee49a62b9ebe"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -989,22 +989,22 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "dnspython"
|
||||
version = "2.5.0"
|
||||
version = "2.6.1"
|
||||
description = "DNS toolkit"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "dnspython-2.5.0-py3-none-any.whl", hash = "sha256:6facdf76b73c742ccf2d07add296f178e629da60be23ce4b0a9c927b1e02c3a6"},
|
||||
{file = "dnspython-2.5.0.tar.gz", hash = "sha256:a0034815a59ba9ae888946be7ccca8f7c157b286f8455b379c692efb51022a15"},
|
||||
{file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"},
|
||||
{file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=5.0.3)", "mypy (>=1.0.1)", "pylint (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0.0)", "sphinx (>=7.0.0)", "twine (>=4.0.0)", "wheel (>=0.41.0)"]
|
||||
dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "sphinx (>=7.2.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"]
|
||||
dnssec = ["cryptography (>=41)"]
|
||||
doh = ["h2 (>=4.1.0)", "httpcore (>=0.17.3)", "httpx (>=0.25.1)"]
|
||||
doq = ["aioquic (>=0.9.20)"]
|
||||
idna = ["idna (>=2.1)"]
|
||||
trio = ["trio (>=0.14)"]
|
||||
doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"]
|
||||
doq = ["aioquic (>=0.9.25)"]
|
||||
idna = ["idna (>=3.6)"]
|
||||
trio = ["trio (>=0.23)"]
|
||||
wmi = ["wmi (>=1.5.1)"]
|
||||
|
||||
[[package]]
|
||||
@@ -1131,53 +1131,53 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "fonttools"
|
||||
version = "4.48.1"
|
||||
version = "4.49.0"
|
||||
description = "Tools to manipulate font files"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "fonttools-4.48.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:702ae93058c81f46461dc4b2c79f11d3c3d8fd7296eaf8f75b4ba5bbf813cd5f"},
|
||||
{file = "fonttools-4.48.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:97f0a49fa6aa2d6205c6f72f4f98b74ef4b9bfdcb06fd78e6fe6c7af4989b63e"},
|
||||
{file = "fonttools-4.48.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3260db55f1843e57115256e91247ad9f68cb02a434b51262fe0019e95a98738"},
|
||||
{file = "fonttools-4.48.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e740a7602c2bb71e1091269b5dbe89549749a8817dc294b34628ffd8b2bf7124"},
|
||||
{file = "fonttools-4.48.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4108b1d247953dd7c90ec8f457a2dec5fceb373485973cc852b14200118a51ee"},
|
||||
{file = "fonttools-4.48.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:56339ec557f0c342bddd7c175f5e41c45fc21282bee58a86bd9aa322bec715f2"},
|
||||
{file = "fonttools-4.48.1-cp310-cp310-win32.whl", hash = "sha256:bff5b38d0e76eb18e0b8abbf35d384e60b3371be92f7be36128ee3e67483b3ec"},
|
||||
{file = "fonttools-4.48.1-cp310-cp310-win_amd64.whl", hash = "sha256:f7449493886da6a17472004d3818cc050ba3f4a0aa03fb47972e4fa5578e6703"},
|
||||
{file = "fonttools-4.48.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:18b35fd1a850ed7233a99bbd6774485271756f717dac8b594958224b54118b61"},
|
||||
{file = "fonttools-4.48.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cad5cfd044ea2e306fda44482b3dd32ee47830fa82dfa4679374b41baa294f5f"},
|
||||
{file = "fonttools-4.48.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f30e605c7565d0da6f0aec75a30ec372072d016957cd8fc4469721a36ea59b7"},
|
||||
{file = "fonttools-4.48.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aee76fd81a8571c68841d6ef0da750d5ff08ff2c5f025576473016f16ac3bcf7"},
|
||||
{file = "fonttools-4.48.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5057ade278e67923000041e2b195c9ea53e87f227690d499b6a4edd3702f7f01"},
|
||||
{file = "fonttools-4.48.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b10633aafc5932995a391ec07eba5e79f52af0003a1735b2306b3dab8a056d48"},
|
||||
{file = "fonttools-4.48.1-cp311-cp311-win32.whl", hash = "sha256:0d533f89819f9b3ee2dbedf0fed3825c425850e32bdda24c558563c71be0064e"},
|
||||
{file = "fonttools-4.48.1-cp311-cp311-win_amd64.whl", hash = "sha256:d20588466367f05025bb1efdf4e5d498ca6d14bde07b6928b79199c588800f0a"},
|
||||
{file = "fonttools-4.48.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0a2417547462e468edf35b32e3dd06a6215ac26aa6316b41e03b8eeaf9f079ea"},
|
||||
{file = "fonttools-4.48.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cf5a0cd974f85a80b74785db2d5c3c1fd6cc09a2ba3c837359b2b5da629ee1b0"},
|
||||
{file = "fonttools-4.48.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0452fcbfbce752ba596737a7c5ec5cf76bc5f83847ce1781f4f90eab14ece252"},
|
||||
{file = "fonttools-4.48.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578c00f93868f64a4102ecc5aa600a03b49162c654676c3fadc33de2ddb88a81"},
|
||||
{file = "fonttools-4.48.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:63dc592a16cd08388d8c4c7502b59ac74190b23e16dfc863c69fe1ea74605b68"},
|
||||
{file = "fonttools-4.48.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9b58638d8a85e3a1b32ec0a91d9f8171a877b4b81c408d4cb3257d0dee63e092"},
|
||||
{file = "fonttools-4.48.1-cp312-cp312-win32.whl", hash = "sha256:d10979ef14a8beaaa32f613bb698743f7241d92f437a3b5e32356dfb9769c65d"},
|
||||
{file = "fonttools-4.48.1-cp312-cp312-win_amd64.whl", hash = "sha256:cdfd7557d1bd294a200bd211aa665ca3b02998dcc18f8211a5532da5b8fad5c5"},
|
||||
{file = "fonttools-4.48.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3cdb9a92521b81bf717ebccf592bd0292e853244d84115bfb4db0c426de58348"},
|
||||
{file = "fonttools-4.48.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9b4ec6d42a7555f5ae35f3b805482f0aad0f1baeeef54859492ea3b782959d4a"},
|
||||
{file = "fonttools-4.48.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:902e9c4e9928301912f34a6638741b8ae0b64824112b42aaf240e06b735774b1"},
|
||||
{file = "fonttools-4.48.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8c8b54bd1420c184a995f980f1a8076f87363e2bb24239ef8c171a369d85a31"},
|
||||
{file = "fonttools-4.48.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:12ee86abca46193359ea69216b3a724e90c66ab05ab220d39e3fc068c1eb72ac"},
|
||||
{file = "fonttools-4.48.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6978bade7b6c0335095bdd0bd97f8f3d590d2877b370f17e03e0865241694eb5"},
|
||||
{file = "fonttools-4.48.1-cp38-cp38-win32.whl", hash = "sha256:bcd77f89fc1a6b18428e7a55dde8ef56dae95640293bfb8f4e929929eba5e2a2"},
|
||||
{file = "fonttools-4.48.1-cp38-cp38-win_amd64.whl", hash = "sha256:f40441437b039930428e04fb05ac3a132e77458fb57666c808d74a556779e784"},
|
||||
{file = "fonttools-4.48.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0d2b01428f7da26f229a5656defc824427b741e454b4e210ad2b25ed6ea2aed4"},
|
||||
{file = "fonttools-4.48.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:df48798f9a4fc4c315ab46e17873436c8746f5df6eddd02fad91299b2af7af95"},
|
||||
{file = "fonttools-4.48.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2eb4167bde04e172a93cf22c875d8b0cff76a2491f67f5eb069566215302d45d"},
|
||||
{file = "fonttools-4.48.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c900508c46274d32d308ae8e82335117f11aaee1f7d369ac16502c9a78930b0a"},
|
||||
{file = "fonttools-4.48.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:594206b31c95fcfa65f484385171fabb4ec69f7d2d7f56d27f17db26b7a31814"},
|
||||
{file = "fonttools-4.48.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:292922dc356d7f11f5063b4111a8b719efb8faea92a2a88ed296408d449d8c2e"},
|
||||
{file = "fonttools-4.48.1-cp39-cp39-win32.whl", hash = "sha256:4709c5bf123ba10eac210d2d5c9027d3f472591d9f1a04262122710fa3d23199"},
|
||||
{file = "fonttools-4.48.1-cp39-cp39-win_amd64.whl", hash = "sha256:63c73b9dd56a94a3cbd2f90544b5fca83666948a9e03370888994143b8d7c070"},
|
||||
{file = "fonttools-4.48.1-py3-none-any.whl", hash = "sha256:e3e33862fc5261d46d9aae3544acb36203b1a337d00bdb5d3753aae50dac860e"},
|
||||
{file = "fonttools-4.48.1.tar.gz", hash = "sha256:8b8a45254218679c7f1127812761e7854ed5c8e34349aebf581e8c9204e7495a"},
|
||||
{file = "fonttools-4.49.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d970ecca0aac90d399e458f0b7a8a597e08f95de021f17785fb68e2dc0b99717"},
|
||||
{file = "fonttools-4.49.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac9a745b7609f489faa65e1dc842168c18530874a5f5b742ac3dd79e26bca8bc"},
|
||||
{file = "fonttools-4.49.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ba0e00620ca28d4ca11fc700806fd69144b463aa3275e1b36e56c7c09915559"},
|
||||
{file = "fonttools-4.49.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdee3ab220283057e7840d5fb768ad4c2ebe65bdba6f75d5d7bf47f4e0ed7d29"},
|
||||
{file = "fonttools-4.49.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ce7033cb61f2bb65d8849658d3786188afd80f53dad8366a7232654804529532"},
|
||||
{file = "fonttools-4.49.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:07bc5ea02bb7bc3aa40a1eb0481ce20e8d9b9642a9536cde0218290dd6085828"},
|
||||
{file = "fonttools-4.49.0-cp310-cp310-win32.whl", hash = "sha256:86eef6aab7fd7c6c8545f3ebd00fd1d6729ca1f63b0cb4d621bccb7d1d1c852b"},
|
||||
{file = "fonttools-4.49.0-cp310-cp310-win_amd64.whl", hash = "sha256:1fac1b7eebfce75ea663e860e7c5b4a8831b858c17acd68263bc156125201abf"},
|
||||
{file = "fonttools-4.49.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:edc0cce355984bb3c1d1e89d6a661934d39586bb32191ebff98c600f8957c63e"},
|
||||
{file = "fonttools-4.49.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:83a0d9336de2cba86d886507dd6e0153df333ac787377325a39a2797ec529814"},
|
||||
{file = "fonttools-4.49.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36c8865bdb5cfeec88f5028e7e592370a0657b676c6f1d84a2108e0564f90e22"},
|
||||
{file = "fonttools-4.49.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33037d9e56e2562c710c8954d0f20d25b8386b397250d65581e544edc9d6b942"},
|
||||
{file = "fonttools-4.49.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8fb022d799b96df3eaa27263e9eea306bd3d437cc9aa981820850281a02b6c9a"},
|
||||
{file = "fonttools-4.49.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33c584c0ef7dc54f5dd4f84082eabd8d09d1871a3d8ca2986b0c0c98165f8e86"},
|
||||
{file = "fonttools-4.49.0-cp311-cp311-win32.whl", hash = "sha256:cbe61b158deb09cffdd8540dc4a948d6e8f4d5b4f3bf5cd7db09bd6a61fee64e"},
|
||||
{file = "fonttools-4.49.0-cp311-cp311-win_amd64.whl", hash = "sha256:fc11e5114f3f978d0cea7e9853627935b30d451742eeb4239a81a677bdee6bf6"},
|
||||
{file = "fonttools-4.49.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d647a0e697e5daa98c87993726da8281c7233d9d4ffe410812a4896c7c57c075"},
|
||||
{file = "fonttools-4.49.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f3bbe672df03563d1f3a691ae531f2e31f84061724c319652039e5a70927167e"},
|
||||
{file = "fonttools-4.49.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bebd91041dda0d511b0d303180ed36e31f4f54b106b1259b69fade68413aa7ff"},
|
||||
{file = "fonttools-4.49.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4145f91531fd43c50f9eb893faa08399816bb0b13c425667c48475c9f3a2b9b5"},
|
||||
{file = "fonttools-4.49.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ea329dafb9670ffbdf4dbc3b0e5c264104abcd8441d56de77f06967f032943cb"},
|
||||
{file = "fonttools-4.49.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c076a9e548521ecc13d944b1d261ff3d7825048c338722a4bd126d22316087b7"},
|
||||
{file = "fonttools-4.49.0-cp312-cp312-win32.whl", hash = "sha256:b607ea1e96768d13be26d2b400d10d3ebd1456343eb5eaddd2f47d1c4bd00880"},
|
||||
{file = "fonttools-4.49.0-cp312-cp312-win_amd64.whl", hash = "sha256:a974c49a981e187381b9cc2c07c6b902d0079b88ff01aed34695ec5360767034"},
|
||||
{file = "fonttools-4.49.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b85ec0bdd7bdaa5c1946398cbb541e90a6dfc51df76dfa88e0aaa41b335940cb"},
|
||||
{file = "fonttools-4.49.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:af20acbe198a8a790618ee42db192eb128afcdcc4e96d99993aca0b60d1faeb4"},
|
||||
{file = "fonttools-4.49.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d418b1fee41a1d14931f7ab4b92dc0bc323b490e41d7a333eec82c9f1780c75"},
|
||||
{file = "fonttools-4.49.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b44a52b8e6244b6548851b03b2b377a9702b88ddc21dcaf56a15a0393d425cb9"},
|
||||
{file = "fonttools-4.49.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7c7125068e04a70739dad11857a4d47626f2b0bd54de39e8622e89701836eabd"},
|
||||
{file = "fonttools-4.49.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:29e89d0e1a7f18bc30f197cfadcbef5a13d99806447c7e245f5667579a808036"},
|
||||
{file = "fonttools-4.49.0-cp38-cp38-win32.whl", hash = "sha256:9d95fa0d22bf4f12d2fb7b07a46070cdfc19ef5a7b1c98bc172bfab5bf0d6844"},
|
||||
{file = "fonttools-4.49.0-cp38-cp38-win_amd64.whl", hash = "sha256:768947008b4dc552d02772e5ebd49e71430a466e2373008ce905f953afea755a"},
|
||||
{file = "fonttools-4.49.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:08877e355d3dde1c11973bb58d4acad1981e6d1140711230a4bfb40b2b937ccc"},
|
||||
{file = "fonttools-4.49.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fdb54b076f25d6b0f0298dc706acee5052de20c83530fa165b60d1f2e9cbe3cb"},
|
||||
{file = "fonttools-4.49.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0af65c720520710cc01c293f9c70bd69684365c6015cc3671db2b7d807fe51f2"},
|
||||
{file = "fonttools-4.49.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f255ce8ed7556658f6d23f6afd22a6d9bbc3edb9b96c96682124dc487e1bf42"},
|
||||
{file = "fonttools-4.49.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d00af0884c0e65f60dfaf9340e26658836b935052fdd0439952ae42e44fdd2be"},
|
||||
{file = "fonttools-4.49.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:263832fae27481d48dfafcc43174644b6706639661e242902ceb30553557e16c"},
|
||||
{file = "fonttools-4.49.0-cp39-cp39-win32.whl", hash = "sha256:0404faea044577a01bb82d47a8fa4bc7a54067fa7e324785dd65d200d6dd1133"},
|
||||
{file = "fonttools-4.49.0-cp39-cp39-win_amd64.whl", hash = "sha256:b050d362df50fc6e38ae3954d8c29bf2da52be384649ee8245fdb5186b620836"},
|
||||
{file = "fonttools-4.49.0-py3-none-any.whl", hash = "sha256:af281525e5dd7fa0b39fb1667b8d5ca0e2a9079967e14c4bfe90fd1cd13e0f18"},
|
||||
{file = "fonttools-4.49.0.tar.gz", hash = "sha256:ebf46e7f01b7af7861310417d7c49591a85d99146fc23a5ba82fdb28af156321"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@@ -1563,13 +1563,13 @@ zoneinfo = ["backports.zoneinfo (>=0.2.1)", "tzdata (>=2022.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "identify"
|
||||
version = "2.5.34"
|
||||
version = "2.5.35"
|
||||
description = "File identification library for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "identify-2.5.34-py2.py3-none-any.whl", hash = "sha256:a4316013779e433d08b96e5eabb7f641e6c7942e4ab5d4c509ebd2e7a8994aed"},
|
||||
{file = "identify-2.5.34.tar.gz", hash = "sha256:ee17bc9d499899bc9eaec1ac7bf2dc9eedd480db9d88b96d123d3b64a9d34f5d"},
|
||||
{file = "identify-2.5.35-py2.py3-none-any.whl", hash = "sha256:c4de0081837b211594f8e877a6b4fad7ca32bbfc1a9307fdd61c28bfe923f13e"},
|
||||
{file = "identify-2.5.35.tar.gz", hash = "sha256:10a7ca245cfcd756a554a7288159f72ff105ad233c7c4b9c6f0f4d108f5f6791"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@@ -2116,39 +2116,39 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "matplotlib"
|
||||
version = "3.8.2"
|
||||
version = "3.8.3"
|
||||
description = "Python plotting package"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "matplotlib-3.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:09796f89fb71a0c0e1e2f4bdaf63fb2cefc84446bb963ecdeb40dfee7dfa98c7"},
|
||||
{file = "matplotlib-3.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9c6976748a25e8b9be51ea028df49b8e561eed7809146da7a47dbecebab367"},
|
||||
{file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b78e4f2cedf303869b782071b55fdde5987fda3038e9d09e58c91cc261b5ad18"},
|
||||
{file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e208f46cf6576a7624195aa047cb344a7f802e113bb1a06cfd4bee431de5e31"},
|
||||
{file = "matplotlib-3.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:46a569130ff53798ea5f50afce7406e91fdc471ca1e0e26ba976a8c734c9427a"},
|
||||
{file = "matplotlib-3.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:830f00640c965c5b7f6bc32f0d4ce0c36dfe0379f7dd65b07a00c801713ec40a"},
|
||||
{file = "matplotlib-3.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d86593ccf546223eb75a39b44c32788e6f6440d13cfc4750c1c15d0fcb850b63"},
|
||||
{file = "matplotlib-3.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a5430836811b7652991939012f43d2808a2db9b64ee240387e8c43e2e5578c8"},
|
||||
{file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9576723858a78751d5aacd2497b8aef29ffea6d1c95981505877f7ac28215c6"},
|
||||
{file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba9cbd8ac6cf422f3102622b20f8552d601bf8837e49a3afed188d560152788"},
|
||||
{file = "matplotlib-3.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:03f9d160a29e0b65c0790bb07f4f45d6a181b1ac33eb1bb0dd225986450148f0"},
|
||||
{file = "matplotlib-3.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:3773002da767f0a9323ba1a9b9b5d00d6257dbd2a93107233167cfb581f64717"},
|
||||
{file = "matplotlib-3.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4c318c1e95e2f5926fba326f68177dee364aa791d6df022ceb91b8221bd0a627"},
|
||||
{file = "matplotlib-3.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:091275d18d942cf1ee9609c830a1bc36610607d8223b1b981c37d5c9fc3e46a4"},
|
||||
{file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b0f3b8ea0e99e233a4bcc44590f01604840d833c280ebb8fe5554fd3e6cfe8d"},
|
||||
{file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7b1704a530395aaf73912be741c04d181f82ca78084fbd80bc737be04848331"},
|
||||
{file = "matplotlib-3.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533b0e3b0c6768eef8cbe4b583731ce25a91ab54a22f830db2b031e83cca9213"},
|
||||
{file = "matplotlib-3.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:0f4fc5d72b75e2c18e55eb32292659cf731d9d5b312a6eb036506304f4675630"},
|
||||
{file = "matplotlib-3.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:deaed9ad4da0b1aea77fe0aa0cebb9ef611c70b3177be936a95e5d01fa05094f"},
|
||||
{file = "matplotlib-3.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:172f4d0fbac3383d39164c6caafd3255ce6fa58f08fc392513a0b1d3b89c4f89"},
|
||||
{file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7d36c2209d9136cd8e02fab1c0ddc185ce79bc914c45054a9f514e44c787917"},
|
||||
{file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5864bdd7da445e4e5e011b199bb67168cdad10b501750367c496420f2ad00843"},
|
||||
{file = "matplotlib-3.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ef8345b48e95cee45ff25192ed1f4857273117917a4dcd48e3905619bcd9c9b8"},
|
||||
{file = "matplotlib-3.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:7c48d9e221b637c017232e3760ed30b4e8d5dfd081daf327e829bf2a72c731b4"},
|
||||
{file = "matplotlib-3.8.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:aa11b3c6928a1e496c1a79917d51d4cd5d04f8a2e75f21df4949eeefdf697f4b"},
|
||||
{file = "matplotlib-3.8.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1095fecf99eeb7384dabad4bf44b965f929a5f6079654b681193edf7169ec20"},
|
||||
{file = "matplotlib-3.8.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:bddfb1db89bfaa855912261c805bd0e10218923cc262b9159a49c29a7a1c1afa"},
|
||||
{file = "matplotlib-3.8.2.tar.gz", hash = "sha256:01a978b871b881ee76017152f1f1a0cbf6bd5f7b8ff8c96df0df1bd57d8755a1"},
|
||||
{file = "matplotlib-3.8.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cf60138ccc8004f117ab2a2bad513cc4d122e55864b4fe7adf4db20ca68a078f"},
|
||||
{file = "matplotlib-3.8.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f557156f7116be3340cdeef7f128fa99b0d5d287d5f41a16e169819dcf22357"},
|
||||
{file = "matplotlib-3.8.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f386cf162b059809ecfac3bcc491a9ea17da69fa35c8ded8ad154cd4b933d5ec"},
|
||||
{file = "matplotlib-3.8.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3c5f96f57b0369c288bf6f9b5274ba45787f7e0589a34d24bdbaf6d3344632f"},
|
||||
{file = "matplotlib-3.8.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:83e0f72e2c116ca7e571c57aa29b0fe697d4c6425c4e87c6e994159e0c008635"},
|
||||
{file = "matplotlib-3.8.3-cp310-cp310-win_amd64.whl", hash = "sha256:1c5c8290074ba31a41db1dc332dc2b62def469ff33766cbe325d32a3ee291aea"},
|
||||
{file = "matplotlib-3.8.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5184e07c7e1d6d1481862ee361905b7059f7fe065fc837f7c3dc11eeb3f2f900"},
|
||||
{file = "matplotlib-3.8.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d7e7e0993d0758933b1a241a432b42c2db22dfa37d4108342ab4afb9557cbe3e"},
|
||||
{file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04b36ad07eac9740fc76c2aa16edf94e50b297d6eb4c081e3add863de4bb19a7"},
|
||||
{file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c42dae72a62f14982f1474f7e5c9959fc4bc70c9de11cc5244c6e766200ba65"},
|
||||
{file = "matplotlib-3.8.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bf5932eee0d428192c40b7eac1399d608f5d995f975cdb9d1e6b48539a5ad8d0"},
|
||||
{file = "matplotlib-3.8.3-cp311-cp311-win_amd64.whl", hash = "sha256:40321634e3a05ed02abf7c7b47a50be50b53ef3eaa3a573847431a545585b407"},
|
||||
{file = "matplotlib-3.8.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:09074f8057917d17ab52c242fdf4916f30e99959c1908958b1fc6032e2d0f6d4"},
|
||||
{file = "matplotlib-3.8.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5745f6d0fb5acfabbb2790318db03809a253096e98c91b9a31969df28ee604aa"},
|
||||
{file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97653d869a71721b639714b42d87cda4cfee0ee74b47c569e4874c7590c55c5"},
|
||||
{file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:242489efdb75b690c9c2e70bb5c6550727058c8a614e4c7716f363c27e10bba1"},
|
||||
{file = "matplotlib-3.8.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:83c0653c64b73926730bd9ea14aa0f50f202ba187c307a881673bad4985967b7"},
|
||||
{file = "matplotlib-3.8.3-cp312-cp312-win_amd64.whl", hash = "sha256:ef6c1025a570354297d6c15f7d0f296d95f88bd3850066b7f1e7b4f2f4c13a39"},
|
||||
{file = "matplotlib-3.8.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c4af3f7317f8a1009bbb2d0bf23dfaba859eb7dd4ccbd604eba146dccaaaf0a4"},
|
||||
{file = "matplotlib-3.8.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c6e00a65d017d26009bac6808f637b75ceade3e1ff91a138576f6b3065eeeba"},
|
||||
{file = "matplotlib-3.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7b49ab49a3bea17802df6872f8d44f664ba8f9be0632a60c99b20b6db2165b7"},
|
||||
{file = "matplotlib-3.8.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6728dde0a3997396b053602dbd907a9bd64ec7d5cf99e728b404083698d3ca01"},
|
||||
{file = "matplotlib-3.8.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:813925d08fb86aba139f2d31864928d67511f64e5945ca909ad5bc09a96189bb"},
|
||||
{file = "matplotlib-3.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:cd3a0c2be76f4e7be03d34a14d49ded6acf22ef61f88da600a18a5cd8b3c5f3c"},
|
||||
{file = "matplotlib-3.8.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fa93695d5c08544f4a0dfd0965f378e7afc410d8672816aff1e81be1f45dbf2e"},
|
||||
{file = "matplotlib-3.8.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9764df0e8778f06414b9d281a75235c1e85071f64bb5d71564b97c1306a2afc"},
|
||||
{file = "matplotlib-3.8.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5e431a09e6fab4012b01fc155db0ce6dccacdbabe8198197f523a4ef4805eb26"},
|
||||
{file = "matplotlib-3.8.3.tar.gz", hash = "sha256:7b416239e9ae38be54b028abbf9048aff5054a9aba5416bef0bd17f9162ce161"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -3041,17 +3041,17 @@ testing = ["pytest", "pytest-benchmark"]
|
||||
|
||||
[[package]]
|
||||
name = "polyline"
|
||||
version = "2.0.1"
|
||||
version = "2.0.2"
|
||||
description = "A Python implementation of Google's Encoded Polyline Algorithm Format."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "polyline-2.0.1-py3-none-any.whl", hash = "sha256:7b1ff647be393143c1b9268738d9efb98a327dd0b29f9c3b84552dff0e34ea3c"},
|
||||
{file = "polyline-2.0.1.tar.gz", hash = "sha256:74cb5cea098dddf09d1a5a1f17af9184d371cbf3e9723de0194e530ec39ca1f6"},
|
||||
{file = "polyline-2.0.2-py3-none-any.whl", hash = "sha256:389655c893bdabf2863c6aaa49490cf83dcdcec86ae715f67044ee98be57bef5"},
|
||||
{file = "polyline-2.0.2.tar.gz", hash = "sha256:10541e759c5fd51f746ee304e9af94744089a4055b6257b293b3afd1df64e369"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["pylint (>=2.15.10,<2.16.0)", "pytest (>=7.0,<8.0)", "pytest-cov (>=4.0,<5.0)", "sphinx (>=4.2.0,<4.3.0)", "sphinx-rtd-theme (>=1.0.0,<1.1.0)", "toml (>=0.10.2,<0.11.0)"]
|
||||
dev = ["pylint (>=3.0.3,<3.1.0)", "pytest (>=7.0,<8.0)", "pytest-cov (>=4.0,<5.0)", "sphinx (>=5.3.0,<5.4.0)", "sphinx-rtd-theme (>=1.2.0,<1.3.0)", "toml (>=0.10.2,<0.11.0)"]
|
||||
publish = ["build (>=0.8,<1.0)", "twine (>=4.0,<5.0)"]
|
||||
|
||||
[[package]]
|
||||
@@ -3085,13 +3085,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "pre-commit"
|
||||
version = "3.6.1"
|
||||
version = "3.6.2"
|
||||
description = "A framework for managing and maintaining multi-language pre-commit hooks."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "pre_commit-3.6.1-py2.py3-none-any.whl", hash = "sha256:9fe989afcf095d2c4796ce7c553cf28d4d4a9b9346de3cda079bcf40748454a4"},
|
||||
{file = "pre_commit-3.6.1.tar.gz", hash = "sha256:c90961d8aa706f75d60935aba09469a6b0bcb8345f127c3fbee4bdc5f114cf4b"},
|
||||
{file = "pre_commit-3.6.2-py2.py3-none-any.whl", hash = "sha256:ba637c2d7a670c10daedc059f5c49b5bd0aadbccfcd7ec15592cf9665117532c"},
|
||||
{file = "pre_commit-3.6.2.tar.gz", hash = "sha256:c3ef34f463045c88658c5b99f38c1e297abdcc0ff13f98d3370055fbbfabc67e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -3113,22 +3113,22 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "protobuf"
|
||||
version = "4.25.2"
|
||||
version = "4.25.3"
|
||||
description = ""
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "protobuf-4.25.2-cp310-abi3-win32.whl", hash = "sha256:b50c949608682b12efb0b2717f53256f03636af5f60ac0c1d900df6213910fd6"},
|
||||
{file = "protobuf-4.25.2-cp310-abi3-win_amd64.whl", hash = "sha256:8f62574857ee1de9f770baf04dde4165e30b15ad97ba03ceac65f760ff018ac9"},
|
||||
{file = "protobuf-4.25.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:2db9f8fa64fbdcdc93767d3cf81e0f2aef176284071507e3ede160811502fd3d"},
|
||||
{file = "protobuf-4.25.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:10894a2885b7175d3984f2be8d9850712c57d5e7587a2410720af8be56cdaf62"},
|
||||
{file = "protobuf-4.25.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fc381d1dd0516343f1440019cedf08a7405f791cd49eef4ae1ea06520bc1c020"},
|
||||
{file = "protobuf-4.25.2-cp38-cp38-win32.whl", hash = "sha256:33a1aeef4b1927431d1be780e87b641e322b88d654203a9e9d93f218ee359e61"},
|
||||
{file = "protobuf-4.25.2-cp38-cp38-win_amd64.whl", hash = "sha256:47f3de503fe7c1245f6f03bea7e8d3ec11c6c4a2ea9ef910e3221c8a15516d62"},
|
||||
{file = "protobuf-4.25.2-cp39-cp39-win32.whl", hash = "sha256:5e5c933b4c30a988b52e0b7c02641760a5ba046edc5e43d3b94a74c9fc57c1b3"},
|
||||
{file = "protobuf-4.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:d66a769b8d687df9024f2985d5137a337f957a0916cf5464d1513eee96a63ff0"},
|
||||
{file = "protobuf-4.25.2-py3-none-any.whl", hash = "sha256:a8b7a98d4ce823303145bf3c1a8bdb0f2f4642a414b196f04ad9853ed0c8f830"},
|
||||
{file = "protobuf-4.25.2.tar.gz", hash = "sha256:fe599e175cb347efc8ee524bcd4b902d11f7262c0e569ececcb89995c15f0a5e"},
|
||||
{file = "protobuf-4.25.3-cp310-abi3-win32.whl", hash = "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa"},
|
||||
{file = "protobuf-4.25.3-cp310-abi3-win_amd64.whl", hash = "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8"},
|
||||
{file = "protobuf-4.25.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c"},
|
||||
{file = "protobuf-4.25.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019"},
|
||||
{file = "protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d"},
|
||||
{file = "protobuf-4.25.3-cp38-cp38-win32.whl", hash = "sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2"},
|
||||
{file = "protobuf-4.25.3-cp38-cp38-win_amd64.whl", hash = "sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4"},
|
||||
{file = "protobuf-4.25.3-cp39-cp39-win32.whl", hash = "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4"},
|
||||
{file = "protobuf-4.25.3-cp39-cp39-win_amd64.whl", hash = "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c"},
|
||||
{file = "protobuf-4.25.3-py3-none-any.whl", hash = "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9"},
|
||||
{file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6468,13 +6468,13 @@ cp2110 = ["hidapi"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "8.0.0"
|
||||
version = "8.0.1"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pytest-8.0.0-py3-none-any.whl", hash = "sha256:50fb9cbe836c3f20f0dfa99c565201fb75dc54c8d76373cd1bde06b06657bdb6"},
|
||||
{file = "pytest-8.0.0.tar.gz", hash = "sha256:249b1b0864530ba251b7438274c4d251c58d868edaaec8762893ad4a0d71c36c"},
|
||||
{file = "pytest-8.0.1-py3-none-any.whl", hash = "sha256:3e4f16fe1c0a9dc9d9389161c127c3edc5d810c38d6793042fb81d9f48a59fca"},
|
||||
{file = "pytest-8.0.1.tar.gz", hash = "sha256:267f6563751877d772019b13aacbe4e860d73fe8f651f28112e9ac37de7513ae"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -6639,12 +6639,12 @@ numpy = ["numpy (>=1.6.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pytweening"
|
||||
version = "1.0.7"
|
||||
version = "1.1.0"
|
||||
description = "A collection of tweening / easing functions."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pytweening-1.0.7.tar.gz", hash = "sha256:767134f1bf57b76c1ce9f692dd1cfc776d9a279de6724e8d04854508fd7ededb"},
|
||||
{file = "pytweening-1.1.0.tar.gz", hash = "sha256:0d8e14af529dd816ad4aa4a86757dfb5fe2fc2897e06f5db60183706a9370828"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6924,28 +6924,28 @@ docs = ["furo (==2023.9.10)", "pyenchant (==3.2.2)", "sphinx (==7.1.2)", "sphinx
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "ruff-0.2.1-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:dd81b911d28925e7e8b323e8d06951554655021df8dd4ac3045d7212ac4ba080"},
|
||||
{file = "ruff-0.2.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dc586724a95b7d980aa17f671e173df00f0a2eef23f8babbeee663229a938fec"},
|
||||
{file = "ruff-0.2.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c92db7101ef5bfc18e96777ed7bc7c822d545fa5977e90a585accac43d22f18a"},
|
||||
{file = "ruff-0.2.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:13471684694d41ae0f1e8e3a7497e14cd57ccb7dd72ae08d56a159d6c9c3e30e"},
|
||||
{file = "ruff-0.2.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a11567e20ea39d1f51aebd778685582d4c56ccb082c1161ffc10f79bebe6df35"},
|
||||
{file = "ruff-0.2.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:00a818e2db63659570403e44383ab03c529c2b9678ba4ba6c105af7854008105"},
|
||||
{file = "ruff-0.2.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be60592f9d218b52f03384d1325efa9d3b41e4c4d55ea022cd548547cc42cd2b"},
|
||||
{file = "ruff-0.2.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbd2288890b88e8aab4499e55148805b58ec711053588cc2f0196a44f6e3d855"},
|
||||
{file = "ruff-0.2.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ef052283da7dec1987bba8d8733051c2325654641dfe5877a4022108098683"},
|
||||
{file = "ruff-0.2.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7022d66366d6fded4ba3889f73cd791c2d5621b2ccf34befc752cb0df70f5fad"},
|
||||
{file = "ruff-0.2.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0a725823cb2a3f08ee743a534cb6935727d9e47409e4ad72c10a3faf042ad5ba"},
|
||||
{file = "ruff-0.2.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:0034d5b6323e6e8fe91b2a1e55b02d92d0b582d2953a2b37a67a2d7dedbb7acc"},
|
||||
{file = "ruff-0.2.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e5cb5526d69bb9143c2e4d2a115d08ffca3d8e0fddc84925a7b54931c96f5c02"},
|
||||
{file = "ruff-0.2.1-py3-none-win32.whl", hash = "sha256:6b95ac9ce49b4fb390634d46d6ece32ace3acdd52814671ccaf20b7f60adb232"},
|
||||
{file = "ruff-0.2.1-py3-none-win_amd64.whl", hash = "sha256:e3affdcbc2afb6f5bd0eb3130139ceedc5e3f28d206fe49f63073cb9e65988e0"},
|
||||
{file = "ruff-0.2.1-py3-none-win_arm64.whl", hash = "sha256:efababa8e12330aa94a53e90a81eb6e2d55f348bc2e71adbf17d9cad23c03ee6"},
|
||||
{file = "ruff-0.2.1.tar.gz", hash = "sha256:3b42b5d8677cd0c72b99fcaf068ffc62abb5a19e71b4a3b9cfa50658a0af02f1"},
|
||||
{file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0a9efb032855ffb3c21f6405751d5e147b0c6b631e3ca3f6b20f917572b97eb6"},
|
||||
{file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d450b7fbff85913f866a5384d8912710936e2b96da74541c82c1b458472ddb39"},
|
||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecd46e3106850a5c26aee114e562c329f9a1fbe9e4821b008c4404f64ff9ce73"},
|
||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e22676a5b875bd72acd3d11d5fa9075d3a5f53b877fe7b4793e4673499318ba"},
|
||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1695700d1e25a99d28f7a1636d85bafcc5030bba9d0578c0781ba1790dbcf51c"},
|
||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b0c232af3d0bd8f521806223723456ffebf8e323bd1e4e82b0befb20ba18388e"},
|
||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f63d96494eeec2fc70d909393bcd76c69f35334cdbd9e20d089fb3f0640216ca"},
|
||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a61ea0ff048e06de273b2e45bd72629f470f5da8f71daf09fe481278b175001"},
|
||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1439c8f407e4f356470e54cdecdca1bd5439a0673792dbe34a2b0a551a2fe3"},
|
||||
{file = "ruff-0.2.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:940de32dc8853eba0f67f7198b3e79bc6ba95c2edbfdfac2144c8235114d6726"},
|
||||
{file = "ruff-0.2.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c126da55c38dd917621552ab430213bdb3273bb10ddb67bc4b761989210eb6e"},
|
||||
{file = "ruff-0.2.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3b65494f7e4bed2e74110dac1f0d17dc8e1f42faaa784e7c58a98e335ec83d7e"},
|
||||
{file = "ruff-0.2.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1ec49be4fe6ddac0503833f3ed8930528e26d1e60ad35c2446da372d16651ce9"},
|
||||
{file = "ruff-0.2.2-py3-none-win32.whl", hash = "sha256:d920499b576f6c68295bc04e7b17b6544d9d05f196bb3aac4358792ef6f34325"},
|
||||
{file = "ruff-0.2.2-py3-none-win_amd64.whl", hash = "sha256:cc9a91ae137d687f43a44c900e5d95e9617cb37d4c989e462980ba27039d239d"},
|
||||
{file = "ruff-0.2.2-py3-none-win_arm64.whl", hash = "sha256:c9d15fc41e6054bfc7200478720570078f0b41c9ae4f010bcc16bd6f4d1aacdd"},
|
||||
{file = "ruff-0.2.2.tar.gz", hash = "sha256:e62ed7f36b3068a30ba39193a14274cd706bc486fad521276458022f7bccb31d"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7027,13 +7027,13 @@ stats = ["scipy (>=1.7)", "statsmodels (>=0.12)"]
|
||||
|
||||
[[package]]
|
||||
name = "sentry-sdk"
|
||||
version = "1.40.3"
|
||||
version = "1.40.5"
|
||||
description = "Python client for Sentry (https://sentry.io)"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "sentry-sdk-1.40.3.tar.gz", hash = "sha256:3c2b027979bb400cd65a47970e64f8cef8acda86b288a27f42a98692505086cd"},
|
||||
{file = "sentry_sdk-1.40.3-py2.py3-none-any.whl", hash = "sha256:73383f28311ae55602bb6cc3b013830811135ba5521e41333a6e68f269413502"},
|
||||
{file = "sentry-sdk-1.40.5.tar.gz", hash = "sha256:d2dca2392cc5c9a2cc9bb874dd7978ebb759682fe4fe889ee7e970ee8dd1c61e"},
|
||||
{file = "sentry_sdk-1.40.5-py2.py3-none-any.whl", hash = "sha256:d188b407c9bacbe2a50a824e1f8fb99ee1aeb309133310488c570cb6d7056643"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -7188,56 +7188,56 @@ testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jar
|
||||
|
||||
[[package]]
|
||||
name = "shapely"
|
||||
version = "2.0.2"
|
||||
version = "2.0.3"
|
||||
description = "Manipulation and analysis of geometric objects"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "shapely-2.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6ca8cffbe84ddde8f52b297b53f8e0687bd31141abb2c373fd8a9f032df415d6"},
|
||||
{file = "shapely-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:baa14fc27771e180c06b499a0a7ba697c7988c7b2b6cba9a929a19a4d2762de3"},
|
||||
{file = "shapely-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:36480e32c434d168cdf2f5e9862c84aaf4d714a43a8465ae3ce8ff327f0affb7"},
|
||||
{file = "shapely-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ef753200cbffd4f652efb2c528c5474e5a14341a473994d90ad0606522a46a2"},
|
||||
{file = "shapely-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9a41ff4323fc9d6257759c26eb1cf3a61ebc7e611e024e6091f42977303fd3a"},
|
||||
{file = "shapely-2.0.2-cp310-cp310-win32.whl", hash = "sha256:72b5997272ae8c25f0fd5b3b967b3237e87fab7978b8d6cd5fa748770f0c5d68"},
|
||||
{file = "shapely-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:34eac2337cbd67650248761b140d2535855d21b969d76d76123317882d3a0c1a"},
|
||||
{file = "shapely-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b0c052709c8a257c93b0d4943b0b7a3035f87e2d6a8ac9407b6a992d206422f"},
|
||||
{file = "shapely-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2d217e56ae067e87b4e1731d0dc62eebe887ced729ba5c2d4590e9e3e9fdbd88"},
|
||||
{file = "shapely-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94ac128ae2ab4edd0bffcd4e566411ea7bdc738aeaf92c32a8a836abad725f9f"},
|
||||
{file = "shapely-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa3ee28f5e63a130ec5af4dc3c4cb9c21c5788bb13c15e89190d163b14f9fb89"},
|
||||
{file = "shapely-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:737dba15011e5a9b54a8302f1748b62daa207c9bc06f820cd0ad32a041f1c6f2"},
|
||||
{file = "shapely-2.0.2-cp311-cp311-win32.whl", hash = "sha256:45ac6906cff0765455a7b49c1670af6e230c419507c13e2f75db638c8fc6f3bd"},
|
||||
{file = "shapely-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:dc9342fc82e374130db86a955c3c4525bfbf315a248af8277a913f30911bed9e"},
|
||||
{file = "shapely-2.0.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:06f193091a7c6112fc08dfd195a1e3846a64306f890b151fa8c63b3e3624202c"},
|
||||
{file = "shapely-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:eebe544df5c018134f3c23b6515877f7e4cd72851f88a8d0c18464f414d141a2"},
|
||||
{file = "shapely-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7e92e7c255f89f5cdf777690313311f422aa8ada9a3205b187113274e0135cd8"},
|
||||
{file = "shapely-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be46d5509b9251dd9087768eaf35a71360de6afac82ce87c636990a0871aa18b"},
|
||||
{file = "shapely-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5533a925d8e211d07636ffc2fdd9a7f9f13d54686d00577eeb11d16f00be9c4"},
|
||||
{file = "shapely-2.0.2-cp312-cp312-win32.whl", hash = "sha256:084b023dae8ad3d5b98acee9d3bf098fdf688eb0bb9b1401e8b075f6a627b611"},
|
||||
{file = "shapely-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:ea84d1cdbcf31e619d672b53c4532f06253894185ee7acb8ceb78f5f33cbe033"},
|
||||
{file = "shapely-2.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ed1e99702125e7baccf401830a3b94d810d5c70b329b765fe93451fe14cf565b"},
|
||||
{file = "shapely-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7d897e6bdc6bc64f7f65155dbbb30e49acaabbd0d9266b9b4041f87d6e52b3a"},
|
||||
{file = "shapely-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0521d76d1e8af01e712db71da9096b484f081e539d4f4a8c97342e7971d5e1b4"},
|
||||
{file = "shapely-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:5324be299d4c533ecfcfd43424dfd12f9428fd6f12cda38a4316da001d6ef0ea"},
|
||||
{file = "shapely-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:78128357a0cee573257a0c2c388d4b7bf13cb7dbe5b3fe5d26d45ebbe2a39e25"},
|
||||
{file = "shapely-2.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:87dc2be34ac3a3a4a319b963c507ac06682978a5e6c93d71917618b14f13066e"},
|
||||
{file = "shapely-2.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:42997ac806e4583dad51c80a32d38570fd9a3d4778f5e2c98f9090aa7db0fe91"},
|
||||
{file = "shapely-2.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ccfd5fa10a37e67dbafc601c1ddbcbbfef70d34c3f6b0efc866ddbdb55893a6c"},
|
||||
{file = "shapely-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7c95d3379ae3abb74058938a9fcbc478c6b2e28d20dace38f8b5c587dde90aa"},
|
||||
{file = "shapely-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a21353d28209fb0d8cc083e08ca53c52666e0d8a1f9bbe23b6063967d89ed24"},
|
||||
{file = "shapely-2.0.2-cp38-cp38-win32.whl", hash = "sha256:03e63a99dfe6bd3beb8d5f41ec2086585bb969991d603f9aeac335ad396a06d4"},
|
||||
{file = "shapely-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:c6fd29fbd9cd76350bd5cc14c49de394a31770aed02d74203e23b928f3d2f1aa"},
|
||||
{file = "shapely-2.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1f217d28ecb48e593beae20a0082a95bd9898d82d14b8fcb497edf6bff9a44d7"},
|
||||
{file = "shapely-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:394e5085b49334fd5b94fa89c086edfb39c3ecab7f669e8b2a4298b9d523b3a5"},
|
||||
{file = "shapely-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fd3ad17b64466a033848c26cb5b509625c87d07dcf39a1541461cacdb8f7e91c"},
|
||||
{file = "shapely-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d41a116fcad58048d7143ddb01285e1a8780df6dc1f56c3b1e1b7f12ed296651"},
|
||||
{file = "shapely-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dea9a0651333cf96ef5bb2035044e3ad6a54f87d90e50fe4c2636debf1b77abc"},
|
||||
{file = "shapely-2.0.2-cp39-cp39-win32.whl", hash = "sha256:b8eb0a92f7b8c74f9d8fdd1b40d395113f59bd8132ca1348ebcc1f5aece94b96"},
|
||||
{file = "shapely-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:794affd80ca0f2c536fc948a3afa90bd8fb61ebe37fe873483ae818e7f21def4"},
|
||||
{file = "shapely-2.0.2.tar.gz", hash = "sha256:1713cc04c171baffc5b259ba8531c58acc2a301707b7f021d88a15ed090649e7"},
|
||||
{file = "shapely-2.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:af7e9abe180b189431b0f490638281b43b84a33a960620e6b2e8d3e3458b61a1"},
|
||||
{file = "shapely-2.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:98040462b36ced9671e266b95c326b97f41290d9d17504a1ee4dc313a7667b9c"},
|
||||
{file = "shapely-2.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:71eb736ef2843f23473c6e37f6180f90f0a35d740ab284321548edf4e55d9a52"},
|
||||
{file = "shapely-2.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:881eb9dbbb4a6419667e91fcb20313bfc1e67f53dbb392c6840ff04793571ed1"},
|
||||
{file = "shapely-2.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f10d2ccf0554fc0e39fad5886c839e47e207f99fdf09547bc687a2330efda35b"},
|
||||
{file = "shapely-2.0.3-cp310-cp310-win32.whl", hash = "sha256:6dfdc077a6fcaf74d3eab23a1ace5abc50c8bce56ac7747d25eab582c5a2990e"},
|
||||
{file = "shapely-2.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:64c5013dacd2d81b3bb12672098a0b2795c1bf8190cfc2980e380f5ef9d9e4d9"},
|
||||
{file = "shapely-2.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:56cee3e4e8159d6f2ce32e421445b8e23154fd02a0ac271d6a6c0b266a8e3cce"},
|
||||
{file = "shapely-2.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:619232c8276fded09527d2a9fd91a7885ff95c0ff9ecd5e3cb1e34fbb676e2ae"},
|
||||
{file = "shapely-2.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b2a7d256db6f5b4b407dc0c98dd1b2fcf1c9c5814af9416e5498d0a2e4307a4b"},
|
||||
{file = "shapely-2.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45f0c8cd4583647db3216d965d49363e6548c300c23fd7e57ce17a03f824034"},
|
||||
{file = "shapely-2.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13cb37d3826972a82748a450328fe02a931dcaed10e69a4d83cc20ba021bc85f"},
|
||||
{file = "shapely-2.0.3-cp311-cp311-win32.whl", hash = "sha256:9302d7011e3e376d25acd30d2d9e70d315d93f03cc748784af19b00988fc30b1"},
|
||||
{file = "shapely-2.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:6b464f2666b13902835f201f50e835f2f153f37741db88f68c7f3b932d3505fa"},
|
||||
{file = "shapely-2.0.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e86e7cb8e331a4850e0c2a8b2d66dc08d7a7b301b8d1d34a13060e3a5b4b3b55"},
|
||||
{file = "shapely-2.0.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c91981c99ade980fc49e41a544629751a0ccd769f39794ae913e53b07b2f78b9"},
|
||||
{file = "shapely-2.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd45d456983dc60a42c4db437496d3f08a4201fbf662b69779f535eb969660af"},
|
||||
{file = "shapely-2.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:882fb1ffc7577e88c1194f4f1757e277dc484ba096a3b94844319873d14b0f2d"},
|
||||
{file = "shapely-2.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9f2d93bff2ea52fa93245798cddb479766a18510ea9b93a4fb9755c79474889"},
|
||||
{file = "shapely-2.0.3-cp312-cp312-win32.whl", hash = "sha256:99abad1fd1303b35d991703432c9481e3242b7b3a393c186cfb02373bf604004"},
|
||||
{file = "shapely-2.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:6f555fe3304a1f40398977789bc4fe3c28a11173196df9ece1e15c5bc75a48db"},
|
||||
{file = "shapely-2.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a983cc418c1fa160b7d797cfef0e0c9f8c6d5871e83eae2c5793fce6a837fad9"},
|
||||
{file = "shapely-2.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18bddb8c327f392189a8d5d6b9a858945722d0bb95ccbd6a077b8e8fc4c7890d"},
|
||||
{file = "shapely-2.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:442f4dcf1eb58c5a4e3428d88e988ae153f97ab69a9f24e07bf4af8038536325"},
|
||||
{file = "shapely-2.0.3-cp37-cp37m-win32.whl", hash = "sha256:31a40b6e3ab00a4fd3a1d44efb2482278642572b8e0451abdc8e0634b787173e"},
|
||||
{file = "shapely-2.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:59b16976c2473fec85ce65cc9239bef97d4205ab3acead4e6cdcc72aee535679"},
|
||||
{file = "shapely-2.0.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:705efbce1950a31a55b1daa9c6ae1c34f1296de71ca8427974ec2f27d57554e3"},
|
||||
{file = "shapely-2.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:601c5c0058a6192df704cb889439f64994708563f57f99574798721e9777a44b"},
|
||||
{file = "shapely-2.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f24ecbb90a45c962b3b60d8d9a387272ed50dc010bfe605f1d16dfc94772d8a1"},
|
||||
{file = "shapely-2.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8c2a2989222c6062f7a0656e16276c01bb308bc7e5d999e54bf4e294ce62e76"},
|
||||
{file = "shapely-2.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42bceb9bceb3710a774ce04908fda0f28b291323da2688f928b3f213373b5aee"},
|
||||
{file = "shapely-2.0.3-cp38-cp38-win32.whl", hash = "sha256:54d925c9a311e4d109ec25f6a54a8bd92cc03481a34ae1a6a92c1fe6729b7e01"},
|
||||
{file = "shapely-2.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:300d203b480a4589adefff4c4af0b13919cd6d760ba3cbb1e56275210f96f654"},
|
||||
{file = "shapely-2.0.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:083d026e97b6c1f4a9bd2a9171c7692461092ed5375218170d91705550eecfd5"},
|
||||
{file = "shapely-2.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:27b6e1910094d93e9627f2664121e0e35613262fc037051680a08270f6058daf"},
|
||||
{file = "shapely-2.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:71b2de56a9e8c0e5920ae5ddb23b923490557ac50cb0b7fa752761bf4851acde"},
|
||||
{file = "shapely-2.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d279e56bbb68d218d63f3efc80c819cedcceef0e64efbf058a1df89dc57201b"},
|
||||
{file = "shapely-2.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88566d01a30f0453f7d038db46bc83ce125e38e47c5f6bfd4c9c287010e9bf74"},
|
||||
{file = "shapely-2.0.3-cp39-cp39-win32.whl", hash = "sha256:58afbba12c42c6ed44c4270bc0e22f3dadff5656d711b0ad335c315e02d04707"},
|
||||
{file = "shapely-2.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:5026b30433a70911979d390009261b8c4021ff87c7c3cbd825e62bb2ffa181bc"},
|
||||
{file = "shapely-2.0.3.tar.gz", hash = "sha256:4d65d0aa7910af71efa72fd6447e02a8e5dd44da81a983de9d736d6e6ccbe674"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
numpy = ">=1.14"
|
||||
numpy = ">=1.14,<2"
|
||||
|
||||
[package.extras]
|
||||
docs = ["matplotlib", "numpydoc (==1.1.*)", "sphinx", "sphinx-book-theme", "sphinx-remove-toctrees"]
|
||||
@@ -7594,13 +7594,13 @@ telegram = ["requests"]
|
||||
|
||||
[[package]]
|
||||
name = "types-requests"
|
||||
version = "2.31.0.20240125"
|
||||
version = "2.31.0.20240218"
|
||||
description = "Typing stubs for requests"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "types-requests-2.31.0.20240125.tar.gz", hash = "sha256:03a28ce1d7cd54199148e043b2079cdded22d6795d19a2c2a6791a4b2b5e2eb5"},
|
||||
{file = "types_requests-2.31.0.20240125-py3-none-any.whl", hash = "sha256:9592a9a4cb92d6d75d9b491a41477272b710e021011a2a3061157e2fb1f1a5d1"},
|
||||
{file = "types-requests-2.31.0.20240218.tar.gz", hash = "sha256:f1721dba8385958f504a5386240b92de4734e047a08a40751c1654d1ac3349c5"},
|
||||
{file = "types_requests-2.31.0.20240218-py3-none-any.whl", hash = "sha256:a82807ec6ddce8f00fe0e949da6d6bc1fbf1715420218a9640d695f70a9e5a9b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -7641,13 +7641,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "2.2.0"
|
||||
version = "2.2.1"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"},
|
||||
{file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"},
|
||||
{file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"},
|
||||
{file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
||||
@@ -206,13 +206,17 @@ def retry_upload(tid: int, end_event: threading.Event, increase_count: bool = Tr
|
||||
break
|
||||
|
||||
|
||||
def cb(sm, item, tid, sz: int, cur: int) -> None:
|
||||
def cb(sm, item, tid, end_event: threading.Event, sz: int, cur: int) -> None:
|
||||
# Abort transfer if connection changed to metered after starting upload
|
||||
# or if athenad is shutting down to re-connect the websocket
|
||||
sm.update(0)
|
||||
metered = sm['deviceState'].networkMetered
|
||||
if metered and (not item.allow_cellular):
|
||||
raise AbortTransferException
|
||||
|
||||
if end_event.is_set():
|
||||
raise AbortTransferException
|
||||
|
||||
cur_upload_items[tid] = replace(item, progress=cur / sz if sz else 1)
|
||||
|
||||
|
||||
@@ -252,7 +256,7 @@ def upload_handler(end_event: threading.Event) -> None:
|
||||
sz = -1
|
||||
|
||||
cloudlog.event("athena.upload_handler.upload_start", fn=fn, sz=sz, network_type=network_type, metered=metered, retry_count=item.retry_count)
|
||||
response = _do_upload(item, partial(cb, sm, item, tid))
|
||||
response = _do_upload(item, partial(cb, sm, item, tid, end_event))
|
||||
|
||||
if response.status_code not in (200, 201, 401, 403, 412):
|
||||
cloudlog.event("athena.upload_handler.retry", status_code=response.status_code, fn=fn, sz=sz, network_type=network_type, metered=metered)
|
||||
@@ -746,6 +750,9 @@ def ws_manage(ws: WebSocket, end_event: threading.Event) -> None:
|
||||
onroad_prev = onroad
|
||||
|
||||
if sock is not None:
|
||||
# While not sending data, onroad, we can expect to time out in 7 + (7 * 2) = 21s
|
||||
# offroad, we can expect to time out in 30 + (10 * 3) = 60s
|
||||
# FIXME: TCP_USER_TIMEOUT is effectively 2x for some reason (32s), so it's mostly unused
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_USER_TIMEOUT, 16000 if onroad else 0)
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 7 if onroad else 30)
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 7 if onroad else 10)
|
||||
|
||||
@@ -233,6 +233,7 @@ class TestAthenadMethods(unittest.TestCase):
|
||||
time.sleep(0.1)
|
||||
|
||||
# TODO: verify that upload actually succeeded
|
||||
# TODO: also check that end_event and metered network raises AbortTransferException
|
||||
self.assertEqual(athenad.upload_queue.qsize(), 0)
|
||||
|
||||
@parameterized.expand([(500, True), (412, False)])
|
||||
|
||||
@@ -12,6 +12,8 @@ from openpilot.selfdrive.athena import athenad
|
||||
from openpilot.selfdrive.manager.helpers import write_onroad_params
|
||||
from openpilot.system.hardware import TICI
|
||||
|
||||
TIMEOUT_TOLERANCE = 20 # seconds
|
||||
|
||||
|
||||
def wifi_radio(on: bool) -> None:
|
||||
if not TICI:
|
||||
@@ -55,7 +57,7 @@ class TestAthenadPing(unittest.TestCase):
|
||||
self.exit_event.set()
|
||||
self.athenad.join()
|
||||
|
||||
@mock.patch('openpilot.selfdrive.athena.athenad.create_connection', autospec=True)
|
||||
@mock.patch('openpilot.selfdrive.athena.athenad.create_connection', new_callable=lambda: mock.MagicMock(wraps=athenad.create_connection))
|
||||
def assertTimeout(self, reconnect_time: float, mock_create_connection: mock.MagicMock) -> None:
|
||||
self.athenad.start()
|
||||
|
||||
@@ -63,7 +65,7 @@ class TestAthenadPing(unittest.TestCase):
|
||||
mock_create_connection.assert_called_once()
|
||||
mock_create_connection.reset_mock()
|
||||
|
||||
# check normal behaviour
|
||||
# check normal behaviour, server pings on connection
|
||||
with self.subTest("Wi-Fi: receives ping"), Timeout(70, "no ping received"):
|
||||
while not self._received_ping():
|
||||
time.sleep(0.1)
|
||||
@@ -92,12 +94,12 @@ class TestAthenadPing(unittest.TestCase):
|
||||
@unittest.skipIf(not TICI, "only run on desk")
|
||||
def test_offroad(self) -> None:
|
||||
write_onroad_params(False, self.params)
|
||||
self.assertTimeout(100) # expect approx 90s
|
||||
self.assertTimeout(60 + TIMEOUT_TOLERANCE) # based using TCP keepalive settings
|
||||
|
||||
@unittest.skipIf(not TICI, "only run on desk")
|
||||
def test_onroad(self) -> None:
|
||||
write_onroad_params(True, self.params)
|
||||
self.assertTimeout(30) # expect 20-30s
|
||||
self.assertTimeout(21 + TIMEOUT_TOLERANCE)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -362,11 +362,11 @@ std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *>
|
||||
ps.setHeartbeatLost((bool)(health.heartbeat_lost_pkt));
|
||||
ps.setAlternativeExperience(health.alternative_experience_pkt);
|
||||
ps.setHarnessStatus(cereal::PandaState::HarnessStatus(health.car_harness_status_pkt));
|
||||
ps.setInterruptLoad(health.interrupt_load);
|
||||
ps.setInterruptLoad(health.interrupt_load_pkt);
|
||||
ps.setFanPower(health.fan_power);
|
||||
ps.setFanStallCount(health.fan_stall_count);
|
||||
ps.setSafetyRxChecksInvalid((bool)(health.safety_rx_checks_invalid));
|
||||
ps.setSpiChecksumErrorCount(health.spi_checksum_error_count);
|
||||
ps.setSafetyRxChecksInvalid((bool)(health.safety_rx_checks_invalid_pkt));
|
||||
ps.setSpiChecksumErrorCount(health.spi_checksum_error_count_pkt);
|
||||
ps.setSbu1Voltage(health.sbu1_voltage_mV / 1000.0f);
|
||||
ps.setSbu2Voltage(health.sbu2_voltage_mV / 1000.0f);
|
||||
|
||||
|
||||
@@ -93,6 +93,11 @@ def main() -> NoReturn:
|
||||
cloudlog.event("pandad.flash_and_connect", count=count)
|
||||
params.remove("PandaSignatures")
|
||||
|
||||
# TODO: remove this in the next AGNOS
|
||||
# wait until USB is up before counting
|
||||
if time.monotonic() < 25.:
|
||||
no_internal_panda_count = 0
|
||||
|
||||
# Handle missing internal panda
|
||||
if no_internal_panda_count > 0:
|
||||
if no_internal_panda_count == 3:
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
# functions common among cars
|
||||
from collections import namedtuple
|
||||
from typing import Dict, List, Optional
|
||||
from dataclasses import dataclass
|
||||
from enum import ReprEnum
|
||||
from typing import Dict, List, Optional, Union
|
||||
|
||||
import capnp
|
||||
|
||||
from cereal import car
|
||||
from openpilot.common.numpy_fast import clip, interp
|
||||
from openpilot.selfdrive.car.docs_definitions import CarInfo
|
||||
|
||||
|
||||
# kg of standard extra cargo to count for drive, gas, etc...
|
||||
@@ -79,7 +82,9 @@ def scale_tire_stiffness(mass, wheelbase, center_to_front, tire_stiffness_factor
|
||||
return tire_stiffness_front, tire_stiffness_rear
|
||||
|
||||
|
||||
def dbc_dict(pt_dbc, radar_dbc, chassis_dbc=None, body_dbc=None) -> Dict[str, str]:
|
||||
DbcDict = Dict[str, str]
|
||||
|
||||
def dbc_dict(pt_dbc, radar_dbc, chassis_dbc=None, body_dbc=None) -> DbcDict:
|
||||
return {'pt': pt_dbc, 'radar': radar_dbc, 'chassis': chassis_dbc, 'body': body_dbc}
|
||||
|
||||
|
||||
@@ -242,3 +247,33 @@ class CanSignalRateCalculator:
|
||||
self.previous_value = current_value
|
||||
|
||||
return self.rate
|
||||
|
||||
|
||||
CarInfos = Union[CarInfo, List[CarInfo]]
|
||||
|
||||
@dataclass(order=True)
|
||||
class PlatformConfig:
|
||||
platform_str: str
|
||||
car_info: CarInfos
|
||||
dbc_dict: DbcDict
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash(self.platform_str)
|
||||
|
||||
|
||||
class Platforms(str, ReprEnum):
|
||||
config: PlatformConfig
|
||||
|
||||
def __new__(cls, platform_config: PlatformConfig):
|
||||
member = str.__new__(cls, platform_config.platform_str)
|
||||
member.config = platform_config
|
||||
member._value_ = platform_config.platform_str
|
||||
return member
|
||||
|
||||
@classmethod
|
||||
def create_dbc_map(cls) -> Dict[str, DbcDict]:
|
||||
return {p.config.platform_str: p.config.dbc_dict for p in cls}
|
||||
|
||||
@classmethod
|
||||
def create_carinfo_map(cls) -> Dict[str, CarInfos]:
|
||||
return {p.config.platform_str: p.config.car_info for p in cls}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
from enum import StrEnum
|
||||
from typing import Dict
|
||||
|
||||
from cereal import car
|
||||
from openpilot.selfdrive.car import dbc_dict
|
||||
from openpilot.selfdrive.car import PlatformConfig, Platforms, dbc_dict
|
||||
from openpilot.selfdrive.car.docs_definitions import CarInfo
|
||||
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
|
||||
|
||||
@@ -22,13 +19,12 @@ class CarControllerParams:
|
||||
pass
|
||||
|
||||
|
||||
class CAR(StrEnum):
|
||||
BODY = "COMMA BODY"
|
||||
|
||||
|
||||
CAR_INFO: Dict[str, CarInfo] = {
|
||||
CAR.BODY: CarInfo("comma body", package="All"),
|
||||
}
|
||||
class CAR(Platforms):
|
||||
BODY = PlatformConfig(
|
||||
"COMMA BODY",
|
||||
CarInfo("comma body", package="All"),
|
||||
dbc_dict('comma_body', None),
|
||||
)
|
||||
|
||||
|
||||
FW_QUERY_CONFIG = FwQueryConfig(
|
||||
@@ -41,7 +37,5 @@ FW_QUERY_CONFIG = FwQueryConfig(
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
DBC = {
|
||||
CAR.BODY: dbc_dict('comma_body', None),
|
||||
}
|
||||
CAR_INFO = CAR.create_carinfo_map()
|
||||
DBC = CAR.create_dbc_map()
|
||||
|
||||
@@ -166,7 +166,7 @@ def fingerprint(logcan, sendcan, num_pandas):
|
||||
cloudlog.warning("VIN %s", vin)
|
||||
params.put("CarVin", vin)
|
||||
|
||||
# disable OBD multiplexing for potential ECU knockouts
|
||||
# disable OBD multiplexing for CAN fingerprinting and potential ECU knockouts
|
||||
set_obd_multiplexing(params, False)
|
||||
params.put_bool("FirmwareQueryDone", True)
|
||||
|
||||
|
||||
@@ -401,6 +401,7 @@ FW_VERSIONS = {
|
||||
b'68527383AD',
|
||||
b'68527387AE',
|
||||
b'68527403AC',
|
||||
b'68546047AF',
|
||||
b'68631938AA',
|
||||
b'68631942AA',
|
||||
],
|
||||
|
||||
@@ -121,6 +121,11 @@ FW_QUERY_CONFIG = FwQueryConfig(
|
||||
requests=[
|
||||
# CAN and CAN FD queries are combined.
|
||||
# FIXME: For CAN FD, ECUs respond with frames larger than 8 bytes on the powertrain bus
|
||||
Request(
|
||||
[StdQueries.TESTER_PRESENT_REQUEST, StdQueries.MANUFACTURER_SOFTWARE_VERSION_REQUEST],
|
||||
[StdQueries.TESTER_PRESENT_RESPONSE, StdQueries.MANUFACTURER_SOFTWARE_VERSION_RESPONSE],
|
||||
logging=True,
|
||||
),
|
||||
Request(
|
||||
[StdQueries.TESTER_PRESENT_REQUEST, StdQueries.MANUFACTURER_SOFTWARE_VERSION_REQUEST],
|
||||
[StdQueries.TESTER_PRESENT_RESPONSE, StdQueries.MANUFACTURER_SOFTWARE_VERSION_RESPONSE],
|
||||
|
||||
@@ -17,7 +17,7 @@ OfflineFwVersions = Dict[str, Dict[EcuAddrSubAddr, List[bytes]]]
|
||||
# A global list of addresses we will only ever consider for VIN responses
|
||||
# engine, hybrid controller, Ford abs, Hyundai CAN FD cluster, 29-bit engine, PGM-FI
|
||||
# TODO: move these to each brand's FW query config
|
||||
STANDARD_VIN_ADDRS = [0x7e0, 0x7e2, 0x760, 0x7c4, 0x18da10f1, 0x18da0ef1]
|
||||
STANDARD_VIN_ADDRS = [0x7e0, 0x7e2, 0x760, 0x7c6, 0x18da10f1, 0x18da0ef1]
|
||||
|
||||
|
||||
def p16(val):
|
||||
@@ -65,6 +65,9 @@ class StdQueries:
|
||||
GM_VIN_REQUEST = b'\x1a\x90'
|
||||
GM_VIN_RESPONSE = b'\x5a\x90'
|
||||
|
||||
KWP_VIN_REQUEST = b'\x21\x81'
|
||||
KWP_VIN_RESPONSE = b'\x61\x81'
|
||||
|
||||
|
||||
@dataclass
|
||||
class Request:
|
||||
|
||||
@@ -7,8 +7,8 @@ from opendbc.can.can_define import CANDefine
|
||||
from opendbc.can.parser import CANParser
|
||||
from openpilot.selfdrive.car.honda.hondacan import get_cruise_speed_conversion, get_pt_bus
|
||||
from openpilot.selfdrive.car.honda.values import CAR, DBC, STEER_THRESHOLD, HONDA_BOSCH, \
|
||||
HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_ALT_BRAKE_SIGNAL, \
|
||||
HONDA_BOSCH_RADARLESS, SERIAL_STEERING
|
||||
HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_RADARLESS, \
|
||||
HondaFlags, SERIAL_STEERING
|
||||
from openpilot.selfdrive.car.interfaces import CarStateBase
|
||||
|
||||
TransmissionType = car.CarParams.TransmissionType
|
||||
@@ -44,7 +44,7 @@ def get_can_messages(CP, gearbox_msg):
|
||||
else:
|
||||
messages.append((gearbox_msg, 100))
|
||||
|
||||
if CP.carFingerprint in HONDA_BOSCH_ALT_BRAKE_SIGNAL:
|
||||
if CP.flags & HondaFlags.BOSCH_ALT_BRAKE:
|
||||
messages.append(("BRAKE_MODULE", 50))
|
||||
|
||||
if CP.carFingerprint in (HONDA_BOSCH | {CAR.CIVIC, CAR.ODYSSEY, CAR.ODYSSEY_CHN, CAR.CLARITY}):
|
||||
@@ -222,7 +222,7 @@ class CarState(CarStateBase):
|
||||
else:
|
||||
ret.cruiseState.speed = cp.vl["CRUISE"]["CRUISE_SPEED_PCM"] * CV.KPH_TO_MS
|
||||
|
||||
if self.CP.carFingerprint in HONDA_BOSCH_ALT_BRAKE_SIGNAL:
|
||||
if self.CP.flags & HondaFlags.BOSCH_ALT_BRAKE:
|
||||
ret.brakePressed = cp.vl["BRAKE_MODULE"]["BRAKE_PRESSED"] != 0
|
||||
else:
|
||||
# brake switch has shown some single time step noise, so only considered when
|
||||
|
||||
@@ -101,10 +101,6 @@ FW_VERSIONS = {
|
||||
b'39990-TVA-X040\x00\x00',
|
||||
b'39990-TVE-H130\x00\x00',
|
||||
],
|
||||
(Ecu.unknown, 0x18da3af1, None): [
|
||||
b'39390-TVA-A020\x00\x00',
|
||||
b'39390-TVA-A120\x00\x00',
|
||||
],
|
||||
(Ecu.srs, 0x18da53f1, None): [
|
||||
b'77959-TBX-H230\x00\x00',
|
||||
b'77959-TVA-A460\x00\x00',
|
||||
@@ -313,6 +309,7 @@ FW_VERSIONS = {
|
||||
(Ecu.srs, 0x18da53f1, None): [
|
||||
b'77959-TBA-A030\x00\x00',
|
||||
b'77959-TBA-A040\x00\x00',
|
||||
b'77959-TBG-A020\x00\x00',
|
||||
b'77959-TBG-A030\x00\x00',
|
||||
b'77959-TEA-Q820\x00\x00',
|
||||
],
|
||||
|
||||
@@ -3,8 +3,9 @@ from cereal import car
|
||||
from panda import Panda
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.numpy_fast import interp
|
||||
from openpilot.selfdrive.car.honda.hondacan import get_pt_bus
|
||||
from openpilot.selfdrive.car.honda.values import CarControllerParams, CruiseButtons, HondaFlags, CAR, HONDA_BOSCH, HONDA_NIDEC_ALT_SCM_MESSAGES, \
|
||||
HONDA_BOSCH_ALT_BRAKE_SIGNAL, HONDA_BOSCH_RADARLESS
|
||||
HONDA_BOSCH_RADARLESS
|
||||
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
|
||||
@@ -315,7 +316,8 @@ class CarInterface(CarInterfaceBase):
|
||||
raise ValueError(f"unsupported car {candidate}")
|
||||
|
||||
# These cars use alternate user brake msg (0x1BE)
|
||||
if candidate in HONDA_BOSCH_ALT_BRAKE_SIGNAL:
|
||||
if 0x1BE in fingerprint[get_pt_bus(candidate)] and candidate in HONDA_BOSCH:
|
||||
ret.flags |= HondaFlags.BOSCH_ALT_BRAKE.value
|
||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_HONDA_ALT_BRAKE
|
||||
|
||||
# These cars use alternate SCM messages (SCM_FEEDBACK AND SCM_BUTTON)
|
||||
|
||||
@@ -49,6 +49,7 @@ class CarControllerParams:
|
||||
class HondaFlags(IntFlag):
|
||||
# Bosch models with alternate set of LKAS_HUD messages
|
||||
BOSCH_EXT_HUD = 1
|
||||
BOSCH_ALT_BRAKE = 2
|
||||
|
||||
|
||||
# Car button codes
|
||||
@@ -267,7 +268,6 @@ HONDA_NIDEC_ALT_SCM_MESSAGES = {CAR.ACURA_ILX, CAR.ACURA_RDX, CAR.CRV, CAR.CRV_E
|
||||
CAR.PILOT, CAR.RIDGELINE, CAR.ACCORD_NIDEC_4CYL}
|
||||
HONDA_BOSCH = {CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_5G,
|
||||
CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E, CAR.CIVIC_2022, CAR.HRV_3G}
|
||||
HONDA_BOSCH_ALT_BRAKE_SIGNAL = {CAR.ACCORD, CAR.CRV_5G, CAR.ACURA_RDX_3G, CAR.HRV_3G}
|
||||
HONDA_BOSCH_RADARLESS = {CAR.CIVIC_2022, CAR.HRV_3G}
|
||||
|
||||
SERIAL_STEERING = {CAR.ACCORD_NIDEC_4CYL, }
|
||||
|
||||
@@ -1549,6 +1549,7 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.06 99211-GI000 210813',
|
||||
b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.01 99211-GI010 211007',
|
||||
b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.02 99211-GI010 211206',
|
||||
b'\xf1\x00NE1 MFC AT KOR LHD 1.00 1.00 99211-GI020 230719',
|
||||
b'\xf1\x00NE1 MFC AT KOR LHD 1.00 1.05 99211-GI010 220614',
|
||||
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.00 99211-GI020 230719',
|
||||
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.01 99211-GI010 211007',
|
||||
@@ -1556,7 +1557,6 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.03 99211-GI010 220401',
|
||||
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.05 99211-GI010 220614',
|
||||
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.06 99211-GI010 230110',
|
||||
b'\xf1\x00NE1 MFC AT KOR LHD 1.00 1.00 99211-GI020 230719',
|
||||
],
|
||||
},
|
||||
CAR.IONIQ_6: {
|
||||
|
||||
@@ -46,6 +46,7 @@ FW_VERSIONS = {
|
||||
CAR.LEAF: {
|
||||
(Ecu.abs, 0x740, None): [
|
||||
b'476605SA1C',
|
||||
b'476605SA7D',
|
||||
b'476605SC2D',
|
||||
b'476606WK7B',
|
||||
b'476606WK9B',
|
||||
@@ -65,6 +66,7 @@ FW_VERSIONS = {
|
||||
],
|
||||
(Ecu.gateway, 0x18dad0f1, None): [
|
||||
b'284U25SA3C',
|
||||
b'284U25SP0C',
|
||||
b'284U25SP1C',
|
||||
b'284U26WK0A',
|
||||
b'284U26WK0C',
|
||||
|
||||
@@ -509,17 +509,20 @@ FW_VERSIONS = {
|
||||
(Ecu.fwdCamera, 0x787, None): [
|
||||
b'\x04!\x01\x1eD\x07!\x00\x04,',
|
||||
b'\x04!\x08\x01.\x07!\x08\x022',
|
||||
b'\r!\x08\x017\n!\x08\x003',
|
||||
],
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'\xd5"`0\x07',
|
||||
b'\xd5"a0\x07',
|
||||
b'\xf1"`q\x07',
|
||||
b'\xf1"aq\x07',
|
||||
b'\xfa"ap\x07',
|
||||
],
|
||||
(Ecu.transmission, 0x7e1, None): [
|
||||
b'\x1d\x86B0\x00',
|
||||
b'\x1d\xf6B0\x00',
|
||||
b'\x1e\x86B0\x00',
|
||||
b'\x1e\x86F0\x00',
|
||||
b'\x1e\xf6D0\x00',
|
||||
],
|
||||
},
|
||||
|
||||
@@ -139,7 +139,7 @@ CAR_INFO: Dict[str, Union[SubaruCarInfo, List[SubaruCarInfo]]] = {
|
||||
CAR.LEGACY_PREGLOBAL: SubaruCarInfo("Subaru Legacy 2015-18"),
|
||||
CAR.OUTBACK_PREGLOBAL: SubaruCarInfo("Subaru Outback 2015-17"),
|
||||
CAR.OUTBACK_PREGLOBAL_2018: SubaruCarInfo("Subaru Outback 2018-19"),
|
||||
CAR.FORESTER_2022: SubaruCarInfo("Subaru Forester 2022-23", "All", car_parts=CarParts.common([CarHarness.subaru_c])),
|
||||
CAR.FORESTER_2022: SubaruCarInfo("Subaru Forester 2022-24", "All", car_parts=CarParts.common([CarHarness.subaru_c])),
|
||||
CAR.OUTBACK_2023: SubaruCarInfo("Subaru Outback 2023", "All", car_parts=CarParts.common([CarHarness.subaru_d])),
|
||||
CAR.ASCENT_2023: SubaruCarInfo("Subaru Ascent 2023", "All", car_parts=CarParts.common([CarHarness.subaru_d])),
|
||||
}
|
||||
|
||||
@@ -187,6 +187,7 @@ routes = [
|
||||
CarTestRoute("5f5afb36036506e4|2019-05-14--02-09-54", TOYOTA.COROLLA_TSS2),
|
||||
CarTestRoute("5ceff72287a5c86c|2019-10-19--10-59-02", TOYOTA.COROLLA_TSS2), # hybrid
|
||||
CarTestRoute("d2525c22173da58b|2021-04-25--16-47-04", TOYOTA.PRIUS),
|
||||
CarTestRoute("b14c5b4742e6fc85|2020-07-28--19-50-11", TOYOTA.RAV4),
|
||||
CarTestRoute("32a7df20486b0f70|2020-02-06--16-06-50", TOYOTA.RAV4H),
|
||||
CarTestRoute("cdf2f7de565d40ae|2019-04-25--03-53-41", TOYOTA.RAV4_TSS2),
|
||||
CarTestRoute("a5c341bb250ca2f0|2022-05-18--16-05-17", TOYOTA.RAV4_TSS2_2022),
|
||||
@@ -223,7 +224,7 @@ routes = [
|
||||
CarTestRoute("ea8fbe72b96a185c|2023-02-08--15-11-46", TOYOTA.CHR_TSS2),
|
||||
CarTestRoute("ea8fbe72b96a185c|2023-02-22--09-20-34", TOYOTA.CHR_TSS2), # openpilot longitudinal, with smartDSU
|
||||
CarTestRoute("6719965b0e1d1737|2023-02-09--22-44-05", TOYOTA.CHR_TSS2), # hybrid
|
||||
# CarTestRoute("6719965b0e1d1737|2023-08-29--06-40-05", TOYOTA.CHR_TSS2), # hybrid, openpilot longitudinal, radar disabled
|
||||
CarTestRoute("6719965b0e1d1737|2023-08-29--06-40-05", TOYOTA.CHR_TSS2), # hybrid, openpilot longitudinal, radar disabled
|
||||
CarTestRoute("14623aae37e549f3|2021-10-24--01-20-49", TOYOTA.PRIUS_V),
|
||||
|
||||
CarTestRoute("202c40641158a6e5|2021-09-21--09-43-24", VOLKSWAGEN.ARTEON_MK1),
|
||||
@@ -291,7 +292,6 @@ routes = [
|
||||
# Segments that test specific issues
|
||||
# Controls mismatch due to interceptor threshold
|
||||
CarTestRoute("cfb32f0fb91b173b|2022-04-06--14-54-45", HONDA.CIVIC, segment=21),
|
||||
CarTestRoute("5a8762b91fc70467|2022-04-14--21-26-20", TOYOTA.RAV4, segment=2),
|
||||
# Controls mismatch due to standstill threshold
|
||||
CarTestRoute("bec2dcfde6a64235|2022-04-08--14-21-32", HONDA.CRV_HYBRID, segment=22),
|
||||
]
|
||||
|
||||
@@ -74,6 +74,10 @@ class TestCarInterfaces(unittest.TestCase):
|
||||
self.assertEqual(len(car_params.longitudinalTuning.kiV), len(car_params.longitudinalTuning.kiBP))
|
||||
self.assertEqual(len(car_params.longitudinalTuning.deadzoneV), len(car_params.longitudinalTuning.deadzoneBP))
|
||||
|
||||
# If we're using the interceptor for gasPressed, we should be commanding gas with it
|
||||
if car_params.enableGasInterceptor:
|
||||
self.assertTrue(car_params.openpilotLongitudinalControl)
|
||||
|
||||
# Lateral sanity checks
|
||||
if car_params.steerControlType != car.CarParams.SteerControlType.angle:
|
||||
tune = car_params.lateralTuning
|
||||
|
||||
@@ -33,18 +33,29 @@ class TestFwFingerprint(unittest.TestCase):
|
||||
self.assertEqual(len(candidates), 1, f"got more than one candidate: {candidates}")
|
||||
self.assertEqual(candidates[0], expected)
|
||||
|
||||
@parameterized.expand([(b, c, e[c]) for b, e in VERSIONS.items() for c in e])
|
||||
def test_exact_match(self, brand, car_model, ecus):
|
||||
@parameterized.expand([(b, c, e[c], n) for b, e in VERSIONS.items() for c in e for n in (True, False)])
|
||||
def test_exact_match(self, brand, car_model, ecus, test_non_essential):
|
||||
config = FW_QUERY_CONFIGS[brand]
|
||||
CP = car.CarParams.new_message()
|
||||
for _ in range(200):
|
||||
for _ in range(100):
|
||||
fw = []
|
||||
for ecu, fw_versions in ecus.items():
|
||||
# Assume non-essential ECUs apply to all cars, so we catch cases where Car A with
|
||||
# missing ECUs won't match to Car B where only Car B has labeled non-essential ECUs
|
||||
if ecu[0] in config.non_essential_ecus and test_non_essential:
|
||||
continue
|
||||
|
||||
ecu_name, addr, sub_addr = ecu
|
||||
fw.append({"ecu": ecu_name, "fwVersion": random.choice(fw_versions), 'brand': brand,
|
||||
"address": addr, "subAddress": 0 if sub_addr is None else sub_addr})
|
||||
CP.carFw = fw
|
||||
_, matches = match_fw_to_car(CP.carFw, allow_fuzzy=False)
|
||||
self.assertFingerprints(matches, car_model)
|
||||
if not test_non_essential:
|
||||
self.assertFingerprints(matches, car_model)
|
||||
else:
|
||||
# if we're removing ECUs we expect some match loss, but it shouldn't mismatch
|
||||
if len(matches) != 0:
|
||||
self.assertFingerprints(matches, car_model)
|
||||
|
||||
@parameterized.expand([(b, c, e[c]) for b, e in VERSIONS.items() for c in e])
|
||||
def test_custom_fuzzy_match(self, brand, car_model, ecus):
|
||||
@@ -225,7 +236,7 @@ class TestFwFingerprintTiming(unittest.TestCase):
|
||||
|
||||
def test_startup_timing(self):
|
||||
# Tests worse-case VIN query time and typical present ECU query time
|
||||
vin_ref_times = {'worst': 1.0, 'best': 0.5} # best assumes we go through all queries to get a match
|
||||
vin_ref_times = {'worst': 1.2, 'best': 0.6} # best assumes we go through all queries to get a match
|
||||
present_ecu_ref_time = 0.75
|
||||
|
||||
def fake_get_ecu_addrs(*_, timeout):
|
||||
@@ -252,13 +263,13 @@ class TestFwFingerprintTiming(unittest.TestCase):
|
||||
print(f'get_vin {name} case, query time={self.total_time / self.N} seconds')
|
||||
|
||||
def test_fw_query_timing(self):
|
||||
total_ref_time = {1: 5.95, 2: 6.85}
|
||||
total_ref_time = {1: 6.05, 2: 6.95}
|
||||
brand_ref_times = {
|
||||
1: {
|
||||
'gm': 0.5,
|
||||
'body': 0.1,
|
||||
'chrysler': 0.3,
|
||||
'ford': 0.1,
|
||||
'ford': 0.2,
|
||||
'honda': 0.55,
|
||||
'hyundai': 1.05,
|
||||
'mazda': 0.1,
|
||||
@@ -269,7 +280,7 @@ class TestFwFingerprintTiming(unittest.TestCase):
|
||||
'volkswagen': 0.2,
|
||||
},
|
||||
2: {
|
||||
'ford': 0.2,
|
||||
'ford': 0.3,
|
||||
'hyundai': 1.85,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,20 +236,16 @@ class CarInterface(CarInterfaceBase):
|
||||
found_ecus = [fw.ecu for fw in car_fw]
|
||||
ret.enableDsu = len(found_ecus) > 0 and Ecu.dsu not in found_ecus and candidate not in (NO_DSU_CAR | UNSUPPORTED_DSU_CAR) \
|
||||
and not (ret.flags & ToyotaFlags.SMART_DSU)
|
||||
ret.enableGasInterceptor = 0x201 in fingerprint[0]
|
||||
|
||||
if ret.enableGasInterceptor:
|
||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_TOYOTA_GAS_INTERCEPTOR
|
||||
|
||||
# if the smartDSU is detected, openpilot can send ACC_CONTROL and the smartDSU will block it from the DSU or radar.
|
||||
# since we don't yet parse radar on TSS2/TSS-P radar-based ACC cars, gate longitudinal behind experimental toggle
|
||||
use_sdsu = bool(ret.flags & ToyotaFlags.SMART_DSU)
|
||||
if candidate in (RADAR_ACC_CAR | NO_DSU_CAR):
|
||||
ret.experimentalLongitudinalAvailable = use_sdsu
|
||||
ret.experimentalLongitudinalAvailable = use_sdsu or candidate in RADAR_ACC_CAR
|
||||
|
||||
if not use_sdsu:
|
||||
# Disabling radar is only supported on TSS2 radar-ACC cars
|
||||
if experimental_long and candidate in RADAR_ACC_CAR and False: # TODO: disabling radar isn't supported yet
|
||||
if experimental_long and candidate in RADAR_ACC_CAR:
|
||||
ret.flags |= ToyotaFlags.DISABLE_RADAR.value
|
||||
else:
|
||||
use_sdsu = use_sdsu and experimental_long
|
||||
@@ -265,12 +261,13 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.openpilotLongitudinalControl = (use_sdsu or ret.enableDsu or candidate in (TSS2_CAR - RADAR_ACC_CAR) or bool(ret.flags & ToyotaFlags.DISABLE_RADAR.value)) and \
|
||||
not Params().get_bool("StockLongToyota")
|
||||
ret.autoResumeSng = ret.openpilotLongitudinalControl and candidate in NO_STOP_TIMER_CAR
|
||||
ret.enableGasInterceptor = 0x201 in fingerprint[0] and ret.openpilotLongitudinalControl
|
||||
|
||||
if not ret.openpilotLongitudinalControl:
|
||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_TOYOTA_STOCK_LONGITUDINAL
|
||||
|
||||
if candidate in UNSUPPORTED_DSU_CAR:
|
||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_TOYOTA_UNSUPPORTED_DSU_CAR
|
||||
if ret.enableGasInterceptor:
|
||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_TOYOTA_GAS_INTERCEPTOR
|
||||
|
||||
# min speed to enable ACC. if car can do stop and go, then set enabling speed
|
||||
# to a negative value, so it won't matter.
|
||||
|
||||
@@ -22,6 +22,7 @@ def get_vin(logcan, sendcan, buses, timeout=0.1, retry=2, debug=False):
|
||||
(StdQueries.UDS_VIN_REQUEST, StdQueries.UDS_VIN_RESPONSE, (0, 1), STANDARD_VIN_ADDRS, FUNCTIONAL_ADDRS, 0x8),
|
||||
(StdQueries.OBD_VIN_REQUEST, StdQueries.OBD_VIN_RESPONSE, (0, 1), STANDARD_VIN_ADDRS, FUNCTIONAL_ADDRS, 0x8),
|
||||
(StdQueries.GM_VIN_REQUEST, StdQueries.GM_VIN_RESPONSE, (0,), [0x24b], None, 0x400), # Bolt fwdCamera
|
||||
(StdQueries.KWP_VIN_REQUEST, StdQueries.KWP_VIN_RESPONSE, (0,), [0x797], None, 0x3), # Nissan Leaf VCM
|
||||
):
|
||||
if bus not in valid_buses:
|
||||
continue
|
||||
@@ -40,8 +41,8 @@ def get_vin(logcan, sendcan, buses, timeout=0.1, retry=2, debug=False):
|
||||
for addr in vin_addrs:
|
||||
vin = results.get((addr, None))
|
||||
if vin is not None:
|
||||
# Ford pads with null bytes
|
||||
if len(vin) == 24:
|
||||
# Ford and Nissan pads with null bytes
|
||||
if len(vin) in (19, 24):
|
||||
vin = re.sub(b'\x00*$', b'', vin)
|
||||
|
||||
# Honda Bosch response starts with a length, trim to correct length
|
||||
|
||||
@@ -1043,6 +1043,7 @@ FW_VERSIONS = {
|
||||
],
|
||||
(Ecu.srs, 0x715, None): [
|
||||
b'\xf1\x873Q0959655AC\xf1\x890200\xf1\x82\r11120011100010022212110200',
|
||||
b'\xf1\x873Q0959655AK\xf1\x890306\xf1\x82\r31210031210021033733310331',
|
||||
b'\xf1\x873Q0959655AP\xf1\x890305\xf1\x82\r11110011110011213331312131',
|
||||
b'\xf1\x873Q0959655AQ\xf1\x890200\xf1\x82\r11120011100010312212113100',
|
||||
b'\xf1\x873Q0959655AS\xf1\x890200\xf1\x82\r11120011100010022212110200',
|
||||
@@ -1062,6 +1063,7 @@ FW_VERSIONS = {
|
||||
(Ecu.fwdRadar, 0x757, None): [
|
||||
b'\xf1\x875Q0907572D \xf1\x890304\xf1\x82\x0101',
|
||||
b'\xf1\x875Q0907572F \xf1\x890400\xf1\x82\x0101',
|
||||
b'\xf1\x875Q0907572H \xf1\x890620',
|
||||
b'\xf1\x875Q0907572J \xf1\x890654',
|
||||
b'\xf1\x875Q0907572K \xf1\x890402\xf1\x82\x0101',
|
||||
b'\xf1\x875Q0907572P \xf1\x890682',
|
||||
|
||||
+165
-97
@@ -6,30 +6,36 @@ import time
|
||||
import threading
|
||||
from typing import SupportsFloat
|
||||
|
||||
from cereal import car, log
|
||||
from openpilot.common.numpy_fast import clip
|
||||
from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL
|
||||
from openpilot.common.params import Params
|
||||
import cereal.messaging as messaging
|
||||
|
||||
from cereal import car, log
|
||||
from cereal.visionipc import VisionIpcClient, VisionStreamType
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
|
||||
from panda import ALTERNATIVE_EXPERIENCE
|
||||
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
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.swaglog import cloudlog
|
||||
from openpilot.system.version import get_short_branch
|
||||
|
||||
from openpilot.selfdrive.athena.registration import is_registered_device
|
||||
from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp
|
||||
from openpilot.selfdrive.car.car_helpers import get_car, get_startup_event, get_one_can
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
from openpilot.selfdrive.controls.lib.alertmanager import AlertManager, set_offroad_alert
|
||||
from openpilot.selfdrive.controls.lib.drive_helpers import VCruiseHelper, clip_curvature, get_lag_adjusted_curvature
|
||||
from openpilot.selfdrive.controls.lib.events import Events, ET
|
||||
from openpilot.selfdrive.controls.lib.latcontrol import LatControl, MIN_LATERAL_CONTROL_SPEED
|
||||
from openpilot.selfdrive.controls.lib.longcontrol import LongControl
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle, STEER_ANGLE_SATURATION_THRESHOLD
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
|
||||
from openpilot.selfdrive.controls.lib.events import Events, ET
|
||||
from openpilot.selfdrive.controls.lib.alertmanager import AlertManager, set_offroad_alert
|
||||
from openpilot.selfdrive.controls.lib.longcontrol import LongControl
|
||||
from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel
|
||||
from openpilot.selfdrive.sunnypilot import get_model_generation
|
||||
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
from openpilot.system.version import get_short_branch
|
||||
|
||||
SOFT_DISABLE_TIME = 3 # seconds
|
||||
LDW_MIN_SPEED = 31 * CV.MPH_TO_MS
|
||||
@@ -59,22 +65,150 @@ ACTIVE_STATES = (State.enabled, State.softDisabling, State.overriding)
|
||||
ENABLED_STATES = (State.preEnabled, *ACTIVE_STATES)
|
||||
|
||||
|
||||
class CarD:
|
||||
CI: CarInterfaceBase
|
||||
CS: car.CarState
|
||||
|
||||
def __init__(self, CI=None):
|
||||
self.can_sock = messaging.sub_sock('can', timeout=20)
|
||||
self.sm = messaging.SubMaster(['pandaStates'])
|
||||
self.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams'])
|
||||
|
||||
self.can_rcv_timeout_counter = 0 # conseuctive timeout count
|
||||
self.can_rcv_cum_timeout_counter = 0 # cumulative timeout count
|
||||
|
||||
self.params = Params()
|
||||
|
||||
if CI is None:
|
||||
# wait for one pandaState and one CAN packet
|
||||
print("Waiting for CAN messages...")
|
||||
get_one_can(self.can_sock)
|
||||
|
||||
num_pandas = len(messaging.recv_one_retry(self.sm.sock['pandaStates']).pandaStates)
|
||||
experimental_long_allowed = self.params.get_bool("ExperimentalLongitudinalEnabled")
|
||||
self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'], experimental_long_allowed, num_pandas)
|
||||
else:
|
||||
self.CI, self.CP = CI, CI.CP
|
||||
|
||||
# set alternative experiences from parameters
|
||||
disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator")
|
||||
enable_mads = self.params.get_bool("EnableMads")
|
||||
mads_disengage_lateral_on_brake = self.params.get_bool("DisengageLateralOnBrake")
|
||||
mads_dlob = enable_mads and mads_disengage_lateral_on_brake
|
||||
mads_ndlob = enable_mads and not mads_disengage_lateral_on_brake
|
||||
self.CP.alternativeExperience = 0
|
||||
if not disengage_on_accelerator:
|
||||
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS
|
||||
if mads_dlob:
|
||||
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.ENABLE_MADS
|
||||
elif mads_ndlob:
|
||||
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.MADS_DISABLE_DISENGAGE_LATERAL_ON_BRAKE
|
||||
|
||||
if self.CP.customStockLongAvailable and self.CP.pcmCruise and self.params.get_bool("CustomStockLong"):
|
||||
self.CP.pcmCruiseSpeed = False
|
||||
|
||||
car_recognized = self.CP.carName != 'mock'
|
||||
openpilot_enabled_toggle = self.params.get_bool("OpenpilotEnabledToggle")
|
||||
|
||||
controller_available = self.CI.CC is not None and openpilot_enabled_toggle and not self.CP.dashcamOnly
|
||||
|
||||
self.CP.passive = not car_recognized or not controller_available or self.CP.dashcamOnly
|
||||
if self.CP.passive:
|
||||
safety_config = car.CarParams.SafetyConfig.new_message()
|
||||
safety_config.safetyModel = car.CarParams.SafetyModel.noOutput
|
||||
self.CP.safetyConfigs = [safety_config]
|
||||
|
||||
# Write previous route's CarParams
|
||||
prev_cp = self.params.get("CarParamsPersistent")
|
||||
if prev_cp is not None:
|
||||
self.params.put("CarParamsPrevRoute", prev_cp)
|
||||
|
||||
# Write CarParams for radard
|
||||
cp_bytes = self.CP.to_bytes()
|
||||
self.params.put("CarParams", cp_bytes)
|
||||
self.params.put_nonblocking("CarParamsCache", cp_bytes)
|
||||
self.params.put_nonblocking("CarParamsPersistent", cp_bytes)
|
||||
|
||||
def initialize(self):
|
||||
"""Initialize CarInterface, once controls are ready"""
|
||||
self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan'])
|
||||
|
||||
def state_update(self, CC: car.CarControl):
|
||||
"""carState update loop, driven by can"""
|
||||
|
||||
# TODO: This should not depend on carControl
|
||||
|
||||
# Update carState from CAN
|
||||
can_strs = messaging.drain_sock_raw(self.can_sock, wait_for_one=True)
|
||||
self.CS = self.CI.update(CC, can_strs)
|
||||
|
||||
self.sm.update(0)
|
||||
|
||||
can_rcv_valid = len(can_strs) > 0
|
||||
|
||||
# Check for CAN timeout
|
||||
if not can_rcv_valid:
|
||||
self.can_rcv_timeout_counter += 1
|
||||
self.can_rcv_cum_timeout_counter += 1
|
||||
else:
|
||||
self.can_rcv_timeout_counter = 0
|
||||
|
||||
self.can_rcv_timeout = self.can_rcv_timeout_counter >= 5
|
||||
|
||||
if can_rcv_valid and REPLAY:
|
||||
self.can_log_mono_time = messaging.log_from_bytes(can_strs[0]).logMonoTime
|
||||
|
||||
return self.CS
|
||||
|
||||
def state_publish(self, car_events):
|
||||
"""carState and carParams publish loop"""
|
||||
|
||||
# TODO: carState should be independent of the event loop
|
||||
|
||||
# carState
|
||||
cs_send = messaging.new_message('carState')
|
||||
cs_send.valid = self.CS.canValid
|
||||
cs_send.carState = self.CS
|
||||
cs_send.carState.events = car_events
|
||||
self.pm.send('carState', cs_send)
|
||||
|
||||
# carParams - logged every 50 seconds (> 1 per segment)
|
||||
if (self.sm.frame % int(50. / DT_CTRL) == 0):
|
||||
cp_send = messaging.new_message('carParams')
|
||||
cp_send.valid = True
|
||||
cp_send.carParams = self.CP
|
||||
self.pm.send('carParams', cp_send)
|
||||
|
||||
def controls_update(self, CC: car.CarControl):
|
||||
"""control update loop, driven by carControl"""
|
||||
|
||||
# send car controls over can
|
||||
now_nanos = self.can_log_mono_time if REPLAY else int(time.monotonic() * 1e9)
|
||||
actuators_output, can_sends = self.CI.apply(CC, now_nanos)
|
||||
self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=self.CS.canValid))
|
||||
|
||||
return actuators_output
|
||||
|
||||
|
||||
class Controls:
|
||||
def __init__(self, CI=None):
|
||||
self.card = CarD(CI)
|
||||
|
||||
self.CP = self.card.CP
|
||||
self.CI = self.card.CI
|
||||
|
||||
config_realtime_process(4, Priority.CTRL_HIGH)
|
||||
|
||||
# Ensure the current branch is cached, otherwise the first iteration of controlsd lags
|
||||
self.branch = get_short_branch()
|
||||
|
||||
# Setup sockets
|
||||
self.pm = messaging.PubMaster(['sendcan', 'controlsState', 'carState',
|
||||
'carControl', 'onroadEvents', 'carParams', 'controlsStateSP'])
|
||||
self.pm = messaging.PubMaster(['controlsState', 'carControl', 'onroadEvents', 'controlsStateSP'])
|
||||
|
||||
self.sensor_packets = ["accelerometer", "gyroscope"]
|
||||
self.camera_packets = ["roadCameraState", "driverCameraState", "wideRoadCameraState"]
|
||||
|
||||
self.log_sock = messaging.sub_sock('androidLog')
|
||||
self.can_sock = messaging.sub_sock('can', timeout=20)
|
||||
|
||||
self.params = Params()
|
||||
|
||||
@@ -96,37 +230,10 @@ class Controls:
|
||||
ignore_alive=ignore, ignore_avg_freq=ignore+['radarState', 'testJoystick'], ignore_valid=['testJoystick', ],
|
||||
frequency=int(1/DT_CTRL))
|
||||
|
||||
if CI is None:
|
||||
# wait for one pandaState and one CAN packet
|
||||
print("Waiting for CAN messages...")
|
||||
get_one_can(self.can_sock)
|
||||
|
||||
num_pandas = len(messaging.recv_one_retry(self.sm.sock['pandaStates']).pandaStates)
|
||||
experimental_long_allowed = self.params.get_bool("ExperimentalLongitudinalEnabled")
|
||||
self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'], experimental_long_allowed, num_pandas)
|
||||
else:
|
||||
self.CI, self.CP = CI, CI.CP
|
||||
|
||||
self.joystick_mode = self.params.get_bool("JoystickDebugMode")
|
||||
|
||||
# set alternative experiences from parameters
|
||||
self.disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator")
|
||||
self.enable_mads = self.params.get_bool("EnableMads")
|
||||
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.CP.alternativeExperience = 0
|
||||
if not self.disengage_on_accelerator:
|
||||
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS
|
||||
if self.mads_dlob:
|
||||
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.ENABLE_MADS
|
||||
elif self.mads_ndlob:
|
||||
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.MADS_DISABLE_DISENGAGE_LATERAL_ON_BRAKE
|
||||
|
||||
if self.CP.customStockLongAvailable and self.CP.pcmCruise and self.params.get_bool("CustomStockLong"):
|
||||
self.CP.pcmCruiseSpeed = False
|
||||
|
||||
# read params
|
||||
self.disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator")
|
||||
self.is_metric = self.params.get_bool("IsMetric")
|
||||
self.is_ldw_enabled = self.params.get_bool("IsLdwEnabled")
|
||||
openpilot_enabled_toggle = self.params.get_bool("OpenpilotEnabledToggle")
|
||||
@@ -137,22 +244,6 @@ class Controls:
|
||||
car_recognized = self.CP.carName != 'mock'
|
||||
|
||||
controller_available = self.CI.CC is not None and openpilot_enabled_toggle and not self.CP.dashcamOnly
|
||||
self.CP.passive = not car_recognized or not controller_available or self.CP.dashcamOnly
|
||||
if self.CP.passive:
|
||||
safety_config = car.CarParams.SafetyConfig.new_message()
|
||||
safety_config.safetyModel = car.CarParams.SafetyModel.noOutput
|
||||
self.CP.safetyConfigs = [safety_config]
|
||||
|
||||
# Write previous route's CarParams
|
||||
prev_cp = self.params.get("CarParamsPersistent")
|
||||
if prev_cp is not None:
|
||||
self.params.put("CarParamsPrevRoute", prev_cp)
|
||||
|
||||
# Write CarParams for radard
|
||||
cp_bytes = self.CP.to_bytes()
|
||||
self.params.put("CarParams", cp_bytes)
|
||||
self.params.put_nonblocking("CarParamsCache", cp_bytes)
|
||||
self.params.put_nonblocking("CarParamsPersistent", cp_bytes)
|
||||
|
||||
# cleanup old params
|
||||
if not self.CP.experimentalLongitudinalAvailable:
|
||||
@@ -184,8 +275,6 @@ class Controls:
|
||||
self.soft_disable_timer = 0
|
||||
self.mismatch_counter = 0
|
||||
self.cruise_mismatch_counter = 0
|
||||
self.can_rcv_timeout_counter = 0 # conseuctive timeout count
|
||||
self.can_rcv_cum_timeout_counter = 0 # cumulative timeout count
|
||||
self.last_blinker_frame = 0
|
||||
self.last_steering_pressed_frame = 0
|
||||
self.distance_traveled = 0
|
||||
@@ -210,6 +299,9 @@ class Controls:
|
||||
self.live_torque = self.params.get_bool("LiveTorque")
|
||||
self.torqued_override = self.params.get_bool("TorquedOverride")
|
||||
|
||||
self.enable_mads = self.params.get_bool("EnableMads")
|
||||
self.mads_disengage_lateral_on_brake = self.params.get_bool("DisengageLateralOnBrake")
|
||||
self.mads_ndlob = self.enable_mads and not self.mads_disengage_lateral_on_brake
|
||||
self.process_not_running = False
|
||||
|
||||
self.custom_model, self.model_gen = get_model_generation(self.params)
|
||||
@@ -394,7 +486,8 @@ class Controls:
|
||||
else:
|
||||
safety_mismatch = pandaState.safetyModel not in IGNORED_SAFETY_MODES
|
||||
|
||||
if safety_mismatch or pandaState.safetyRxChecksInvalid or self.mismatch_counter >= 200:
|
||||
# safety mismatch allows some time for boardd to set the safety mode and publish it back from panda
|
||||
if (safety_mismatch and self.sm.frame*DT_CTRL > 10.) or pandaState.safetyRxChecksInvalid or self.mismatch_counter >= 200:
|
||||
self.events.add(EventName.controlsMismatch)
|
||||
|
||||
if log.PandaState.FaultType.relayMalfunction in pandaState.faults:
|
||||
@@ -434,10 +527,9 @@ class Controls:
|
||||
self.events.add(EventName.canError)
|
||||
|
||||
# generic catch-all. ideally, a more specific event should be added above instead
|
||||
can_rcv_timeout = self.can_rcv_timeout_counter >= 5
|
||||
has_disable_events = self.events.contains(ET.NO_ENTRY) and (self.events.contains(ET.SOFT_DISABLE) or self.events.contains(ET.IMMEDIATE_DISABLE))
|
||||
no_system_errors = (not has_disable_events) or (len(self.events) == num_events)
|
||||
if (not self.sm.all_checks() or can_rcv_timeout) and no_system_errors:
|
||||
if (not self.sm.all_checks() or self.card.can_rcv_timeout) and no_system_errors:
|
||||
if not self.sm.all_alive():
|
||||
self.events.add(EventName.commIssue)
|
||||
elif not self.sm.all_freq_ok():
|
||||
@@ -449,7 +541,7 @@ class Controls:
|
||||
'invalid': [s for s, valid in self.sm.valid.items() if not valid],
|
||||
'not_alive': [s for s, alive in self.sm.alive.items() if not alive],
|
||||
'not_freq_ok': [s for s, freq_ok in self.sm.freq_ok.items() if not freq_ok],
|
||||
'can_rcv_timeout': can_rcv_timeout,
|
||||
'can_rcv_timeout': self.card.can_rcv_timeout,
|
||||
}
|
||||
if logs != self.logged_comm_issue:
|
||||
cloudlog.event("commIssue", error=True, **logs)
|
||||
@@ -501,9 +593,12 @@ class Controls:
|
||||
|
||||
# TODO: fix simulator
|
||||
if not SIMULATION or REPLAY:
|
||||
# Not show in first 1 km to allow for driving out of garage. This event shows after 5 minutes
|
||||
if not self.sm['liveLocationKalman'].gpsOK and self.sm['liveLocationKalman'].inputsOK and (self.distance_traveled > 1000):
|
||||
# Not show in first 1 km to allow for driving out of garage. This event shows after 5 minutes
|
||||
self.events.add(EventName.noGps)
|
||||
if self.sm['liveLocationKalman'].gpsOK:
|
||||
self.distance_traveled = 0
|
||||
self.distance_traveled += CS.vEgo * DT_CTRL
|
||||
|
||||
if self.sm['modelV2'].frameDropPerc > 20:
|
||||
self.events.add(EventName.modeldLagging)
|
||||
@@ -511,17 +606,13 @@ class Controls:
|
||||
def data_sample(self):
|
||||
"""Receive data from sockets and update carState"""
|
||||
|
||||
# Update carState from CAN
|
||||
can_strs = messaging.drain_sock_raw(self.can_sock, wait_for_one=True)
|
||||
CS = self.CI.update(self.CC, can_strs)
|
||||
if len(can_strs) and REPLAY:
|
||||
self.can_log_mono_time = messaging.log_from_bytes(can_strs[0]).logMonoTime
|
||||
CS = self.card.state_update(self.CC)
|
||||
|
||||
self.sm.update(0)
|
||||
|
||||
if not self.initialized:
|
||||
all_valid = CS.canValid and self.sm.all_checks()
|
||||
timed_out = self.sm.frame * DT_CTRL > (6. if REPLAY else 3.5)
|
||||
timed_out = self.sm.frame * DT_CTRL > 6.
|
||||
if all_valid or timed_out or (SIMULATION and not REPLAY):
|
||||
available_streams = VisionIpcClient.available_streams("camerad", block=False)
|
||||
if VisionStreamType.VISION_STREAM_ROAD not in available_streams:
|
||||
@@ -530,7 +621,7 @@ class Controls:
|
||||
self.sm.ignore_alive.append('wideRoadCameraState')
|
||||
|
||||
if not self.CP.passive:
|
||||
self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan'])
|
||||
self.card.initialize()
|
||||
|
||||
self.initialized = True
|
||||
self.set_initial_state()
|
||||
@@ -547,13 +638,6 @@ class Controls:
|
||||
error=True,
|
||||
)
|
||||
|
||||
# Check for CAN timeout
|
||||
if not can_strs:
|
||||
self.can_rcv_timeout_counter += 1
|
||||
self.can_rcv_cum_timeout_counter += 1
|
||||
else:
|
||||
self.can_rcv_timeout_counter = 0
|
||||
|
||||
# When the panda and controlsd do not agree on controls_allowed
|
||||
# we want to disengage openpilot. However the status from the panda goes through
|
||||
# another socket other than the CAN messages and one can arrive earlier than the other.
|
||||
@@ -566,8 +650,6 @@ class Controls:
|
||||
if ps.safetyModel not in IGNORED_SAFETY_MODES):
|
||||
self.mismatch_counter += 1
|
||||
|
||||
self.distance_traveled += CS.vEgo * DT_CTRL
|
||||
|
||||
return CS
|
||||
|
||||
def state_transition(self, CS):
|
||||
@@ -870,10 +952,7 @@ class Controls:
|
||||
hudControl.visualAlert = current_alert.visual_alert
|
||||
|
||||
if not self.CP.passive and self.initialized:
|
||||
# send car controls over can
|
||||
now_nanos = self.can_log_mono_time if REPLAY else int(time.monotonic() * 1e9)
|
||||
self.last_actuators, can_sends = self.CI.apply(CC, now_nanos)
|
||||
self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid))
|
||||
self.last_actuators = self.card.controls_update(CC)
|
||||
CC.actuatorsOutput = self.last_actuators
|
||||
if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
|
||||
self.steer_limited = abs(CC.actuators.steeringAngleDeg - CC.actuatorsOutput.steeringAngleDeg) > \
|
||||
@@ -922,7 +1001,7 @@ class Controls:
|
||||
controlsState.cumLagMs = -self.rk.remaining * 1000.
|
||||
controlsState.startMonoTime = int(start_time * 1e9)
|
||||
controlsState.forceDecel = bool(force_decel)
|
||||
controlsState.canErrorCounter = self.can_rcv_cum_timeout_counter
|
||||
controlsState.canErrorCounter = self.card.can_rcv_cum_timeout_counter
|
||||
controlsState.experimentalMode = self.experimental_mode
|
||||
|
||||
lat_tuning = self.CP.lateralTuning.which()
|
||||
@@ -947,13 +1026,9 @@ class Controls:
|
||||
|
||||
self.pm.send('controlsStateSP', dat_sp)
|
||||
|
||||
# carState
|
||||
car_events = self.events.to_msg()
|
||||
cs_send = messaging.new_message('carState')
|
||||
cs_send.valid = CS.canValid
|
||||
cs_send.carState = CS
|
||||
cs_send.carState.events = car_events
|
||||
self.pm.send('carState', cs_send)
|
||||
|
||||
self.card.state_publish(car_events)
|
||||
|
||||
# onroadEvents - logged every second or on change
|
||||
if (self.sm.frame % int(1. / DT_CTRL) == 0) or (self.events.names != self.events_prev):
|
||||
@@ -963,13 +1038,6 @@ class Controls:
|
||||
self.pm.send('onroadEvents', ce_send)
|
||||
self.events_prev = self.events.names.copy()
|
||||
|
||||
# carParams - logged every 50 seconds (> 1 per segment)
|
||||
if (self.sm.frame % int(50. / DT_CTRL) == 0):
|
||||
cp_send = messaging.new_message('carParams')
|
||||
cp_send.valid = True
|
||||
cp_send.carParams = self.CP
|
||||
self.pm.send('carParams', cp_send)
|
||||
|
||||
# carControl
|
||||
cc_send = messaging.new_message('carControl')
|
||||
cc_send.valid = CS.canValid
|
||||
|
||||
@@ -926,12 +926,12 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
|
||||
# is thrown. This can mean a service crashed, did not broadcast a message for
|
||||
# ten times the regular interval, or the average interval is more than 10% too high.
|
||||
EventName.commIssue: {
|
||||
ET.SOFT_DISABLE: soft_disable_alert("Communication Issue between Processes"),
|
||||
ET.SOFT_DISABLE: soft_disable_alert("Communication Issue Between Processes"),
|
||||
ET.NO_ENTRY: comm_issue_alert,
|
||||
},
|
||||
EventName.commIssueAvgFreq: {
|
||||
ET.SOFT_DISABLE: soft_disable_alert("Low Communication Rate between Processes"),
|
||||
ET.NO_ENTRY: NoEntryAlert("Low Communication Rate between Processes"),
|
||||
ET.SOFT_DISABLE: soft_disable_alert("Low Communication Rate Between Processes"),
|
||||
ET.NO_ENTRY: NoEntryAlert("Low Communication Rate Between Processes"),
|
||||
},
|
||||
|
||||
EventName.controlsdLagging: {
|
||||
|
||||
@@ -10,48 +10,52 @@ from cereal.services import SERVICE_LIST
|
||||
from openpilot.tools.lib.logreader import LogReader, ReadMode
|
||||
|
||||
if __name__ == "__main__":
|
||||
cnt_valid: Counter = Counter()
|
||||
cnt_events: Counter = Counter()
|
||||
|
||||
cams = [s for s in SERVICE_LIST if s.endswith('CameraState')]
|
||||
cnt_cameras = dict.fromkeys(cams, 0)
|
||||
|
||||
events: List[Tuple[float, set[str]]] = []
|
||||
alerts: List[Tuple[float, str]] = []
|
||||
start_time = math.inf
|
||||
end_time = -math.inf
|
||||
ignition_off = None
|
||||
for msg in LogReader(sys.argv[1], ReadMode.QLOG):
|
||||
t = (msg.logMonoTime - start_time) / 1e9
|
||||
end_time = max(end_time, msg.logMonoTime)
|
||||
start_time = min(start_time, msg.logMonoTime)
|
||||
|
||||
if msg.which() == 'onroadEvents':
|
||||
for e in msg.onroadEvents:
|
||||
cnt_events[e.name] += 1
|
||||
|
||||
ae = {str(e.name) for e in msg.onroadEvents if e.name not in ('pedalPressed', 'steerOverride', 'gasPressedOverride')}
|
||||
if len(events) == 0 or ae != events[-1][1]:
|
||||
events.append((t, ae))
|
||||
|
||||
elif msg.which() == 'controlsState':
|
||||
at = msg.controlsState.alertType
|
||||
if "/override" not in at or "lanechange" in at.lower():
|
||||
if len(alerts) == 0 or alerts[-1][1] != at:
|
||||
t = (msg.logMonoTime - start_time) / 1e9
|
||||
alerts.append((t, at))
|
||||
elif msg.which() == 'pandaStates':
|
||||
if ignition_off is None:
|
||||
ign = any(ps.ignitionLine or ps.ignitionCan for ps in msg.pandaStates)
|
||||
if not ign:
|
||||
ignition_off = msg.logMonoTime
|
||||
break
|
||||
elif msg.which() in cams:
|
||||
cnt_cameras[msg.which()] += 1
|
||||
|
||||
if not msg.valid:
|
||||
cnt_valid[msg.which()] += 1
|
||||
|
||||
duration = (end_time - start_time) / 1e9
|
||||
|
||||
print("Events")
|
||||
pprint(cnt_events)
|
||||
|
||||
print("\n")
|
||||
print("Not valid")
|
||||
pprint(cnt_valid)
|
||||
print("Events")
|
||||
for t, evt in events:
|
||||
print(f"{t:8.2f} {evt}")
|
||||
|
||||
print("\n")
|
||||
print("Cameras")
|
||||
@@ -64,9 +68,9 @@ if __name__ == "__main__":
|
||||
print("Alerts")
|
||||
for t, a in alerts:
|
||||
print(f"{t:8.2f} {a}")
|
||||
|
||||
print("\n")
|
||||
if ignition_off is not None:
|
||||
ignition_off = round((ignition_off - start_time) / 1e9, 2)
|
||||
print("Ignition off at", ignition_off)
|
||||
|
||||
print("\n")
|
||||
print("Route duration", datetime.timedelta(seconds=duration))
|
||||
|
||||
@@ -46,6 +46,7 @@ def print_androidlog(t, msg):
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--absolute', action='store_true')
|
||||
parser.add_argument('--level', default='DEBUG')
|
||||
parser.add_argument('--addr', default='127.0.0.1')
|
||||
parser.add_argument("route", type=str, nargs='*', help="route name + segment number for offline usage")
|
||||
@@ -54,15 +55,18 @@ if __name__ == "__main__":
|
||||
min_level = LEVELS[args.level]
|
||||
|
||||
if args.route:
|
||||
st = None if not args.absolute else 0
|
||||
for route in args.route:
|
||||
lr = LogReader(route)
|
||||
lr = LogReader(route, sort_by_time=True)
|
||||
for m in lr:
|
||||
if st is None:
|
||||
st = m.logMonoTime
|
||||
if m.which() == 'logMessage':
|
||||
print_logmessage(m.logMonoTime, m.logMessage, min_level)
|
||||
print_logmessage(m.logMonoTime-st, m.logMessage, min_level)
|
||||
elif m.which() == 'errorLogMessage':
|
||||
print_logmessage(m.logMonoTime, m.errorLogMessage, min_level)
|
||||
print_logmessage(m.logMonoTime-st, m.errorLogMessage, min_level)
|
||||
elif m.which() == 'androidLog':
|
||||
print_androidlog(m.logMonoTime, m.androidLog)
|
||||
print_androidlog(m.logMonoTime-st, m.androidLog)
|
||||
else:
|
||||
sm = messaging.SubMaster(['logMessage', 'androidLog'], addr=args.addr)
|
||||
while True:
|
||||
|
||||
@@ -44,11 +44,15 @@ if __name__ == "__main__":
|
||||
|
||||
dongles = []
|
||||
for route in tqdm(routes):
|
||||
dongle_id = SegmentRange(route).dongle_id
|
||||
sr = SegmentRange(route)
|
||||
dongle_id = sr.dongle_id
|
||||
|
||||
if dongle_id in dongles:
|
||||
continue
|
||||
|
||||
if sr.slice == '' and sr.selector is None:
|
||||
route += '/0'
|
||||
|
||||
lr = LogReader(route, default_mode=ReadMode.QLOG)
|
||||
|
||||
try:
|
||||
|
||||
@@ -27,17 +27,17 @@ class PointBuckets:
|
||||
self.buckets_min_points = dict(zip(x_bounds, min_points, strict=True))
|
||||
self.min_points_total = min_points_total
|
||||
|
||||
def bucket_lengths(self) -> List[int]:
|
||||
return [len(v) for v in self.buckets.values()]
|
||||
|
||||
def __len__(self) -> int:
|
||||
return sum(self.bucket_lengths())
|
||||
return sum([len(v) for v in self.buckets.values()])
|
||||
|
||||
def is_valid(self) -> bool:
|
||||
individual_buckets_valid = all(len(v) >= min_pts for v, min_pts in zip(self.buckets.values(), self.buckets_min_points.values(), strict=True))
|
||||
total_points_valid = self.__len__() >= self.min_points_total
|
||||
return individual_buckets_valid and total_points_valid
|
||||
|
||||
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:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@@ -193,23 +193,23 @@ class TorqueEstimator(ParameterEstimator):
|
||||
liveTorqueParameters.version = VERSION
|
||||
liveTorqueParameters.useParams = self.use_params
|
||||
|
||||
if self.filtered_points.is_valid():
|
||||
# Calculate raw estimates when possible, only update filters when enough points are gathered
|
||||
if self.filtered_points.is_calculable():
|
||||
latAccelFactor, latAccelOffset, frictionCoeff = self.estimate_params()
|
||||
liveTorqueParameters.latAccelFactorRaw = float(latAccelFactor)
|
||||
liveTorqueParameters.latAccelOffsetRaw = float(latAccelOffset)
|
||||
liveTorqueParameters.frictionCoefficientRaw = float(frictionCoeff)
|
||||
|
||||
if any(val is None or np.isnan(val) for val in [latAccelFactor, latAccelOffset, frictionCoeff]):
|
||||
cloudlog.exception("Live torque parameters are invalid.")
|
||||
liveTorqueParameters.liveValid = False
|
||||
self.reset()
|
||||
else:
|
||||
liveTorqueParameters.liveValid = True
|
||||
latAccelFactor = np.clip(latAccelFactor, self.min_lataccel_factor, self.max_lataccel_factor)
|
||||
frictionCoeff = np.clip(frictionCoeff, self.min_friction, self.max_friction)
|
||||
self.update_params({'latAccelFactor': latAccelFactor, 'latAccelOffset': latAccelOffset, 'frictionCoefficient': frictionCoeff})
|
||||
else:
|
||||
liveTorqueParameters.liveValid = False
|
||||
if self.filtered_points.is_valid():
|
||||
if any(val is None or np.isnan(val) for val in [latAccelFactor, latAccelOffset, frictionCoeff]):
|
||||
cloudlog.exception("Live torque parameters are invalid.")
|
||||
liveTorqueParameters.liveValid = False
|
||||
self.reset()
|
||||
else:
|
||||
liveTorqueParameters.liveValid = True
|
||||
latAccelFactor = np.clip(latAccelFactor, self.min_lataccel_factor, self.max_lataccel_factor)
|
||||
frictionCoeff = np.clip(frictionCoeff, self.min_friction, self.max_friction)
|
||||
self.update_params({'latAccelFactor': latAccelFactor, 'latAccelOffset': latAccelOffset, 'frictionCoefficient': frictionCoeff})
|
||||
|
||||
if with_points:
|
||||
liveTorqueParameters.points = self.filtered_points.get_points()[:, [0, 2]].tolist()
|
||||
|
||||
@@ -20,7 +20,7 @@ from openpilot.selfdrive.athena.registration import register, UNREGISTERED_DONGL
|
||||
from openpilot.common.swaglog import cloudlog, add_file_handler
|
||||
from openpilot.system.version import is_dirty, get_commit, get_version, get_origin, get_short_branch, \
|
||||
get_normalized_origin, terms_version, training_version, \
|
||||
is_tested_branch, is_release_branch, is_release_sp_branch
|
||||
is_tested_branch, is_release_branch, get_commit_date, is_release_sp_branch
|
||||
|
||||
|
||||
def manager_init() -> None:
|
||||
@@ -131,6 +131,7 @@ def manager_init() -> None:
|
||||
params.put("TermsVersion", terms_version)
|
||||
params.put("TrainingVersion", training_version)
|
||||
params.put("GitCommit", get_commit())
|
||||
params.put("GitCommitDate", get_commit_date())
|
||||
params.put("GitBranch", get_short_branch())
|
||||
params.put("GitRemote", get_origin())
|
||||
params.put_bool("IsTestedBranch", is_tested_branch())
|
||||
|
||||
@@ -286,11 +286,13 @@ def ensure_running(procs: ValuesView[ManagerProcess], started: bool, params=None
|
||||
running = []
|
||||
for p in procs:
|
||||
if p.enabled and p.name not in not_run and p.should_run(started, params, CP):
|
||||
p.start()
|
||||
running.append(p)
|
||||
else:
|
||||
p.stop(block=False)
|
||||
|
||||
p.check_watchdog(started)
|
||||
|
||||
for p in running:
|
||||
p.start()
|
||||
|
||||
return running
|
||||
|
||||
@@ -46,7 +46,7 @@ def fill_xyvat(builder, t, x, y, v, a, x_std=None, y_std=None, v_std=None, a_std
|
||||
def fill_model_msg(msg: capnp._DynamicStructBuilder, net_output_data: Dict[str, np.ndarray], publish_state: PublishState,
|
||||
vipc_frame_id: int, vipc_frame_id_extra: int, frame_id: int, frame_drop: float,
|
||||
timestamp_eof: int, timestamp_llk: int, model_execution_time: float,
|
||||
nav_enabled: bool, v_ego: float, steer_delay: float, valid: bool, model_use_lateral_planner: bool) -> None:
|
||||
nav_enabled: bool, valid: bool, model_use_lateral_planner: bool) -> None:
|
||||
frame_age = frame_id - vipc_frame_id if frame_id > vipc_frame_id else 0
|
||||
msg.valid = valid
|
||||
|
||||
|
||||
+11
-13
@@ -158,12 +158,16 @@ class ModelState:
|
||||
|
||||
|
||||
def main(demo=False):
|
||||
cloudlog.warning("modeld init")
|
||||
|
||||
sentry.set_tag("daemon", PROCESS_NAME)
|
||||
cloudlog.bind(daemon=PROCESS_NAME)
|
||||
setproctitle(PROCESS_NAME)
|
||||
config_realtime_process(7, 54)
|
||||
|
||||
cloudlog.warning("setting up CL context")
|
||||
cl_context = CLContext()
|
||||
cloudlog.warning("CL context ready; loading model")
|
||||
model = ModelState(cl_context)
|
||||
cloudlog.warning("models loaded, modeld starting")
|
||||
|
||||
@@ -194,14 +198,9 @@ def main(demo=False):
|
||||
pm = PubMaster(["modelV2", "modelV2SP", "cameraOdometry"])
|
||||
sm = SubMaster(["carState", "roadCameraState", "liveCalibration", "driverMonitoringState", "navModel", "navInstruction", "carControl", "lateralPlanDEPRECATED", "lateralPlanSPDEPRECATED"])
|
||||
|
||||
|
||||
publish_state = PublishState()
|
||||
params = Params()
|
||||
custom_model, model_gen = get_model_generation(params)
|
||||
if not (custom_model and model_gen == 1):
|
||||
with car.CarParams.from_bytes(params.get("CarParams", block=True)) as msg:
|
||||
steer_delay = msg.steerActuatorDelay + .2
|
||||
#steer_delay = 0.4
|
||||
|
||||
# setup filter to track dropped frames
|
||||
frame_dropped_filter = FirstOrderFilter(0., 10., 1. / ModelConstants.MODEL_FREQ)
|
||||
@@ -223,13 +222,15 @@ def main(demo=False):
|
||||
|
||||
if demo:
|
||||
CP = get_demo_car_params()
|
||||
with car.CarParams.from_bytes(params.get("CarParams", block=True)) as msg:
|
||||
CP = msg
|
||||
cloudlog.info("plannerd got CarParams: %s", CP.carName)
|
||||
else:
|
||||
with car.CarParams.from_bytes(params.get("CarParams", block=True)) as msg:
|
||||
CP = msg
|
||||
cloudlog.info("modeld got CarParams: %s", CP.carName)
|
||||
|
||||
# TODO this needs more thought, use .2s extra for now to estimate other delays
|
||||
steer_delay = CP.steerActuatorDelay + .2
|
||||
DH = DesireHelper()
|
||||
|
||||
DH = DesireHelper()
|
||||
|
||||
while True:
|
||||
# Keep receiving frames until we are at least 1 frame ahead of previous extra frame
|
||||
@@ -265,14 +266,11 @@ def main(demo=False):
|
||||
buf_extra = buf_main
|
||||
meta_extra = meta_main
|
||||
|
||||
# TODO: path planner timeout?
|
||||
sm.update(0)
|
||||
desire = sm["lateralPlanDEPRECATED"].desire.raw if custom_model and model_gen == 1 else DH.desire
|
||||
v_ego = sm["carState"].vEgo
|
||||
is_rhd = sm["driverMonitoringState"].isRHD
|
||||
frame_id = sm["roadCameraState"].frameId
|
||||
if not (custom_model and model_gen == 1):
|
||||
# TODO add lag
|
||||
lateral_control_params = np.array([sm["carState"].vEgo, steer_delay], dtype=np.float32)
|
||||
if sm.updated["liveCalibration"]:
|
||||
device_from_calib_euler = np.array(sm["liveCalibration"].rpyCalib, dtype=np.float32)
|
||||
@@ -351,7 +349,7 @@ def main(demo=False):
|
||||
modelv2_send = messaging.new_message('modelV2')
|
||||
posenet_send = messaging.new_message('cameraOdometry')
|
||||
fill_model_msg(modelv2_send, model_output, publish_state, meta_main.frame_id, meta_extra.frame_id, frame_id, frame_drop_ratio,
|
||||
meta_main.timestamp_eof, timestamp_llk, model_execution_time, nav_enabled, v_ego, steer_delay, live_calib_seen, custom_model and model_gen == 1)
|
||||
meta_main.timestamp_eof, timestamp_llk, model_execution_time, nav_enabled, live_calib_seen, custom_model and model_gen == 1)
|
||||
|
||||
if not (custom_model and model_gen == 1):
|
||||
desire_state = modelv2_send.modelV2.meta.desireState
|
||||
|
||||
@@ -7,7 +7,7 @@ cdef class CLContext(BaseCLContext):
|
||||
pass
|
||||
|
||||
cdef class CLMem:
|
||||
cdef cl_mem * mem;
|
||||
cdef cl_mem * mem
|
||||
|
||||
@staticmethod
|
||||
cdef create(void*)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:763821410b35b06b598cacfa5bc3e312610b3f8de2729e0d5954d7571b6794be
|
||||
size 48219112
|
||||
oid sha256:c11f99aab832242a604b1bb4c4cf391c9c3d5e90cbc07ab0d4c133473b56a3a4
|
||||
size 48193749
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
# cython: c_string_encoding=ascii
|
||||
|
||||
from libcpp.string cimport string
|
||||
from libc.string cimport memcpy
|
||||
|
||||
from .runmodel cimport USE_CPU_RUNTIME, USE_GPU_RUNTIME, USE_DSP_RUNTIME
|
||||
from selfdrive.modeld.models.commonmodel_pyx cimport CLMem
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
#include "third_party/json11/json11.hpp"
|
||||
#include "common/util.h"
|
||||
#include "common/clutil.h"
|
||||
#include "common/swaglog.h"
|
||||
#include "selfdrive/modeld/thneed/thneed.h"
|
||||
using namespace json11;
|
||||
|
||||
extern map<cl_program, string> g_program_source;
|
||||
|
||||
void Thneed::load(const char *filename) {
|
||||
printf("Thneed::load: loading from %s\n", filename);
|
||||
LOGD("Thneed::load: loading from %s\n", filename);
|
||||
|
||||
string buf = util::read_file(filename);
|
||||
int jsz = *(int *)buf.data();
|
||||
@@ -74,8 +75,8 @@ void Thneed::load(const char *filename) {
|
||||
clbuf = clCreateImage(context, CL_MEM_READ_WRITE, &format, &desc, NULL, &errcode);
|
||||
#endif
|
||||
if (clbuf == NULL) {
|
||||
printf("clError: %s create image %zux%zu rp %zu with buffer %p\n", cl_get_error_string(errcode),
|
||||
desc.image_width, desc.image_height, desc.image_row_pitch, desc.buffer);
|
||||
LOGE("clError: %s create image %zux%zu rp %zu with buffer %p\n", cl_get_error_string(errcode),
|
||||
desc.image_width, desc.image_height, desc.image_row_pitch, desc.buffer);
|
||||
}
|
||||
assert(clbuf != NULL);
|
||||
}
|
||||
@@ -95,11 +96,11 @@ void Thneed::load(const char *filename) {
|
||||
cl_mem aa = real_mem[*(cl_mem*)(mobj["buffer_id"].string_value().data())];
|
||||
input_clmem.push_back(aa);
|
||||
input_sizes.push_back(sz);
|
||||
printf("Thneed::load: adding input %s with size %d\n", mobj["name"].string_value().data(), sz);
|
||||
LOGD("Thneed::load: adding input %s with size %d\n", mobj["name"].string_value().data(), sz);
|
||||
|
||||
cl_int cl_err;
|
||||
void *ret = clEnqueueMapBuffer(command_queue, aa, CL_TRUE, CL_MAP_WRITE, 0, sz, 0, NULL, NULL, &cl_err);
|
||||
if (cl_err != CL_SUCCESS) printf("clError: %s map %p %d\n", cl_get_error_string(cl_err), aa, sz);
|
||||
if (cl_err != CL_SUCCESS) LOGE("clError: %s map %p %d\n", cl_get_error_string(cl_err), aa, sz);
|
||||
assert(cl_err == CL_SUCCESS);
|
||||
inputs.push_back(ret);
|
||||
}
|
||||
@@ -107,7 +108,7 @@ void Thneed::load(const char *filename) {
|
||||
for (auto &obj : jdat["outputs"].array_items()) {
|
||||
auto mobj = obj.object_items();
|
||||
int sz = mobj["size"].int_value();
|
||||
printf("Thneed::save: adding output with size %d\n", sz);
|
||||
LOGD("Thneed::save: adding output with size %d\n", sz);
|
||||
// TODO: support multiple outputs
|
||||
output = real_mem[*(cl_mem*)(mobj["buffer_id"].string_value().data())];
|
||||
assert(output != NULL);
|
||||
|
||||
@@ -22,20 +22,20 @@ __kernel void warpPerspective(__global const uchar * src,
|
||||
W = W != 0.0f ? INTER_TAB_SIZE / W : 0.0f;
|
||||
int X = rint(X0 * W), Y = rint(Y0 * W);
|
||||
|
||||
short sx = convert_short_sat(X >> INTER_BITS);
|
||||
short sy = convert_short_sat(Y >> INTER_BITS);
|
||||
int sx = convert_short_sat(X >> INTER_BITS);
|
||||
int sy = convert_short_sat(Y >> INTER_BITS);
|
||||
|
||||
short sx_clamp = clamp(sx, 0, src_cols - 1);
|
||||
short sx_p1_clamp = clamp(sx + 1, 0, src_cols - 1);
|
||||
short sy_clamp = clamp(sy, 0, src_rows - 1);
|
||||
short sy_p1_clamp = clamp(sy + 1, 0, src_rows - 1);
|
||||
int v0 = convert_int(src[mad24(sy_clamp, src_row_stride, src_offset + sx_clamp*src_px_stride)]);
|
||||
int v1 = convert_int(src[mad24(sy_clamp, src_row_stride, src_offset + sx_p1_clamp*src_px_stride)]);
|
||||
int v2 = convert_int(src[mad24(sy_p1_clamp, src_row_stride, src_offset + sx_clamp*src_px_stride)]);
|
||||
int v3 = convert_int(src[mad24(sy_p1_clamp, src_row_stride, src_offset + sx_p1_clamp*src_px_stride)]);
|
||||
|
||||
short ay = (short)(Y & (INTER_TAB_SIZE - 1));
|
||||
short ax = (short)(X & (INTER_TAB_SIZE - 1));
|
||||
|
||||
int v0 = (sx >= 0 && sx < src_cols && sy >= 0 && sy < src_rows) ?
|
||||
convert_int(src[mad24(sy, src_row_stride, src_offset + sx*src_px_stride)]) : 0;
|
||||
int v1 = (sx+1 >= 0 && sx+1 < src_cols && sy >= 0 && sy < src_rows) ?
|
||||
convert_int(src[mad24(sy, src_row_stride, src_offset + (sx+1)*src_px_stride)]) : 0;
|
||||
int v2 = (sx >= 0 && sx < src_cols && sy+1 >= 0 && sy+1 < src_rows) ?
|
||||
convert_int(src[mad24(sy+1, src_row_stride, src_offset + sx*src_px_stride)]) : 0;
|
||||
int v3 = (sx+1 >= 0 && sx+1 < src_cols && sy+1 >= 0 && sy+1 < src_rows) ?
|
||||
convert_int(src[mad24(sy+1, src_row_stride, src_offset + (sx+1)*src_px_stride)]) : 0;
|
||||
|
||||
float taby = 1.f/INTER_TAB_SIZE*ay;
|
||||
float tabx = 1.f/INTER_TAB_SIZE*ax;
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ from openpilot.system.version import training_version, terms_version
|
||||
|
||||
|
||||
def set_params_enabled():
|
||||
os.environ['REPLAY'] = "1"
|
||||
os.environ['FINGERPRINT'] = "TOYOTA COROLLA TSS2 2019"
|
||||
os.environ['LOGPRINT'] = "debug"
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
fee90bcee1e545c7ec9a39d3c7d4e42cfefb9955
|
||||
fd6421f7551573c549480f9d29bb0dee4678344d
|
||||
|
||||
@@ -1 +1 @@
|
||||
7d25b1f7d0bd3b506fa4e72ff893728894eb1a45
|
||||
d0cdea7eb15f3cac8a921f7ace3eaa6baebb4fd5
|
||||
|
||||
@@ -29,7 +29,7 @@ from openpilot.tools.lib.logreader import LogReader
|
||||
|
||||
# Baseline CPU usage by process
|
||||
PROCS = {
|
||||
"selfdrive.controls.controlsd": 39.0,
|
||||
"selfdrive.controls.controlsd": 41.0,
|
||||
"./loggerd": 14.0,
|
||||
"./encoderd": 17.0,
|
||||
"./camerad": 14.5,
|
||||
@@ -114,6 +114,7 @@ class TestOnroad(unittest.TestCase):
|
||||
params = Params()
|
||||
params.remove("CurrentRoute")
|
||||
set_params_enabled()
|
||||
os.environ['REPLAY'] = '1'
|
||||
os.environ['TESTING_CLOSET'] = '1'
|
||||
if os.path.exists(Paths.log_root()):
|
||||
shutil.rmtree(Paths.log_root())
|
||||
|
||||
@@ -18,33 +18,40 @@ def test_time_to_onroad():
|
||||
proc = subprocess.Popen(["python", manager_path])
|
||||
|
||||
start_time = time.monotonic()
|
||||
sm = messaging.SubMaster(['controlsState', 'deviceState', 'onroadEvents'])
|
||||
sm = messaging.SubMaster(['controlsState', 'deviceState', 'onroadEvents', 'sendcan'])
|
||||
try:
|
||||
# wait for onroad
|
||||
with Timeout(20, "timed out waiting to go onroad"):
|
||||
while True:
|
||||
sm.update(1000)
|
||||
if sm['deviceState'].started:
|
||||
break
|
||||
time.sleep(1)
|
||||
# wait for onroad. timeout assumes panda is up to date
|
||||
with Timeout(10, "timed out waiting to go onroad"):
|
||||
while not sm['deviceState'].started:
|
||||
sm.update(100)
|
||||
|
||||
# wait for engageability
|
||||
try:
|
||||
with Timeout(10, "timed out waiting for engageable"):
|
||||
sendcan_frame = None
|
||||
while True:
|
||||
sm.update(1000)
|
||||
if sm['controlsState'].engageable:
|
||||
sm.update(100)
|
||||
|
||||
# sendcan is only sent once we're initialized
|
||||
if sm.seen['controlsState'] and sendcan_frame is None:
|
||||
sendcan_frame = sm.frame
|
||||
|
||||
if sendcan_frame is not None and sm.recv_frame['sendcan'] > sendcan_frame:
|
||||
sm.update(100)
|
||||
assert sm['controlsState'].engageable, f"events: {sm['onroadEvents']}"
|
||||
break
|
||||
time.sleep(1)
|
||||
finally:
|
||||
print(f"onroad events: {sm['onroadEvents']}")
|
||||
print(f"engageable after {time.monotonic() - start_time:.2f}s")
|
||||
|
||||
# once we're enageable, must be for the next few seconds
|
||||
for _ in range(500):
|
||||
# once we're enageable, must stay for the next few seconds
|
||||
st = time.monotonic()
|
||||
while (time.monotonic() - st) < 10.:
|
||||
sm.update(100)
|
||||
assert sm.all_alive(), sm.alive
|
||||
assert sm['controlsState'].engageable, f"events: {sm['onroadEvents']}"
|
||||
assert sm['controlsState'].cumLagMs < 10.
|
||||
finally:
|
||||
proc.terminate()
|
||||
if proc.wait(60) is None:
|
||||
if proc.wait(20) is None:
|
||||
proc.kill()
|
||||
|
||||
@@ -15,7 +15,6 @@ CAR_BATTERY_CAPACITY_uWh = 30e6
|
||||
CAR_CHARGING_RATE_W = 45
|
||||
|
||||
VBATT_PAUSE_CHARGING = 11.8 # Lower limit on the LPF car battery voltage
|
||||
VBATT_INSTANT_PAUSE_CHARGING = 7.0 # Lower limit on the instant car battery voltage measurements to avoid triggering on instant power loss
|
||||
MIN_ON_TIME_S = 3600
|
||||
DELAY_SHUTDOWN_TIME_S = 300 # Wait at least DELAY_SHUTDOWN_TIME_S seconds after offroad_time to shutdown.
|
||||
VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S = 60
|
||||
@@ -120,7 +119,6 @@ class PowerMonitoring:
|
||||
should_shutdown = False
|
||||
offroad_time = (now - offroad_timestamp)
|
||||
low_voltage_shutdown = (self.car_voltage_mV < (VBATT_PAUSE_CHARGING * 1e3) and
|
||||
self.car_voltage_instant_mV > (VBATT_INSTANT_PAUSE_CHARGING * 1e3) and
|
||||
offroad_time > VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S)
|
||||
should_shutdown |= (offroad_time > max_time_offroad_s) if max_time_offroad_s != 0 else False
|
||||
should_shutdown |= low_voltage_shutdown
|
||||
|
||||
@@ -83,7 +83,6 @@ def read_thermal(thermal_config):
|
||||
dat.deviceState.cpuTempC = [read_tz(z) / thermal_config.cpu[1] for z in thermal_config.cpu[0]]
|
||||
dat.deviceState.gpuTempC = [read_tz(z) / thermal_config.gpu[1] for z in thermal_config.gpu[0]]
|
||||
dat.deviceState.memoryTempC = read_tz(thermal_config.mem[0]) / thermal_config.mem[1]
|
||||
dat.deviceState.ambientTempC = read_tz(thermal_config.ambient[0]) / thermal_config.ambient[1]
|
||||
dat.deviceState.pmicTempC = [read_tz(z) / thermal_config.pmic[1] for z in thermal_config.pmic[0]]
|
||||
return dat
|
||||
|
||||
@@ -247,8 +246,10 @@ def thermald_thread(end_event, hw_queue) -> None:
|
||||
|
||||
msg.deviceState.freeSpacePercent = get_available_percent(default=100.0)
|
||||
msg.deviceState.memoryUsagePercent = int(round(psutil.virtual_memory().percent))
|
||||
msg.deviceState.cpuUsagePercent = [int(round(n)) for n in psutil.cpu_percent(percpu=True)]
|
||||
msg.deviceState.gpuUsagePercent = int(round(HARDWARE.get_gpu_usage_percent()))
|
||||
online_cpu_usage = [int(round(n)) for n in psutil.cpu_percent(percpu=True)]
|
||||
offline_cpu_usage = [0., ] * (len(msg.deviceState.cpuTempC) - len(online_cpu_usage))
|
||||
msg.deviceState.cpuUsagePercent = online_cpu_usage + offline_cpu_usage
|
||||
|
||||
msg.deviceState.networkType = last_hw_state.network_type
|
||||
msg.deviceState.networkMetered = last_hw_state.network_metered
|
||||
@@ -412,7 +413,6 @@ def thermald_thread(end_event, hw_queue) -> None:
|
||||
for i, temp in enumerate(msg.deviceState.gpuTempC):
|
||||
statlog.gauge(f"gpu{i}_temperature", temp)
|
||||
statlog.gauge("memory_temperature", msg.deviceState.memoryTempC)
|
||||
statlog.gauge("ambient_temperature", msg.deviceState.ambientTempC)
|
||||
for i, temp in enumerate(msg.deviceState.pmicTempC):
|
||||
statlog.gauge(f"pmic{i}_temperature", temp)
|
||||
for i, temp in enumerate(last_hw_state.nvme_temps):
|
||||
|
||||
@@ -3,12 +3,13 @@ moc_*
|
||||
|
||||
translations/main_test_en.*
|
||||
|
||||
_text
|
||||
_spinner
|
||||
|
||||
ui
|
||||
mui
|
||||
watch3
|
||||
installer/installers/*
|
||||
qt/text
|
||||
qt/spinner
|
||||
qt/setup/setup
|
||||
qt/setup/reset
|
||||
qt/setup/wifi
|
||||
|
||||
@@ -83,8 +83,8 @@ 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("qt/text", ["qt/text.cc"], LIBS=qt_libs)
|
||||
qt_env.Program("qt/spinner", ["qt/spinner.cc"], LIBS=qt_libs)
|
||||
qt_env.Program("_text", ["qt/text.cc"], LIBS=qt_libs)
|
||||
qt_env.Program("_spinner", ["qt/spinner.cc"], LIBS=qt_libs)
|
||||
|
||||
# build main UI
|
||||
# include dashcam / screenrecorder
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QHash>
|
||||
@@ -127,6 +128,11 @@ void initApp(int argc, char *argv[], bool disable_hidpi) {
|
||||
|
||||
qputenv("QT_DBL_CLICK_DIST", QByteArray::number(150));
|
||||
|
||||
// ensure the current dir matches the exectuable's directory
|
||||
QApplication tmp(argc, argv);
|
||||
QString appDir = QCoreApplication::applicationDirPath();
|
||||
QDir::setCurrent(appDir);
|
||||
|
||||
setQtSurfaceFormat();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ -f /TICI ] && [ ! -f qt/spinner ]; then
|
||||
cp qt/spinner_larch64 qt/spinner
|
||||
if [ -f /TICI ] && [ ! -f _spinner ]; then
|
||||
cp qt/spinner_larch64 _spinner
|
||||
fi
|
||||
|
||||
exec ./qt/spinner "$1"
|
||||
exec ./_spinner "$1"
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ -f /TICI ] && [ ! -f qt/text ]; then
|
||||
cp qt/text_larch64 qt/text
|
||||
if [ -f /TICI ] && [ ! -f _text ]; then
|
||||
cp qt/text_larch64 _text
|
||||
fi
|
||||
|
||||
exec ./qt/text "$1"
|
||||
exec ./_text "$1"
|
||||
|
||||
@@ -4,7 +4,7 @@ from typing import Dict
|
||||
|
||||
from cereal import log
|
||||
|
||||
ThermalConfig = namedtuple('ThermalConfig', ['cpu', 'gpu', 'mem', 'bat', 'ambient', 'pmic'])
|
||||
ThermalConfig = namedtuple('ThermalConfig', ['cpu', 'gpu', 'mem', 'bat', 'pmic'])
|
||||
NetworkType = log.DeviceState.NetworkType
|
||||
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ class Pc(HardwareBase):
|
||||
print("SHUTDOWN!")
|
||||
|
||||
def get_thermal_config(self):
|
||||
return ThermalConfig(cpu=((None,), 1), gpu=((None,), 1), mem=(None, 1), bat=(None, 1), ambient=(None, 1), pmic=((None,), 1))
|
||||
return ThermalConfig(cpu=((None,), 1), gpu=((None,), 1), mem=(None, 1), bat=(None, 1), pmic=((None,), 1))
|
||||
|
||||
def set_screen_brightness(self, percentage):
|
||||
pass
|
||||
|
||||
@@ -20,7 +20,7 @@ class StreamingDecompressor:
|
||||
def __init__(self, url: str) -> None:
|
||||
self.buf = b""
|
||||
|
||||
self.req = requests.get(url, stream=True, headers={'Accept-Encoding': None}, timeout=60) # type: ignore
|
||||
self.req = requests.get(url, stream=True, headers={'Accept-Encoding': None}, timeout=60)
|
||||
self.it = self.req.iter_content(chunk_size=1024 * 1024)
|
||||
self.decompressor = lzma.LZMADecompressor(format=lzma.FORMAT_AUTO)
|
||||
self.eof = False
|
||||
|
||||
@@ -349,7 +349,6 @@ class Tici(HardwareBase):
|
||||
gpu=(("gpu0-usr", "gpu1-usr"), 1000),
|
||||
mem=("ddr-usr", 1000),
|
||||
bat=(None, 1),
|
||||
ambient=("xo-therm-adc", 1000),
|
||||
pmic=(("pm8998_tz", "pm8005_tz"), 1000))
|
||||
|
||||
def set_screen_brightness(self, percentage):
|
||||
|
||||
@@ -44,6 +44,7 @@ kj::Array<capnp::word> logger_build_init_data() {
|
||||
std::map<std::string, std::string> params_map = params.readAll();
|
||||
|
||||
init.setGitCommit(params_map["GitCommit"]);
|
||||
init.setGitCommitDate(params_map["GitCommitDate"]);
|
||||
init.setGitBranch(params_map["GitBranch"]);
|
||||
init.setGitRemote(params_map["GitRemote"]);
|
||||
init.setPassive(false);
|
||||
|
||||
@@ -107,6 +107,7 @@ class TestLoggerd:
|
||||
# param, initData field, value
|
||||
("DongleId", "dongleId", dongle),
|
||||
("GitCommit", "gitCommit", "commit"),
|
||||
("GitCommitDate", "gitCommitDate", "date"),
|
||||
("GitBranch", "gitBranch", "branch"),
|
||||
("GitRemote", "gitRemote", "remote"),
|
||||
]
|
||||
|
||||
@@ -209,10 +209,10 @@ class Uploader:
|
||||
return success
|
||||
|
||||
|
||||
def step(self, network_type: int, metered: bool) -> bool:
|
||||
def step(self, network_type: int, metered: bool) -> Optional[bool]:
|
||||
d = self.next_file_to_upload(metered)
|
||||
if d is None:
|
||||
return True
|
||||
return None
|
||||
|
||||
name, key, fn = d
|
||||
|
||||
@@ -280,12 +280,15 @@ def main(exit_event: Optional[threading.Event] = None) -> None:
|
||||
continue
|
||||
|
||||
success = uploader.step(sm['deviceState'].networkType.raw, sm['deviceState'].networkMetered)
|
||||
if success:
|
||||
if success is None:
|
||||
backoff = 60 if offroad else 5
|
||||
elif success:
|
||||
backoff = 0.1
|
||||
elif allow_sleep:
|
||||
else:
|
||||
cloudlog.info("upload backoff %r", backoff)
|
||||
backoff = min(backoff*2, 120)
|
||||
time.sleep(backoff + random.uniform(0, backoff))
|
||||
if allow_sleep:
|
||||
time.sleep(backoff + random.uniform(0, backoff))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -94,11 +94,7 @@ def at_cmd(cmd: str) -> Optional[str]:
|
||||
return subprocess.check_output(f"mmcli -m any --timeout 30 --command='{cmd}'", shell=True, encoding='utf8')
|
||||
|
||||
def gps_enabled() -> bool:
|
||||
try:
|
||||
p = subprocess.check_output("mmcli -m any --command=\"AT+QGPS?\"", shell=True)
|
||||
return b"QGPS: 1" in p
|
||||
except subprocess.CalledProcessError as exc:
|
||||
raise Exception("failed to execute QGPS mmcli command") from exc
|
||||
return "QGPS: 1" in at_cmd("AT+QGPS?")
|
||||
|
||||
def download_assistance():
|
||||
try:
|
||||
|
||||
@@ -68,13 +68,14 @@ class TestRawgpsd(unittest.TestCase):
|
||||
|
||||
def test_turns_off_gnss(self):
|
||||
for s in (0.1, 1, 5):
|
||||
managed_processes['qcomgpsd'].start()
|
||||
time.sleep(s)
|
||||
managed_processes['qcomgpsd'].stop()
|
||||
with self.subTest(runtime=s):
|
||||
managed_processes['qcomgpsd'].start()
|
||||
time.sleep(s)
|
||||
managed_processes['qcomgpsd'].stop()
|
||||
|
||||
ls = subprocess.check_output("mmcli -m any --location-status --output-json", shell=True, encoding='utf-8')
|
||||
loc_status = json.loads(ls)
|
||||
assert set(loc_status['modem']['location']['enabled']) <= {'3gpp-lac-ci'}
|
||||
ls = subprocess.check_output("mmcli -m any --location-status --output-json", shell=True, encoding='utf-8')
|
||||
loc_status = json.loads(ls)
|
||||
assert set(loc_status['modem']['location']['enabled']) <= {'3gpp-lac-ci'}
|
||||
|
||||
|
||||
def check_assistance(self, should_be_loaded):
|
||||
|
||||
+12
-6
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import subprocess
|
||||
from typing import List, Optional, Callable, TypeVar
|
||||
from typing import List, Callable, TypeVar
|
||||
from functools import lru_cache
|
||||
|
||||
from openpilot.common.basedir import BASEDIR
|
||||
@@ -23,7 +23,7 @@ def run_cmd(cmd: List[str]) -> str:
|
||||
return subprocess.check_output(cmd, encoding='utf8').strip()
|
||||
|
||||
|
||||
def run_cmd_default(cmd: List[str], default: Optional[str] = None) -> Optional[str]:
|
||||
def run_cmd_default(cmd: List[str], default: str = "") -> str:
|
||||
try:
|
||||
return run_cmd(cmd)
|
||||
except subprocess.CalledProcessError:
|
||||
@@ -32,17 +32,22 @@ def run_cmd_default(cmd: List[str], default: Optional[str] = None) -> Optional[s
|
||||
|
||||
@cache
|
||||
def get_commit(branch: str = "HEAD") -> str:
|
||||
return run_cmd_default(["git", "rev-parse", branch]) or ""
|
||||
return run_cmd_default(["git", "rev-parse", branch])
|
||||
|
||||
|
||||
@cache
|
||||
def get_commit_date(commit: str = "HEAD") -> str:
|
||||
return run_cmd_default(["git", "show", "--no-patch", "--format='%ct %ci'", commit])
|
||||
|
||||
|
||||
@cache
|
||||
def get_short_branch() -> str:
|
||||
return run_cmd_default(["git", "rev-parse", "--abbrev-ref", "HEAD"]) or ""
|
||||
return run_cmd_default(["git", "rev-parse", "--abbrev-ref", "HEAD"])
|
||||
|
||||
|
||||
@cache
|
||||
def get_branch() -> str:
|
||||
return run_cmd_default(["git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"]) or ""
|
||||
return run_cmd_default(["git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"])
|
||||
|
||||
|
||||
@cache
|
||||
@@ -52,7 +57,7 @@ def get_origin() -> str:
|
||||
tracking_remote = run_cmd(["git", "config", "branch." + local_branch + ".remote"])
|
||||
return run_cmd(["git", "config", "remote." + tracking_remote + ".url"])
|
||||
except subprocess.CalledProcessError: # Not on a branch, fallback
|
||||
return run_cmd_default(["git", "config", "--get", "remote.origin.url"]) or ""
|
||||
return run_cmd_default(["git", "config", "--get", "remote.origin.url"])
|
||||
|
||||
|
||||
@cache
|
||||
@@ -152,3 +157,4 @@ if __name__ == "__main__":
|
||||
print(f"Branch: {get_branch()}")
|
||||
print(f"Short branch: {get_short_branch()}")
|
||||
print(f"Prebuilt: {is_prebuilt()}")
|
||||
print(f"Commit date: {get_commit_date()}")
|
||||
|
||||
@@ -73,7 +73,7 @@ class ReadMode(enum.StrEnum):
|
||||
QLOG = "q" # only read qlogs
|
||||
SANITIZED = "s" # read from the commaCarSegments database
|
||||
AUTO = "a" # default to rlogs, fallback to qlogs
|
||||
AUTO_INTERACIVE = "i" # default to rlogs, fallback to qlogs with a prompt from the user
|
||||
AUTO_INTERACTIVE = "i" # default to rlogs, fallback to qlogs with a prompt from the user
|
||||
|
||||
|
||||
LogPath = Optional[str]
|
||||
@@ -81,6 +81,8 @@ LogPaths = List[LogPath]
|
||||
ValidFileCallable = Callable[[LogPath], bool]
|
||||
Source = Callable[[SegmentRange, ReadMode], LogPaths]
|
||||
|
||||
InternalUnavailableException = Exception("Internal source not available")
|
||||
|
||||
def default_valid_file(fn: LogPath) -> bool:
|
||||
return fn is not None and file_exists(fn)
|
||||
|
||||
@@ -106,7 +108,7 @@ def apply_strategy(mode: ReadMode, rlog_paths: LogPaths, qlog_paths: LogPaths, v
|
||||
return qlog_paths
|
||||
elif mode == ReadMode.AUTO:
|
||||
return auto_strategy(rlog_paths, qlog_paths, False, valid_file)
|
||||
elif mode == ReadMode.AUTO_INTERACIVE:
|
||||
elif mode == ReadMode.AUTO_INTERACTIVE:
|
||||
return auto_strategy(rlog_paths, qlog_paths, True, valid_file)
|
||||
raise Exception(f"invalid mode: {mode}")
|
||||
|
||||
@@ -126,7 +128,7 @@ def comma_api_source(sr: SegmentRange, mode: ReadMode) -> LogPaths:
|
||||
|
||||
def internal_source(sr: SegmentRange, mode: ReadMode) -> LogPaths:
|
||||
if not internal_source_available():
|
||||
raise Exception("Internal source not available")
|
||||
raise InternalUnavailableException
|
||||
|
||||
def get_internal_url(sr: SegmentRange, seg, file):
|
||||
return f"cd:/{sr.dongle_id}/{sr.timestamp}/{seg}/{file}.bz2"
|
||||
@@ -160,7 +162,7 @@ def get_invalid_files(files):
|
||||
|
||||
def check_source(source: Source, *args) -> LogPaths:
|
||||
files = source(*args)
|
||||
assert next(get_invalid_files(files), None) is None
|
||||
assert next(get_invalid_files(files), False) is False
|
||||
return files
|
||||
|
||||
|
||||
|
||||
+5
-5
@@ -264,7 +264,7 @@ class SegmentRange:
|
||||
return self.m.group("timestamp")
|
||||
|
||||
@property
|
||||
def _slice(self) -> str:
|
||||
def slice(self) -> str:
|
||||
return self.m.group("slice") or ""
|
||||
|
||||
@property
|
||||
@@ -273,12 +273,12 @@ class SegmentRange:
|
||||
|
||||
@property
|
||||
def seg_idxs(self) -> list[int]:
|
||||
m = re.fullmatch(RE.SLICE, self._slice)
|
||||
assert m is not None, f"Invalid slice: {self._slice}"
|
||||
m = re.fullmatch(RE.SLICE, self.slice)
|
||||
assert m is not None, f"Invalid slice: {self.slice}"
|
||||
start, end, step = (None if s is None else int(s) for s in m.groups())
|
||||
|
||||
# one segment specified
|
||||
if start is not None and end is None and ':' not in self._slice:
|
||||
if start is not None and end is None and ':' not in self.slice:
|
||||
if start < 0:
|
||||
start += get_max_seg_number_cached(self) + 1
|
||||
return [start]
|
||||
@@ -291,7 +291,7 @@ class SegmentRange:
|
||||
return list(range(end + 1))[s]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.dongle_id}/{self.timestamp}" + (f"/{self._slice}" if self._slice else "") + (f"/{self.selector}" if self.selector else "")
|
||||
return f"{self.dongle_id}/{self.timestamp}" + (f"/{self.slice}" if self.slice else "") + (f"/{self.selector}" if self.selector else "")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return self.__str__()
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
from functools import partial
|
||||
import http.server
|
||||
import os
|
||||
import shutil
|
||||
import socket
|
||||
import unittest
|
||||
|
||||
from parameterized import parameterized
|
||||
from openpilot.selfdrive.athena.tests.helpers import with_http_server
|
||||
|
||||
from openpilot.system.hardware.hw import Paths
|
||||
from openpilot.tools.lib.url_file import URLFile
|
||||
|
||||
|
||||
@@ -15,7 +17,7 @@ class CachingTestRequestHandler(http.server.BaseHTTPRequestHandler):
|
||||
|
||||
def do_GET(self):
|
||||
if self.FILE_EXISTS:
|
||||
self.send_response(200, b'1234')
|
||||
self.send_response(206 if "Range" in self.headers else 200, b'1234')
|
||||
else:
|
||||
self.send_response(404)
|
||||
self.end_headers()
|
||||
@@ -34,6 +36,34 @@ with_caching_server = partial(with_http_server, handler=CachingTestRequestHandle
|
||||
|
||||
class TestFileDownload(unittest.TestCase):
|
||||
|
||||
@with_caching_server
|
||||
def test_pipeline_defaults(self, host):
|
||||
# TODO: parameterize the defaults so we don't rely on hard-coded values in xx
|
||||
|
||||
self.assertEqual(URLFile.pool_manager().pools._maxsize, 10) # PoolManager num_pools param
|
||||
pool_manager_defaults = {
|
||||
"maxsize": 100,
|
||||
"socket_options": [(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),],
|
||||
}
|
||||
for k, v in pool_manager_defaults.items():
|
||||
self.assertEqual(URLFile.pool_manager().connection_pool_kw.get(k), v)
|
||||
|
||||
retry_defaults = {
|
||||
"total": 5,
|
||||
"backoff_factor": 0.5,
|
||||
"status_forcelist": [409, 429, 503, 504],
|
||||
}
|
||||
for k, v in retry_defaults.items():
|
||||
self.assertEqual(getattr(URLFile.pool_manager().connection_pool_kw["retries"], k), v)
|
||||
|
||||
# ensure caching off by default and cache dir doesn't get created
|
||||
os.environ.pop("FILEREADER_CACHE", None)
|
||||
if os.path.exists(Paths.download_cache_root()):
|
||||
shutil.rmtree(Paths.download_cache_root())
|
||||
URLFile(f"{host}/test.txt").get_length()
|
||||
URLFile(f"{host}/test.txt").read()
|
||||
self.assertEqual(os.path.exists(Paths.download_cache_root()), False)
|
||||
|
||||
def compare_loads(self, url, start=0, length=None):
|
||||
"""Compares range between cached and non cached version"""
|
||||
file_cached = URLFile(url, cache=True)
|
||||
|
||||
@@ -25,7 +25,7 @@ class TestCommaCarSegments(unittest.TestCase):
|
||||
|
||||
sr = SegmentRange(segment)
|
||||
|
||||
url = get_url(sr.route_name, sr._slice)
|
||||
url = get_url(sr.route_name, sr.slice)
|
||||
|
||||
resp = requests.get(url)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
import contextlib
|
||||
import io
|
||||
import shutil
|
||||
import tempfile
|
||||
import os
|
||||
@@ -9,7 +11,7 @@ import requests
|
||||
from parameterized import parameterized
|
||||
from unittest import mock
|
||||
|
||||
from openpilot.tools.lib.logreader import LogIterable, LogReader, comma_api_source, parse_indirect, ReadMode
|
||||
from openpilot.tools.lib.logreader import LogIterable, LogReader, comma_api_source, parse_indirect, ReadMode, InternalUnavailableException
|
||||
from openpilot.tools.lib.route import SegmentRange
|
||||
from openpilot.tools.lib.url_file import URLFileException
|
||||
|
||||
@@ -23,6 +25,24 @@ def noop(segment: LogIterable):
|
||||
return segment
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def setup_source_scenario(is_internal=False):
|
||||
with (
|
||||
mock.patch("openpilot.tools.lib.logreader.internal_source") as internal_source_mock,
|
||||
mock.patch("openpilot.tools.lib.logreader.openpilotci_source") as openpilotci_source_mock,
|
||||
mock.patch("openpilot.tools.lib.logreader.comma_api_source") as comma_api_source_mock,
|
||||
):
|
||||
if is_internal:
|
||||
internal_source_mock.return_value = [QLOG_FILE]
|
||||
else:
|
||||
internal_source_mock.side_effect = InternalUnavailableException
|
||||
|
||||
openpilotci_source_mock.return_value = [None]
|
||||
comma_api_source_mock.return_value = [QLOG_FILE]
|
||||
|
||||
yield
|
||||
|
||||
|
||||
class TestLogReader(unittest.TestCase):
|
||||
@parameterized.expand([
|
||||
(f"{TEST_ROUTE}", ALL_SEGS),
|
||||
@@ -168,10 +188,33 @@ class TestLogReader(unittest.TestCase):
|
||||
with mock.patch("openpilot.tools.lib.route.Route.log_paths") as log_paths_mock:
|
||||
log_paths_mock.return_value = [None] * NUM_SEGS
|
||||
# Should fall back to qlogs since rlogs are not available
|
||||
lr = LogReader(f"{TEST_ROUTE}/0/a", default_source=comma_api_source)
|
||||
log_len = len(list(lr))
|
||||
|
||||
self.assertEqual(qlog_len, log_len)
|
||||
with self.subTest("interactive_yes"):
|
||||
with mock.patch("sys.stdin", new=io.StringIO("y\n")):
|
||||
lr = LogReader(f"{TEST_ROUTE}/0", default_mode=ReadMode.AUTO_INTERACTIVE, default_source=comma_api_source)
|
||||
log_len = len(list(lr))
|
||||
self.assertEqual(qlog_len, log_len)
|
||||
|
||||
with self.subTest("interactive_no"):
|
||||
with mock.patch("sys.stdin", new=io.StringIO("n\n")):
|
||||
with self.assertRaises(AssertionError):
|
||||
lr = LogReader(f"{TEST_ROUTE}/0", default_mode=ReadMode.AUTO_INTERACTIVE, default_source=comma_api_source)
|
||||
|
||||
with self.subTest("non_interactive"):
|
||||
lr = LogReader(f"{TEST_ROUTE}/0", default_mode=ReadMode.AUTO, default_source=comma_api_source)
|
||||
log_len = len(list(lr))
|
||||
self.assertEqual(qlog_len, log_len)
|
||||
|
||||
@parameterized.expand([(True,), (False,)])
|
||||
@pytest.mark.slow
|
||||
def test_auto_source_scenarios(self, is_internal):
|
||||
lr = LogReader(QLOG_FILE)
|
||||
qlog_len = len(list(lr))
|
||||
|
||||
with setup_source_scenario(is_internal=is_internal):
|
||||
lr = LogReader(f"{TEST_ROUTE}/0/q")
|
||||
log_len = len(list(lr))
|
||||
self.assertEqual(qlog_len, log_len)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -73,7 +73,7 @@ def process(can, lr):
|
||||
return [d for d in lr if can or d.which() not in ['can', 'sendcan']]
|
||||
|
||||
def juggle_route(route_or_segment_name, can, layout, dbc=None):
|
||||
sr = LogReader(route_or_segment_name, default_mode=ReadMode.AUTO_INTERACIVE)
|
||||
sr = LogReader(route_or_segment_name, default_mode=ReadMode.AUTO_INTERACTIVE)
|
||||
|
||||
all_data = sr.run_across_segments(24, partial(process, can))
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
<curve name="/deviceState/cpuUsagePercent/5" color="#9467bd"/>
|
||||
<curve name="/deviceState/cpuUsagePercent/6" color="#17becf"/>
|
||||
<curve name="/deviceState/cpuUsagePercent/7" color="#bcbd22"/>
|
||||
<curve name="/deviceState/gpuUsagePercent" color="#1f77b4"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
|
||||
+29
-27
@@ -10,45 +10,49 @@ os.environ['FILEREADER_CACHE'] = '1'
|
||||
from openpilot.common.realtime import config_realtime_process, Ratekeeper, DT_CTRL
|
||||
from openpilot.selfdrive.boardd.boardd import can_capnp_to_can_list
|
||||
from openpilot.tools.lib.logreader import LogReader
|
||||
from panda import Panda, PandaJungle
|
||||
from panda import PandaJungle
|
||||
|
||||
# set both to cycle power or ignition
|
||||
PWR_ON = int(os.getenv("PWR_ON", "0"))
|
||||
PWR_OFF = int(os.getenv("PWR_OFF", "0"))
|
||||
IGN_ON = int(os.getenv("ON", "0"))
|
||||
IGN_OFF = int(os.getenv("OFF", "0"))
|
||||
ENABLE_IGN = IGN_ON > 0 and IGN_OFF > 0
|
||||
ENABLE_PWR = PWR_ON > 0 and PWR_OFF > 0
|
||||
|
||||
|
||||
def send_thread(s, flock):
|
||||
if "Jungle" in str(type(s)):
|
||||
if "FLASH" in os.environ:
|
||||
with flock:
|
||||
s.flash()
|
||||
if "FLASH" in os.environ:
|
||||
with flock:
|
||||
s.flash()
|
||||
|
||||
for i in [0, 1, 2, 3, 0xFFFF]:
|
||||
s.can_clear(i)
|
||||
s.set_can_speed_kbps(i, 500)
|
||||
s.set_can_data_speed_kbps(i, 500)
|
||||
s.set_ignition(False)
|
||||
time.sleep(5)
|
||||
s.set_ignition(True)
|
||||
s.set_panda_power(True)
|
||||
else:
|
||||
s.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
|
||||
for i in [0, 1, 2, 3, 0xFFFF]:
|
||||
s.can_clear(i)
|
||||
s.set_can_speed_kbps(i, 500)
|
||||
s.set_can_data_speed_kbps(i, 500)
|
||||
s.set_ignition(False)
|
||||
time.sleep(5)
|
||||
s.set_ignition(True)
|
||||
s.set_panda_power(True)
|
||||
s.set_can_loopback(False)
|
||||
|
||||
idx = 0
|
||||
ign = True
|
||||
rk = Ratekeeper(1 / DT_CTRL, print_delay_threshold=None)
|
||||
while True:
|
||||
# handle ignition cycling
|
||||
# handle cycling
|
||||
if ENABLE_PWR:
|
||||
i = (rk.frame*DT_CTRL) % (PWR_ON + PWR_OFF) < PWR_ON
|
||||
s.set_panda_power(i)
|
||||
if ENABLE_IGN:
|
||||
i = (rk.frame*DT_CTRL) % (IGN_ON + IGN_OFF) < IGN_ON
|
||||
if i != ign:
|
||||
ign = i
|
||||
s.set_ignition(ign)
|
||||
s.set_ignition(i)
|
||||
|
||||
snd = CAN_MSGS[idx]
|
||||
snd = CAN_MSGS[rk.frame % len(CAN_MSGS)]
|
||||
snd = list(filter(lambda x: x[-1] <= 2, snd))
|
||||
try:
|
||||
s.can_send_many(snd)
|
||||
except usb1.USBErrorTimeout:
|
||||
# timeout is fine, just means the CAN TX buffer is full
|
||||
pass
|
||||
idx = (idx + 1) % len(CAN_MSGS)
|
||||
|
||||
# Drain panda message buffer
|
||||
s.can_recv()
|
||||
@@ -98,10 +102,8 @@ if __name__ == "__main__":
|
||||
|
||||
print("Finished loading...")
|
||||
|
||||
# set both to cycle ignition
|
||||
IGN_ON = int(os.getenv("ON", "0"))
|
||||
IGN_OFF = int(os.getenv("OFF", "0"))
|
||||
ENABLE_IGN = IGN_ON > 0 and IGN_OFF > 0
|
||||
if ENABLE_PWR:
|
||||
print(f"Cycling power: on for {PWR_ON}s, off for {PWR_OFF}s")
|
||||
if ENABLE_IGN:
|
||||
print(f"Cycling ignition: on for {IGN_ON}s, off for {IGN_OFF}s")
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import cereal.messaging as messaging
|
||||
|
||||
from opendbc.can.packer import CANPacker
|
||||
from opendbc.can.parser import CANParser
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.selfdrive.boardd.boardd_api_impl import can_list_to_can_capnp
|
||||
from openpilot.selfdrive.car import crc8_pedal
|
||||
from openpilot.tools.sim.lib.common import SimulatorState
|
||||
@@ -18,6 +19,8 @@ class SimulatedCar:
|
||||
self.sm = messaging.SubMaster(['carControl', 'controlsState', 'carParams'])
|
||||
self.cp = self.get_car_can_parser()
|
||||
self.idx = 0
|
||||
self.params = Params()
|
||||
self.obd_multiplexing = False
|
||||
|
||||
@staticmethod
|
||||
def get_car_can_parser():
|
||||
@@ -100,6 +103,11 @@ class SimulatedCar:
|
||||
|
||||
def send_panda_state(self, simulator_state):
|
||||
self.sm.update(0)
|
||||
|
||||
if self.params.get_bool("ObdMultiplexingEnabled") != self.obd_multiplexing:
|
||||
self.obd_multiplexing = not self.obd_multiplexing
|
||||
self.params.put_bool("ObdMultiplexingChanged", True)
|
||||
|
||||
dat = messaging.new_message('pandaStates', 1)
|
||||
dat.valid = True
|
||||
dat.pandaStates[0] = {
|
||||
|
||||
@@ -3,7 +3,6 @@ import time
|
||||
from cereal import log
|
||||
import cereal.messaging as messaging
|
||||
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import DT_DMON
|
||||
from openpilot.tools.sim.lib.camerad import Camerad
|
||||
|
||||
@@ -80,7 +79,6 @@ class SimulatedSensors:
|
||||
'current': 5678,
|
||||
'fanSpeedRpm': 1000
|
||||
}
|
||||
Params().put_bool("ObdMultiplexingEnabled", False)
|
||||
self.pm.send('peripheralState', dat)
|
||||
|
||||
def send_fake_driver_monitoring(self):
|
||||
|
||||
Reference in New Issue
Block a user