mirror of https://github.com/commaai/openpilot.git
use pyupgrade to update to new typing syntax (#31580)
* add pyupgrade hook * run pyupgrade (pre-commit run -a) * ruff --fix * Revert "add pyupgrade hook" This reverts commit56ec18bb6b
. * revert changes to third_party/ * manual type fixes * explicit Optional wrapping capnp objects old-commit-hash:995250ae49
This commit is contained in:
parent
8af72c9330
commit
9bd90112d0
|
@ -1,7 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import contextlib
|
import contextlib
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
|
|
||||||
class CallbackReader:
|
class CallbackReader:
|
||||||
|
@ -24,7 +23,7 @@ class CallbackReader:
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def atomic_write_in_dir(path: str, mode: str = 'w', buffering: int = -1, encoding: Optional[str] = None, newline: Optional[str] = None,
|
def atomic_write_in_dir(path: str, mode: str = 'w', buffering: int = -1, encoding: str | None = None, newline: str | None = None,
|
||||||
overwrite: bool = False):
|
overwrite: bool = False):
|
||||||
"""Write to a file atomically using a temporary file in the same directory as the destination file."""
|
"""Write to a file atomically using a temporary file in the same directory as the destination file."""
|
||||||
dir_name = os.path.dirname(path)
|
dir_name = os.path.dirname(path)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import os
|
import os
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from typing import Optional, List
|
|
||||||
|
|
||||||
def gpio_init(pin: int, output: bool) -> None:
|
def gpio_init(pin: int, output: bool) -> None:
|
||||||
try:
|
try:
|
||||||
|
@ -16,7 +15,7 @@ def gpio_set(pin: int, high: bool) -> None:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to set gpio {pin} value: {e}")
|
print(f"Failed to set gpio {pin} value: {e}")
|
||||||
|
|
||||||
def gpio_read(pin: int) -> Optional[bool]:
|
def gpio_read(pin: int) -> bool | None:
|
||||||
val = None
|
val = None
|
||||||
try:
|
try:
|
||||||
with open(f"/sys/class/gpio/gpio{pin}/value", 'rb') as f:
|
with open(f"/sys/class/gpio/gpio{pin}/value", 'rb') as f:
|
||||||
|
@ -37,7 +36,7 @@ def gpio_export(pin: int) -> None:
|
||||||
print(f"Failed to export gpio {pin}")
|
print(f"Failed to export gpio {pin}")
|
||||||
|
|
||||||
@lru_cache(maxsize=None)
|
@lru_cache(maxsize=None)
|
||||||
def get_irq_action(irq: int) -> List[str]:
|
def get_irq_action(irq: int) -> list[str]:
|
||||||
try:
|
try:
|
||||||
with open(f"/sys/kernel/irq/{irq}/actions") as f:
|
with open(f"/sys/kernel/irq/{irq}/actions") as f:
|
||||||
actions = f.read().strip().split(',')
|
actions = f.read().strip().split(',')
|
||||||
|
@ -45,7 +44,7 @@ def get_irq_action(irq: int) -> List[str]:
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def get_irqs_for_action(action: str) -> List[str]:
|
def get_irqs_for_action(action: str) -> list[str]:
|
||||||
ret = []
|
ret = []
|
||||||
with open("/proc/interrupts") as f:
|
with open("/proc/interrupts") as f:
|
||||||
for l in f.readlines():
|
for l in f.readlines():
|
||||||
|
|
|
@ -6,7 +6,6 @@ example in common/tests/test_mock.py
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
import threading
|
import threading
|
||||||
from typing import List, Union
|
|
||||||
from cereal.messaging import PubMaster
|
from cereal.messaging import PubMaster
|
||||||
from cereal.services import SERVICE_LIST
|
from cereal.services import SERVICE_LIST
|
||||||
from openpilot.common.mock.generators import generate_liveLocationKalman
|
from openpilot.common.mock.generators import generate_liveLocationKalman
|
||||||
|
@ -18,7 +17,7 @@ MOCK_GENERATOR = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def generate_messages_loop(services: List[str], done: threading.Event):
|
def generate_messages_loop(services: list[str], done: threading.Event):
|
||||||
pm = PubMaster(services)
|
pm = PubMaster(services)
|
||||||
rk = Ratekeeper(100)
|
rk = Ratekeeper(100)
|
||||||
i = 0
|
i = 0
|
||||||
|
@ -32,7 +31,7 @@ def generate_messages_loop(services: List[str], done: threading.Event):
|
||||||
rk.keep_time()
|
rk.keep_time()
|
||||||
|
|
||||||
|
|
||||||
def mock_messages(services: Union[List[str], str]):
|
def mock_messages(services: list[str] | str):
|
||||||
if isinstance(services, str):
|
if isinstance(services, str):
|
||||||
services = [services]
|
services = [services]
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,13 @@ import os
|
||||||
import shutil
|
import shutil
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
from openpilot.system.hardware.hw import Paths
|
from openpilot.system.hardware.hw import Paths
|
||||||
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
|
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
|
||||||
|
|
||||||
class OpenpilotPrefix:
|
class OpenpilotPrefix:
|
||||||
def __init__(self, prefix: Optional[str] = None, clean_dirs_on_exit: bool = True, shared_download_cache: bool = False):
|
def __init__(self, prefix: str | None = None, clean_dirs_on_exit: bool = True, shared_download_cache: bool = False):
|
||||||
self.prefix = prefix if prefix else str(uuid.uuid4().hex[0:15])
|
self.prefix = prefix if prefix else str(uuid.uuid4().hex[0:15])
|
||||||
self.msgq_path = os.path.join('/dev/shm', self.prefix)
|
self.msgq_path = os.path.join('/dev/shm', self.prefix)
|
||||||
self.clean_dirs_on_exit = clean_dirs_on_exit
|
self.clean_dirs_on_exit = clean_dirs_on_exit
|
||||||
|
|
|
@ -3,7 +3,6 @@ import gc
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from typing import Optional, List, Union
|
|
||||||
|
|
||||||
from setproctitle import getproctitle
|
from setproctitle import getproctitle
|
||||||
|
|
||||||
|
@ -33,12 +32,12 @@ def set_realtime_priority(level: int) -> None:
|
||||||
os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(level))
|
os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(level))
|
||||||
|
|
||||||
|
|
||||||
def set_core_affinity(cores: List[int]) -> None:
|
def set_core_affinity(cores: list[int]) -> None:
|
||||||
if not PC:
|
if not PC:
|
||||||
os.sched_setaffinity(0, cores)
|
os.sched_setaffinity(0, cores)
|
||||||
|
|
||||||
|
|
||||||
def config_realtime_process(cores: Union[int, List[int]], priority: int) -> None:
|
def config_realtime_process(cores: int | list[int], priority: int) -> None:
|
||||||
gc.disable()
|
gc.disable()
|
||||||
set_realtime_priority(priority)
|
set_realtime_priority(priority)
|
||||||
c = cores if isinstance(cores, list) else [cores, ]
|
c = cores if isinstance(cores, list) else [cores, ]
|
||||||
|
@ -46,7 +45,7 @@ def config_realtime_process(cores: Union[int, List[int]], priority: int) -> None
|
||||||
|
|
||||||
|
|
||||||
class Ratekeeper:
|
class Ratekeeper:
|
||||||
def __init__(self, rate: float, print_delay_threshold: Optional[float] = 0.0) -> None:
|
def __init__(self, rate: float, print_delay_threshold: float | None = 0.0) -> None:
|
||||||
"""Rate in Hz for ratekeeping. print_delay_threshold must be nonnegative."""
|
"""Rate in Hz for ratekeeping. print_delay_threshold must be nonnegative."""
|
||||||
self._interval = 1. / rate
|
self._interval = 1. / rate
|
||||||
self._next_frame_time = time.monotonic() + self._interval
|
self._next_frame_time = time.monotonic() + self._interval
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from typing import Callable
|
from collections.abc import Callable
|
||||||
|
|
||||||
from openpilot.common.transformations.transformations import (ecef_euler_from_ned_single,
|
from openpilot.common.transformations.transformations import (ecef_euler_from_ned_single,
|
||||||
euler2quat_single,
|
euler2quat_single,
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,8 @@ from dataclasses import asdict, dataclass, replace
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
from typing import Callable, Dict, List, Optional, Set, Union, cast
|
from typing import cast
|
||||||
|
from collections.abc import Callable
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from jsonrpc import JSONRPCResponseManager, dispatcher
|
from jsonrpc import JSONRPCResponseManager, dispatcher
|
||||||
|
@ -55,17 +56,17 @@ WS_FRAME_SIZE = 4096
|
||||||
|
|
||||||
NetworkType = log.DeviceState.NetworkType
|
NetworkType = log.DeviceState.NetworkType
|
||||||
|
|
||||||
UploadFileDict = Dict[str, Union[str, int, float, bool]]
|
UploadFileDict = dict[str, str | int | float | bool]
|
||||||
UploadItemDict = Dict[str, Union[str, bool, int, float, Dict[str, str]]]
|
UploadItemDict = dict[str, str | bool | int | float | dict[str, str]]
|
||||||
|
|
||||||
UploadFilesToUrlResponse = Dict[str, Union[int, List[UploadItemDict], List[str]]]
|
UploadFilesToUrlResponse = dict[str, int | list[UploadItemDict] | list[str]]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class UploadFile:
|
class UploadFile:
|
||||||
fn: str
|
fn: str
|
||||||
url: str
|
url: str
|
||||||
headers: Dict[str, str]
|
headers: dict[str, str]
|
||||||
allow_cellular: bool
|
allow_cellular: bool
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -77,9 +78,9 @@ class UploadFile:
|
||||||
class UploadItem:
|
class UploadItem:
|
||||||
path: str
|
path: str
|
||||||
url: str
|
url: str
|
||||||
headers: Dict[str, str]
|
headers: dict[str, str]
|
||||||
created_at: int
|
created_at: int
|
||||||
id: Optional[str]
|
id: str | None
|
||||||
retry_count: int = 0
|
retry_count: int = 0
|
||||||
current: bool = False
|
current: bool = False
|
||||||
progress: float = 0
|
progress: float = 0
|
||||||
|
@ -97,9 +98,9 @@ send_queue: Queue[str] = queue.Queue()
|
||||||
upload_queue: Queue[UploadItem] = queue.Queue()
|
upload_queue: Queue[UploadItem] = queue.Queue()
|
||||||
low_priority_send_queue: Queue[str] = queue.Queue()
|
low_priority_send_queue: Queue[str] = queue.Queue()
|
||||||
log_recv_queue: Queue[str] = queue.Queue()
|
log_recv_queue: Queue[str] = queue.Queue()
|
||||||
cancelled_uploads: Set[str] = set()
|
cancelled_uploads: set[str] = set()
|
||||||
|
|
||||||
cur_upload_items: Dict[int, Optional[UploadItem]] = {}
|
cur_upload_items: dict[int, UploadItem | None] = {}
|
||||||
|
|
||||||
|
|
||||||
def strip_bz2_extension(fn: str) -> str:
|
def strip_bz2_extension(fn: str) -> str:
|
||||||
|
@ -127,14 +128,14 @@ class UploadQueueCache:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def cache(upload_queue: Queue[UploadItem]) -> None:
|
def cache(upload_queue: Queue[UploadItem]) -> None:
|
||||||
try:
|
try:
|
||||||
queue: List[Optional[UploadItem]] = list(upload_queue.queue)
|
queue: list[UploadItem | None] = list(upload_queue.queue)
|
||||||
items = [asdict(i) for i in queue if i is not None and (i.id not in cancelled_uploads)]
|
items = [asdict(i) for i in queue if i is not None and (i.id not in cancelled_uploads)]
|
||||||
Params().put("AthenadUploadQueue", json.dumps(items))
|
Params().put("AthenadUploadQueue", json.dumps(items))
|
||||||
except Exception:
|
except Exception:
|
||||||
cloudlog.exception("athena.UploadQueueCache.cache.exception")
|
cloudlog.exception("athena.UploadQueueCache.cache.exception")
|
||||||
|
|
||||||
|
|
||||||
def handle_long_poll(ws: WebSocket, exit_event: Optional[threading.Event]) -> None:
|
def handle_long_poll(ws: WebSocket, exit_event: threading.Event | None) -> None:
|
||||||
end_event = threading.Event()
|
end_event = threading.Event()
|
||||||
|
|
||||||
threads = [
|
threads = [
|
||||||
|
@ -278,7 +279,7 @@ def upload_handler(end_event: threading.Event) -> None:
|
||||||
cloudlog.exception("athena.upload_handler.exception")
|
cloudlog.exception("athena.upload_handler.exception")
|
||||||
|
|
||||||
|
|
||||||
def _do_upload(upload_item: UploadItem, callback: Optional[Callable] = None) -> requests.Response:
|
def _do_upload(upload_item: UploadItem, callback: Callable | None = None) -> requests.Response:
|
||||||
path = upload_item.path
|
path = upload_item.path
|
||||||
compress = False
|
compress = False
|
||||||
|
|
||||||
|
@ -317,7 +318,7 @@ def getMessage(service: str, timeout: int = 1000) -> dict:
|
||||||
|
|
||||||
|
|
||||||
@dispatcher.add_method
|
@dispatcher.add_method
|
||||||
def getVersion() -> Dict[str, str]:
|
def getVersion() -> dict[str, str]:
|
||||||
return {
|
return {
|
||||||
"version": get_version(),
|
"version": get_version(),
|
||||||
"remote": get_normalized_origin(),
|
"remote": get_normalized_origin(),
|
||||||
|
@ -327,7 +328,7 @@ def getVersion() -> Dict[str, str]:
|
||||||
|
|
||||||
|
|
||||||
@dispatcher.add_method
|
@dispatcher.add_method
|
||||||
def setNavDestination(latitude: int = 0, longitude: int = 0, place_name: Optional[str] = None, place_details: Optional[str] = None) -> Dict[str, int]:
|
def setNavDestination(latitude: int = 0, longitude: int = 0, place_name: str | None = None, place_details: str | None = None) -> dict[str, int]:
|
||||||
destination = {
|
destination = {
|
||||||
"latitude": latitude,
|
"latitude": latitude,
|
||||||
"longitude": longitude,
|
"longitude": longitude,
|
||||||
|
@ -339,7 +340,7 @@ def setNavDestination(latitude: int = 0, longitude: int = 0, place_name: Optiona
|
||||||
return {"success": 1}
|
return {"success": 1}
|
||||||
|
|
||||||
|
|
||||||
def scan_dir(path: str, prefix: str) -> List[str]:
|
def scan_dir(path: str, prefix: str) -> list[str]:
|
||||||
files = []
|
files = []
|
||||||
# only walk directories that match the prefix
|
# only walk directories that match the prefix
|
||||||
# (glob and friends traverse entire dir tree)
|
# (glob and friends traverse entire dir tree)
|
||||||
|
@ -359,12 +360,12 @@ def scan_dir(path: str, prefix: str) -> List[str]:
|
||||||
return files
|
return files
|
||||||
|
|
||||||
@dispatcher.add_method
|
@dispatcher.add_method
|
||||||
def listDataDirectory(prefix='') -> List[str]:
|
def listDataDirectory(prefix='') -> list[str]:
|
||||||
return scan_dir(Paths.log_root(), prefix)
|
return scan_dir(Paths.log_root(), prefix)
|
||||||
|
|
||||||
|
|
||||||
@dispatcher.add_method
|
@dispatcher.add_method
|
||||||
def uploadFileToUrl(fn: str, url: str, headers: Dict[str, str]) -> UploadFilesToUrlResponse:
|
def uploadFileToUrl(fn: str, url: str, headers: dict[str, str]) -> UploadFilesToUrlResponse:
|
||||||
# this is because mypy doesn't understand that the decorator doesn't change the return type
|
# this is because mypy doesn't understand that the decorator doesn't change the return type
|
||||||
response: UploadFilesToUrlResponse = uploadFilesToUrls([{
|
response: UploadFilesToUrlResponse = uploadFilesToUrls([{
|
||||||
"fn": fn,
|
"fn": fn,
|
||||||
|
@ -375,11 +376,11 @@ def uploadFileToUrl(fn: str, url: str, headers: Dict[str, str]) -> UploadFilesTo
|
||||||
|
|
||||||
|
|
||||||
@dispatcher.add_method
|
@dispatcher.add_method
|
||||||
def uploadFilesToUrls(files_data: List[UploadFileDict]) -> UploadFilesToUrlResponse:
|
def uploadFilesToUrls(files_data: list[UploadFileDict]) -> UploadFilesToUrlResponse:
|
||||||
files = map(UploadFile.from_dict, files_data)
|
files = map(UploadFile.from_dict, files_data)
|
||||||
|
|
||||||
items: List[UploadItemDict] = []
|
items: list[UploadItemDict] = []
|
||||||
failed: List[str] = []
|
failed: list[str] = []
|
||||||
for file in files:
|
for file in files:
|
||||||
if len(file.fn) == 0 or file.fn[0] == '/' or '..' in file.fn or len(file.url) == 0:
|
if len(file.fn) == 0 or file.fn[0] == '/' or '..' in file.fn or len(file.url) == 0:
|
||||||
failed.append(file.fn)
|
failed.append(file.fn)
|
||||||
|
@ -418,13 +419,13 @@ def uploadFilesToUrls(files_data: List[UploadFileDict]) -> UploadFilesToUrlRespo
|
||||||
|
|
||||||
|
|
||||||
@dispatcher.add_method
|
@dispatcher.add_method
|
||||||
def listUploadQueue() -> List[UploadItemDict]:
|
def listUploadQueue() -> list[UploadItemDict]:
|
||||||
items = list(upload_queue.queue) + list(cur_upload_items.values())
|
items = list(upload_queue.queue) + list(cur_upload_items.values())
|
||||||
return [asdict(i) for i in items if (i is not None) and (i.id not in cancelled_uploads)]
|
return [asdict(i) for i in items if (i is not None) and (i.id not in cancelled_uploads)]
|
||||||
|
|
||||||
|
|
||||||
@dispatcher.add_method
|
@dispatcher.add_method
|
||||||
def cancelUpload(upload_id: Union[str, List[str]]) -> Dict[str, Union[int, str]]:
|
def cancelUpload(upload_id: str | list[str]) -> dict[str, int | str]:
|
||||||
if not isinstance(upload_id, list):
|
if not isinstance(upload_id, list):
|
||||||
upload_id = [upload_id]
|
upload_id = [upload_id]
|
||||||
|
|
||||||
|
@ -437,7 +438,7 @@ def cancelUpload(upload_id: Union[str, List[str]]) -> Dict[str, Union[int, str]]
|
||||||
return {"success": 1}
|
return {"success": 1}
|
||||||
|
|
||||||
@dispatcher.add_method
|
@dispatcher.add_method
|
||||||
def setRouteViewed(route: str) -> Dict[str, Union[int, str]]:
|
def setRouteViewed(route: str) -> dict[str, int | str]:
|
||||||
# maintain a list of the last 10 routes viewed in connect
|
# maintain a list of the last 10 routes viewed in connect
|
||||||
params = Params()
|
params = Params()
|
||||||
|
|
||||||
|
@ -452,7 +453,7 @@ def setRouteViewed(route: str) -> Dict[str, Union[int, str]]:
|
||||||
return {"success": 1}
|
return {"success": 1}
|
||||||
|
|
||||||
|
|
||||||
def startLocalProxy(global_end_event: threading.Event, remote_ws_uri: str, local_port: int) -> Dict[str, int]:
|
def startLocalProxy(global_end_event: threading.Event, remote_ws_uri: str, local_port: int) -> dict[str, int]:
|
||||||
try:
|
try:
|
||||||
if local_port not in LOCAL_PORT_WHITELIST:
|
if local_port not in LOCAL_PORT_WHITELIST:
|
||||||
raise Exception("Requested local port not whitelisted")
|
raise Exception("Requested local port not whitelisted")
|
||||||
|
@ -486,7 +487,7 @@ def startLocalProxy(global_end_event: threading.Event, remote_ws_uri: str, local
|
||||||
|
|
||||||
|
|
||||||
@dispatcher.add_method
|
@dispatcher.add_method
|
||||||
def getPublicKey() -> Optional[str]:
|
def getPublicKey() -> str | None:
|
||||||
if not os.path.isfile(Paths.persist_root() + '/comma/id_rsa.pub'):
|
if not os.path.isfile(Paths.persist_root() + '/comma/id_rsa.pub'):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -526,7 +527,7 @@ def getNetworks():
|
||||||
|
|
||||||
|
|
||||||
@dispatcher.add_method
|
@dispatcher.add_method
|
||||||
def takeSnapshot() -> Optional[Union[str, Dict[str, str]]]:
|
def takeSnapshot() -> str | dict[str, str] | None:
|
||||||
from openpilot.system.camerad.snapshot.snapshot import jpeg_write, snapshot
|
from openpilot.system.camerad.snapshot.snapshot import jpeg_write, snapshot
|
||||||
ret = snapshot()
|
ret = snapshot()
|
||||||
if ret is not None:
|
if ret is not None:
|
||||||
|
@ -543,7 +544,7 @@ def takeSnapshot() -> Optional[Union[str, Dict[str, str]]]:
|
||||||
raise Exception("not available while camerad is started")
|
raise Exception("not available while camerad is started")
|
||||||
|
|
||||||
|
|
||||||
def get_logs_to_send_sorted() -> List[str]:
|
def get_logs_to_send_sorted() -> list[str]:
|
||||||
# TODO: scan once then use inotify to detect file creation/deletion
|
# TODO: scan once then use inotify to detect file creation/deletion
|
||||||
curr_time = int(time.time())
|
curr_time = int(time.time())
|
||||||
logs = []
|
logs = []
|
||||||
|
@ -766,7 +767,7 @@ def backoff(retries: int) -> int:
|
||||||
return random.randrange(0, min(128, int(2 ** retries)))
|
return random.randrange(0, min(128, int(2 ** retries)))
|
||||||
|
|
||||||
|
|
||||||
def main(exit_event: Optional[threading.Event] = None):
|
def main(exit_event: threading.Event | None = None):
|
||||||
try:
|
try:
|
||||||
set_core_affinity([0, 1, 2, 3])
|
set_core_affinity([0, 1, 2, 3])
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
|
@ -3,7 +3,6 @@ import time
|
||||||
import json
|
import json
|
||||||
import jwt
|
import jwt
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from openpilot.common.api import api_get
|
from openpilot.common.api import api_get
|
||||||
|
@ -23,12 +22,12 @@ def is_registered_device() -> bool:
|
||||||
return dongle not in (None, UNREGISTERED_DONGLE_ID)
|
return dongle not in (None, UNREGISTERED_DONGLE_ID)
|
||||||
|
|
||||||
|
|
||||||
def register(show_spinner=False) -> Optional[str]:
|
def register(show_spinner=False) -> str | None:
|
||||||
params = Params()
|
params = Params()
|
||||||
|
|
||||||
IMEI = params.get("IMEI", encoding='utf8')
|
IMEI = params.get("IMEI", encoding='utf8')
|
||||||
HardwareSerial = params.get("HardwareSerial", encoding='utf8')
|
HardwareSerial = params.get("HardwareSerial", encoding='utf8')
|
||||||
dongle_id: Optional[str] = params.get("DongleId", encoding='utf8')
|
dongle_id: str | None = params.get("DongleId", encoding='utf8')
|
||||||
needs_registration = None in (IMEI, HardwareSerial, dongle_id)
|
needs_registration = None in (IMEI, HardwareSerial, dongle_id)
|
||||||
|
|
||||||
pubkey = Path(Paths.persist_root()+"/comma/id_rsa.pub")
|
pubkey = Path(Paths.persist_root()+"/comma/id_rsa.pub")
|
||||||
|
@ -48,8 +47,8 @@ def register(show_spinner=False) -> Optional[str]:
|
||||||
# Block until we get the imei
|
# Block until we get the imei
|
||||||
serial = HARDWARE.get_serial()
|
serial = HARDWARE.get_serial()
|
||||||
start_time = time.monotonic()
|
start_time = time.monotonic()
|
||||||
imei1: Optional[str] = None
|
imei1: str | None = None
|
||||||
imei2: Optional[str] = None
|
imei2: str | None = None
|
||||||
while imei1 is None and imei2 is None:
|
while imei1 is None and imei2 is None:
|
||||||
try:
|
try:
|
||||||
imei1, imei2 = HARDWARE.get_imei(0), HARDWARE.get_imei(1)
|
imei1, imei2 = HARDWARE.get_imei(0), HARDWARE.get_imei(1)
|
||||||
|
|
|
@ -12,7 +12,6 @@ import unittest
|
||||||
from dataclasses import asdict, replace
|
from dataclasses import asdict, replace
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from parameterized import parameterized
|
from parameterized import parameterized
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
from websocket import ABNF
|
from websocket import ABNF
|
||||||
|
@ -97,7 +96,7 @@ class TestAthenadMethods(unittest.TestCase):
|
||||||
break
|
break
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _create_file(file: str, parent: Optional[str] = None, data: bytes = b'') -> str:
|
def _create_file(file: str, parent: str | None = None, data: bytes = b'') -> str:
|
||||||
fn = os.path.join(Paths.log_root() if parent is None else parent, file)
|
fn = os.path.join(Paths.log_root() if parent is None else parent, file)
|
||||||
os.makedirs(os.path.dirname(fn), exist_ok=True)
|
os.makedirs(os.path.dirname(fn), exist_ok=True)
|
||||||
with open(fn, 'wb') as f:
|
with open(fn, 'wb') as f:
|
||||||
|
|
|
@ -3,7 +3,7 @@ import subprocess
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
from typing import cast, Optional
|
from typing import cast
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
|
@ -29,8 +29,8 @@ class TestAthenadPing(unittest.TestCase):
|
||||||
athenad: threading.Thread
|
athenad: threading.Thread
|
||||||
exit_event: threading.Event
|
exit_event: threading.Event
|
||||||
|
|
||||||
def _get_ping_time(self) -> Optional[str]:
|
def _get_ping_time(self) -> str | None:
|
||||||
return cast(Optional[str], self.params.get("LastAthenaPingTime", encoding="utf-8"))
|
return cast(str | None, self.params.get("LastAthenaPingTime", encoding="utf-8"))
|
||||||
|
|
||||||
def _clear_ping_time(self) -> None:
|
def _clear_ping_time(self) -> None:
|
||||||
self.params.remove("LastAthenaPingTime")
|
self.params.remove("LastAthenaPingTime")
|
||||||
|
|
|
@ -4,7 +4,7 @@ import os
|
||||||
import usb1
|
import usb1
|
||||||
import time
|
import time
|
||||||
import subprocess
|
import subprocess
|
||||||
from typing import List, NoReturn
|
from typing import NoReturn
|
||||||
from functools import cmp_to_key
|
from functools import cmp_to_key
|
||||||
|
|
||||||
from panda import Panda, PandaDFU, PandaProtocolMismatch, FW_PATH
|
from panda import Panda, PandaDFU, PandaProtocolMismatch, FW_PATH
|
||||||
|
@ -124,7 +124,7 @@ def main() -> NoReturn:
|
||||||
cloudlog.info(f"{len(panda_serials)} panda(s) found, connecting - {panda_serials}")
|
cloudlog.info(f"{len(panda_serials)} panda(s) found, connecting - {panda_serials}")
|
||||||
|
|
||||||
# Flash pandas
|
# Flash pandas
|
||||||
pandas: List[Panda] = []
|
pandas: list[Panda] = []
|
||||||
for serial in panda_serials:
|
for serial in panda_serials:
|
||||||
pandas.append(flash_panda(serial))
|
pandas.append(flash_panda(serial))
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import ReprEnum
|
from enum import ReprEnum
|
||||||
from typing import Dict, List, Optional, Union
|
|
||||||
|
|
||||||
import capnp
|
import capnp
|
||||||
|
|
||||||
|
@ -27,9 +26,9 @@ def apply_hysteresis(val: float, val_steady: float, hyst_gap: float) -> float:
|
||||||
return val_steady
|
return val_steady
|
||||||
|
|
||||||
|
|
||||||
def create_button_events(cur_btn: int, prev_btn: int, buttons_dict: Dict[int, capnp.lib.capnp._EnumModule],
|
def create_button_events(cur_btn: int, prev_btn: int, buttons_dict: dict[int, capnp.lib.capnp._EnumModule],
|
||||||
unpressed_btn: int = 0) -> List[capnp.lib.capnp._DynamicStructBuilder]:
|
unpressed_btn: int = 0) -> list[capnp.lib.capnp._DynamicStructBuilder]:
|
||||||
events: List[capnp.lib.capnp._DynamicStructBuilder] = []
|
events: list[capnp.lib.capnp._DynamicStructBuilder] = []
|
||||||
|
|
||||||
if cur_btn == prev_btn:
|
if cur_btn == prev_btn:
|
||||||
return events
|
return events
|
||||||
|
@ -76,7 +75,7 @@ def scale_tire_stiffness(mass, wheelbase, center_to_front, tire_stiffness_factor
|
||||||
return tire_stiffness_front, tire_stiffness_rear
|
return tire_stiffness_front, tire_stiffness_rear
|
||||||
|
|
||||||
|
|
||||||
DbcDict = Dict[str, str]
|
DbcDict = dict[str, str]
|
||||||
|
|
||||||
|
|
||||||
def dbc_dict(pt_dbc, radar_dbc, chassis_dbc=None, body_dbc=None) -> DbcDict:
|
def dbc_dict(pt_dbc, radar_dbc, chassis_dbc=None, body_dbc=None) -> DbcDict:
|
||||||
|
@ -214,7 +213,7 @@ def get_safety_config(safety_model, safety_param = None):
|
||||||
class CanBusBase:
|
class CanBusBase:
|
||||||
offset: int
|
offset: int
|
||||||
|
|
||||||
def __init__(self, CP, fingerprint: Optional[Dict[int, Dict[int, int]]]) -> None:
|
def __init__(self, CP, fingerprint: dict[int, dict[int, int]] | None) -> None:
|
||||||
if CP is None:
|
if CP is None:
|
||||||
assert fingerprint is not None
|
assert fingerprint is not None
|
||||||
num = max([k for k, v in fingerprint.items() if len(v)], default=0) // 4 + 1
|
num = max([k for k, v in fingerprint.items() if len(v)], default=0) // 4 + 1
|
||||||
|
@ -244,7 +243,7 @@ class CanSignalRateCalculator:
|
||||||
return self.rate
|
return self.rate
|
||||||
|
|
||||||
|
|
||||||
CarInfos = Union[CarInfo, List[CarInfo]]
|
CarInfos = CarInfo | list[CarInfo]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -260,7 +259,7 @@ class PlatformConfig:
|
||||||
car_info: CarInfos
|
car_info: CarInfos
|
||||||
dbc_dict: DbcDict
|
dbc_dict: DbcDict
|
||||||
|
|
||||||
specs: Optional[CarSpecs] = None
|
specs: CarSpecs | None = None
|
||||||
|
|
||||||
def __hash__(self) -> int:
|
def __hash__(self) -> int:
|
||||||
return hash(self.platform_str)
|
return hash(self.platform_str)
|
||||||
|
@ -276,9 +275,9 @@ class Platforms(str, ReprEnum):
|
||||||
return member
|
return member
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_dbc_map(cls) -> Dict[str, DbcDict]:
|
def create_dbc_map(cls) -> dict[str, DbcDict]:
|
||||||
return {p: p.config.dbc_dict for p in cls}
|
return {p: p.config.dbc_dict for p in cls}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_carinfo_map(cls) -> Dict[str, CarInfos]:
|
def create_carinfo_map(cls) -> dict[str, CarInfos]:
|
||||||
return {p: p.config.car_info for p in cls}
|
return {p: p.config.car_info for p in cls}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
from typing import Callable, Dict, List, Optional, Tuple
|
from collections.abc import Callable
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
|
@ -63,7 +63,7 @@ def load_interfaces(brand_names):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def _get_interface_names() -> Dict[str, List[str]]:
|
def _get_interface_names() -> dict[str, list[str]]:
|
||||||
# returns a dict of brand name and its respective models
|
# returns a dict of brand name and its respective models
|
||||||
brand_names = {}
|
brand_names = {}
|
||||||
for brand_name, brand_models in get_interface_attr("CAR").items():
|
for brand_name, brand_models in get_interface_attr("CAR").items():
|
||||||
|
@ -77,7 +77,7 @@ interface_names = _get_interface_names()
|
||||||
interfaces = load_interfaces(interface_names)
|
interfaces = load_interfaces(interface_names)
|
||||||
|
|
||||||
|
|
||||||
def can_fingerprint(next_can: Callable) -> Tuple[Optional[str], Dict[int, dict]]:
|
def can_fingerprint(next_can: Callable) -> tuple[str | None, dict[int, dict]]:
|
||||||
finger = gen_empty_fingerprint()
|
finger = gen_empty_fingerprint()
|
||||||
candidate_cars = {i: all_legacy_fingerprint_cars() for i in [0, 1]} # attempt fingerprint on both bus 0 and 1
|
candidate_cars = {i: all_legacy_fingerprint_cars() for i in [0, 1]} # attempt fingerprint on both bus 0 and 1
|
||||||
frame = 0
|
frame = 0
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
from enum import IntFlag, StrEnum
|
from enum import IntFlag, StrEnum
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Dict, List, Optional, Union
|
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from panda.python import uds
|
from panda.python import uds
|
||||||
|
@ -66,7 +65,7 @@ class ChryslerCarInfo(CarInfo):
|
||||||
car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.fca]))
|
car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.fca]))
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = {
|
CAR_INFO: dict[str, ChryslerCarInfo | list[ChryslerCarInfo] | None] = {
|
||||||
CAR.PACIFICA_2017_HYBRID: ChryslerCarInfo("Chrysler Pacifica Hybrid 2017"),
|
CAR.PACIFICA_2017_HYBRID: ChryslerCarInfo("Chrysler Pacifica Hybrid 2017"),
|
||||||
CAR.PACIFICA_2018_HYBRID: ChryslerCarInfo("Chrysler Pacifica Hybrid 2018"),
|
CAR.PACIFICA_2018_HYBRID: ChryslerCarInfo("Chrysler Pacifica Hybrid 2018"),
|
||||||
CAR.PACIFICA_2019_HYBRID: ChryslerCarInfo("Chrysler Pacifica Hybrid 2019-23"),
|
CAR.PACIFICA_2019_HYBRID: ChryslerCarInfo("Chrysler Pacifica Hybrid 2019-23"),
|
||||||
|
|
|
@ -5,7 +5,6 @@ import jinja2
|
||||||
import os
|
import os
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from natsort import natsorted
|
from natsort import natsorted
|
||||||
from typing import Dict, List
|
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from openpilot.common.basedir import BASEDIR
|
from openpilot.common.basedir import BASEDIR
|
||||||
|
@ -14,7 +13,7 @@ from openpilot.selfdrive.car.docs_definitions import CarInfo, Column, CommonFoot
|
||||||
from openpilot.selfdrive.car.car_helpers import interfaces, get_interface_attr
|
from openpilot.selfdrive.car.car_helpers import interfaces, get_interface_attr
|
||||||
|
|
||||||
|
|
||||||
def get_all_footnotes() -> Dict[Enum, int]:
|
def get_all_footnotes() -> dict[Enum, int]:
|
||||||
all_footnotes = list(CommonFootnote)
|
all_footnotes = list(CommonFootnote)
|
||||||
for footnotes in get_interface_attr("Footnote", ignore_none=True).values():
|
for footnotes in get_interface_attr("Footnote", ignore_none=True).values():
|
||||||
all_footnotes.extend(footnotes)
|
all_footnotes.extend(footnotes)
|
||||||
|
@ -25,8 +24,8 @@ CARS_MD_OUT = os.path.join(BASEDIR, "docs", "CARS.md")
|
||||||
CARS_MD_TEMPLATE = os.path.join(BASEDIR, "selfdrive", "car", "CARS_template.md")
|
CARS_MD_TEMPLATE = os.path.join(BASEDIR, "selfdrive", "car", "CARS_template.md")
|
||||||
|
|
||||||
|
|
||||||
def get_all_car_info() -> List[CarInfo]:
|
def get_all_car_info() -> list[CarInfo]:
|
||||||
all_car_info: List[CarInfo] = []
|
all_car_info: list[CarInfo] = []
|
||||||
footnotes = get_all_footnotes()
|
footnotes = get_all_footnotes()
|
||||||
for model, car_info in get_interface_attr("CAR_INFO", combine_brands=True).items():
|
for model, car_info in get_interface_attr("CAR_INFO", combine_brands=True).items():
|
||||||
# If available, uses experimental longitudinal limits for the docs
|
# If available, uses experimental longitudinal limits for the docs
|
||||||
|
@ -47,19 +46,19 @@ def get_all_car_info() -> List[CarInfo]:
|
||||||
all_car_info.append(_car_info)
|
all_car_info.append(_car_info)
|
||||||
|
|
||||||
# Sort cars by make and model + year
|
# Sort cars by make and model + year
|
||||||
sorted_cars: List[CarInfo] = natsorted(all_car_info, key=lambda car: car.name.lower())
|
sorted_cars: list[CarInfo] = natsorted(all_car_info, key=lambda car: car.name.lower())
|
||||||
return sorted_cars
|
return sorted_cars
|
||||||
|
|
||||||
|
|
||||||
def group_by_make(all_car_info: List[CarInfo]) -> Dict[str, List[CarInfo]]:
|
def group_by_make(all_car_info: list[CarInfo]) -> dict[str, list[CarInfo]]:
|
||||||
sorted_car_info = defaultdict(list)
|
sorted_car_info = defaultdict(list)
|
||||||
for car_info in all_car_info:
|
for car_info in all_car_info:
|
||||||
sorted_car_info[car_info.make].append(car_info)
|
sorted_car_info[car_info.make].append(car_info)
|
||||||
return dict(sorted_car_info)
|
return dict(sorted_car_info)
|
||||||
|
|
||||||
|
|
||||||
def generate_cars_md(all_car_info: List[CarInfo], template_fn: str) -> str:
|
def generate_cars_md(all_car_info: list[CarInfo], template_fn: str) -> str:
|
||||||
with open(template_fn, "r") as f:
|
with open(template_fn) as f:
|
||||||
template = jinja2.Template(f.read(), trim_blocks=True, lstrip_blocks=True)
|
template = jinja2.Template(f.read(), trim_blocks=True, lstrip_blocks=True)
|
||||||
|
|
||||||
footnotes = [fn.value.text for fn in get_all_footnotes()]
|
footnotes = [fn.value.text for fn in get_all_footnotes()]
|
||||||
|
|
|
@ -3,7 +3,6 @@ from collections import namedtuple
|
||||||
import copy
|
import copy
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Dict, List, Optional, Tuple, Union
|
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from openpilot.common.conversions import Conversions as CV
|
from openpilot.common.conversions import Conversions as CV
|
||||||
|
@ -35,7 +34,7 @@ class Star(Enum):
|
||||||
@dataclass
|
@dataclass
|
||||||
class BasePart:
|
class BasePart:
|
||||||
name: str
|
name: str
|
||||||
parts: List[Enum] = field(default_factory=list)
|
parts: list[Enum] = field(default_factory=list)
|
||||||
|
|
||||||
def all_parts(self):
|
def all_parts(self):
|
||||||
# Recursively get all parts
|
# Recursively get all parts
|
||||||
|
@ -76,7 +75,7 @@ class Accessory(EnumBase):
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class BaseCarHarness(BasePart):
|
class BaseCarHarness(BasePart):
|
||||||
parts: List[Enum] = field(default_factory=lambda: [Accessory.harness_box, Accessory.comma_power_v2, Cable.rj45_cable_7ft])
|
parts: list[Enum] = field(default_factory=lambda: [Accessory.harness_box, Accessory.comma_power_v2, Cable.rj45_cable_7ft])
|
||||||
has_connector: bool = True # without are hidden on the harness connector page
|
has_connector: bool = True # without are hidden on the harness connector page
|
||||||
|
|
||||||
|
|
||||||
|
@ -149,18 +148,18 @@ class PartType(Enum):
|
||||||
tool = Tool
|
tool = Tool
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_CAR_PARTS: List[EnumBase] = [Device.threex]
|
DEFAULT_CAR_PARTS: list[EnumBase] = [Device.threex]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class CarParts:
|
class CarParts:
|
||||||
parts: List[EnumBase] = field(default_factory=list)
|
parts: list[EnumBase] = field(default_factory=list)
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
return copy.deepcopy(self)
|
return copy.deepcopy(self)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def common(cls, add: Optional[List[EnumBase]] = None, remove: Optional[List[EnumBase]] = None):
|
def common(cls, add: list[EnumBase] | None = None, remove: list[EnumBase] | None = None):
|
||||||
p = [part for part in (add or []) + DEFAULT_CAR_PARTS if part not in (remove or [])]
|
p = [part for part in (add or []) + DEFAULT_CAR_PARTS if part not in (remove or [])]
|
||||||
return cls(p)
|
return cls(p)
|
||||||
|
|
||||||
|
@ -186,7 +185,7 @@ class CommonFootnote(Enum):
|
||||||
Column.LONGITUDINAL)
|
Column.LONGITUDINAL)
|
||||||
|
|
||||||
|
|
||||||
def get_footnotes(footnotes: List[Enum], column: Column) -> List[Enum]:
|
def get_footnotes(footnotes: list[Enum], column: Column) -> list[Enum]:
|
||||||
# Returns applicable footnotes given current column
|
# Returns applicable footnotes given current column
|
||||||
return [fn for fn in footnotes if fn.value.column == column]
|
return [fn for fn in footnotes if fn.value.column == column]
|
||||||
|
|
||||||
|
@ -209,7 +208,7 @@ def get_year_list(years):
|
||||||
return years_list
|
return years_list
|
||||||
|
|
||||||
|
|
||||||
def split_name(name: str) -> Tuple[str, str, str]:
|
def split_name(name: str) -> tuple[str, str, str]:
|
||||||
make, model = name.split(" ", 1)
|
make, model = name.split(" ", 1)
|
||||||
years = ""
|
years = ""
|
||||||
match = re.search(MODEL_YEARS_RE, model)
|
match = re.search(MODEL_YEARS_RE, model)
|
||||||
|
@ -233,13 +232,13 @@ class CarInfo:
|
||||||
|
|
||||||
# the minimum compatibility requirements for this model, regardless
|
# the minimum compatibility requirements for this model, regardless
|
||||||
# of market. can be a package, trim, or list of features
|
# of market. can be a package, trim, or list of features
|
||||||
requirements: Optional[str] = None
|
requirements: str | None = None
|
||||||
|
|
||||||
video_link: Optional[str] = None
|
video_link: str | None = None
|
||||||
footnotes: List[Enum] = field(default_factory=list)
|
footnotes: list[Enum] = field(default_factory=list)
|
||||||
min_steer_speed: Optional[float] = None
|
min_steer_speed: float | None = None
|
||||||
min_enable_speed: Optional[float] = None
|
min_enable_speed: float | None = None
|
||||||
auto_resume: Optional[bool] = None
|
auto_resume: bool | None = None
|
||||||
|
|
||||||
# all the parts needed for the supported car
|
# all the parts needed for the supported car
|
||||||
car_parts: CarParts = field(default_factory=CarParts)
|
car_parts: CarParts = field(default_factory=CarParts)
|
||||||
|
@ -248,7 +247,7 @@ class CarInfo:
|
||||||
self.make, self.model, self.years = split_name(self.name)
|
self.make, self.model, self.years = split_name(self.name)
|
||||||
self.year_list = get_year_list(self.years)
|
self.year_list = get_year_list(self.years)
|
||||||
|
|
||||||
def init(self, CP: car.CarParams, all_footnotes: Dict[Enum, int]):
|
def init(self, CP: car.CarParams, all_footnotes: dict[Enum, int]):
|
||||||
self.car_name = CP.carName
|
self.car_name = CP.carName
|
||||||
self.car_fingerprint = CP.carFingerprint
|
self.car_fingerprint = CP.carFingerprint
|
||||||
|
|
||||||
|
@ -293,7 +292,7 @@ class CarInfo:
|
||||||
if len(tools_docs):
|
if len(tools_docs):
|
||||||
hardware_col += f'<details><summary>Tools</summary><sub>{display_func(tools_docs)}</sub></details>'
|
hardware_col += f'<details><summary>Tools</summary><sub>{display_func(tools_docs)}</sub></details>'
|
||||||
|
|
||||||
self.row: Dict[Enum, Union[str, Star]] = {
|
self.row: dict[Enum, str | Star] = {
|
||||||
Column.MAKE: self.make,
|
Column.MAKE: self.make,
|
||||||
Column.MODEL: self.model,
|
Column.MODEL: self.model,
|
||||||
Column.PACKAGE: self.package,
|
Column.PACKAGE: self.package,
|
||||||
|
@ -352,7 +351,7 @@ class CarInfo:
|
||||||
raise Exception(f"This notCar does not have a detail sentence: {CP.carFingerprint}")
|
raise Exception(f"This notCar does not have a detail sentence: {CP.carFingerprint}")
|
||||||
|
|
||||||
def get_column(self, column: Column, star_icon: str, video_icon: str, footnote_tag: str) -> str:
|
def get_column(self, column: Column, star_icon: str, video_icon: str, footnote_tag: str) -> str:
|
||||||
item: Union[str, Star] = self.row[column]
|
item: str | Star = self.row[column]
|
||||||
if isinstance(item, Star):
|
if isinstance(item, Star):
|
||||||
item = star_icon.format(item.value)
|
item = star_icon.format(item.value)
|
||||||
elif column == Column.MODEL and len(self.years):
|
elif column == Column.MODEL and len(self.years):
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import capnp
|
import capnp
|
||||||
import time
|
import time
|
||||||
from typing import Optional, Set
|
|
||||||
|
|
||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
from panda.python.uds import SERVICE_TYPE
|
from panda.python.uds import SERVICE_TYPE
|
||||||
|
@ -20,7 +19,7 @@ def make_tester_present_msg(addr, bus, subaddr=None):
|
||||||
return make_can_msg(addr, bytes(dat), bus)
|
return make_can_msg(addr, bytes(dat), bus)
|
||||||
|
|
||||||
|
|
||||||
def is_tester_present_response(msg: capnp.lib.capnp._DynamicStructReader, subaddr: Optional[int] = None) -> bool:
|
def is_tester_present_response(msg: capnp.lib.capnp._DynamicStructReader, subaddr: int | None = None) -> bool:
|
||||||
# ISO-TP messages are always padded to 8 bytes
|
# ISO-TP messages are always padded to 8 bytes
|
||||||
# tester present response is always a single frame
|
# tester present response is always a single frame
|
||||||
dat_offset = 1 if subaddr is not None else 0
|
dat_offset = 1 if subaddr is not None else 0
|
||||||
|
@ -34,16 +33,16 @@ def is_tester_present_response(msg: capnp.lib.capnp._DynamicStructReader, subadd
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_all_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, bus: int, timeout: float = 1, debug: bool = True) -> Set[EcuAddrBusType]:
|
def get_all_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, bus: int, timeout: float = 1, debug: bool = True) -> set[EcuAddrBusType]:
|
||||||
addr_list = [0x700 + i for i in range(256)] + [0x18da00f1 + (i << 8) for i in range(256)]
|
addr_list = [0x700 + i for i in range(256)] + [0x18da00f1 + (i << 8) for i in range(256)]
|
||||||
queries: Set[EcuAddrBusType] = {(addr, None, bus) for addr in addr_list}
|
queries: set[EcuAddrBusType] = {(addr, None, bus) for addr in addr_list}
|
||||||
responses = queries
|
responses = queries
|
||||||
return get_ecu_addrs(logcan, sendcan, queries, responses, timeout=timeout, debug=debug)
|
return get_ecu_addrs(logcan, sendcan, queries, responses, timeout=timeout, debug=debug)
|
||||||
|
|
||||||
|
|
||||||
def get_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, queries: Set[EcuAddrBusType],
|
def get_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, queries: set[EcuAddrBusType],
|
||||||
responses: Set[EcuAddrBusType], timeout: float = 1, debug: bool = False) -> Set[EcuAddrBusType]:
|
responses: set[EcuAddrBusType], timeout: float = 1, debug: bool = False) -> set[EcuAddrBusType]:
|
||||||
ecu_responses: Set[EcuAddrBusType] = set() # set((addr, subaddr, bus),)
|
ecu_responses: set[EcuAddrBusType] = set() # set((addr, subaddr, bus),)
|
||||||
try:
|
try:
|
||||||
msgs = [make_tester_present_msg(addr, bus, subaddr) for addr, subaddr, bus in queries]
|
msgs = [make_tester_present_msg(addr, bus, subaddr) for addr, subaddr, bus in queries]
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import unittest
|
import unittest
|
||||||
from parameterized import parameterized
|
from parameterized import parameterized
|
||||||
from typing import Dict, Iterable, Optional, Tuple
|
from collections.abc import Iterable
|
||||||
|
|
||||||
import capnp
|
import capnp
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ class TestFordFW(unittest.TestCase):
|
||||||
self.assertIsNone(subaddr, "Unexpected ECU subaddress")
|
self.assertIsNone(subaddr, "Unexpected ECU subaddress")
|
||||||
|
|
||||||
@parameterized.expand(FW_VERSIONS.items())
|
@parameterized.expand(FW_VERSIONS.items())
|
||||||
def test_fw_versions(self, car_model: str, fw_versions: Dict[Tuple[capnp.lib.capnp._EnumModule, int, Optional[int]], Iterable[bytes]]):
|
def test_fw_versions(self, car_model: str, fw_versions: dict[tuple[capnp.lib.capnp._EnumModule, int, int | None], Iterable[bytes]]):
|
||||||
for (ecu, addr, subaddr), fws in fw_versions.items():
|
for (ecu, addr, subaddr), fws in fw_versions.items():
|
||||||
self.assertIn(ecu, ECU_FW_CORE, "Unexpected ECU")
|
self.assertIn(ecu, ECU_FW_CORE, "Unexpected ECU")
|
||||||
self.assertEqual(addr, ECU_ADDRESSES[ecu], "ECU address mismatch")
|
self.assertEqual(addr, ECU_ADDRESSES[ecu], "ECU address mismatch")
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum, StrEnum
|
from enum import Enum, StrEnum
|
||||||
from typing import Dict, List, Union
|
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from openpilot.selfdrive.car import AngleRateLimit, dbc_dict
|
from openpilot.selfdrive.car import AngleRateLimit, dbc_dict
|
||||||
|
@ -59,7 +58,7 @@ class RADAR:
|
||||||
DELPHI_MRR = 'FORD_CADS'
|
DELPHI_MRR = 'FORD_CADS'
|
||||||
|
|
||||||
|
|
||||||
DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict("ford_lincoln_base_pt", RADAR.DELPHI_MRR))
|
DBC: dict[str, dict[str, str]] = defaultdict(lambda: dbc_dict("ford_lincoln_base_pt", RADAR.DELPHI_MRR))
|
||||||
|
|
||||||
# F-150 radar is not yet supported
|
# F-150 radar is not yet supported
|
||||||
DBC[CAR.F_150_MK14] = dbc_dict("ford_lincoln_base_pt", None)
|
DBC[CAR.F_150_MK14] = dbc_dict("ford_lincoln_base_pt", None)
|
||||||
|
@ -87,7 +86,7 @@ class FordCarInfo(CarInfo):
|
||||||
self.car_parts = CarParts([Device.threex, harness])
|
self.car_parts = CarParts([Device.threex, harness])
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = {
|
CAR_INFO: dict[str, CarInfo | list[CarInfo]] = {
|
||||||
CAR.BRONCO_SPORT_MK1: FordCarInfo("Ford Bronco Sport 2021-22"),
|
CAR.BRONCO_SPORT_MK1: FordCarInfo("Ford Bronco Sport 2021-22"),
|
||||||
CAR.ESCAPE_MK4: [
|
CAR.ESCAPE_MK4: [
|
||||||
FordCarInfo("Ford Escape 2020-22"),
|
FordCarInfo("Ford Escape 2020-22"),
|
||||||
|
|
|
@ -3,16 +3,16 @@ import capnp
|
||||||
import copy
|
import copy
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
import struct
|
import struct
|
||||||
from typing import Callable, Dict, List, Optional, Set, Tuple
|
from collections.abc import Callable
|
||||||
|
|
||||||
import panda.python.uds as uds
|
import panda.python.uds as uds
|
||||||
|
|
||||||
AddrType = Tuple[int, Optional[int]]
|
AddrType = tuple[int, int | None]
|
||||||
EcuAddrBusType = Tuple[int, Optional[int], int]
|
EcuAddrBusType = tuple[int, int | None, int]
|
||||||
EcuAddrSubAddr = Tuple[int, int, Optional[int]]
|
EcuAddrSubAddr = tuple[int, int, int | None]
|
||||||
|
|
||||||
LiveFwVersions = Dict[AddrType, Set[bytes]]
|
LiveFwVersions = dict[AddrType, set[bytes]]
|
||||||
OfflineFwVersions = Dict[str, Dict[EcuAddrSubAddr, List[bytes]]]
|
OfflineFwVersions = dict[str, dict[EcuAddrSubAddr, list[bytes]]]
|
||||||
|
|
||||||
# A global list of addresses we will only ever consider for VIN responses
|
# 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
|
# engine, hybrid controller, Ford abs, Hyundai CAN FD cluster, 29-bit engine, PGM-FI
|
||||||
|
@ -71,9 +71,9 @@ class StdQueries:
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Request:
|
class Request:
|
||||||
request: List[bytes]
|
request: list[bytes]
|
||||||
response: List[bytes]
|
response: list[bytes]
|
||||||
whitelist_ecus: List[int] = field(default_factory=list)
|
whitelist_ecus: list[int] = field(default_factory=list)
|
||||||
rx_offset: int = 0x8
|
rx_offset: int = 0x8
|
||||||
bus: int = 1
|
bus: int = 1
|
||||||
# Whether this query should be run on the first auxiliary panda (CAN FD cars for example)
|
# Whether this query should be run on the first auxiliary panda (CAN FD cars for example)
|
||||||
|
@ -86,15 +86,15 @@ class Request:
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FwQueryConfig:
|
class FwQueryConfig:
|
||||||
requests: List[Request]
|
requests: list[Request]
|
||||||
# TODO: make this automatic and remove hardcoded lists, or do fingerprinting with ecus
|
# TODO: make this automatic and remove hardcoded lists, or do fingerprinting with ecus
|
||||||
# Overrides and removes from essential ecus for specific models and ecus (exact matching)
|
# Overrides and removes from essential ecus for specific models and ecus (exact matching)
|
||||||
non_essential_ecus: Dict[capnp.lib.capnp._EnumModule, List[str]] = field(default_factory=dict)
|
non_essential_ecus: dict[capnp.lib.capnp._EnumModule, list[str]] = field(default_factory=dict)
|
||||||
# Ecus added for data collection, not to be fingerprinted on
|
# Ecus added for data collection, not to be fingerprinted on
|
||||||
extra_ecus: List[Tuple[capnp.lib.capnp._EnumModule, int, Optional[int]]] = field(default_factory=list)
|
extra_ecus: list[tuple[capnp.lib.capnp._EnumModule, int, int | None]] = field(default_factory=list)
|
||||||
# Function a brand can implement to provide better fuzzy matching. Takes in FW versions,
|
# Function a brand can implement to provide better fuzzy matching. Takes in FW versions,
|
||||||
# returns set of candidates. Only will match if one candidate is returned
|
# returns set of candidates. Only will match if one candidate is returned
|
||||||
match_fw_to_car_fuzzy: Optional[Callable[[LiveFwVersions, OfflineFwVersions], Set[str]]] = None
|
match_fw_to_car_fuzzy: Callable[[LiveFwVersions, OfflineFwVersions], set[str]] | None = None
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
for i in range(len(self.requests)):
|
for i in range(len(self.requests)):
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import Any, DefaultDict, Dict, Iterator, List, Optional, Set, TypeVar
|
from typing import Any, TypeVar
|
||||||
|
from collections.abc import Iterator
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
import capnp
|
import capnp
|
||||||
|
|
||||||
|
@ -27,19 +28,19 @@ REQUESTS = [(brand, config, r) for brand, config in FW_QUERY_CONFIGS.items() for
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
|
|
||||||
|
|
||||||
def chunks(l: List[T], n: int = 128) -> Iterator[List[T]]:
|
def chunks(l: list[T], n: int = 128) -> Iterator[list[T]]:
|
||||||
for i in range(0, len(l), n):
|
for i in range(0, len(l), n):
|
||||||
yield l[i:i + n]
|
yield l[i:i + n]
|
||||||
|
|
||||||
|
|
||||||
def is_brand(brand: str, filter_brand: Optional[str]) -> bool:
|
def is_brand(brand: str, filter_brand: str | None) -> bool:
|
||||||
"""Returns if brand matches filter_brand or no brand filter is specified"""
|
"""Returns if brand matches filter_brand or no brand filter is specified"""
|
||||||
return filter_brand is None or brand == filter_brand
|
return filter_brand is None or brand == filter_brand
|
||||||
|
|
||||||
|
|
||||||
def build_fw_dict(fw_versions: List[capnp.lib.capnp._DynamicStructBuilder],
|
def build_fw_dict(fw_versions: list[capnp.lib.capnp._DynamicStructBuilder],
|
||||||
filter_brand: Optional[str] = None) -> Dict[AddrType, Set[bytes]]:
|
filter_brand: str | None = None) -> dict[AddrType, set[bytes]]:
|
||||||
fw_versions_dict: DefaultDict[AddrType, Set[bytes]] = defaultdict(set)
|
fw_versions_dict: defaultdict[AddrType, set[bytes]] = defaultdict(set)
|
||||||
for fw in fw_versions:
|
for fw in fw_versions:
|
||||||
if is_brand(fw.brand, filter_brand) and not fw.logging:
|
if is_brand(fw.brand, filter_brand) and not fw.logging:
|
||||||
sub_addr = fw.subAddress if fw.subAddress != 0 else None
|
sub_addr = fw.subAddress if fw.subAddress != 0 else None
|
||||||
|
@ -97,7 +98,7 @@ def match_fw_to_car_fuzzy(live_fw_versions, match_brand=None, log=True, exclude=
|
||||||
return set()
|
return set()
|
||||||
|
|
||||||
|
|
||||||
def match_fw_to_car_exact(live_fw_versions, match_brand=None, log=True, extra_fw_versions=None) -> Set[str]:
|
def match_fw_to_car_exact(live_fw_versions, match_brand=None, log=True, extra_fw_versions=None) -> set[str]:
|
||||||
"""Do an exact FW match. Returns all cars that match the given
|
"""Do an exact FW match. Returns all cars that match the given
|
||||||
FW versions for a list of "essential" ECUs. If an ECU is not considered
|
FW versions for a list of "essential" ECUs. If an ECU is not considered
|
||||||
essential the FW version can be missing to get a fingerprint, but if it's present it
|
essential the FW version can be missing to get a fingerprint, but if it's present it
|
||||||
|
@ -164,11 +165,11 @@ def match_fw_to_car(fw_versions, allow_exact=True, allow_fuzzy=True, log=True):
|
||||||
return True, set()
|
return True, set()
|
||||||
|
|
||||||
|
|
||||||
def get_present_ecus(logcan, sendcan, num_pandas=1) -> Set[EcuAddrBusType]:
|
def get_present_ecus(logcan, sendcan, num_pandas=1) -> set[EcuAddrBusType]:
|
||||||
params = Params()
|
params = Params()
|
||||||
# queries are split by OBD multiplexing mode
|
# queries are split by OBD multiplexing mode
|
||||||
queries: Dict[bool, List[List[EcuAddrBusType]]] = {True: [], False: []}
|
queries: dict[bool, list[list[EcuAddrBusType]]] = {True: [], False: []}
|
||||||
parallel_queries: Dict[bool, List[EcuAddrBusType]] = {True: [], False: []}
|
parallel_queries: dict[bool, list[EcuAddrBusType]] = {True: [], False: []}
|
||||||
responses = set()
|
responses = set()
|
||||||
|
|
||||||
for brand, config, r in REQUESTS:
|
for brand, config, r in REQUESTS:
|
||||||
|
@ -203,7 +204,7 @@ def get_present_ecus(logcan, sendcan, num_pandas=1) -> Set[EcuAddrBusType]:
|
||||||
return ecu_responses
|
return ecu_responses
|
||||||
|
|
||||||
|
|
||||||
def get_brand_ecu_matches(ecu_rx_addrs: Set[EcuAddrBusType]) -> dict[str, set[AddrType]]:
|
def get_brand_ecu_matches(ecu_rx_addrs: set[EcuAddrBusType]) -> dict[str, set[AddrType]]:
|
||||||
"""Returns dictionary of brands and matches with ECUs in their FW versions"""
|
"""Returns dictionary of brands and matches with ECUs in their FW versions"""
|
||||||
|
|
||||||
brand_addrs = {brand: {(addr, subaddr) for _, addr, subaddr in config.get_all_ecus(VERSIONS[brand])} for
|
brand_addrs = {brand: {(addr, subaddr) for _, addr, subaddr in config.get_all_ecus(VERSIONS[brand])} for
|
||||||
|
@ -231,7 +232,7 @@ def set_obd_multiplexing(params: Params, obd_multiplexing: bool):
|
||||||
|
|
||||||
|
|
||||||
def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pandas=1, debug=False, progress=False) -> \
|
def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pandas=1, debug=False, progress=False) -> \
|
||||||
List[capnp.lib.capnp._DynamicStructBuilder]:
|
list[capnp.lib.capnp._DynamicStructBuilder]:
|
||||||
"""Queries for FW versions ordering brands by likelihood, breaks when exact match is found"""
|
"""Queries for FW versions ordering brands by likelihood, breaks when exact match is found"""
|
||||||
|
|
||||||
all_car_fw = []
|
all_car_fw = []
|
||||||
|
@ -254,7 +255,7 @@ def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pand
|
||||||
|
|
||||||
|
|
||||||
def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, num_pandas=1, debug=False, progress=False) -> \
|
def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, num_pandas=1, debug=False, progress=False) -> \
|
||||||
List[capnp.lib.capnp._DynamicStructBuilder]:
|
list[capnp.lib.capnp._DynamicStructBuilder]:
|
||||||
versions = VERSIONS.copy()
|
versions = VERSIONS.copy()
|
||||||
params = Params()
|
params = Params()
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum, StrEnum
|
from enum import Enum, StrEnum
|
||||||
from typing import Dict, List, Union
|
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from openpilot.selfdrive.car import dbc_dict
|
from openpilot.selfdrive.car import dbc_dict
|
||||||
|
@ -98,7 +97,7 @@ class GMCarInfo(CarInfo):
|
||||||
self.footnotes.append(Footnote.OBD_II)
|
self.footnotes.append(Footnote.OBD_II)
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Union[GMCarInfo, List[GMCarInfo]]] = {
|
CAR_INFO: dict[str, GMCarInfo | list[GMCarInfo]] = {
|
||||||
CAR.HOLDEN_ASTRA: GMCarInfo("Holden Astra 2017"),
|
CAR.HOLDEN_ASTRA: GMCarInfo("Holden Astra 2017"),
|
||||||
CAR.VOLT: GMCarInfo("Chevrolet Volt 2017-18", min_enable_speed=0, video_link="https://youtu.be/QeMCN_4TFfQ"),
|
CAR.VOLT: GMCarInfo("Chevrolet Volt 2017-18", min_enable_speed=0, video_link="https://youtu.be/QeMCN_4TFfQ"),
|
||||||
CAR.CADILLAC_ATS: GMCarInfo("Cadillac ATS Premium Performance 2018"),
|
CAR.CADILLAC_ATS: GMCarInfo("Cadillac ATS Premium Performance 2018"),
|
||||||
|
@ -181,7 +180,7 @@ FW_QUERY_CONFIG = FwQueryConfig(
|
||||||
extra_ecus=[(Ecu.fwdCamera, 0x24b, None)],
|
extra_ecus=[(Ecu.fwdCamera, 0x24b, None)],
|
||||||
)
|
)
|
||||||
|
|
||||||
DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict('gm_global_a_powertrain_generated', 'gm_global_a_object', chassis_dbc='gm_global_a_chassis'))
|
DBC: dict[str, dict[str, str]] = defaultdict(lambda: dbc_dict('gm_global_a_powertrain_generated', 'gm_global_a_object', chassis_dbc='gm_global_a_chassis'))
|
||||||
|
|
||||||
EV_CAR = {CAR.VOLT, CAR.BOLT_EUV}
|
EV_CAR = {CAR.VOLT, CAR.BOLT_EUV}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum, IntFlag, StrEnum
|
from enum import Enum, IntFlag, StrEnum
|
||||||
from typing import Dict, List, Optional, Union
|
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from openpilot.common.conversions import Conversions as CV
|
from openpilot.common.conversions import Conversions as CV
|
||||||
|
@ -116,7 +115,7 @@ class HondaCarInfo(CarInfo):
|
||||||
self.car_parts = CarParts.common([CarHarness.nidec])
|
self.car_parts = CarParts.common([CarHarness.nidec])
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Optional[Union[HondaCarInfo, List[HondaCarInfo]]]] = {
|
CAR_INFO: dict[str, HondaCarInfo | list[HondaCarInfo] | None] = {
|
||||||
CAR.ACCORD: [
|
CAR.ACCORD: [
|
||||||
HondaCarInfo("Honda Accord 2018-22", "All", video_link="https://www.youtube.com/watch?v=mrUwlj3Mi58", min_steer_speed=3. * CV.MPH_TO_MS),
|
HondaCarInfo("Honda Accord 2018-22", "All", video_link="https://www.youtube.com/watch?v=mrUwlj3Mi58", min_steer_speed=3. * CV.MPH_TO_MS),
|
||||||
HondaCarInfo("Honda Inspire 2018", "All", min_steer_speed=3. * CV.MPH_TO_MS),
|
HondaCarInfo("Honda Inspire 2018", "All", min_steer_speed=3. * CV.MPH_TO_MS),
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import re
|
import re
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum, IntFlag, StrEnum
|
from enum import Enum, IntFlag, StrEnum
|
||||||
from typing import Dict, List, Optional, Set, Tuple, Union
|
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from panda.python import uds
|
from panda.python import uds
|
||||||
|
@ -157,7 +156,7 @@ class HyundaiCarInfo(CarInfo):
|
||||||
self.footnotes.insert(0, Footnote.CANFD)
|
self.footnotes.insert(0, Footnote.CANFD)
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
|
CAR_INFO: dict[str, HyundaiCarInfo | list[HyundaiCarInfo] | None] = {
|
||||||
CAR.AZERA_6TH_GEN: HyundaiCarInfo("Hyundai Azera 2022", "All", car_parts=CarParts.common([CarHarness.hyundai_k])),
|
CAR.AZERA_6TH_GEN: HyundaiCarInfo("Hyundai Azera 2022", "All", car_parts=CarParts.common([CarHarness.hyundai_k])),
|
||||||
CAR.AZERA_HEV_6TH_GEN: [
|
CAR.AZERA_HEV_6TH_GEN: [
|
||||||
HyundaiCarInfo("Hyundai Azera Hybrid 2019", "All", car_parts=CarParts.common([CarHarness.hyundai_c])),
|
HyundaiCarInfo("Hyundai Azera Hybrid 2019", "All", car_parts=CarParts.common([CarHarness.hyundai_c])),
|
||||||
|
@ -316,7 +315,7 @@ class Buttons:
|
||||||
CANCEL = 4 # on newer models, this is a pause/resume button
|
CANCEL = 4 # on newer models, this is a pause/resume button
|
||||||
|
|
||||||
|
|
||||||
def get_platform_codes(fw_versions: List[bytes]) -> Set[Tuple[bytes, Optional[bytes]]]:
|
def get_platform_codes(fw_versions: list[bytes]) -> set[tuple[bytes, bytes | None]]:
|
||||||
# Returns unique, platform-specific identification codes for a set of versions
|
# Returns unique, platform-specific identification codes for a set of versions
|
||||||
codes = set() # (code-Optional[part], date)
|
codes = set() # (code-Optional[part], date)
|
||||||
for fw in fw_versions:
|
for fw in fw_versions:
|
||||||
|
@ -335,12 +334,12 @@ def get_platform_codes(fw_versions: List[bytes]) -> Set[Tuple[bytes, Optional[by
|
||||||
return codes
|
return codes
|
||||||
|
|
||||||
|
|
||||||
def match_fw_to_car_fuzzy(live_fw_versions, offline_fw_versions) -> Set[str]:
|
def match_fw_to_car_fuzzy(live_fw_versions, offline_fw_versions) -> set[str]:
|
||||||
# Non-electric CAN FD platforms often do not have platform code specifiers needed
|
# Non-electric CAN FD platforms often do not have platform code specifiers needed
|
||||||
# to distinguish between hybrid and ICE. All EVs so far are either exclusively
|
# to distinguish between hybrid and ICE. All EVs so far are either exclusively
|
||||||
# electric or specify electric in the platform code.
|
# electric or specify electric in the platform code.
|
||||||
fuzzy_platform_blacklist = {str(c) for c in (CANFD_CAR - EV_CAR - CANFD_FUZZY_WHITELIST)}
|
fuzzy_platform_blacklist = {str(c) for c in (CANFD_CAR - EV_CAR - CANFD_FUZZY_WHITELIST)}
|
||||||
candidates: Set[str] = set()
|
candidates: set[str] = set()
|
||||||
|
|
||||||
for candidate, fws in offline_fw_versions.items():
|
for candidate, fws in offline_fw_versions.items():
|
||||||
# Keep track of ECUs which pass all checks (platform codes, within date range)
|
# Keep track of ECUs which pass all checks (platform codes, within date range)
|
||||||
|
|
|
@ -4,7 +4,8 @@ import numpy as np
|
||||||
import tomllib
|
import tomllib
|
||||||
from abc import abstractmethod, ABC
|
from abc import abstractmethod, ABC
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
from typing import Any, Dict, Optional, Tuple, List, Callable, NamedTuple, cast
|
from typing import Any, NamedTuple, cast
|
||||||
|
from collections.abc import Callable
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from openpilot.common.basedir import BASEDIR
|
from openpilot.common.basedir import BASEDIR
|
||||||
|
@ -107,7 +108,7 @@ class CarInterfaceBase(ABC):
|
||||||
return cls.get_params(candidate, gen_empty_fingerprint(), list(), False, False)
|
return cls.get_params(candidate, gen_empty_fingerprint(), list(), False, False)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_params(cls, candidate: str, fingerprint: Dict[int, Dict[int, int]], car_fw: List[car.CarParams.CarFw], experimental_long: bool, docs: bool):
|
def get_params(cls, candidate: str, fingerprint: dict[int, dict[int, int]], car_fw: list[car.CarParams.CarFw], experimental_long: bool, docs: bool):
|
||||||
ret = CarInterfaceBase.get_std_params(candidate)
|
ret = CarInterfaceBase.get_std_params(candidate)
|
||||||
|
|
||||||
if hasattr(candidate, "config"):
|
if hasattr(candidate, "config"):
|
||||||
|
@ -131,8 +132,8 @@ class CarInterfaceBase(ABC):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _get_params(ret: car.CarParams, candidate: str, fingerprint: Dict[int, Dict[int, int]],
|
def _get_params(ret: car.CarParams, candidate: str, fingerprint: dict[int, dict[int, int]],
|
||||||
car_fw: List[car.CarParams.CarFw], experimental_long: bool, docs: bool):
|
car_fw: list[car.CarParams.CarFw], experimental_long: bool, docs: bool):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -212,7 +213,7 @@ class CarInterfaceBase(ABC):
|
||||||
def _update(self, c: car.CarControl) -> car.CarState:
|
def _update(self, c: car.CarControl) -> car.CarState:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def update(self, c: car.CarControl, can_strings: List[bytes]) -> car.CarState:
|
def update(self, c: car.CarControl, can_strings: list[bytes]) -> car.CarState:
|
||||||
# parse can
|
# parse can
|
||||||
for cp in self.can_parsers:
|
for cp in self.can_parsers:
|
||||||
if cp is not None:
|
if cp is not None:
|
||||||
|
@ -246,7 +247,7 @@ class CarInterfaceBase(ABC):
|
||||||
return reader
|
return reader
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def apply(self, c: car.CarControl, now_nanos: int) -> Tuple[car.CarControl.Actuators, List[bytes]]:
|
def apply(self, c: car.CarControl, now_nanos: int) -> tuple[car.CarControl.Actuators, list[bytes]]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def create_common_events(self, cs_out, extra_gears=None, pcm_enable=True, allow_enable=True,
|
def create_common_events(self, cs_out, extra_gears=None, pcm_enable=True, allow_enable=True,
|
||||||
|
@ -417,11 +418,11 @@ class CarStateBase(ABC):
|
||||||
return bool(left_blinker_stalk or self.left_blinker_cnt > 0), bool(right_blinker_stalk or self.right_blinker_cnt > 0)
|
return bool(left_blinker_stalk or self.left_blinker_cnt > 0), bool(right_blinker_stalk or self.right_blinker_cnt > 0)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_gear_shifter(gear: Optional[str]) -> car.CarState.GearShifter:
|
def parse_gear_shifter(gear: str | None) -> car.CarState.GearShifter:
|
||||||
if gear is None:
|
if gear is None:
|
||||||
return GearShifter.unknown
|
return GearShifter.unknown
|
||||||
|
|
||||||
d: Dict[str, car.CarState.GearShifter] = {
|
d: dict[str, car.CarState.GearShifter] = {
|
||||||
'P': GearShifter.park, 'PARK': GearShifter.park,
|
'P': GearShifter.park, 'PARK': GearShifter.park,
|
||||||
'R': GearShifter.reverse, 'REVERSE': GearShifter.reverse,
|
'R': GearShifter.reverse, 'REVERSE': GearShifter.reverse,
|
||||||
'N': GearShifter.neutral, 'NEUTRAL': GearShifter.neutral,
|
'N': GearShifter.neutral, 'NEUTRAL': GearShifter.neutral,
|
||||||
|
@ -458,7 +459,7 @@ INTERFACE_ATTR_FILE = {
|
||||||
|
|
||||||
# interface-specific helpers
|
# interface-specific helpers
|
||||||
|
|
||||||
def get_interface_attr(attr: str, combine_brands: bool = False, ignore_none: bool = False) -> Dict[str | StrEnum, Any]:
|
def get_interface_attr(attr: str, combine_brands: bool = False, ignore_none: bool = False) -> dict[str | StrEnum, Any]:
|
||||||
# read all the folders in selfdrive/car and return a dict where:
|
# read all the folders in selfdrive/car and return a dict where:
|
||||||
# - keys are all the car models or brand names
|
# - keys are all the car models or brand names
|
||||||
# - values are attr values from all car folders
|
# - values are attr values from all car folders
|
||||||
|
@ -491,7 +492,7 @@ class NanoFFModel:
|
||||||
self.load_weights(platform)
|
self.load_weights(platform)
|
||||||
|
|
||||||
def load_weights(self, platform: str):
|
def load_weights(self, platform: str):
|
||||||
with open(self.weights_loc, 'r') as fob:
|
with open(self.weights_loc) as fob:
|
||||||
self.weights = {k: np.array(v) for k, v in json.load(fob)[platform].items()}
|
self.weights = {k: np.array(v) for k, v in json.load(fob)[platform].items()}
|
||||||
|
|
||||||
def relu(self, x: np.ndarray):
|
def relu(self, x: np.ndarray):
|
||||||
|
@ -506,7 +507,7 @@ class NanoFFModel:
|
||||||
x = np.dot(x, self.weights['w_4']) + self.weights['b_4']
|
x = np.dot(x, self.weights['w_4']) + self.weights['b_4']
|
||||||
return x
|
return x
|
||||||
|
|
||||||
def predict(self, x: List[float], do_sample: bool = False):
|
def predict(self, x: list[float], do_sample: bool = False):
|
||||||
x = self.forward(np.array(x))
|
x = self.forward(np.array(x))
|
||||||
if do_sample:
|
if do_sample:
|
||||||
pred = np.random.laplace(x[0], np.exp(x[1]) / self.weights['temperature'])
|
pred = np.random.laplace(x[0], np.exp(x[1]) / self.weights['temperature'])
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
from typing import Dict, List, Union
|
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from openpilot.selfdrive.car import dbc_dict
|
from openpilot.selfdrive.car import dbc_dict
|
||||||
|
@ -41,7 +40,7 @@ class MazdaCarInfo(CarInfo):
|
||||||
car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.mazda]))
|
car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.mazda]))
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Union[MazdaCarInfo, List[MazdaCarInfo]]] = {
|
CAR_INFO: dict[str, MazdaCarInfo | list[MazdaCarInfo]] = {
|
||||||
CAR.CX5: MazdaCarInfo("Mazda CX-5 2017-21"),
|
CAR.CX5: MazdaCarInfo("Mazda CX-5 2017-21"),
|
||||||
CAR.CX9: MazdaCarInfo("Mazda CX-9 2016-20"),
|
CAR.CX9: MazdaCarInfo("Mazda CX-9 2016-20"),
|
||||||
CAR.MAZDA3: MazdaCarInfo("Mazda 3 2017-18"),
|
CAR.MAZDA3: MazdaCarInfo("Mazda 3 2017-18"),
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
from typing import Dict, List, Optional, Union
|
|
||||||
|
|
||||||
from openpilot.selfdrive.car.docs_definitions import CarInfo
|
from openpilot.selfdrive.car.docs_definitions import CarInfo
|
||||||
|
|
||||||
|
@ -8,6 +7,6 @@ class CAR(StrEnum):
|
||||||
MOCK = 'mock'
|
MOCK = 'mock'
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Optional[Union[CarInfo, List[CarInfo]]]] = {
|
CAR_INFO: dict[str, CarInfo | list[CarInfo] | None] = {
|
||||||
CAR.MOCK: None,
|
CAR.MOCK: None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
from typing import Dict, List, Optional, Union
|
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from panda.python import uds
|
from panda.python import uds
|
||||||
|
@ -37,7 +36,7 @@ class NissanCarInfo(CarInfo):
|
||||||
car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.nissan_a]))
|
car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.nissan_a]))
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Optional[Union[NissanCarInfo, List[NissanCarInfo]]]] = {
|
CAR_INFO: dict[str, NissanCarInfo | list[NissanCarInfo] | None] = {
|
||||||
CAR.XTRAIL: NissanCarInfo("Nissan X-Trail 2017"),
|
CAR.XTRAIL: NissanCarInfo("Nissan X-Trail 2017"),
|
||||||
CAR.LEAF: NissanCarInfo("Nissan Leaf 2018-23", video_link="https://youtu.be/vaMbtAh_0cY"),
|
CAR.LEAF: NissanCarInfo("Nissan Leaf 2018-23", video_link="https://youtu.be/vaMbtAh_0cY"),
|
||||||
CAR.LEAF_IC: None, # same platforms
|
CAR.LEAF_IC: None, # same platforms
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from enum import Enum, IntFlag
|
from enum import Enum, IntFlag
|
||||||
from typing import List
|
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from panda.python import uds
|
from panda.python import uds
|
||||||
|
@ -81,7 +80,7 @@ class Footnote(Enum):
|
||||||
class SubaruCarInfo(CarInfo):
|
class SubaruCarInfo(CarInfo):
|
||||||
package: str = "EyeSight Driver Assistance"
|
package: str = "EyeSight Driver Assistance"
|
||||||
car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.subaru_a]))
|
car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.subaru_a]))
|
||||||
footnotes: List[Enum] = field(default_factory=lambda: [Footnote.GLOBAL])
|
footnotes: list[Enum] = field(default_factory=lambda: [Footnote.GLOBAL])
|
||||||
|
|
||||||
def init_make(self, CP: car.CarParams):
|
def init_make(self, CP: car.CarParams):
|
||||||
self.car_parts.parts.extend([Tool.socket_8mm_deep, Tool.pry_tool])
|
self.car_parts.parts.extend([Tool.socket_8mm_deep, Tool.pry_tool])
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
from typing import Dict, List, Union
|
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from openpilot.selfdrive.car import AngleRateLimit, dbc_dict
|
from openpilot.selfdrive.car import AngleRateLimit, dbc_dict
|
||||||
|
@ -17,7 +16,7 @@ class CAR(StrEnum):
|
||||||
AP2_MODELS = 'TESLA AP2 MODEL S'
|
AP2_MODELS = 'TESLA AP2 MODEL S'
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = {
|
CAR_INFO: dict[str, CarInfo | list[CarInfo]] = {
|
||||||
CAR.AP1_MODELS: CarInfo("Tesla AP1 Model S", "All"),
|
CAR.AP1_MODELS: CarInfo("Tesla AP1 Model S", "All"),
|
||||||
CAR.AP2_MODELS: CarInfo("Tesla AP2 Model S", "All"),
|
CAR.AP2_MODELS: CarInfo("Tesla AP2 Model S", "All"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from typing import NamedTuple, Optional
|
from typing import NamedTuple
|
||||||
|
|
||||||
from openpilot.selfdrive.car.chrysler.values import CAR as CHRYSLER
|
from openpilot.selfdrive.car.chrysler.values import CAR as CHRYSLER
|
||||||
from openpilot.selfdrive.car.gm.values import CAR as GM
|
from openpilot.selfdrive.car.gm.values import CAR as GM
|
||||||
|
@ -29,8 +29,8 @@ non_tested_cars = [
|
||||||
|
|
||||||
class CarTestRoute(NamedTuple):
|
class CarTestRoute(NamedTuple):
|
||||||
route: str
|
route: str
|
||||||
car_model: Optional[str]
|
car_model: str | None
|
||||||
segment: Optional[int] = None
|
segment: int | None = None
|
||||||
|
|
||||||
|
|
||||||
routes = [
|
routes = [
|
||||||
|
|
|
@ -20,7 +20,7 @@ class TestCarDocs(unittest.TestCase):
|
||||||
|
|
||||||
def test_generator(self):
|
def test_generator(self):
|
||||||
generated_cars_md = generate_cars_md(self.all_cars, CARS_MD_TEMPLATE)
|
generated_cars_md = generate_cars_md(self.all_cars, CARS_MD_TEMPLATE)
|
||||||
with open(CARS_MD_OUT, "r") as f:
|
with open(CARS_MD_OUT) as f:
|
||||||
current_cars_md = f.read()
|
current_cars_md = f.read()
|
||||||
|
|
||||||
self.assertEqual(generated_cars_md, current_cars_md,
|
self.assertEqual(generated_cars_md, current_cars_md,
|
||||||
|
@ -45,7 +45,7 @@ class TestCarDocs(unittest.TestCase):
|
||||||
all_car_info_platforms = get_interface_attr("CAR_INFO", combine_brands=True).keys()
|
all_car_info_platforms = get_interface_attr("CAR_INFO", combine_brands=True).keys()
|
||||||
for platform in sorted(interfaces.keys()):
|
for platform in sorted(interfaces.keys()):
|
||||||
with self.subTest(platform=platform):
|
with self.subTest(platform=platform):
|
||||||
self.assertTrue(platform in all_car_info_platforms, "Platform: {} doesn't exist in CarInfo".format(platform))
|
self.assertTrue(platform in all_car_info_platforms, f"Platform: {platform} doesn't exist in CarInfo")
|
||||||
|
|
||||||
def test_naming_conventions(self):
|
def test_naming_conventions(self):
|
||||||
# Asserts market-standard car naming conventions by brand
|
# Asserts market-standard car naming conventions by brand
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from typing import Dict, List
|
|
||||||
|
|
||||||
from openpilot.common.basedir import BASEDIR
|
from openpilot.common.basedir import BASEDIR
|
||||||
|
|
||||||
|
@ -64,7 +63,7 @@ def check_can_ignition_conflicts(fingerprints, brands):
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
fingerprints = _get_fingerprints()
|
fingerprints = _get_fingerprints()
|
||||||
|
|
||||||
fingerprints_flat: List[Dict] = []
|
fingerprints_flat: list[dict] = []
|
||||||
car_names = []
|
car_names = []
|
||||||
brand_names = []
|
brand_names = []
|
||||||
for brand in fingerprints:
|
for brand in fingerprints:
|
||||||
|
|
|
@ -3,7 +3,6 @@ from collections import defaultdict
|
||||||
import importlib
|
import importlib
|
||||||
from parameterized import parameterized_class
|
from parameterized import parameterized_class
|
||||||
import sys
|
import sys
|
||||||
from typing import DefaultDict, Dict
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from openpilot.common.realtime import DT_CTRL
|
from openpilot.common.realtime import DT_CTRL
|
||||||
|
@ -29,7 +28,7 @@ ABOVE_LIMITS_CARS = [
|
||||||
SUBARU.OUTBACK,
|
SUBARU.OUTBACK,
|
||||||
]
|
]
|
||||||
|
|
||||||
car_model_jerks: DefaultDict[str, Dict[str, float]] = defaultdict(dict)
|
car_model_jerks: defaultdict[str, dict[str, float]] = defaultdict(dict)
|
||||||
|
|
||||||
|
|
||||||
@parameterized_class('car_model', [(c,) for c in sorted(CAR_MODELS)])
|
@parameterized_class('car_model', [(c,) for c in sorted(CAR_MODELS)])
|
||||||
|
|
|
@ -8,7 +8,6 @@ import unittest
|
||||||
from collections import defaultdict, Counter
|
from collections import defaultdict, Counter
|
||||||
import hypothesis.strategies as st
|
import hypothesis.strategies as st
|
||||||
from hypothesis import Phase, given, settings
|
from hypothesis import Phase, given, settings
|
||||||
from typing import List, Optional, Tuple
|
|
||||||
from parameterized import parameterized_class
|
from parameterized import parameterized_class
|
||||||
|
|
||||||
from cereal import messaging, log, car
|
from cereal import messaging, log, car
|
||||||
|
@ -40,7 +39,7 @@ MAX_EXAMPLES = int(os.environ.get("MAX_EXAMPLES", "300"))
|
||||||
CI = os.environ.get("CI", None) is not None
|
CI = os.environ.get("CI", None) is not None
|
||||||
|
|
||||||
|
|
||||||
def get_test_cases() -> List[Tuple[str, Optional[CarTestRoute]]]:
|
def get_test_cases() -> list[tuple[str, CarTestRoute | None]]:
|
||||||
# build list of test cases
|
# build list of test cases
|
||||||
test_cases = []
|
test_cases = []
|
||||||
if not len(INTERNAL_SEG_LIST):
|
if not len(INTERNAL_SEG_LIST):
|
||||||
|
@ -65,14 +64,14 @@ def get_test_cases() -> List[Tuple[str, Optional[CarTestRoute]]]:
|
||||||
@pytest.mark.slow
|
@pytest.mark.slow
|
||||||
@pytest.mark.shared_download_cache
|
@pytest.mark.shared_download_cache
|
||||||
class TestCarModelBase(unittest.TestCase):
|
class TestCarModelBase(unittest.TestCase):
|
||||||
car_model: Optional[str] = None
|
car_model: str | None = None
|
||||||
test_route: Optional[CarTestRoute] = None
|
test_route: CarTestRoute | None = None
|
||||||
test_route_on_bucket: bool = True # whether the route is on the preserved CI bucket
|
test_route_on_bucket: bool = True # whether the route is on the preserved CI bucket
|
||||||
|
|
||||||
can_msgs: List[capnp.lib.capnp._DynamicStructReader]
|
can_msgs: list[capnp.lib.capnp._DynamicStructReader]
|
||||||
fingerprint: dict[int, dict[int, int]]
|
fingerprint: dict[int, dict[int, int]]
|
||||||
elm_frame: Optional[int]
|
elm_frame: int | None
|
||||||
car_safety_mode_frame: Optional[int]
|
car_safety_mode_frame: int | None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_testing_data_from_logreader(cls, lr):
|
def get_testing_data_from_logreader(cls, lr):
|
||||||
|
@ -408,7 +407,7 @@ class TestCarModelBase(unittest.TestCase):
|
||||||
|
|
||||||
controls_allowed_prev = False
|
controls_allowed_prev = False
|
||||||
CS_prev = car.CarState.new_message()
|
CS_prev = car.CarState.new_message()
|
||||||
checks = defaultdict(lambda: 0)
|
checks = defaultdict(int)
|
||||||
controlsd = Controls(CI=self.CI)
|
controlsd = Controls(CI=self.CI)
|
||||||
controlsd.initialized = True
|
controlsd.initialized = True
|
||||||
for idx, can in enumerate(self.can_msgs):
|
for idx, can in enumerate(self.can_msgs):
|
||||||
|
|
|
@ -2,7 +2,6 @@ import re
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from enum import Enum, IntFlag, StrEnum
|
from enum import Enum, IntFlag, StrEnum
|
||||||
from typing import Dict, List, Set, Union
|
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from openpilot.common.conversions import Conversions as CV
|
from openpilot.common.conversions import Conversions as CV
|
||||||
|
@ -100,7 +99,7 @@ class ToyotaCarInfo(CarInfo):
|
||||||
car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.toyota_a]))
|
car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.toyota_a]))
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = {
|
CAR_INFO: dict[str, ToyotaCarInfo | list[ToyotaCarInfo]] = {
|
||||||
# Toyota
|
# Toyota
|
||||||
CAR.ALPHARD_TSS2: [
|
CAR.ALPHARD_TSS2: [
|
||||||
ToyotaCarInfo("Toyota Alphard 2019-20"),
|
ToyotaCarInfo("Toyota Alphard 2019-20"),
|
||||||
|
@ -253,7 +252,7 @@ STATIC_DSU_MSGS = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def get_platform_codes(fw_versions: List[bytes]) -> Dict[bytes, Set[bytes]]:
|
def get_platform_codes(fw_versions: list[bytes]) -> dict[bytes, set[bytes]]:
|
||||||
# Returns sub versions in a dict so comparisons can be made within part-platform-major_version combos
|
# Returns sub versions in a dict so comparisons can be made within part-platform-major_version combos
|
||||||
codes = defaultdict(set) # Optional[part]-platform-major_version: set of sub_version
|
codes = defaultdict(set) # Optional[part]-platform-major_version: set of sub_version
|
||||||
for fw in fw_versions:
|
for fw in fw_versions:
|
||||||
|
@ -297,7 +296,7 @@ def get_platform_codes(fw_versions: List[bytes]) -> Dict[bytes, Set[bytes]]:
|
||||||
return dict(codes)
|
return dict(codes)
|
||||||
|
|
||||||
|
|
||||||
def match_fw_to_car_fuzzy(live_fw_versions, offline_fw_versions) -> Set[str]:
|
def match_fw_to_car_fuzzy(live_fw_versions, offline_fw_versions) -> set[str]:
|
||||||
candidates = set()
|
candidates = set()
|
||||||
|
|
||||||
for candidate, fws in offline_fw_versions.items():
|
for candidate, fws in offline_fw_versions.items():
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from collections import defaultdict, namedtuple
|
from collections import defaultdict, namedtuple
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from enum import Enum, IntFlag, StrEnum
|
from enum import Enum, IntFlag, StrEnum
|
||||||
from typing import Dict, List, Union
|
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from panda.python import uds
|
from panda.python import uds
|
||||||
|
@ -151,7 +150,7 @@ class CAR(StrEnum):
|
||||||
PQ_CARS = {CAR.PASSAT_NMS, CAR.SHARAN_MK2}
|
PQ_CARS = {CAR.PASSAT_NMS, CAR.SHARAN_MK2}
|
||||||
|
|
||||||
|
|
||||||
DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict("vw_mqb_2010", None))
|
DBC: dict[str, dict[str, str]] = defaultdict(lambda: dbc_dict("vw_mqb_2010", None))
|
||||||
for car_type in PQ_CARS:
|
for car_type in PQ_CARS:
|
||||||
DBC[car_type] = dbc_dict("vw_golf_mk4", None)
|
DBC[car_type] = dbc_dict("vw_golf_mk4", None)
|
||||||
|
|
||||||
|
@ -191,7 +190,7 @@ class VWCarInfo(CarInfo):
|
||||||
self.car_parts = CarParts([Device.threex_angled_mount, CarHarness.j533])
|
self.car_parts = CarParts([Device.threex_angled_mount, CarHarness.j533])
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = {
|
CAR_INFO: dict[str, VWCarInfo | list[VWCarInfo]] = {
|
||||||
CAR.ARTEON_MK1: [
|
CAR.ARTEON_MK1: [
|
||||||
VWCarInfo("Volkswagen Arteon 2018-23", video_link="https://youtu.be/FAomFKPFlDA"),
|
VWCarInfo("Volkswagen Arteon 2018-23", video_link="https://youtu.be/FAomFKPFlDA"),
|
||||||
VWCarInfo("Volkswagen Arteon R 2020-23", video_link="https://youtu.be/FAomFKPFlDA"),
|
VWCarInfo("Volkswagen Arteon R 2020-23", video_link="https://youtu.be/FAomFKPFlDA"),
|
||||||
|
|
|
@ -3,7 +3,6 @@ import os
|
||||||
import json
|
import json
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import List, Dict, Optional
|
|
||||||
|
|
||||||
from openpilot.common.basedir import BASEDIR
|
from openpilot.common.basedir import BASEDIR
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
|
@ -14,7 +13,7 @@ with open(os.path.join(BASEDIR, "selfdrive/controls/lib/alerts_offroad.json")) a
|
||||||
OFFROAD_ALERTS = json.load(f)
|
OFFROAD_ALERTS = json.load(f)
|
||||||
|
|
||||||
|
|
||||||
def set_offroad_alert(alert: str, show_alert: bool, extra_text: Optional[str] = None) -> None:
|
def set_offroad_alert(alert: str, show_alert: bool, extra_text: str | None = None) -> None:
|
||||||
if show_alert:
|
if show_alert:
|
||||||
a = copy.copy(OFFROAD_ALERTS[alert])
|
a = copy.copy(OFFROAD_ALERTS[alert])
|
||||||
a['extra'] = extra_text or ''
|
a['extra'] = extra_text or ''
|
||||||
|
@ -25,7 +24,7 @@ def set_offroad_alert(alert: str, show_alert: bool, extra_text: Optional[str] =
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class AlertEntry:
|
class AlertEntry:
|
||||||
alert: Optional[Alert] = None
|
alert: Alert | None = None
|
||||||
start_frame: int = -1
|
start_frame: int = -1
|
||||||
end_frame: int = -1
|
end_frame: int = -1
|
||||||
|
|
||||||
|
@ -34,9 +33,9 @@ class AlertEntry:
|
||||||
|
|
||||||
class AlertManager:
|
class AlertManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.alerts: Dict[str, AlertEntry] = defaultdict(AlertEntry)
|
self.alerts: dict[str, AlertEntry] = defaultdict(AlertEntry)
|
||||||
|
|
||||||
def add_many(self, frame: int, alerts: List[Alert]) -> None:
|
def add_many(self, frame: int, alerts: list[Alert]) -> None:
|
||||||
for alert in alerts:
|
for alert in alerts:
|
||||||
entry = self.alerts[alert.alert_type]
|
entry = self.alerts[alert.alert_type]
|
||||||
entry.alert = alert
|
entry.alert = alert
|
||||||
|
@ -45,7 +44,7 @@ class AlertManager:
|
||||||
min_end_frame = entry.start_frame + alert.duration
|
min_end_frame = entry.start_frame + alert.duration
|
||||||
entry.end_frame = max(frame + 1, min_end_frame)
|
entry.end_frame = max(frame + 1, min_end_frame)
|
||||||
|
|
||||||
def process_alerts(self, frame: int, clear_event_types: set) -> Optional[Alert]:
|
def process_alerts(self, frame: int, clear_event_types: set) -> Alert | None:
|
||||||
current_alert = AlertEntry()
|
current_alert = AlertEntry()
|
||||||
for v in self.alerts.values():
|
for v in self.alerts.values():
|
||||||
if not v.alert:
|
if not v.alert:
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import math
|
import math
|
||||||
import os
|
import os
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from typing import Dict, Union, Callable, List, Optional
|
from collections.abc import Callable
|
||||||
|
|
||||||
from cereal import log, car
|
from cereal import log, car
|
||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
|
@ -48,12 +48,12 @@ EVENT_NAME = {v: k for k, v in EventName.schema.enumerants.items()}
|
||||||
|
|
||||||
class Events:
|
class Events:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.events: List[int] = []
|
self.events: list[int] = []
|
||||||
self.static_events: List[int] = []
|
self.static_events: list[int] = []
|
||||||
self.events_prev = dict.fromkeys(EVENTS.keys(), 0)
|
self.events_prev = dict.fromkeys(EVENTS.keys(), 0)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def names(self) -> List[int]:
|
def names(self) -> list[int]:
|
||||||
return self.events
|
return self.events
|
||||||
|
|
||||||
def __len__(self) -> int:
|
def __len__(self) -> int:
|
||||||
|
@ -71,7 +71,7 @@ class Events:
|
||||||
def contains(self, event_type: str) -> bool:
|
def contains(self, event_type: str) -> bool:
|
||||||
return any(event_type in EVENTS.get(e, {}) for e in self.events)
|
return any(event_type in EVENTS.get(e, {}) for e in self.events)
|
||||||
|
|
||||||
def create_alerts(self, event_types: List[str], callback_args=None):
|
def create_alerts(self, event_types: list[str], callback_args=None):
|
||||||
if callback_args is None:
|
if callback_args is None:
|
||||||
callback_args = []
|
callback_args = []
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ class Alert:
|
||||||
self.creation_delay = creation_delay
|
self.creation_delay = creation_delay
|
||||||
|
|
||||||
self.alert_type = ""
|
self.alert_type = ""
|
||||||
self.event_type: Optional[str] = None
|
self.event_type: str | None = None
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return f"{self.alert_text_1}/{self.alert_text_2} {self.priority} {self.visual_alert} {self.audible_alert}"
|
return f"{self.alert_text_1}/{self.alert_text_2} {self.priority} {self.visual_alert} {self.audible_alert}"
|
||||||
|
@ -333,7 +333,7 @@ def joystick_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
|
EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
|
||||||
# ********** events with no alerts **********
|
# ********** events with no alerts **********
|
||||||
|
|
||||||
EventName.stockFcw: {},
|
EventName.stockFcw: {},
|
||||||
|
@ -965,7 +965,7 @@ if __name__ == '__main__':
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
event_names = {v: k for k, v in EventName.schema.enumerants.items()}
|
event_names = {v: k for k, v in EventName.schema.enumerants.items()}
|
||||||
alerts_by_type: Dict[str, Dict[Priority, List[str]]] = defaultdict(lambda: defaultdict(list))
|
alerts_by_type: dict[str, dict[Priority, list[str]]] = defaultdict(lambda: defaultdict(list))
|
||||||
|
|
||||||
CP = car.CarParams.new_message()
|
CP = car.CarParams.new_message()
|
||||||
CS = car.CarState.new_message()
|
CS = car.CarState.new_message()
|
||||||
|
@ -977,7 +977,7 @@ if __name__ == '__main__':
|
||||||
alert = alert(CP, CS, sm, False, 1)
|
alert = alert(CP, CS, sm, False, 1)
|
||||||
alerts_by_type[et][alert.priority].append(event_names[i])
|
alerts_by_type[et][alert.priority].append(event_names[i])
|
||||||
|
|
||||||
all_alerts: Dict[str, List[tuple[Priority, List[str]]]] = {}
|
all_alerts: dict[str, list[tuple[Priority, list[str]]]] = {}
|
||||||
for et, priority_alerts in alerts_by_type.items():
|
for et, priority_alerts in alerts_by_type.items():
|
||||||
all_alerts[et] = sorted(priority_alerts.items(), key=lambda x: x[0], reverse=True)
|
all_alerts[et] = sorted(priority_alerts.items(), key=lambda x: x[0], reverse=True)
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ x_dot = A*x + B*u
|
||||||
|
|
||||||
A depends on longitudinal speed, u [m/s], and vehicle parameters CP
|
A depends on longitudinal speed, u [m/s], and vehicle parameters CP
|
||||||
"""
|
"""
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from numpy.linalg import solve
|
from numpy.linalg import solve
|
||||||
|
@ -169,7 +168,7 @@ def kin_ss_sol(sa: float, u: float, VM: VehicleModel) -> np.ndarray:
|
||||||
return K * sa
|
return K * sa
|
||||||
|
|
||||||
|
|
||||||
def create_dyn_state_matrices(u: float, VM: VehicleModel) -> Tuple[np.ndarray, np.ndarray]:
|
def create_dyn_state_matrices(u: float, VM: VehicleModel) -> tuple[np.ndarray, np.ndarray]:
|
||||||
"""Returns the A and B matrix for the dynamics system
|
"""Returns the A and B matrix for the dynamics system
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import importlib
|
import importlib
|
||||||
import math
|
import math
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from typing import Optional, Dict, Any
|
from typing import Any, Optional
|
||||||
|
|
||||||
import capnp
|
import capnp
|
||||||
from cereal import messaging, log, car
|
from cereal import messaging, log, car
|
||||||
|
@ -125,7 +125,7 @@ def laplacian_pdf(x: float, mu: float, b: float):
|
||||||
return math.exp(-abs(x-mu)/b)
|
return math.exp(-abs(x-mu)/b)
|
||||||
|
|
||||||
|
|
||||||
def match_vision_to_track(v_ego: float, lead: capnp._DynamicStructReader, tracks: Dict[int, Track]):
|
def match_vision_to_track(v_ego: float, lead: capnp._DynamicStructReader, tracks: dict[int, Track]):
|
||||||
offset_vision_dist = lead.x[0] - RADAR_TO_CAMERA
|
offset_vision_dist = lead.x[0] - RADAR_TO_CAMERA
|
||||||
|
|
||||||
def prob(c):
|
def prob(c):
|
||||||
|
@ -166,8 +166,8 @@ def get_RadarState_from_vision(lead_msg: capnp._DynamicStructReader, v_ego: floa
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_lead(v_ego: float, ready: bool, tracks: Dict[int, Track], lead_msg: capnp._DynamicStructReader,
|
def get_lead(v_ego: float, ready: bool, tracks: dict[int, Track], lead_msg: capnp._DynamicStructReader,
|
||||||
model_v_ego: float, low_speed_override: bool = True) -> Dict[str, Any]:
|
model_v_ego: float, low_speed_override: bool = True) -> dict[str, Any]:
|
||||||
# Determine leads, this is where the essential logic happens
|
# Determine leads, this is where the essential logic happens
|
||||||
if len(tracks) > 0 and ready and lead_msg.prob > .5:
|
if len(tracks) > 0 and ready and lead_msg.prob > .5:
|
||||||
track = match_vision_to_track(v_ego, lead_msg, tracks)
|
track = match_vision_to_track(v_ego, lead_msg, tracks)
|
||||||
|
@ -196,14 +196,14 @@ class RadarD:
|
||||||
def __init__(self, radar_ts: float, delay: int = 0):
|
def __init__(self, radar_ts: float, delay: int = 0):
|
||||||
self.current_time = 0.0
|
self.current_time = 0.0
|
||||||
|
|
||||||
self.tracks: Dict[int, Track] = {}
|
self.tracks: dict[int, Track] = {}
|
||||||
self.kalman_params = KalmanParams(radar_ts)
|
self.kalman_params = KalmanParams(radar_ts)
|
||||||
|
|
||||||
self.v_ego = 0.0
|
self.v_ego = 0.0
|
||||||
self.v_ego_hist = deque([0.0], maxlen=delay+1)
|
self.v_ego_hist = deque([0.0], maxlen=delay+1)
|
||||||
self.last_v_ego_frame = -1
|
self.last_v_ego_frame = -1
|
||||||
|
|
||||||
self.radar_state: Optional[capnp._DynamicStructBuilder] = None
|
self.radar_state: capnp._DynamicStructBuilder | None = None
|
||||||
self.radar_state_valid = False
|
self.radar_state_valid = False
|
||||||
|
|
||||||
self.ready = False
|
self.ready = False
|
||||||
|
|
|
@ -3,7 +3,6 @@ import argparse
|
||||||
import binascii
|
import binascii
|
||||||
import time
|
import time
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
from openpilot.selfdrive.debug.can_table import can_table
|
from openpilot.selfdrive.debug.can_table import can_table
|
||||||
|
@ -96,8 +95,8 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
init_lr: Optional[LogIterable] = None
|
init_lr: LogIterable | None = None
|
||||||
new_lr: Optional[LogIterable] = None
|
new_lr: LogIterable | None = None
|
||||||
|
|
||||||
if args.init:
|
if args.init:
|
||||||
if args.init == '':
|
if args.init == '':
|
||||||
|
|
|
@ -3,7 +3,7 @@ import argparse
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import time
|
import time
|
||||||
from collections import defaultdict, deque
|
from collections import defaultdict, deque
|
||||||
from typing import DefaultDict, Deque, MutableSequence
|
from collections.abc import MutableSequence
|
||||||
|
|
||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@ if __name__ == "__main__":
|
||||||
socket_names = args.socket
|
socket_names = args.socket
|
||||||
sockets = {}
|
sockets = {}
|
||||||
|
|
||||||
rcv_times: DefaultDict[str, MutableSequence[float]] = defaultdict(lambda: deque(maxlen=100))
|
rcv_times: defaultdict[str, MutableSequence[float]] = defaultdict(lambda: deque(maxlen=100))
|
||||||
valids: DefaultDict[str, Deque[bool]] = defaultdict(lambda: deque(maxlen=100))
|
valids: defaultdict[str, deque[bool]] = defaultdict(lambda: deque(maxlen=100))
|
||||||
|
|
||||||
t = time.monotonic()
|
t = time.monotonic()
|
||||||
for name in socket_names:
|
for name in socket_names:
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from typing import Dict
|
|
||||||
|
|
||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
from cereal.services import SERVICE_LIST
|
from cereal.services import SERVICE_LIST
|
||||||
|
@ -10,7 +9,7 @@ TO_CHECK = ['carState']
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
sm = messaging.SubMaster(TO_CHECK)
|
sm = messaging.SubMaster(TO_CHECK)
|
||||||
|
|
||||||
prev_t: Dict[str, float] = {}
|
prev_t: dict[str, float] = {}
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
sm.update()
|
sm.update()
|
||||||
|
|
|
@ -3,13 +3,13 @@
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from typing import DefaultDict, MutableSequence
|
from collections.abc import MutableSequence
|
||||||
from collections import defaultdict, deque
|
from collections import defaultdict, deque
|
||||||
|
|
||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
|
|
||||||
socks = {s: messaging.sub_sock(s, conflate=False) for s in sys.argv[1:]}
|
socks = {s: messaging.sub_sock(s, conflate=False) for s in sys.argv[1:]}
|
||||||
ts: DefaultDict[str, MutableSequence[float]] = defaultdict(lambda: deque(maxlen=100))
|
ts: defaultdict[str, MutableSequence[float]] = defaultdict(lambda: deque(maxlen=100))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
while True:
|
while True:
|
||||||
|
|
|
@ -4,7 +4,7 @@ import math
|
||||||
import datetime
|
import datetime
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
from typing import List, Tuple, cast
|
from typing import cast
|
||||||
|
|
||||||
from cereal.services import SERVICE_LIST
|
from cereal.services import SERVICE_LIST
|
||||||
from openpilot.tools.lib.logreader import LogReader, ReadMode
|
from openpilot.tools.lib.logreader import LogReader, ReadMode
|
||||||
|
@ -15,8 +15,8 @@ if __name__ == "__main__":
|
||||||
cams = [s for s in SERVICE_LIST if s.endswith('CameraState')]
|
cams = [s for s in SERVICE_LIST if s.endswith('CameraState')]
|
||||||
cnt_cameras = dict.fromkeys(cams, 0)
|
cnt_cameras = dict.fromkeys(cams, 0)
|
||||||
|
|
||||||
events: List[Tuple[float, set[str]]] = []
|
events: list[tuple[float, set[str]]] = []
|
||||||
alerts: List[Tuple[float, str]] = []
|
alerts: list[tuple[float, str]] = []
|
||||||
start_time = math.inf
|
start_time = math.inf
|
||||||
end_time = -math.inf
|
end_time = -math.inf
|
||||||
ignition_off = None
|
ignition_off = None
|
||||||
|
|
|
@ -66,12 +66,12 @@ if __name__ == "__main__":
|
||||||
for p in psutil.process_iter():
|
for p in psutil.process_iter():
|
||||||
if p == psutil.Process():
|
if p == psutil.Process():
|
||||||
continue
|
continue
|
||||||
matched = any(l for l in p.cmdline() if any(pn for pn in monitored_proc_names if re.match(r'.*{}.*'.format(pn), l, re.M | re.I)))
|
matched = any(l for l in p.cmdline() if any(pn for pn in monitored_proc_names if re.match(fr'.*{pn}.*', l, re.M | re.I)))
|
||||||
if matched:
|
if matched:
|
||||||
k = ' '.join(p.cmdline())
|
k = ' '.join(p.cmdline())
|
||||||
print('Add monitored proc:', k)
|
print('Add monitored proc:', k)
|
||||||
stats[k] = {'cpu_samples': defaultdict(list), 'min': defaultdict(lambda: None), 'max': defaultdict(lambda: None),
|
stats[k] = {'cpu_samples': defaultdict(list), 'min': defaultdict(lambda: None), 'max': defaultdict(lambda: None),
|
||||||
'avg': defaultdict(lambda: 0.0), 'last_cpu_times': None, 'last_sys_time': None}
|
'avg': defaultdict(float), 'last_cpu_times': None, 'last_sys_time': None}
|
||||||
stats[k]['last_sys_time'] = timer()
|
stats[k]['last_sys_time'] = timer()
|
||||||
stats[k]['last_cpu_times'] = p.cpu_times()
|
stats[k]['last_cpu_times'] = p.cpu_times()
|
||||||
monitored_procs.append(p)
|
monitored_procs.append(p)
|
||||||
|
|
|
@ -67,7 +67,7 @@ def format_brand_fw_versions(brand, extra_fw_versions: None | dict[str, dict[tup
|
||||||
extra_fw_versions = extra_fw_versions or {}
|
extra_fw_versions = extra_fw_versions or {}
|
||||||
|
|
||||||
fingerprints_file = os.path.join(BASEDIR, f"selfdrive/car/{brand}/fingerprints.py")
|
fingerprints_file = os.path.join(BASEDIR, f"selfdrive/car/{brand}/fingerprints.py")
|
||||||
with open(fingerprints_file, "r") as f:
|
with open(fingerprints_file) as f:
|
||||||
comments = [line for line in f.readlines() if line.startswith("#") and "noqa" not in line]
|
comments = [line for line in f.readlines() if line.startswith("#") and "noqa" not in line]
|
||||||
|
|
||||||
with open(fingerprints_file, "w") as f:
|
with open(fingerprints_file, "w") as f:
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
modeld_sock = messaging.sub_sock("modelV2")
|
modeld_sock = messaging.sub_sock("modelV2")
|
||||||
|
|
||||||
last_frame_id = None
|
last_frame_id = None
|
||||||
start_t: Optional[int] = None
|
start_t: int | None = None
|
||||||
frame_cnt = 0
|
frame_cnt = 0
|
||||||
dropped = 0
|
dropped = 0
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ from collections import defaultdict
|
||||||
|
|
||||||
from cereal.messaging import SubMaster
|
from cereal.messaging import SubMaster
|
||||||
from openpilot.common.numpy_fast import mean
|
from openpilot.common.numpy_fast import mean
|
||||||
from typing import Optional, Dict
|
|
||||||
|
|
||||||
def cputime_total(ct):
|
def cputime_total(ct):
|
||||||
return ct.user + ct.nice + ct.system + ct.idle + ct.iowait + ct.irq + ct.softirq
|
return ct.user + ct.nice + ct.system + ct.idle + ct.iowait + ct.irq + ct.softirq
|
||||||
|
@ -42,8 +41,8 @@ if __name__ == "__main__":
|
||||||
total_times = [0.]*8
|
total_times = [0.]*8
|
||||||
busy_times = [0.]*8
|
busy_times = [0.]*8
|
||||||
|
|
||||||
prev_proclog: Optional[capnp._DynamicStructReader] = None
|
prev_proclog: capnp._DynamicStructReader | None = None
|
||||||
prev_proclog_t: Optional[int] = None
|
prev_proclog_t: int | None = None
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
sm.update()
|
sm.update()
|
||||||
|
@ -76,7 +75,7 @@ if __name__ == "__main__":
|
||||||
print(f"CPU {100.0 * mean(cores):.2f}% - RAM: {last_mem:.2f}% - Temp {last_temp:.2f}C")
|
print(f"CPU {100.0 * mean(cores):.2f}% - RAM: {last_mem:.2f}% - Temp {last_temp:.2f}C")
|
||||||
|
|
||||||
if args.cpu and prev_proclog is not None and prev_proclog_t is not None:
|
if args.cpu and prev_proclog is not None and prev_proclog_t is not None:
|
||||||
procs: Dict[str, float] = defaultdict(float)
|
procs: dict[str, float] = defaultdict(float)
|
||||||
dt = (sm.logMonoTime['procLog'] - prev_proclog_t) / 1e9
|
dt = (sm.logMonoTime['procLog'] - prev_proclog_t) / 1e9
|
||||||
for proc in m.procs:
|
for proc in m.procs:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -10,7 +10,7 @@ import gc
|
||||||
import os
|
import os
|
||||||
import capnp
|
import capnp
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from typing import List, NoReturn, Optional
|
from typing import NoReturn
|
||||||
|
|
||||||
from cereal import log
|
from cereal import log
|
||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
|
@ -89,7 +89,7 @@ class Calibrator:
|
||||||
valid_blocks: int = 0,
|
valid_blocks: int = 0,
|
||||||
wide_from_device_euler_init: np.ndarray = WIDE_FROM_DEVICE_EULER_INIT,
|
wide_from_device_euler_init: np.ndarray = WIDE_FROM_DEVICE_EULER_INIT,
|
||||||
height_init: np.ndarray = HEIGHT_INIT,
|
height_init: np.ndarray = HEIGHT_INIT,
|
||||||
smooth_from: Optional[np.ndarray] = None) -> None:
|
smooth_from: np.ndarray | None = None) -> None:
|
||||||
if not np.isfinite(rpy_init).all():
|
if not np.isfinite(rpy_init).all():
|
||||||
self.rpy = RPY_INIT.copy()
|
self.rpy = RPY_INIT.copy()
|
||||||
else:
|
else:
|
||||||
|
@ -125,7 +125,7 @@ class Calibrator:
|
||||||
self.old_rpy = smooth_from
|
self.old_rpy = smooth_from
|
||||||
self.old_rpy_weight = 1.0
|
self.old_rpy_weight = 1.0
|
||||||
|
|
||||||
def get_valid_idxs(self) -> List[int]:
|
def get_valid_idxs(self) -> list[int]:
|
||||||
# exclude current block_idx from validity window
|
# exclude current block_idx from validity window
|
||||||
before_current = list(range(self.block_idx))
|
before_current = list(range(self.block_idx))
|
||||||
after_current = list(range(min(self.valid_blocks, self.block_idx + 1), self.valid_blocks))
|
after_current = list(range(min(self.valid_blocks, self.block_idx + 1), self.valid_blocks))
|
||||||
|
@ -175,12 +175,12 @@ class Calibrator:
|
||||||
else:
|
else:
|
||||||
return self.rpy
|
return self.rpy
|
||||||
|
|
||||||
def handle_cam_odom(self, trans: List[float],
|
def handle_cam_odom(self, trans: list[float],
|
||||||
rot: List[float],
|
rot: list[float],
|
||||||
wide_from_device_euler: List[float],
|
wide_from_device_euler: list[float],
|
||||||
trans_std: List[float],
|
trans_std: list[float],
|
||||||
road_transform_trans: List[float],
|
road_transform_trans: list[float],
|
||||||
road_transform_trans_std: List[float]) -> Optional[np.ndarray]:
|
road_transform_trans_std: list[float]) -> np.ndarray | None:
|
||||||
self.old_rpy_weight = max(0.0, self.old_rpy_weight - 1/SMOOTH_CYCLES)
|
self.old_rpy_weight = max(0.0, self.old_rpy_weight - 1/SMOOTH_CYCLES)
|
||||||
|
|
||||||
straight_and_fast = ((self.v_ego > MIN_SPEED_FILTER) and (trans[0] > MIN_SPEED_FILTER) and (abs(rot[2]) < MAX_YAW_RATE_FILTER))
|
straight_and_fast = ((self.v_ego > MIN_SPEED_FILTER) and (trans[0] > MIN_SPEED_FILTER) and (abs(rot[2]) < MAX_YAW_RATE_FILTER))
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from typing import List, Optional, Tuple, Any
|
from typing import Any
|
||||||
|
|
||||||
from cereal import log
|
from cereal import log
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ class NPQueue:
|
||||||
def __len__(self) -> int:
|
def __len__(self) -> int:
|
||||||
return len(self.arr)
|
return len(self.arr)
|
||||||
|
|
||||||
def append(self, pt: List[float]) -> None:
|
def append(self, pt: list[float]) -> None:
|
||||||
if len(self.arr) < self.maxlen:
|
if len(self.arr) < self.maxlen:
|
||||||
self.arr = np.append(self.arr, [pt], axis=0)
|
self.arr = np.append(self.arr, [pt], axis=0)
|
||||||
else:
|
else:
|
||||||
|
@ -21,7 +21,7 @@ class NPQueue:
|
||||||
|
|
||||||
|
|
||||||
class PointBuckets:
|
class PointBuckets:
|
||||||
def __init__(self, x_bounds: List[Tuple[float, float]], min_points: List[float], min_points_total: int, points_per_bucket: int, rowsize: int) -> None:
|
def __init__(self, x_bounds: list[tuple[float, float]], min_points: list[float], min_points_total: int, points_per_bucket: int, rowsize: int) -> None:
|
||||||
self.x_bounds = x_bounds
|
self.x_bounds = x_bounds
|
||||||
self.buckets = {bounds: NPQueue(maxlen=points_per_bucket, rowsize=rowsize) for bounds in x_bounds}
|
self.buckets = {bounds: NPQueue(maxlen=points_per_bucket, rowsize=rowsize) for bounds in x_bounds}
|
||||||
self.buckets_min_points = dict(zip(x_bounds, min_points, strict=True))
|
self.buckets_min_points = dict(zip(x_bounds, min_points, strict=True))
|
||||||
|
@ -41,13 +41,13 @@ class PointBuckets:
|
||||||
def add_point(self, x: float, y: float, bucket_val: float) -> None:
|
def add_point(self, x: float, y: float, bucket_val: float) -> None:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def get_points(self, num_points: Optional[int] = None) -> Any:
|
def get_points(self, num_points: int | None = None) -> Any:
|
||||||
points = np.vstack([x.arr for x in self.buckets.values()])
|
points = np.vstack([x.arr for x in self.buckets.values()])
|
||||||
if num_points is None:
|
if num_points is None:
|
||||||
return points
|
return points
|
||||||
return points[np.random.choice(np.arange(len(points)), min(len(points), num_points), replace=False)]
|
return points[np.random.choice(np.arange(len(points)), min(len(points), num_points), replace=False)]
|
||||||
|
|
||||||
def load_points(self, points: List[List[float]]) -> None:
|
def load_points(self, points: list[list[float]]) -> None:
|
||||||
for point in points:
|
for point in points:
|
||||||
self.add_point(*point)
|
self.add_point(*point)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import math
|
import math
|
||||||
import sys
|
import sys
|
||||||
from typing import Any, Dict
|
from typing import Any
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ class CarKalman(KalmanFilter):
|
||||||
])
|
])
|
||||||
P_initial = Q.copy()
|
P_initial = Q.copy()
|
||||||
|
|
||||||
obs_noise: Dict[int, Any] = {
|
obs_noise: dict[int, Any] = {
|
||||||
ObservationKind.STEER_ANGLE: np.atleast_2d(math.radians(0.05)**2),
|
ObservationKind.STEER_ANGLE: np.atleast_2d(math.radians(0.05)**2),
|
||||||
ObservationKind.ANGLE_OFFSET_FAST: np.atleast_2d(math.radians(10.0)**2),
|
ObservationKind.ANGLE_OFFSET_FAST: np.atleast_2d(math.radians(10.0)**2),
|
||||||
ObservationKind.ROAD_ROLL: np.atleast_2d(math.radians(1.0)**2),
|
ObservationKind.ROAD_ROLL: np.atleast_2d(math.radians(1.0)**2),
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List
|
|
||||||
|
|
||||||
# NOTE: Do NOT import anything here that needs be built (e.g. params)
|
# NOTE: Do NOT import anything here that needs be built (e.g. params)
|
||||||
from openpilot.common.basedir import BASEDIR
|
from openpilot.common.basedir import BASEDIR
|
||||||
|
@ -29,7 +28,7 @@ def build(spinner: Spinner, dirty: bool = False, minimal: bool = False) -> None:
|
||||||
|
|
||||||
# building with all cores can result in using too
|
# building with all cores can result in using too
|
||||||
# much memory, so retry with less parallelism
|
# much memory, so retry with less parallelism
|
||||||
compile_output: List[bytes] = []
|
compile_output: list[bytes] = []
|
||||||
for n in (nproc, nproc/2, 1):
|
for n in (nproc, nproc/2, 1):
|
||||||
compile_output.clear()
|
compile_output.clear()
|
||||||
scons: subprocess.Popen = subprocess.Popen(["scons", f"-j{int(n)}", "--cache-populate", *extra_args], cwd=BASEDIR, env=env, stderr=subprocess.PIPE)
|
scons: subprocess.Popen = subprocess.Popen(["scons", f"-j{int(n)}", "--cache-populate", *extra_args], cwd=BASEDIR, env=env, stderr=subprocess.PIPE)
|
||||||
|
|
|
@ -4,7 +4,6 @@ import os
|
||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
from typing import List, Tuple, Union
|
|
||||||
|
|
||||||
from cereal import log
|
from cereal import log
|
||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
|
@ -33,7 +32,7 @@ def manager_init() -> None:
|
||||||
if is_release_branch():
|
if is_release_branch():
|
||||||
params.clear_all(ParamKeyType.DEVELOPMENT_ONLY)
|
params.clear_all(ParamKeyType.DEVELOPMENT_ONLY)
|
||||||
|
|
||||||
default_params: List[Tuple[str, Union[str, bytes]]] = [
|
default_params: list[tuple[str, str | bytes]] = [
|
||||||
("CompletedTrainingVersion", "0"),
|
("CompletedTrainingVersion", "0"),
|
||||||
("DisengageOnAccelerator", "0"),
|
("DisengageOnAccelerator", "0"),
|
||||||
("GsmMetered", "1"),
|
("GsmMetered", "1"),
|
||||||
|
@ -121,7 +120,7 @@ def manager_thread() -> None:
|
||||||
|
|
||||||
params = Params()
|
params = Params()
|
||||||
|
|
||||||
ignore: List[str] = []
|
ignore: list[str] = []
|
||||||
if params.get("DongleId", encoding='utf8') in (None, UNREGISTERED_DONGLE_ID):
|
if params.get("DongleId", encoding='utf8') in (None, UNREGISTERED_DONGLE_ID):
|
||||||
ignore += ["manage_athenad", "uploader"]
|
ignore += ["manage_athenad", "uploader"]
|
||||||
if os.getenv("NOBOARD") is not None:
|
if os.getenv("NOBOARD") is not None:
|
||||||
|
@ -154,7 +153,7 @@ def manager_thread() -> None:
|
||||||
|
|
||||||
ensure_running(managed_processes.values(), started, params=params, CP=sm['carParams'], not_run=ignore)
|
ensure_running(managed_processes.values(), started, params=params, CP=sm['carParams'], not_run=ignore)
|
||||||
|
|
||||||
running = ' '.join("%s%s\u001b[0m" % ("\u001b[32m" if p.proc.is_alive() else "\u001b[31m", p.name)
|
running = ' '.join("{}{}\u001b[0m".format("\u001b[32m" if p.proc.is_alive() else "\u001b[31m", p.name)
|
||||||
for p in managed_processes.values() if p.proc)
|
for p in managed_processes.values() if p.proc)
|
||||||
print(running)
|
print(running)
|
||||||
cloudlog.debug(running)
|
cloudlog.debug(running)
|
||||||
|
|
|
@ -4,7 +4,7 @@ import signal
|
||||||
import struct
|
import struct
|
||||||
import time
|
import time
|
||||||
import subprocess
|
import subprocess
|
||||||
from typing import Optional, Callable, List, ValuesView
|
from collections.abc import Callable, ValuesView
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from multiprocessing import Process
|
from multiprocessing import Process
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ def launcher(proc: str, name: str) -> None:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def nativelauncher(pargs: List[str], cwd: str, name: str) -> None:
|
def nativelauncher(pargs: list[str], cwd: str, name: str) -> None:
|
||||||
os.environ['MANAGER_DAEMON'] = name
|
os.environ['MANAGER_DAEMON'] = name
|
||||||
|
|
||||||
# exec the process
|
# exec the process
|
||||||
|
@ -67,12 +67,12 @@ class ManagerProcess(ABC):
|
||||||
daemon = False
|
daemon = False
|
||||||
sigkill = False
|
sigkill = False
|
||||||
should_run: Callable[[bool, Params, car.CarParams], bool]
|
should_run: Callable[[bool, Params, car.CarParams], bool]
|
||||||
proc: Optional[Process] = None
|
proc: Process | None = None
|
||||||
enabled = True
|
enabled = True
|
||||||
name = ""
|
name = ""
|
||||||
|
|
||||||
last_watchdog_time = 0
|
last_watchdog_time = 0
|
||||||
watchdog_max_dt: Optional[int] = None
|
watchdog_max_dt: int | None = None
|
||||||
watchdog_seen = False
|
watchdog_seen = False
|
||||||
shutting_down = False
|
shutting_down = False
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ class ManagerProcess(ABC):
|
||||||
else:
|
else:
|
||||||
self.watchdog_seen = True
|
self.watchdog_seen = True
|
||||||
|
|
||||||
def stop(self, retry: bool = True, block: bool = True, sig: Optional[signal.Signals] = None) -> Optional[int]:
|
def stop(self, retry: bool = True, block: bool = True, sig: signal.Signals | None = None) -> int | None:
|
||||||
if self.proc is None:
|
if self.proc is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -274,7 +274,7 @@ class DaemonProcess(ManagerProcess):
|
||||||
|
|
||||||
|
|
||||||
def ensure_running(procs: ValuesView[ManagerProcess], started: bool, params=None, CP: car.CarParams=None,
|
def ensure_running(procs: ValuesView[ManagerProcess], started: bool, params=None, CP: car.CarParams=None,
|
||||||
not_run: Optional[List[str]]=None) -> List[ManagerProcess]:
|
not_run: list[str] | None=None) -> list[ManagerProcess]:
|
||||||
if not_run is None:
|
if not_run is None:
|
||||||
not_run = []
|
not_run = []
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import time
|
||||||
import ctypes
|
import ctypes
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Tuple, Dict
|
|
||||||
|
|
||||||
from cereal import messaging
|
from cereal import messaging
|
||||||
from cereal.messaging import PubMaster, SubMaster
|
from cereal.messaging import PubMaster, SubMaster
|
||||||
|
@ -53,7 +52,7 @@ class DMonitoringModelResult(ctypes.Structure):
|
||||||
("wheel_on_right_prob", ctypes.c_float)]
|
("wheel_on_right_prob", ctypes.c_float)]
|
||||||
|
|
||||||
class ModelState:
|
class ModelState:
|
||||||
inputs: Dict[str, np.ndarray]
|
inputs: dict[str, np.ndarray]
|
||||||
output: np.ndarray
|
output: np.ndarray
|
||||||
model: ModelRunner
|
model: ModelRunner
|
||||||
|
|
||||||
|
@ -68,7 +67,7 @@ class ModelState:
|
||||||
self.model.addInput("input_img", None)
|
self.model.addInput("input_img", None)
|
||||||
self.model.addInput("calib", self.inputs['calib'])
|
self.model.addInput("calib", self.inputs['calib'])
|
||||||
|
|
||||||
def run(self, buf:VisionBuf, calib:np.ndarray) -> Tuple[np.ndarray, float]:
|
def run(self, buf:VisionBuf, calib:np.ndarray) -> tuple[np.ndarray, float]:
|
||||||
self.inputs['calib'][:] = calib
|
self.inputs['calib'][:] = calib
|
||||||
|
|
||||||
v_offset = buf.height - MODEL_HEIGHT
|
v_offset = buf.height - MODEL_HEIGHT
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import capnp
|
import capnp
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from typing import Dict
|
|
||||||
from cereal import log
|
from cereal import log
|
||||||
from openpilot.selfdrive.modeld.constants import ModelConstants, Plan, Meta
|
from openpilot.selfdrive.modeld.constants import ModelConstants, Plan, Meta
|
||||||
|
|
||||||
|
@ -42,7 +41,7 @@ def fill_xyvat(builder, t, x, y, v, a, x_std=None, y_std=None, v_std=None, a_std
|
||||||
if a_std is not None:
|
if a_std is not None:
|
||||||
builder.aStd = a_std.tolist()
|
builder.aStd = a_std.tolist()
|
||||||
|
|
||||||
def fill_model_msg(msg: capnp._DynamicStructBuilder, net_output_data: Dict[str, np.ndarray], publish_state: PublishState,
|
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,
|
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,
|
timestamp_eof: int, timestamp_llk: int, model_execution_time: float,
|
||||||
nav_enabled: bool, valid: bool) -> None:
|
nav_enabled: bool, valid: bool) -> None:
|
||||||
|
@ -174,7 +173,7 @@ def fill_model_msg(msg: capnp._DynamicStructBuilder, net_output_data: Dict[str,
|
||||||
if SEND_RAW_PRED:
|
if SEND_RAW_PRED:
|
||||||
modelV2.rawPredictions = net_output_data['raw_pred'].tobytes()
|
modelV2.rawPredictions = net_output_data['raw_pred'].tobytes()
|
||||||
|
|
||||||
def fill_pose_msg(msg: capnp._DynamicStructBuilder, net_output_data: Dict[str, np.ndarray],
|
def fill_pose_msg(msg: capnp._DynamicStructBuilder, net_output_data: dict[str, np.ndarray],
|
||||||
vipc_frame_id: int, vipc_dropped_frames: int, timestamp_eof: int, live_calib_seen: bool) -> None:
|
vipc_frame_id: int, vipc_dropped_frames: int, timestamp_eof: int, live_calib_seen: bool) -> None:
|
||||||
msg.valid = live_calib_seen & (vipc_dropped_frames < 1)
|
msg.valid = live_calib_seen & (vipc_dropped_frames < 1)
|
||||||
cameraOdometry = msg.cameraOdometry
|
cameraOdometry = msg.cameraOdometry
|
||||||
|
|
|
@ -4,9 +4,8 @@ import pathlib
|
||||||
import onnx
|
import onnx
|
||||||
import codecs
|
import codecs
|
||||||
import pickle
|
import pickle
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
def get_name_and_shape(value_info:onnx.ValueInfoProto) -> Tuple[str, Tuple[int,...]]:
|
def get_name_and_shape(value_info:onnx.ValueInfoProto) -> tuple[str, tuple[int,...]]:
|
||||||
shape = tuple([int(dim.dim_value) for dim in value_info.type.tensor_type.shape.dim])
|
shape = tuple([int(dim.dim_value) for dim in value_info.type.tensor_type.shape.dim])
|
||||||
name = value_info.name
|
name = value_info.name
|
||||||
return name, shape
|
return name, shape
|
||||||
|
|
|
@ -6,7 +6,6 @@ import numpy as np
|
||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
from cereal import car, log
|
from cereal import car, log
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Optional
|
|
||||||
from setproctitle import setproctitle
|
from setproctitle import setproctitle
|
||||||
from cereal.messaging import PubMaster, SubMaster
|
from cereal.messaging import PubMaster, SubMaster
|
||||||
from cereal.visionipc import VisionIpcClient, VisionStreamType, VisionBuf
|
from cereal.visionipc import VisionIpcClient, VisionStreamType, VisionBuf
|
||||||
|
@ -45,7 +44,7 @@ class FrameMeta:
|
||||||
class ModelState:
|
class ModelState:
|
||||||
frame: ModelFrame
|
frame: ModelFrame
|
||||||
wide_frame: ModelFrame
|
wide_frame: ModelFrame
|
||||||
inputs: Dict[str, np.ndarray]
|
inputs: dict[str, np.ndarray]
|
||||||
output: np.ndarray
|
output: np.ndarray
|
||||||
prev_desire: np.ndarray # for tracking the rising edge of the pulse
|
prev_desire: np.ndarray # for tracking the rising edge of the pulse
|
||||||
model: ModelRunner
|
model: ModelRunner
|
||||||
|
@ -78,14 +77,14 @@ class ModelState:
|
||||||
for k,v in self.inputs.items():
|
for k,v in self.inputs.items():
|
||||||
self.model.addInput(k, v)
|
self.model.addInput(k, v)
|
||||||
|
|
||||||
def slice_outputs(self, model_outputs: np.ndarray) -> Dict[str, np.ndarray]:
|
def slice_outputs(self, model_outputs: np.ndarray) -> dict[str, np.ndarray]:
|
||||||
parsed_model_outputs = {k: model_outputs[np.newaxis, v] for k,v in self.output_slices.items()}
|
parsed_model_outputs = {k: model_outputs[np.newaxis, v] for k,v in self.output_slices.items()}
|
||||||
if SEND_RAW_PRED:
|
if SEND_RAW_PRED:
|
||||||
parsed_model_outputs['raw_pred'] = model_outputs.copy()
|
parsed_model_outputs['raw_pred'] = model_outputs.copy()
|
||||||
return parsed_model_outputs
|
return parsed_model_outputs
|
||||||
|
|
||||||
def run(self, buf: VisionBuf, wbuf: VisionBuf, transform: np.ndarray, transform_wide: np.ndarray,
|
def run(self, buf: VisionBuf, wbuf: VisionBuf, transform: np.ndarray, transform_wide: np.ndarray,
|
||||||
inputs: Dict[str, np.ndarray], prepare_only: bool) -> Optional[Dict[str, np.ndarray]]:
|
inputs: dict[str, np.ndarray], prepare_only: bool) -> dict[str, np.ndarray] | None:
|
||||||
# Model decides when action is completed, so desire input is just a pulse triggered on rising edge
|
# Model decides when action is completed, so desire input is just a pulse triggered on rising edge
|
||||||
inputs['desire'][0] = 0
|
inputs['desire'][0] = 0
|
||||||
self.inputs['desire'][:-ModelConstants.DESIRE_LEN] = self.inputs['desire'][ModelConstants.DESIRE_LEN:]
|
self.inputs['desire'][:-ModelConstants.DESIRE_LEN] = self.inputs['desire'][ModelConstants.DESIRE_LEN:]
|
||||||
|
@ -276,7 +275,7 @@ def main(demo=False):
|
||||||
if prepare_only:
|
if prepare_only:
|
||||||
cloudlog.error(f"skipping model eval. Dropped {vipc_dropped_frames} frames")
|
cloudlog.error(f"skipping model eval. Dropped {vipc_dropped_frames} frames")
|
||||||
|
|
||||||
inputs:Dict[str, np.ndarray] = {
|
inputs:dict[str, np.ndarray] = {
|
||||||
'desire': vec_desire,
|
'desire': vec_desire,
|
||||||
'traffic_convention': traffic_convention,
|
'traffic_convention': traffic_convention,
|
||||||
'lateral_control_params': lateral_control_params,
|
'lateral_control_params': lateral_control_params,
|
||||||
|
|
|
@ -5,7 +5,6 @@ import time
|
||||||
import ctypes
|
import ctypes
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Tuple, Dict
|
|
||||||
|
|
||||||
from cereal import messaging
|
from cereal import messaging
|
||||||
from cereal.messaging import PubMaster, SubMaster
|
from cereal.messaging import PubMaster, SubMaster
|
||||||
|
@ -41,7 +40,7 @@ class NavModelResult(ctypes.Structure):
|
||||||
("features", ctypes.c_float*NAV_FEATURE_LEN)]
|
("features", ctypes.c_float*NAV_FEATURE_LEN)]
|
||||||
|
|
||||||
class ModelState:
|
class ModelState:
|
||||||
inputs: Dict[str, np.ndarray]
|
inputs: dict[str, np.ndarray]
|
||||||
output: np.ndarray
|
output: np.ndarray
|
||||||
model: ModelRunner
|
model: ModelRunner
|
||||||
|
|
||||||
|
@ -52,7 +51,7 @@ class ModelState:
|
||||||
self.model = ModelRunner(MODEL_PATHS, self.output, Runtime.DSP, True, None)
|
self.model = ModelRunner(MODEL_PATHS, self.output, Runtime.DSP, True, None)
|
||||||
self.model.addInput("input_img", None)
|
self.model.addInput("input_img", None)
|
||||||
|
|
||||||
def run(self, buf:np.ndarray) -> Tuple[np.ndarray, float]:
|
def run(self, buf:np.ndarray) -> tuple[np.ndarray, float]:
|
||||||
self.inputs['input_img'][:] = buf
|
self.inputs['input_img'][:] = buf
|
||||||
|
|
||||||
t1 = time.perf_counter()
|
t1 = time.perf_counter()
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from typing import Dict
|
|
||||||
from openpilot.selfdrive.modeld.constants import ModelConstants
|
from openpilot.selfdrive.modeld.constants import ModelConstants
|
||||||
|
|
||||||
def sigmoid(x):
|
def sigmoid(x):
|
||||||
|
@ -82,7 +81,7 @@ class Parser:
|
||||||
outs[name] = pred_mu_final.reshape(final_shape)
|
outs[name] = pred_mu_final.reshape(final_shape)
|
||||||
outs[name + '_stds'] = pred_std_final.reshape(final_shape)
|
outs[name + '_stds'] = pred_std_final.reshape(final_shape)
|
||||||
|
|
||||||
def parse_outputs(self, outs: Dict[str, np.ndarray]) -> Dict[str, np.ndarray]:
|
def parse_outputs(self, outs: dict[str, np.ndarray]) -> dict[str, np.ndarray]:
|
||||||
self.parse_mdn('plan', outs, in_N=ModelConstants.PLAN_MHP_N, out_N=ModelConstants.PLAN_MHP_SELECTION,
|
self.parse_mdn('plan', outs, in_N=ModelConstants.PLAN_MHP_N, out_N=ModelConstants.PLAN_MHP_SELECTION,
|
||||||
out_shape=(ModelConstants.IDX_N,ModelConstants.PLAN_WIDTH))
|
out_shape=(ModelConstants.IDX_N,ModelConstants.PLAN_WIDTH))
|
||||||
self.parse_mdn('lane_lines', outs, in_N=0, out_N=0, out_shape=(ModelConstants.NUM_LANE_LINES,ModelConstants.IDX_N,ModelConstants.LANE_LINES_WIDTH))
|
self.parse_mdn('lane_lines', outs, in_N=0, out_N=0, out_shape=(ModelConstants.NUM_LANE_LINES,ModelConstants.IDX_N,ModelConstants.LANE_LINES_WIDTH))
|
||||||
|
|
|
@ -3,7 +3,7 @@ import itertools
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from typing import Tuple, Dict, Union, Any
|
from typing import Any
|
||||||
|
|
||||||
from openpilot.selfdrive.modeld.runners.runmodel_pyx import RunModel
|
from openpilot.selfdrive.modeld.runners.runmodel_pyx import RunModel
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ def create_ort_session(path, fp16_to_fp32):
|
||||||
options = ort.SessionOptions()
|
options = ort.SessionOptions()
|
||||||
options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_DISABLE_ALL
|
options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_DISABLE_ALL
|
||||||
|
|
||||||
provider: Union[str, Tuple[str, Dict[Any, Any]]]
|
provider: str | tuple[str, dict[Any, Any]]
|
||||||
if 'OpenVINOExecutionProvider' in ort.get_available_providers() and 'ONNXCPU' not in os.environ:
|
if 'OpenVINOExecutionProvider' in ort.get_available_providers() and 'ONNXCPU' not in os.environ:
|
||||||
provider = 'OpenVINOExecutionProvider'
|
provider = 'OpenVINOExecutionProvider'
|
||||||
elif 'CUDAExecutionProvider' in ort.get_available_providers() and 'ONNXCPU' not in os.environ:
|
elif 'CUDAExecutionProvider' in ort.get_available_providers() and 'ONNXCPU' not in os.environ:
|
||||||
|
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import math
|
import math
|
||||||
from typing import Any, Dict, List, Optional, Tuple, Union, cast
|
from typing import Any, cast
|
||||||
|
|
||||||
from openpilot.common.conversions import Conversions
|
from openpilot.common.conversions import Conversions
|
||||||
from openpilot.common.numpy_fast import clip
|
from openpilot.common.numpy_fast import clip
|
||||||
|
@ -22,13 +22,13 @@ class Coordinate:
|
||||||
def __init__(self, latitude: float, longitude: float) -> None:
|
def __init__(self, latitude: float, longitude: float) -> None:
|
||||||
self.latitude = latitude
|
self.latitude = latitude
|
||||||
self.longitude = longitude
|
self.longitude = longitude
|
||||||
self.annotations: Dict[str, float] = {}
|
self.annotations: dict[str, float] = {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_mapbox_tuple(cls, t: Tuple[float, float]) -> Coordinate:
|
def from_mapbox_tuple(cls, t: tuple[float, float]) -> Coordinate:
|
||||||
return cls(t[1], t[0])
|
return cls(t[1], t[0])
|
||||||
|
|
||||||
def as_dict(self) -> Dict[str, float]:
|
def as_dict(self) -> dict[str, float]:
|
||||||
return {'latitude': self.latitude, 'longitude': self.longitude}
|
return {'latitude': self.latitude, 'longitude': self.longitude}
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
|
@ -83,7 +83,7 @@ def minimum_distance(a: Coordinate, b: Coordinate, p: Coordinate):
|
||||||
return projection.distance_to(p)
|
return projection.distance_to(p)
|
||||||
|
|
||||||
|
|
||||||
def distance_along_geometry(geometry: List[Coordinate], pos: Coordinate) -> float:
|
def distance_along_geometry(geometry: list[Coordinate], pos: Coordinate) -> float:
|
||||||
if len(geometry) <= 2:
|
if len(geometry) <= 2:
|
||||||
return geometry[0].distance_to(pos)
|
return geometry[0].distance_to(pos)
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ def distance_along_geometry(geometry: List[Coordinate], pos: Coordinate) -> floa
|
||||||
return total_distance_closest
|
return total_distance_closest
|
||||||
|
|
||||||
|
|
||||||
def coordinate_from_param(param: str, params: Optional[Params] = None) -> Optional[Coordinate]:
|
def coordinate_from_param(param: str, params: Params | None = None) -> Coordinate | None:
|
||||||
if params is None:
|
if params is None:
|
||||||
params = Params()
|
params = Params()
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ def string_to_direction(direction: str) -> str:
|
||||||
return 'none'
|
return 'none'
|
||||||
|
|
||||||
|
|
||||||
def maxspeed_to_ms(maxspeed: Dict[str, Union[str, float]]) -> float:
|
def maxspeed_to_ms(maxspeed: dict[str, str | float]) -> float:
|
||||||
unit = cast(str, maxspeed['unit'])
|
unit = cast(str, maxspeed['unit'])
|
||||||
speed = cast(float, maxspeed['speed'])
|
speed = cast(float, maxspeed['speed'])
|
||||||
return SPEED_CONVERSIONS[unit] * speed
|
return SPEED_CONVERSIONS[unit] * speed
|
||||||
|
@ -140,7 +140,7 @@ def field_valid(dat: dict, field: str) -> bool:
|
||||||
return field in dat and dat[field] is not None
|
return field in dat and dat[field] is not None
|
||||||
|
|
||||||
|
|
||||||
def parse_banner_instructions(banners: Any, distance_to_maneuver: float = 0.0) -> Optional[Dict[str, Any]]:
|
def parse_banner_instructions(banners: Any, distance_to_maneuver: float = 0.0) -> dict[str, Any] | None:
|
||||||
if not len(banners):
|
if not len(banners):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import NoReturn, Union, List, Dict
|
from typing import NoReturn
|
||||||
|
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
from cereal.messaging import SubMaster
|
from cereal.messaging import SubMaster
|
||||||
|
@ -61,7 +61,7 @@ class StatLog:
|
||||||
|
|
||||||
def main() -> NoReturn:
|
def main() -> NoReturn:
|
||||||
dongle_id = Params().get("DongleId", encoding='utf-8')
|
dongle_id = Params().get("DongleId", encoding='utf-8')
|
||||||
def get_influxdb_line(measurement: str, value: Union[float, Dict[str, float]], timestamp: datetime, tags: dict) -> str:
|
def get_influxdb_line(measurement: str, value: float | dict[str, float], timestamp: datetime, tags: dict) -> str:
|
||||||
res = f"{measurement}"
|
res = f"{measurement}"
|
||||||
for k, v in tags.items():
|
for k, v in tags.items():
|
||||||
res += f",{k}={str(v)}"
|
res += f",{k}={str(v)}"
|
||||||
|
@ -102,7 +102,7 @@ def main() -> NoReturn:
|
||||||
idx = 0
|
idx = 0
|
||||||
last_flush_time = time.monotonic()
|
last_flush_time = time.monotonic()
|
||||||
gauges = {}
|
gauges = {}
|
||||||
samples: Dict[str, List[float]] = defaultdict(list)
|
samples: dict[str, list[float]] = defaultdict(list)
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
started_prev = sm['deviceState'].started
|
started_prev = sm['deviceState'].started
|
||||||
|
|
|
@ -11,7 +11,7 @@ from openpilot.selfdrive.ui.qt.python_helpers import set_main_window
|
||||||
|
|
||||||
class Window(QWidget):
|
class Window(QWidget):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(Window, self).__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
||||||
layout = QVBoxLayout()
|
layout = QVBoxLayout()
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
@ -47,7 +47,7 @@ class Window(QWidget):
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
for cmd, label in self.labels.items():
|
for cmd, label in self.labels.items():
|
||||||
out = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
out = subprocess.run(cmd, capture_output=True,
|
||||||
shell=True, check=False, encoding='utf8').stdout
|
shell=True, check=False, encoding='utf8').stdout
|
||||||
label.setText(out.strip())
|
label.setText(out.strip())
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import capnp
|
import capnp
|
||||||
import hypothesis.strategies as st
|
import hypothesis.strategies as st
|
||||||
from typing import Any, Callable, Dict, List, Optional, Union
|
from typing import Any
|
||||||
|
from collections.abc import Callable
|
||||||
|
|
||||||
from cereal import log
|
from cereal import log
|
||||||
|
|
||||||
|
@ -12,7 +13,7 @@ class FuzzyGenerator:
|
||||||
self.draw = draw
|
self.draw = draw
|
||||||
self.real_floats = real_floats
|
self.real_floats = real_floats
|
||||||
|
|
||||||
def generate_native_type(self, field: str) -> st.SearchStrategy[Union[bool, int, float, str, bytes]]:
|
def generate_native_type(self, field: str) -> st.SearchStrategy[bool | int | float | str | bytes]:
|
||||||
def floats(**kwargs) -> st.SearchStrategy[float]:
|
def floats(**kwargs) -> st.SearchStrategy[float]:
|
||||||
allow_nan = not self.real_floats
|
allow_nan = not self.real_floats
|
||||||
allow_infinity = not self.real_floats
|
allow_infinity = not self.real_floats
|
||||||
|
@ -67,18 +68,18 @@ class FuzzyGenerator:
|
||||||
else:
|
else:
|
||||||
return self.generate_struct(field.schema)
|
return self.generate_struct(field.schema)
|
||||||
|
|
||||||
def generate_struct(self, schema: capnp.lib.capnp._StructSchema, event: Optional[str] = None) -> st.SearchStrategy[Dict[str, Any]]:
|
def generate_struct(self, schema: capnp.lib.capnp._StructSchema, event: str | None = None) -> st.SearchStrategy[dict[str, Any]]:
|
||||||
full_fill: List[str] = list(schema.non_union_fields)
|
full_fill: list[str] = list(schema.non_union_fields)
|
||||||
single_fill: List[str] = [event] if event else [self.draw(st.sampled_from(schema.union_fields))] if schema.union_fields else []
|
single_fill: list[str] = [event] if event else [self.draw(st.sampled_from(schema.union_fields))] if schema.union_fields else []
|
||||||
return st.fixed_dictionaries({field: self.generate_field(schema.fields[field]) for field in full_fill + single_fill})
|
return st.fixed_dictionaries({field: self.generate_field(schema.fields[field]) for field in full_fill + single_fill})
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_random_msg(cls, draw: DrawType, struct: capnp.lib.capnp._StructModule, real_floats: bool = False) -> Dict[str, Any]:
|
def get_random_msg(cls, draw: DrawType, struct: capnp.lib.capnp._StructModule, real_floats: bool = False) -> dict[str, Any]:
|
||||||
fg = cls(draw, real_floats=real_floats)
|
fg = cls(draw, real_floats=real_floats)
|
||||||
data: Dict[str, Any] = draw(fg.generate_struct(struct.schema))
|
data: dict[str, Any] = draw(fg.generate_struct(struct.schema))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_random_event_msg(cls, draw: DrawType, events: List[str], real_floats: bool = False) -> List[Dict[str, Any]]:
|
def get_random_event_msg(cls, draw: DrawType, events: list[str], real_floats: bool = False) -> list[dict[str, Any]]:
|
||||||
fg = cls(draw, real_floats=real_floats)
|
fg = cls(draw, real_floats=real_floats)
|
||||||
return [draw(fg.generate_struct(log.Event.schema, e)) for e in sorted(events)]
|
return [draw(fg.generate_struct(log.Event.schema, e)) for e in sorted(events)]
|
||||||
|
|
|
@ -72,7 +72,7 @@ def noop(*args, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
def read_segment_list(segment_list_path):
|
def read_segment_list(segment_list_path):
|
||||||
with open(segment_list_path, "r") as f:
|
with open(segment_list_path) as f:
|
||||||
seg_list = f.read().splitlines()
|
seg_list = f.read().splitlines()
|
||||||
|
|
||||||
return [(platform[2:], segment) for platform, segment in zip(seg_list[::2], seg_list[1::2], strict=True)]
|
return [(platform[2:], segment) for platform, segment in zip(seg_list[::2], seg_list[1::2], strict=True)]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from typing import Tuple, no_type_check
|
from typing import no_type_check
|
||||||
|
|
||||||
class FdRedirect:
|
class FdRedirect:
|
||||||
def __init__(self, file_prefix: str, fd: int):
|
def __init__(self, file_prefix: str, fd: int):
|
||||||
|
@ -53,7 +53,7 @@ class ProcessOutputCapture:
|
||||||
self.stdout_redirect.link()
|
self.stdout_redirect.link()
|
||||||
self.stderr_redirect.link()
|
self.stderr_redirect.link()
|
||||||
|
|
||||||
def read_outerr(self) -> Tuple[str, str]:
|
def read_outerr(self) -> tuple[str, str]:
|
||||||
out_str = self.stdout_redirect.read().decode()
|
out_str = self.stdout_redirect.read().decode()
|
||||||
err_str = self.stderr_redirect.read().decode()
|
err_str = self.stderr_redirect.read().decode()
|
||||||
return out_str, err_str
|
return out_str, err_str
|
||||||
|
|
|
@ -5,7 +5,6 @@ import capnp
|
||||||
import numbers
|
import numbers
|
||||||
import dictdiffer
|
import dictdiffer
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from typing import Dict
|
|
||||||
|
|
||||||
from openpilot.tools.lib.logreader import LogReader
|
from openpilot.tools.lib.logreader import LogReader
|
||||||
|
|
||||||
|
@ -97,7 +96,7 @@ def format_process_diff(diff):
|
||||||
diff_short += f" {diff}\n"
|
diff_short += f" {diff}\n"
|
||||||
diff_long += f"\t{diff}\n"
|
diff_long += f"\t{diff}\n"
|
||||||
else:
|
else:
|
||||||
cnt: Dict[str, int] = {}
|
cnt: dict[str, int] = {}
|
||||||
for d in diff:
|
for d in diff:
|
||||||
diff_long += f"\t{str(d)}\n"
|
diff_long += f"\t{str(d)}\n"
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,8 @@ import signal
|
||||||
import platform
|
import platform
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Dict, List, Optional, Callable, Union, Any, Iterable, Tuple
|
from typing import Any
|
||||||
|
from collections.abc import Callable, Iterable
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
import capnp
|
import capnp
|
||||||
|
|
||||||
|
@ -36,9 +37,9 @@ FAKEDATA = os.path.join(PROC_REPLAY_DIR, "fakedata/")
|
||||||
|
|
||||||
class DummySocket:
|
class DummySocket:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.data: List[bytes] = []
|
self.data: list[bytes] = []
|
||||||
|
|
||||||
def receive(self, non_blocking: bool = False) -> Optional[bytes]:
|
def receive(self, non_blocking: bool = False) -> bytes | None:
|
||||||
if non_blocking:
|
if non_blocking:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -128,21 +129,21 @@ class ReplayContext:
|
||||||
@dataclass
|
@dataclass
|
||||||
class ProcessConfig:
|
class ProcessConfig:
|
||||||
proc_name: str
|
proc_name: str
|
||||||
pubs: List[str]
|
pubs: list[str]
|
||||||
subs: List[str]
|
subs: list[str]
|
||||||
ignore: List[str]
|
ignore: list[str]
|
||||||
config_callback: Optional[Callable] = None
|
config_callback: Callable | None = None
|
||||||
init_callback: Optional[Callable] = None
|
init_callback: Callable | None = None
|
||||||
should_recv_callback: Optional[Callable] = None
|
should_recv_callback: Callable | None = None
|
||||||
tolerance: Optional[float] = None
|
tolerance: float | None = None
|
||||||
processing_time: float = 0.001
|
processing_time: float = 0.001
|
||||||
timeout: int = 30
|
timeout: int = 30
|
||||||
simulation: bool = True
|
simulation: bool = True
|
||||||
main_pub: Optional[str] = None
|
main_pub: str | None = None
|
||||||
main_pub_drained: bool = True
|
main_pub_drained: bool = True
|
||||||
vision_pubs: List[str] = field(default_factory=list)
|
vision_pubs: list[str] = field(default_factory=list)
|
||||||
ignore_alive_pubs: List[str] = field(default_factory=list)
|
ignore_alive_pubs: list[str] = field(default_factory=list)
|
||||||
unlocked_pubs: List[str] = field(default_factory=list)
|
unlocked_pubs: list[str] = field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
class ProcessContainer:
|
class ProcessContainer:
|
||||||
|
@ -150,25 +151,25 @@ class ProcessContainer:
|
||||||
self.prefix = OpenpilotPrefix(clean_dirs_on_exit=False)
|
self.prefix = OpenpilotPrefix(clean_dirs_on_exit=False)
|
||||||
self.cfg = copy.deepcopy(cfg)
|
self.cfg = copy.deepcopy(cfg)
|
||||||
self.process = copy.deepcopy(managed_processes[cfg.proc_name])
|
self.process = copy.deepcopy(managed_processes[cfg.proc_name])
|
||||||
self.msg_queue: List[capnp._DynamicStructReader] = []
|
self.msg_queue: list[capnp._DynamicStructReader] = []
|
||||||
self.cnt = 0
|
self.cnt = 0
|
||||||
self.pm: Optional[messaging.PubMaster] = None
|
self.pm: messaging.PubMaster | None = None
|
||||||
self.sockets: Optional[List[messaging.SubSocket]] = None
|
self.sockets: list[messaging.SubSocket] | None = None
|
||||||
self.rc: Optional[ReplayContext] = None
|
self.rc: ReplayContext | None = None
|
||||||
self.vipc_server: Optional[VisionIpcServer] = None
|
self.vipc_server: VisionIpcServer | None = None
|
||||||
self.environ_config: Optional[Dict[str, Any]] = None
|
self.environ_config: dict[str, Any] | None = None
|
||||||
self.capture: Optional[ProcessOutputCapture] = None
|
self.capture: ProcessOutputCapture | None = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def has_empty_queue(self) -> bool:
|
def has_empty_queue(self) -> bool:
|
||||||
return len(self.msg_queue) == 0
|
return len(self.msg_queue) == 0
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pubs(self) -> List[str]:
|
def pubs(self) -> list[str]:
|
||||||
return self.cfg.pubs
|
return self.cfg.pubs
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def subs(self) -> List[str]:
|
def subs(self) -> list[str]:
|
||||||
return self.cfg.subs
|
return self.cfg.subs
|
||||||
|
|
||||||
def _clean_env(self):
|
def _clean_env(self):
|
||||||
|
@ -180,7 +181,7 @@ class ProcessContainer:
|
||||||
if k in os.environ:
|
if k in os.environ:
|
||||||
del os.environ[k]
|
del os.environ[k]
|
||||||
|
|
||||||
def _setup_env(self, params_config: Dict[str, Any], environ_config: Dict[str, Any]):
|
def _setup_env(self, params_config: dict[str, Any], environ_config: dict[str, Any]):
|
||||||
for k, v in environ_config.items():
|
for k, v in environ_config.items():
|
||||||
if len(v) != 0:
|
if len(v) != 0:
|
||||||
os.environ[k] = v
|
os.environ[k] = v
|
||||||
|
@ -202,7 +203,7 @@ class ProcessContainer:
|
||||||
|
|
||||||
self.environ_config = environ_config
|
self.environ_config = environ_config
|
||||||
|
|
||||||
def _setup_vision_ipc(self, all_msgs: LogIterable, frs: Dict[str, Any]):
|
def _setup_vision_ipc(self, all_msgs: LogIterable, frs: dict[str, Any]):
|
||||||
assert len(self.cfg.vision_pubs) != 0
|
assert len(self.cfg.vision_pubs) != 0
|
||||||
|
|
||||||
vipc_server = VisionIpcServer("camerad")
|
vipc_server = VisionIpcServer("camerad")
|
||||||
|
@ -223,9 +224,9 @@ class ProcessContainer:
|
||||||
self.process.start()
|
self.process.start()
|
||||||
|
|
||||||
def start(
|
def start(
|
||||||
self, params_config: Dict[str, Any], environ_config: Dict[str, Any],
|
self, params_config: dict[str, Any], environ_config: dict[str, Any],
|
||||||
all_msgs: LogIterable, frs: Optional[Dict[str, BaseFrameReader]],
|
all_msgs: LogIterable, frs: dict[str, BaseFrameReader] | None,
|
||||||
fingerprint: Optional[str], capture_output: bool
|
fingerprint: str | None, capture_output: bool
|
||||||
):
|
):
|
||||||
with self.prefix as p:
|
with self.prefix as p:
|
||||||
self._setup_env(params_config, environ_config)
|
self._setup_env(params_config, environ_config)
|
||||||
|
@ -266,7 +267,7 @@ class ProcessContainer:
|
||||||
self.prefix.clean_dirs()
|
self.prefix.clean_dirs()
|
||||||
self._clean_env()
|
self._clean_env()
|
||||||
|
|
||||||
def run_step(self, msg: capnp._DynamicStructReader, frs: Optional[Dict[str, BaseFrameReader]]) -> List[capnp._DynamicStructReader]:
|
def run_step(self, msg: capnp._DynamicStructReader, frs: dict[str, BaseFrameReader] | None) -> list[capnp._DynamicStructReader]:
|
||||||
assert self.rc and self.pm and self.sockets and self.process.proc
|
assert self.rc and self.pm and self.sockets and self.process.proc
|
||||||
|
|
||||||
output_msgs = []
|
output_msgs = []
|
||||||
|
@ -580,7 +581,7 @@ def get_process_config(name: str) -> ProcessConfig:
|
||||||
raise Exception(f"Cannot find process config with name: {name}") from ex
|
raise Exception(f"Cannot find process config with name: {name}") from ex
|
||||||
|
|
||||||
|
|
||||||
def get_custom_params_from_lr(lr: LogIterable, initial_state: str = "first") -> Dict[str, Any]:
|
def get_custom_params_from_lr(lr: LogIterable, initial_state: str = "first") -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Use this to get custom params dict based on provided logs.
|
Use this to get custom params dict based on provided logs.
|
||||||
Useful when replaying following processes: calibrationd, paramsd, torqued
|
Useful when replaying following processes: calibrationd, paramsd, torqued
|
||||||
|
@ -614,7 +615,7 @@ def get_custom_params_from_lr(lr: LogIterable, initial_state: str = "first") ->
|
||||||
return custom_params
|
return custom_params
|
||||||
|
|
||||||
|
|
||||||
def replay_process_with_name(name: Union[str, Iterable[str]], lr: LogIterable, *args, **kwargs) -> List[capnp._DynamicStructReader]:
|
def replay_process_with_name(name: str | Iterable[str], lr: LogIterable, *args, **kwargs) -> list[capnp._DynamicStructReader]:
|
||||||
if isinstance(name, str):
|
if isinstance(name, str):
|
||||||
cfgs = [get_process_config(name)]
|
cfgs = [get_process_config(name)]
|
||||||
elif isinstance(name, Iterable):
|
elif isinstance(name, Iterable):
|
||||||
|
@ -626,10 +627,10 @@ def replay_process_with_name(name: Union[str, Iterable[str]], lr: LogIterable, *
|
||||||
|
|
||||||
|
|
||||||
def replay_process(
|
def replay_process(
|
||||||
cfg: Union[ProcessConfig, Iterable[ProcessConfig]], lr: LogIterable, frs: Optional[Dict[str, BaseFrameReader]] = None,
|
cfg: ProcessConfig | Iterable[ProcessConfig], lr: LogIterable, frs: dict[str, BaseFrameReader] | None = None,
|
||||||
fingerprint: Optional[str] = None, return_all_logs: bool = False, custom_params: Optional[Dict[str, Any]] = None,
|
fingerprint: str | None = None, return_all_logs: bool = False, custom_params: dict[str, Any] | None = None,
|
||||||
captured_output_store: Optional[Dict[str, Dict[str, str]]] = None, disable_progress: bool = False
|
captured_output_store: dict[str, dict[str, str]] | None = None, disable_progress: bool = False
|
||||||
) -> List[capnp._DynamicStructReader]:
|
) -> list[capnp._DynamicStructReader]:
|
||||||
if isinstance(cfg, Iterable):
|
if isinstance(cfg, Iterable):
|
||||||
cfgs = list(cfg)
|
cfgs = list(cfg)
|
||||||
else:
|
else:
|
||||||
|
@ -654,9 +655,9 @@ def replay_process(
|
||||||
|
|
||||||
|
|
||||||
def _replay_multi_process(
|
def _replay_multi_process(
|
||||||
cfgs: List[ProcessConfig], lr: LogIterable, frs: Optional[Dict[str, BaseFrameReader]], fingerprint: Optional[str],
|
cfgs: list[ProcessConfig], lr: LogIterable, frs: dict[str, BaseFrameReader] | None, fingerprint: str | None,
|
||||||
custom_params: Optional[Dict[str, Any]], captured_output_store: Optional[Dict[str, Dict[str, str]]], disable_progress: bool
|
custom_params: dict[str, Any] | None, captured_output_store: dict[str, dict[str, str]] | None, disable_progress: bool
|
||||||
) -> List[capnp._DynamicStructReader]:
|
) -> list[capnp._DynamicStructReader]:
|
||||||
if fingerprint is not None:
|
if fingerprint is not None:
|
||||||
params_config = generate_params_config(lr=lr, fingerprint=fingerprint, custom_params=custom_params)
|
params_config = generate_params_config(lr=lr, fingerprint=fingerprint, custom_params=custom_params)
|
||||||
env_config = generate_environ_config(fingerprint=fingerprint)
|
env_config = generate_environ_config(fingerprint=fingerprint)
|
||||||
|
@ -690,10 +691,10 @@ def _replay_multi_process(
|
||||||
|
|
||||||
pub_msgs = [msg for msg in all_msgs if msg.which() in lr_pubs]
|
pub_msgs = [msg for msg in all_msgs if msg.which() in lr_pubs]
|
||||||
# external queue for messages taken from logs; internal queue for messages generated by processes, which will be republished
|
# external queue for messages taken from logs; internal queue for messages generated by processes, which will be republished
|
||||||
external_pub_queue: List[capnp._DynamicStructReader] = pub_msgs.copy()
|
external_pub_queue: list[capnp._DynamicStructReader] = pub_msgs.copy()
|
||||||
internal_pub_queue: List[capnp._DynamicStructReader] = []
|
internal_pub_queue: list[capnp._DynamicStructReader] = []
|
||||||
# heap for maintaining the order of messages generated by processes, where each element: (logMonoTime, index in internal_pub_queue)
|
# heap for maintaining the order of messages generated by processes, where each element: (logMonoTime, index in internal_pub_queue)
|
||||||
internal_pub_index_heap: List[Tuple[int, int]] = []
|
internal_pub_index_heap: list[tuple[int, int]] = []
|
||||||
|
|
||||||
pbar = tqdm(total=len(external_pub_queue), disable=disable_progress)
|
pbar = tqdm(total=len(external_pub_queue), disable=disable_progress)
|
||||||
while len(external_pub_queue) != 0 or (len(internal_pub_index_heap) != 0 and not all(c.has_empty_queue for c in containers)):
|
while len(external_pub_queue) != 0 or (len(internal_pub_index_heap) != 0 and not all(c.has_empty_queue for c in containers)):
|
||||||
|
@ -723,7 +724,7 @@ def _replay_multi_process(
|
||||||
return log_msgs
|
return log_msgs
|
||||||
|
|
||||||
|
|
||||||
def generate_params_config(lr=None, CP=None, fingerprint=None, custom_params=None) -> Dict[str, Any]:
|
def generate_params_config(lr=None, CP=None, fingerprint=None, custom_params=None) -> dict[str, Any]:
|
||||||
params_dict = {
|
params_dict = {
|
||||||
"OpenpilotEnabledToggle": True,
|
"OpenpilotEnabledToggle": True,
|
||||||
"DisengageOnAccelerator": True,
|
"DisengageOnAccelerator": True,
|
||||||
|
@ -755,7 +756,7 @@ def generate_params_config(lr=None, CP=None, fingerprint=None, custom_params=Non
|
||||||
return params_dict
|
return params_dict
|
||||||
|
|
||||||
|
|
||||||
def generate_environ_config(CP=None, fingerprint=None, log_dir=None) -> Dict[str, Any]:
|
def generate_environ_config(CP=None, fingerprint=None, log_dir=None) -> dict[str, Any]:
|
||||||
environ_dict = {}
|
environ_dict = {}
|
||||||
if platform.system() != "Darwin":
|
if platform.system() != "Darwin":
|
||||||
environ_dict["PARAMS_ROOT"] = "/dev/shm/params"
|
environ_dict["PARAMS_ROOT"] = "/dev/shm/params"
|
||||||
|
|
|
@ -5,7 +5,8 @@ import time
|
||||||
import capnp
|
import capnp
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from typing import Union, Iterable, Optional, List, Any, Dict, Tuple
|
from typing import Any
|
||||||
|
from collections.abc import Iterable
|
||||||
|
|
||||||
from openpilot.selfdrive.test.process_replay.process_replay import CONFIGS, FAKEDATA, ProcessConfig, replay_process, get_process_config, \
|
from openpilot.selfdrive.test.process_replay.process_replay import CONFIGS, FAKEDATA, ProcessConfig, replay_process, get_process_config, \
|
||||||
check_openpilot_enabled, get_custom_params_from_lr
|
check_openpilot_enabled, get_custom_params_from_lr
|
||||||
|
@ -40,9 +41,9 @@ class DummyFrameReader(BaseFrameReader):
|
||||||
|
|
||||||
|
|
||||||
def regen_segment(
|
def regen_segment(
|
||||||
lr: LogIterable, frs: Optional[Dict[str, Any]] = None,
|
lr: LogIterable, frs: dict[str, Any] | None = None,
|
||||||
processes: Iterable[ProcessConfig] = CONFIGS, disable_tqdm: bool = False
|
processes: Iterable[ProcessConfig] = CONFIGS, disable_tqdm: bool = False
|
||||||
) -> List[capnp._DynamicStructReader]:
|
) -> list[capnp._DynamicStructReader]:
|
||||||
all_msgs = sorted(lr, key=lambda m: m.logMonoTime)
|
all_msgs = sorted(lr, key=lambda m: m.logMonoTime)
|
||||||
custom_params = get_custom_params_from_lr(all_msgs)
|
custom_params = get_custom_params_from_lr(all_msgs)
|
||||||
|
|
||||||
|
@ -57,7 +58,7 @@ def regen_segment(
|
||||||
def setup_data_readers(
|
def setup_data_readers(
|
||||||
route: str, sidx: int, use_route_meta: bool,
|
route: str, sidx: int, use_route_meta: bool,
|
||||||
needs_driver_cam: bool = True, needs_road_cam: bool = True, dummy_driver_cam: bool = False
|
needs_driver_cam: bool = True, needs_road_cam: bool = True, dummy_driver_cam: bool = False
|
||||||
) -> Tuple[LogReader, Dict[str, Any]]:
|
) -> tuple[LogReader, dict[str, Any]]:
|
||||||
if use_route_meta:
|
if use_route_meta:
|
||||||
r = Route(route)
|
r = Route(route)
|
||||||
lr = LogReader(r.log_paths()[sidx])
|
lr = LogReader(r.log_paths()[sidx])
|
||||||
|
@ -92,7 +93,7 @@ def setup_data_readers(
|
||||||
|
|
||||||
|
|
||||||
def regen_and_save(
|
def regen_and_save(
|
||||||
route: str, sidx: int, processes: Union[str, Iterable[str]] = "all", outdir: str = FAKEDATA,
|
route: str, sidx: int, processes: str | Iterable[str] = "all", outdir: str = FAKEDATA,
|
||||||
upload: bool = False, use_route_meta: bool = False, disable_tqdm: bool = False, dummy_driver_cam: bool = False
|
upload: bool = False, use_route_meta: bool = False, disable_tqdm: bool = False, dummy_driver_cam: bool = False
|
||||||
) -> str:
|
) -> str:
|
||||||
if not isinstance(processes, str) and not hasattr(processes, "__iter__"):
|
if not isinstance(processes, str) and not hasattr(processes, "__iter__"):
|
||||||
|
|
|
@ -30,7 +30,7 @@ def get_frame_fn(ref_commit, test_route, tici=True):
|
||||||
|
|
||||||
|
|
||||||
def bzip_frames(frames):
|
def bzip_frames(frames):
|
||||||
data = bytes()
|
data = b''
|
||||||
for y, u, v in frames:
|
for y, u, v in frames:
|
||||||
data += y.tobytes()
|
data += y.tobytes()
|
||||||
data += u.tobytes()
|
data += u.tobytes()
|
||||||
|
|
|
@ -5,7 +5,7 @@ import os
|
||||||
import sys
|
import sys
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from typing import Any, DefaultDict, Dict
|
from typing import Any
|
||||||
|
|
||||||
from openpilot.selfdrive.car.car_helpers import interface_names
|
from openpilot.selfdrive.car.car_helpers import interface_names
|
||||||
from openpilot.tools.lib.openpilotci import get_url, upload_file
|
from openpilot.tools.lib.openpilotci import get_url, upload_file
|
||||||
|
@ -172,11 +172,11 @@ if __name__ == "__main__":
|
||||||
untested = (set(interface_names) - set(excluded_interfaces)) - {c.lower() for c in tested_cars}
|
untested = (set(interface_names) - set(excluded_interfaces)) - {c.lower() for c in tested_cars}
|
||||||
assert len(untested) == 0, f"Cars missing routes: {str(untested)}"
|
assert len(untested) == 0, f"Cars missing routes: {str(untested)}"
|
||||||
|
|
||||||
log_paths: DefaultDict[str, Dict[str, Dict[str, str]]] = defaultdict(lambda: defaultdict(dict))
|
log_paths: defaultdict[str, dict[str, dict[str, str]]] = defaultdict(lambda: defaultdict(dict))
|
||||||
with concurrent.futures.ProcessPoolExecutor(max_workers=args.jobs) as pool:
|
with concurrent.futures.ProcessPoolExecutor(max_workers=args.jobs) as pool:
|
||||||
if not args.upload_only:
|
if not args.upload_only:
|
||||||
download_segments = [seg for car, seg in segments if car in tested_cars]
|
download_segments = [seg for car, seg in segments if car in tested_cars]
|
||||||
log_data: Dict[str, LogReader] = {}
|
log_data: dict[str, LogReader] = {}
|
||||||
p1 = pool.map(get_log_data, download_segments)
|
p1 = pool.map(get_log_data, download_segments)
|
||||||
for segment, lr in tqdm(p1, desc="Getting Logs", total=len(download_segments)):
|
for segment, lr in tqdm(p1, desc="Getting Logs", total=len(download_segments)):
|
||||||
log_data[segment] = lr
|
log_data[segment] = lr
|
||||||
|
|
|
@ -3,7 +3,7 @@ import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from typing import Iterable, List, Optional
|
from collections.abc import Iterable
|
||||||
|
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
@ -12,14 +12,14 @@ from openpilot.selfdrive.test.process_replay.test_processes import source_segmen
|
||||||
from openpilot.tools.lib.azure_container import AzureContainer
|
from openpilot.tools.lib.azure_container import AzureContainer
|
||||||
from openpilot.tools.lib.openpilotcontainers import DataCIContainer, DataProdContainer, OpenpilotCIContainer
|
from openpilot.tools.lib.openpilotcontainers import DataCIContainer, DataProdContainer, OpenpilotCIContainer
|
||||||
|
|
||||||
SOURCES: List[AzureContainer] = [
|
SOURCES: list[AzureContainer] = [
|
||||||
DataProdContainer,
|
DataProdContainer,
|
||||||
DataCIContainer
|
DataCIContainer
|
||||||
]
|
]
|
||||||
|
|
||||||
DEST = OpenpilotCIContainer
|
DEST = OpenpilotCIContainer
|
||||||
|
|
||||||
def upload_route(path: str, exclude_patterns: Optional[Iterable[str]] = None) -> None:
|
def upload_route(path: str, exclude_patterns: Iterable[str] | None = None) -> None:
|
||||||
if exclude_patterns is None:
|
if exclude_patterns is None:
|
||||||
exclude_patterns = [r'dcamera\.hevc']
|
exclude_patterns = [r'dcamera\.hevc']
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
from openpilot.system.hardware import HARDWARE
|
from openpilot.system.hardware import HARDWARE
|
||||||
|
@ -38,7 +37,7 @@ class PowerMonitoring:
|
||||||
self.car_battery_capacity_uWh = max((CAR_BATTERY_CAPACITY_uWh / 10), int(car_battery_capacity_uWh))
|
self.car_battery_capacity_uWh = max((CAR_BATTERY_CAPACITY_uWh / 10), int(car_battery_capacity_uWh))
|
||||||
|
|
||||||
# Calculation tick
|
# Calculation tick
|
||||||
def calculate(self, voltage: Optional[int], ignition: bool):
|
def calculate(self, voltage: int | None, ignition: bool):
|
||||||
try:
|
try:
|
||||||
now = time.monotonic()
|
now = time.monotonic()
|
||||||
|
|
||||||
|
@ -108,7 +107,7 @@ class PowerMonitoring:
|
||||||
return int(self.car_battery_capacity_uWh)
|
return int(self.car_battery_capacity_uWh)
|
||||||
|
|
||||||
# See if we need to shutdown
|
# See if we need to shutdown
|
||||||
def should_shutdown(self, ignition: bool, in_car: bool, offroad_timestamp: Optional[float], started_seen: bool):
|
def should_shutdown(self, ignition: bool, in_car: bool, offroad_timestamp: float | None, started_seen: bool):
|
||||||
if offroad_timestamp is None:
|
if offroad_timestamp is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import threading
|
||||||
import time
|
import time
|
||||||
from collections import OrderedDict, namedtuple
|
from collections import OrderedDict, namedtuple
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Optional, Tuple
|
|
||||||
|
|
||||||
import psutil
|
import psutil
|
||||||
|
|
||||||
|
@ -50,9 +49,9 @@ THERMAL_BANDS = OrderedDict({
|
||||||
# Override to highest thermal band when offroad and above this temp
|
# Override to highest thermal band when offroad and above this temp
|
||||||
OFFROAD_DANGER_TEMP = 75
|
OFFROAD_DANGER_TEMP = 75
|
||||||
|
|
||||||
prev_offroad_states: Dict[str, Tuple[bool, Optional[str]]] = {}
|
prev_offroad_states: dict[str, tuple[bool, str | None]] = {}
|
||||||
|
|
||||||
tz_by_type: Optional[Dict[str, int]] = None
|
tz_by_type: dict[str, int] | None = None
|
||||||
def populate_tz_by_type():
|
def populate_tz_by_type():
|
||||||
global tz_by_type
|
global tz_by_type
|
||||||
tz_by_type = {}
|
tz_by_type = {}
|
||||||
|
@ -87,7 +86,7 @@ def read_thermal(thermal_config):
|
||||||
return dat
|
return dat
|
||||||
|
|
||||||
|
|
||||||
def set_offroad_alert_if_changed(offroad_alert: str, show_alert: bool, extra_text: Optional[str]=None):
|
def set_offroad_alert_if_changed(offroad_alert: str, show_alert: bool, extra_text: str | None=None):
|
||||||
if prev_offroad_states.get(offroad_alert, None) == (show_alert, extra_text):
|
if prev_offroad_states.get(offroad_alert, None) == (show_alert, extra_text):
|
||||||
return
|
return
|
||||||
prev_offroad_states[offroad_alert] = (show_alert, extra_text)
|
prev_offroad_states[offroad_alert] = (show_alert, extra_text)
|
||||||
|
@ -169,16 +168,16 @@ def thermald_thread(end_event, hw_queue) -> None:
|
||||||
|
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
onroad_conditions: Dict[str, bool] = {
|
onroad_conditions: dict[str, bool] = {
|
||||||
"ignition": False,
|
"ignition": False,
|
||||||
}
|
}
|
||||||
startup_conditions: Dict[str, bool] = {}
|
startup_conditions: dict[str, bool] = {}
|
||||||
startup_conditions_prev: Dict[str, bool] = {}
|
startup_conditions_prev: dict[str, bool] = {}
|
||||||
|
|
||||||
off_ts: Optional[float] = None
|
off_ts: float | None = None
|
||||||
started_ts: Optional[float] = None
|
started_ts: float | None = None
|
||||||
started_seen = False
|
started_seen = False
|
||||||
startup_blocked_ts: Optional[float] = None
|
startup_blocked_ts: float | None = None
|
||||||
thermal_status = ThermalStatus.yellow
|
thermal_status = ThermalStatus.yellow
|
||||||
|
|
||||||
last_hw_state = HardwareState(
|
last_hw_state = HardwareState(
|
||||||
|
|
|
@ -3,7 +3,6 @@ import numpy as np
|
||||||
import time
|
import time
|
||||||
import wave
|
import wave
|
||||||
|
|
||||||
from typing import Dict, Optional, Tuple
|
|
||||||
|
|
||||||
from cereal import car, messaging
|
from cereal import car, messaging
|
||||||
from openpilot.common.basedir import BASEDIR
|
from openpilot.common.basedir import BASEDIR
|
||||||
|
@ -27,7 +26,7 @@ DB_SCALE = 30 # AMBIENT_DB + DB_SCALE is where MAX_VOLUME is applied
|
||||||
AudibleAlert = car.CarControl.HUDControl.AudibleAlert
|
AudibleAlert = car.CarControl.HUDControl.AudibleAlert
|
||||||
|
|
||||||
|
|
||||||
sound_list: Dict[int, Tuple[str, Optional[int], float]] = {
|
sound_list: dict[int, tuple[str, int | None, float]] = {
|
||||||
# AudibleAlert, file name, play count (none for infinite)
|
# AudibleAlert, file name, play count (none for infinite)
|
||||||
AudibleAlert.engage: ("engage.wav", 1, MAX_VOLUME),
|
AudibleAlert.engage: ("engage.wav", 1, MAX_VOLUME),
|
||||||
AudibleAlert.disengage: ("disengage.wav", 1, MAX_VOLUME),
|
AudibleAlert.disengage: ("disengage.wav", 1, MAX_VOLUME),
|
||||||
|
@ -64,7 +63,7 @@ class Soundd:
|
||||||
self.spl_filter_weighted = FirstOrderFilter(0, 2.5, FILTER_DT, initialized=False)
|
self.spl_filter_weighted = FirstOrderFilter(0, 2.5, FILTER_DT, initialized=False)
|
||||||
|
|
||||||
def load_sounds(self):
|
def load_sounds(self):
|
||||||
self.loaded_sounds: Dict[int, np.ndarray] = {}
|
self.loaded_sounds: dict[int, np.ndarray] = {}
|
||||||
|
|
||||||
# Load all sounds
|
# Load all sounds
|
||||||
for sound in sound_list:
|
for sound in sound_list:
|
||||||
|
|
|
@ -12,7 +12,7 @@ from parameterized import parameterized_class
|
||||||
|
|
||||||
from openpilot.selfdrive.ui.update_translations import TRANSLATIONS_DIR, LANGUAGES_FILE, update_translations
|
from openpilot.selfdrive.ui.update_translations import TRANSLATIONS_DIR, LANGUAGES_FILE, update_translations
|
||||||
|
|
||||||
with open(LANGUAGES_FILE, "r") as f:
|
with open(LANGUAGES_FILE) as f:
|
||||||
translation_files = json.load(f)
|
translation_files = json.load(f)
|
||||||
|
|
||||||
UNFINISHED_TRANSLATION_TAG = "<translation type=\"unfinished\"" # non-empty translations can be marked unfinished
|
UNFINISHED_TRANSLATION_TAG = "<translation type=\"unfinished\"" # non-empty translations can be marked unfinished
|
||||||
|
@ -28,7 +28,7 @@ class TestTranslations(unittest.TestCase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _read_translation_file(path, file):
|
def _read_translation_file(path, file):
|
||||||
tr_file = os.path.join(path, f"{file}.ts")
|
tr_file = os.path.join(path, f"{file}.ts")
|
||||||
with open(tr_file, "r") as f:
|
with open(tr_file) as f:
|
||||||
return f.read()
|
return f.read()
|
||||||
|
|
||||||
def test_missing_translation_files(self):
|
def test_missing_translation_files(self):
|
||||||
|
@ -83,7 +83,7 @@ class TestTranslations(unittest.TestCase):
|
||||||
for nf in numerusform:
|
for nf in numerusform:
|
||||||
self.assertIsNotNone(nf, f"Ensure all plural translation forms are completed: {source_text}")
|
self.assertIsNotNone(nf, f"Ensure all plural translation forms are completed: {source_text}")
|
||||||
self.assertIn("%n", nf, "Ensure numerus argument (%n) exists in translation.")
|
self.assertIn("%n", nf, "Ensure numerus argument (%n) exists in translation.")
|
||||||
self.assertIsNone(FORMAT_ARG.search(nf), "Plural translations must use %n, not %1, %2, etc.: {}".format(numerusform))
|
self.assertIsNone(FORMAT_ARG.search(nf), f"Plural translations must use %n, not %1, %2, etc.: {numerusform}")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.assertIsNotNone(translation.text, f"Ensure translation is completed: {source_text}")
|
self.assertIsNotNone(translation.text, f"Ensure translation is completed: {source_text}")
|
||||||
|
|
|
@ -13,13 +13,13 @@ BADGE_HEIGHT = 20 + 8
|
||||||
SHIELDS_URL = "https://img.shields.io/badge"
|
SHIELDS_URL = "https://img.shields.io/badge"
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
with open(LANGUAGES_FILE, "r") as f:
|
with open(LANGUAGES_FILE) as f:
|
||||||
translation_files = json.load(f)
|
translation_files = json.load(f)
|
||||||
|
|
||||||
badge_svg = []
|
badge_svg = []
|
||||||
max_badge_width = 0 # keep track of max width to set parent element
|
max_badge_width = 0 # keep track of max width to set parent element
|
||||||
for idx, (name, file) in enumerate(translation_files.items()):
|
for idx, (name, file) in enumerate(translation_files.items()):
|
||||||
with open(os.path.join(TRANSLATIONS_DIR, f"{file}.ts"), "r") as tr_f:
|
with open(os.path.join(TRANSLATIONS_DIR, f"{file}.ts")) as tr_f:
|
||||||
tr_file = tr_f.read()
|
tr_file = tr_f.read()
|
||||||
|
|
||||||
total_translations = 0
|
total_translations = 0
|
||||||
|
|
|
@ -28,7 +28,7 @@ def update_translations(vanish: bool = False, translation_files: None | list[str
|
||||||
generate_translations_include()
|
generate_translations_include()
|
||||||
|
|
||||||
if translation_files is None:
|
if translation_files is None:
|
||||||
with open(LANGUAGES_FILE, "r") as f:
|
with open(LANGUAGES_FILE) as f:
|
||||||
translation_files = json.load(f).values()
|
translation_files = json.load(f).values()
|
||||||
|
|
||||||
for file in translation_files:
|
for file in translation_files:
|
||||||
|
|
|
@ -11,7 +11,6 @@ import time
|
||||||
import threading
|
import threading
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Union, Optional
|
|
||||||
from markdown_it import MarkdownIt
|
from markdown_it import MarkdownIt
|
||||||
|
|
||||||
from openpilot.common.basedir import BASEDIR
|
from openpilot.common.basedir import BASEDIR
|
||||||
|
@ -64,7 +63,7 @@ def write_time_to_param(params, param) -> None:
|
||||||
t = datetime.datetime.utcnow()
|
t = datetime.datetime.utcnow()
|
||||||
params.put(param, t.isoformat().encode('utf8'))
|
params.put(param, t.isoformat().encode('utf8'))
|
||||||
|
|
||||||
def read_time_from_param(params, param) -> Optional[datetime.datetime]:
|
def read_time_from_param(params, param) -> datetime.datetime | None:
|
||||||
t = params.get(param, encoding='utf8')
|
t = params.get(param, encoding='utf8')
|
||||||
try:
|
try:
|
||||||
return datetime.datetime.fromisoformat(t)
|
return datetime.datetime.fromisoformat(t)
|
||||||
|
@ -72,7 +71,7 @@ def read_time_from_param(params, param) -> Optional[datetime.datetime]:
|
||||||
pass
|
pass
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def run(cmd: List[str], cwd: Optional[str] = None) -> str:
|
def run(cmd: list[str], cwd: str | None = None) -> str:
|
||||||
return subprocess.check_output(cmd, cwd=cwd, stderr=subprocess.STDOUT, encoding='utf8')
|
return subprocess.check_output(cmd, cwd=cwd, stderr=subprocess.STDOUT, encoding='utf8')
|
||||||
|
|
||||||
|
|
||||||
|
@ -234,7 +233,7 @@ def handle_agnos_update() -> None:
|
||||||
class Updater:
|
class Updater:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.params = Params()
|
self.params = Params()
|
||||||
self.branches = defaultdict(lambda: '')
|
self.branches = defaultdict(str)
|
||||||
self._has_internet: bool = False
|
self._has_internet: bool = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -243,7 +242,7 @@ class Updater:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target_branch(self) -> str:
|
def target_branch(self) -> str:
|
||||||
b: Union[str, None] = self.params.get("UpdaterTargetBranch", encoding='utf-8')
|
b: str | None = self.params.get("UpdaterTargetBranch", encoding='utf-8')
|
||||||
if b is None:
|
if b is None:
|
||||||
b = self.get_branch(BASEDIR)
|
b = self.get_branch(BASEDIR)
|
||||||
return b
|
return b
|
||||||
|
@ -272,7 +271,7 @@ class Updater:
|
||||||
def get_commit_hash(self, path: str = OVERLAY_MERGED) -> str:
|
def get_commit_hash(self, path: str = OVERLAY_MERGED) -> str:
|
||||||
return run(["git", "rev-parse", "HEAD"], path).rstrip()
|
return run(["git", "rev-parse", "HEAD"], path).rstrip()
|
||||||
|
|
||||||
def set_params(self, update_success: bool, failed_count: int, exception: Optional[str]) -> None:
|
def set_params(self, update_success: bool, failed_count: int, exception: str | None) -> None:
|
||||||
self.params.put("UpdateFailedCount", str(failed_count))
|
self.params.put("UpdateFailedCount", str(failed_count))
|
||||||
self.params.put("UpdaterTargetBranch", self.target_branch)
|
self.params.put("UpdaterTargetBranch", self.target_branch)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
from abc import abstractmethod, ABC
|
from abc import abstractmethod, ABC
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from typing import Dict
|
|
||||||
|
|
||||||
from cereal import log
|
from cereal import log
|
||||||
|
|
||||||
|
@ -10,7 +9,7 @@ NetworkType = log.DeviceState.NetworkType
|
||||||
|
|
||||||
class HardwareBase(ABC):
|
class HardwareBase(ABC):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_cmdline() -> Dict[str, str]:
|
def get_cmdline() -> dict[str, str]:
|
||||||
with open('/proc/cmdline') as f:
|
with open('/proc/cmdline') as f:
|
||||||
cmdline = f.read()
|
cmdline = f.read()
|
||||||
return {kv[0]: kv[1] for kv in [s.split('=') for s in cmdline.split(' ')] if len(kv) == 2}
|
return {kv[0]: kv[1] for kv in [s.split('=') for s in cmdline.split(' ')] if len(kv) == 2}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import os
|
||||||
import struct
|
import struct
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
from typing import Dict, Generator, List, Tuple, Union
|
from collections.abc import Generator
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ def get_raw_hash(path: str, partition_size: int) -> str:
|
||||||
return raw_hash.hexdigest().lower()
|
return raw_hash.hexdigest().lower()
|
||||||
|
|
||||||
|
|
||||||
def verify_partition(target_slot_number: int, partition: Dict[str, Union[str, int]], force_full_check: bool = False) -> bool:
|
def verify_partition(target_slot_number: int, partition: dict[str, str | int], force_full_check: bool = False) -> bool:
|
||||||
full_check = partition['full_check'] or force_full_check
|
full_check = partition['full_check'] or force_full_check
|
||||||
path = get_partition_path(target_slot_number, partition)
|
path = get_partition_path(target_slot_number, partition)
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ def extract_casync_image(target_slot_number: int, partition: dict, cloudlog):
|
||||||
|
|
||||||
target = casync.parse_caibx(partition['casync_caibx'])
|
target = casync.parse_caibx(partition['casync_caibx'])
|
||||||
|
|
||||||
sources: List[Tuple[str, casync.ChunkReader, casync.ChunkDict]] = []
|
sources: list[tuple[str, casync.ChunkReader, casync.ChunkDict]] = []
|
||||||
|
|
||||||
# First source is the current partition.
|
# First source is the current partition.
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import time
|
import time
|
||||||
from smbus2 import SMBus
|
from smbus2 import SMBus
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from typing import List
|
|
||||||
|
|
||||||
# https://datasheets.maximintegrated.com/en/ds/MAX98089.pdf
|
# https://datasheets.maximintegrated.com/en/ds/MAX98089.pdf
|
||||||
|
|
||||||
|
@ -110,7 +109,7 @@ class Amplifier:
|
||||||
def _get_shutdown_config(self, amp_disabled: bool) -> AmpConfig:
|
def _get_shutdown_config(self, amp_disabled: bool) -> AmpConfig:
|
||||||
return AmpConfig("Global shutdown", 0b0 if amp_disabled else 0b1, 0x51, 7, 0b10000000)
|
return AmpConfig("Global shutdown", 0b0 if amp_disabled else 0b1, 0x51, 7, 0b10000000)
|
||||||
|
|
||||||
def _set_configs(self, configs: List[AmpConfig]) -> None:
|
def _set_configs(self, configs: list[AmpConfig]) -> None:
|
||||||
with SMBus(self.AMP_I2C_BUS) as bus:
|
with SMBus(self.AMP_I2C_BUS) as bus:
|
||||||
for config in configs:
|
for config in configs:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
|
@ -123,7 +122,7 @@ class Amplifier:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(f" Changed {hex(config.register)}: {hex(old_value)} -> {hex(new_value)}")
|
print(f" Changed {hex(config.register)}: {hex(old_value)} -> {hex(new_value)}")
|
||||||
|
|
||||||
def set_configs(self, configs: List[AmpConfig]) -> bool:
|
def set_configs(self, configs: list[AmpConfig]) -> bool:
|
||||||
# retry in case panda is using the amp
|
# retry in case panda is using the amp
|
||||||
tries = 15
|
tries = 15
|
||||||
for i in range(15):
|
for i in range(15):
|
||||||
|
|
|
@ -7,7 +7,7 @@ import sys
|
||||||
import time
|
import time
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from collections import defaultdict, namedtuple
|
from collections import defaultdict, namedtuple
|
||||||
from typing import Callable, Dict, List, Optional, Tuple
|
from collections.abc import Callable
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from Crypto.Hash import SHA512
|
from Crypto.Hash import SHA512
|
||||||
|
@ -28,7 +28,7 @@ CHUNK_DOWNLOAD_RETRIES = 3
|
||||||
CAIBX_DOWNLOAD_TIMEOUT = 120
|
CAIBX_DOWNLOAD_TIMEOUT = 120
|
||||||
|
|
||||||
Chunk = namedtuple('Chunk', ['sha', 'offset', 'length'])
|
Chunk = namedtuple('Chunk', ['sha', 'offset', 'length'])
|
||||||
ChunkDict = Dict[bytes, Chunk]
|
ChunkDict = dict[bytes, Chunk]
|
||||||
|
|
||||||
|
|
||||||
class ChunkReader(ABC):
|
class ChunkReader(ABC):
|
||||||
|
@ -83,7 +83,7 @@ class RemoteChunkReader(ChunkReader):
|
||||||
return decompressor.decompress(contents)
|
return decompressor.decompress(contents)
|
||||||
|
|
||||||
|
|
||||||
def parse_caibx(caibx_path: str) -> List[Chunk]:
|
def parse_caibx(caibx_path: str) -> list[Chunk]:
|
||||||
"""Parses the chunks from a caibx file. Can handle both local and remote files.
|
"""Parses the chunks from a caibx file. Can handle both local and remote files.
|
||||||
Returns a list of chunks with hash, offset and length"""
|
Returns a list of chunks with hash, offset and length"""
|
||||||
caibx: io.BufferedIOBase
|
caibx: io.BufferedIOBase
|
||||||
|
@ -132,7 +132,7 @@ def parse_caibx(caibx_path: str) -> List[Chunk]:
|
||||||
return chunks
|
return chunks
|
||||||
|
|
||||||
|
|
||||||
def build_chunk_dict(chunks: List[Chunk]) -> ChunkDict:
|
def build_chunk_dict(chunks: list[Chunk]) -> ChunkDict:
|
||||||
"""Turn a list of chunks into a dict for faster lookups based on hash.
|
"""Turn a list of chunks into a dict for faster lookups based on hash.
|
||||||
Keep first chunk since it's more likely to be already downloaded."""
|
Keep first chunk since it's more likely to be already downloaded."""
|
||||||
r = {}
|
r = {}
|
||||||
|
@ -142,11 +142,11 @@ def build_chunk_dict(chunks: List[Chunk]) -> ChunkDict:
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def extract(target: List[Chunk],
|
def extract(target: list[Chunk],
|
||||||
sources: List[Tuple[str, ChunkReader, ChunkDict]],
|
sources: list[tuple[str, ChunkReader, ChunkDict]],
|
||||||
out_path: str,
|
out_path: str,
|
||||||
progress: Optional[Callable[[int], None]] = None):
|
progress: Callable[[int], None] | None = None):
|
||||||
stats: Dict[str, int] = defaultdict(int)
|
stats: dict[str, int] = defaultdict(int)
|
||||||
|
|
||||||
mode = 'rb+' if os.path.exists(out_path) else 'wb'
|
mode = 'rb+' if os.path.exists(out_path) else 'wb'
|
||||||
with open(out_path, mode) as out:
|
with open(out_path, mode) as out:
|
||||||
|
@ -181,7 +181,7 @@ def extract(target: List[Chunk],
|
||||||
return stats
|
return stats
|
||||||
|
|
||||||
|
|
||||||
def print_stats(stats: Dict[str, int]):
|
def print_stats(stats: dict[str, int]):
|
||||||
total_bytes = sum(stats.values())
|
total_bytes = sum(stats.values())
|
||||||
print(f"Total size: {total_bytes / 1024 / 1024:.2f} MB")
|
print(f"Total size: {total_bytes / 1024 / 1024:.2f} MB")
|
||||||
for name, total in stats.items():
|
for name, total in stats.items():
|
||||||
|
|
|
@ -3,7 +3,6 @@ import sys
|
||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from typing import List
|
|
||||||
from collections import deque
|
from collections import deque
|
||||||
|
|
||||||
from openpilot.common.realtime import Ratekeeper
|
from openpilot.common.realtime import Ratekeeper
|
||||||
|
@ -14,7 +13,7 @@ def read_power():
|
||||||
with open("/sys/bus/i2c/devices/0-0040/hwmon/hwmon1/power1_input") as f:
|
with open("/sys/bus/i2c/devices/0-0040/hwmon/hwmon1/power1_input") as f:
|
||||||
return int(f.read()) / 1e6
|
return int(f.read()) / 1e6
|
||||||
|
|
||||||
def sample_power(seconds=5) -> List[float]:
|
def sample_power(seconds=5) -> list[float]:
|
||||||
rate = 123
|
rate = 123
|
||||||
rk = Ratekeeper(rate, print_delay_threshold=None)
|
rk = Ratekeeper(rate, print_delay_threshold=None)
|
||||||
|
|
||||||
|
|
|
@ -6,4 +6,4 @@ if __name__ == '__main__':
|
||||||
print("measuring for 5 seconds")
|
print("measuring for 5 seconds")
|
||||||
for _ in range(3):
|
for _ in range(3):
|
||||||
pwrs = sample_power()
|
pwrs = sample_power()
|
||||||
print("mean %.2f std %.2f" % (np.mean(pwrs), np.std(pwrs)))
|
print(f"mean {np.mean(pwrs):.2f} std {np.std(pwrs):.2f}")
|
||||||
|
|
|
@ -3,7 +3,6 @@ import argparse
|
||||||
import collections
|
import collections
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
from typing import Dict, List
|
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
@ -42,7 +41,7 @@ if __name__ == "__main__":
|
||||||
szs = list(tqdm(pool.imap(get_chunk_download_size, to), total=len(to)))
|
szs = list(tqdm(pool.imap(get_chunk_download_size, to), total=len(to)))
|
||||||
chunk_sizes = {t.sha: sz for (t, sz) in zip(to, szs, strict=True)}
|
chunk_sizes = {t.sha: sz for (t, sz) in zip(to, szs, strict=True)}
|
||||||
|
|
||||||
sources: Dict[str, List[int]] = {
|
sources: dict[str, list[int]] = {
|
||||||
'seed': [],
|
'seed': [],
|
||||||
'remote_uncompressed': [],
|
'remote_uncompressed': [],
|
||||||
'remote_compressed': [],
|
'remote_compressed': [],
|
||||||
|
|
|
@ -7,7 +7,6 @@ import time
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
from typing import List
|
|
||||||
|
|
||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
from cereal.services import SERVICE_LIST
|
from cereal.services import SERVICE_LIST
|
||||||
|
@ -22,9 +21,9 @@ MAX_WARMUP_TIME = 30 # seconds to wait for SAMPLE_TIME consecutive valid sample
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Proc:
|
class Proc:
|
||||||
procs: List[str]
|
procs: list[str]
|
||||||
power: float
|
power: float
|
||||||
msgs: List[str]
|
msgs: list[str]
|
||||||
rtol: float = 0.05
|
rtol: float = 0.05
|
||||||
atol: float = 0.12
|
atol: float = 0.12
|
||||||
|
|
||||||
|
@ -66,7 +65,7 @@ class TestPowerDraw(unittest.TestCase):
|
||||||
return np.core.numeric.isclose(used, proc.power, rtol=proc.rtol, atol=proc.atol)
|
return np.core.numeric.isclose(used, proc.power, rtol=proc.rtol, atol=proc.atol)
|
||||||
|
|
||||||
def tabulate_msg_counts(self, msgs_and_power):
|
def tabulate_msg_counts(self, msgs_and_power):
|
||||||
msg_counts = defaultdict(lambda: 0)
|
msg_counts = defaultdict(int)
|
||||||
for _, counts in msgs_and_power:
|
for _, counts in msgs_and_power:
|
||||||
for msg, count in counts.items():
|
for msg, count in counts.items():
|
||||||
msg_counts[msg] += count
|
msg_counts[msg] += count
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import threading
|
import threading
|
||||||
from typing import List
|
|
||||||
from openpilot.system.hardware.hw import Paths
|
from openpilot.system.hardware.hw import Paths
|
||||||
from openpilot.common.swaglog import cloudlog
|
from openpilot.common.swaglog import cloudlog
|
||||||
from openpilot.system.loggerd.config import get_available_bytes, get_available_percent
|
from openpilot.system.loggerd.config import get_available_bytes, get_available_percent
|
||||||
|
@ -23,7 +22,7 @@ def has_preserve_xattr(d: str) -> bool:
|
||||||
return getxattr(os.path.join(Paths.log_root(), d), PRESERVE_ATTR_NAME) == PRESERVE_ATTR_VALUE
|
return getxattr(os.path.join(Paths.log_root(), d), PRESERVE_ATTR_NAME) == PRESERVE_ATTR_VALUE
|
||||||
|
|
||||||
|
|
||||||
def get_preserved_segments(dirs_by_creation: List[str]) -> List[str]:
|
def get_preserved_segments(dirs_by_creation: list[str]) -> list[str]:
|
||||||
preserved = []
|
preserved = []
|
||||||
for n, d in enumerate(filter(has_preserve_xattr, reversed(dirs_by_creation))):
|
for n, d in enumerate(filter(has_preserve_xattr, reversed(dirs_by_creation))):
|
||||||
if n == PRESERVE_COUNT:
|
if n == PRESERVE_COUNT:
|
||||||
|
|
|
@ -2,7 +2,6 @@ import os
|
||||||
import random
|
import random
|
||||||
import unittest
|
import unittest
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
|
|
||||||
import openpilot.system.loggerd.deleter as deleter
|
import openpilot.system.loggerd.deleter as deleter
|
||||||
|
@ -12,7 +11,7 @@ from openpilot.system.hardware.hw import Paths
|
||||||
from openpilot.system.loggerd.xattr_cache import setxattr
|
from openpilot.system.loggerd.xattr_cache import setxattr
|
||||||
|
|
||||||
|
|
||||||
def create_random_file(file_path: Path, size_mb: float, lock: bool = False, upload_xattr: Optional[bytes] = None) -> None:
|
def create_random_file(file_path: Path, size_mb: float, lock: bool = False, upload_xattr: bytes | None = None) -> None:
|
||||||
file_path.parent.mkdir(parents=True, exist_ok=True)
|
file_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
if lock:
|
if lock:
|
||||||
|
@ -82,7 +81,7 @@ class UploaderTestCase(unittest.TestCase):
|
||||||
self.params.put("DongleId", "0000000000000000")
|
self.params.put("DongleId", "0000000000000000")
|
||||||
|
|
||||||
def make_file_with_data(self, f_dir: str, fn: str, size_mb: float = .1, lock: bool = False,
|
def make_file_with_data(self, f_dir: str, fn: str, size_mb: float = .1, lock: bool = False,
|
||||||
upload_xattr: Optional[bytes] = None, preserve_xattr: Optional[bytes] = None) -> Path:
|
upload_xattr: bytes | None = None, preserve_xattr: bytes | None = None) -> Path:
|
||||||
file_path = Path(Paths.log_root()) / f_dir / fn
|
file_path = Path(Paths.log_root()) / f_dir / fn
|
||||||
create_random_file(file_path, size_mb, lock, upload_xattr)
|
create_random_file(file_path, size_mb, lock, upload_xattr)
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import threading
|
||||||
import unittest
|
import unittest
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Sequence
|
from collections.abc import Sequence
|
||||||
|
|
||||||
import openpilot.system.loggerd.deleter as deleter
|
import openpilot.system.loggerd.deleter as deleter
|
||||||
from openpilot.common.timeout import Timeout, TimeoutException
|
from openpilot.common.timeout import Timeout, TimeoutException
|
||||||
|
|
|
@ -8,7 +8,6 @@ import subprocess
|
||||||
import time
|
import time
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List
|
|
||||||
from flaky import flaky
|
from flaky import flaky
|
||||||
|
|
||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
|
@ -76,7 +75,7 @@ class TestLoggerd:
|
||||||
end_type = SentinelType.endOfRoute if route else SentinelType.endOfSegment
|
end_type = SentinelType.endOfRoute if route else SentinelType.endOfSegment
|
||||||
assert msgs[-1].sentinel.type == end_type
|
assert msgs[-1].sentinel.type == end_type
|
||||||
|
|
||||||
def _publish_random_messages(self, services: List[str]) -> Dict[str, list]:
|
def _publish_random_messages(self, services: list[str]) -> dict[str, list]:
|
||||||
pm = messaging.PubMaster(services)
|
pm = messaging.PubMaster(services)
|
||||||
|
|
||||||
managed_processes["loggerd"].start()
|
managed_processes["loggerd"].start()
|
||||||
|
|
|
@ -6,7 +6,6 @@ import unittest
|
||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional
|
|
||||||
from openpilot.system.hardware.hw import Paths
|
from openpilot.system.hardware.hw import Paths
|
||||||
|
|
||||||
from openpilot.common.swaglog import cloudlog
|
from openpilot.common.swaglog import cloudlog
|
||||||
|
@ -53,7 +52,7 @@ class TestUploader(UploaderTestCase):
|
||||||
self.end_event.set()
|
self.end_event.set()
|
||||||
self.up_thread.join()
|
self.up_thread.join()
|
||||||
|
|
||||||
def gen_files(self, lock=False, xattr: Optional[bytes] = None, boot=True) -> List[Path]:
|
def gen_files(self, lock=False, xattr: bytes | None = None, boot=True) -> list[Path]:
|
||||||
f_paths = []
|
f_paths = []
|
||||||
for t in ["qlog", "rlog", "dcamera.hevc", "fcamera.hevc"]:
|
for t in ["qlog", "rlog", "dcamera.hevc", "fcamera.hevc"]:
|
||||||
f_paths.append(self.make_file_with_data(self.seg_dir, t, 1, lock=lock, upload_xattr=xattr))
|
f_paths.append(self.make_file_with_data(self.seg_dir, t, 1, lock=lock, upload_xattr=xattr))
|
||||||
|
@ -62,7 +61,7 @@ class TestUploader(UploaderTestCase):
|
||||||
f_paths.append(self.make_file_with_data("boot", f"{self.seg_dir}", 1, lock=lock, upload_xattr=xattr))
|
f_paths.append(self.make_file_with_data("boot", f"{self.seg_dir}", 1, lock=lock, upload_xattr=xattr))
|
||||||
return f_paths
|
return f_paths
|
||||||
|
|
||||||
def gen_order(self, seg1: List[int], seg2: List[int], boot=True) -> List[str]:
|
def gen_order(self, seg1: list[int], seg2: list[int], boot=True) -> list[str]:
|
||||||
keys = []
|
keys = []
|
||||||
if boot:
|
if boot:
|
||||||
keys += [f"boot/{self.seg_format.format(i)}.bz2" for i in seg1]
|
keys += [f"boot/{self.seg_format.format(i)}.bz2" for i in seg1]
|
||||||
|
|
|
@ -9,7 +9,8 @@ import threading
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
import datetime
|
import datetime
|
||||||
from typing import BinaryIO, Iterator, List, Optional, Tuple
|
from typing import BinaryIO
|
||||||
|
from collections.abc import Iterator
|
||||||
|
|
||||||
from cereal import log
|
from cereal import log
|
||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
|
@ -42,10 +43,10 @@ class FakeResponse:
|
||||||
self.request = FakeRequest()
|
self.request = FakeRequest()
|
||||||
|
|
||||||
|
|
||||||
def get_directory_sort(d: str) -> List[str]:
|
def get_directory_sort(d: str) -> list[str]:
|
||||||
return [s.rjust(10, '0') for s in d.rsplit('--', 1)]
|
return [s.rjust(10, '0') for s in d.rsplit('--', 1)]
|
||||||
|
|
||||||
def listdir_by_creation(d: str) -> List[str]:
|
def listdir_by_creation(d: str) -> list[str]:
|
||||||
if not os.path.isdir(d):
|
if not os.path.isdir(d):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
@ -82,7 +83,7 @@ class Uploader:
|
||||||
self.immediate_folders = ["crash/", "boot/"]
|
self.immediate_folders = ["crash/", "boot/"]
|
||||||
self.immediate_priority = {"qlog": 0, "qlog.bz2": 0, "qcamera.ts": 1}
|
self.immediate_priority = {"qlog": 0, "qlog.bz2": 0, "qcamera.ts": 1}
|
||||||
|
|
||||||
def list_upload_files(self, metered: bool) -> Iterator[Tuple[str, str, str]]:
|
def list_upload_files(self, metered: bool) -> Iterator[tuple[str, str, str]]:
|
||||||
r = self.params.get("AthenadRecentlyViewedRoutes", encoding="utf8")
|
r = self.params.get("AthenadRecentlyViewedRoutes", encoding="utf8")
|
||||||
requested_routes = [] if r is None else r.split(",")
|
requested_routes = [] if r is None else r.split(",")
|
||||||
|
|
||||||
|
@ -121,7 +122,7 @@ class Uploader:
|
||||||
|
|
||||||
yield name, key, fn
|
yield name, key, fn
|
||||||
|
|
||||||
def next_file_to_upload(self, metered: bool) -> Optional[Tuple[str, str, str]]:
|
def next_file_to_upload(self, metered: bool) -> tuple[str, str, str] | None:
|
||||||
upload_files = list(self.list_upload_files(metered))
|
upload_files = list(self.list_upload_files(metered))
|
||||||
|
|
||||||
for name, key, fn in upload_files:
|
for name, key, fn in upload_files:
|
||||||
|
@ -207,7 +208,7 @@ class Uploader:
|
||||||
return success
|
return success
|
||||||
|
|
||||||
|
|
||||||
def step(self, network_type: int, metered: bool) -> Optional[bool]:
|
def step(self, network_type: int, metered: bool) -> bool | None:
|
||||||
d = self.next_file_to_upload(metered)
|
d = self.next_file_to_upload(metered)
|
||||||
if d is None:
|
if d is None:
|
||||||
return None
|
return None
|
||||||
|
@ -221,7 +222,7 @@ class Uploader:
|
||||||
return self.upload(name, key, fn, network_type, metered)
|
return self.upload(name, key, fn, network_type, metered)
|
||||||
|
|
||||||
|
|
||||||
def main(exit_event: Optional[threading.Event] = None) -> None:
|
def main(exit_event: threading.Event | None = None) -> None:
|
||||||
if exit_event is None:
|
if exit_event is None:
|
||||||
exit_event = threading.Event()
|
exit_event = threading.Event()
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import os
|
import os
|
||||||
import errno
|
import errno
|
||||||
from typing import Dict, Optional, Tuple
|
|
||||||
|
|
||||||
_cached_attributes: Dict[Tuple, Optional[bytes]] = {}
|
_cached_attributes: dict[tuple, bytes | None] = {}
|
||||||
|
|
||||||
def getxattr(path: str, attr_name: str) -> Optional[bytes]:
|
def getxattr(path: str, attr_name: str) -> bytes | None:
|
||||||
key = (path, attr_name)
|
key = (path, attr_name)
|
||||||
if key not in _cached_attributes:
|
if key not in _cached_attributes:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -93,7 +93,7 @@ def nmea_checksum_ok(s):
|
||||||
def process_nmea_port_messages(device:str="/dev/ttyUSB1") -> NoReturn:
|
def process_nmea_port_messages(device:str="/dev/ttyUSB1") -> NoReturn:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
with open(device, "r") as nmeaport:
|
with open(device) as nmeaport:
|
||||||
for line in nmeaport:
|
for line in nmeaport:
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
|
|
|
@ -10,7 +10,7 @@ import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import datetime
|
import datetime
|
||||||
from multiprocessing import Process, Event
|
from multiprocessing import Process, Event
|
||||||
from typing import NoReturn, Optional
|
from typing import NoReturn
|
||||||
from struct import unpack_from, calcsize, pack
|
from struct import unpack_from, calcsize, pack
|
||||||
|
|
||||||
from cereal import log
|
from cereal import log
|
||||||
|
@ -90,7 +90,7 @@ def try_setup_logs(diag, logs):
|
||||||
return setup_logs(diag, logs)
|
return setup_logs(diag, logs)
|
||||||
|
|
||||||
@retry(attempts=3, delay=1.0)
|
@retry(attempts=3, delay=1.0)
|
||||||
def at_cmd(cmd: str) -> Optional[str]:
|
def at_cmd(cmd: str) -> str | None:
|
||||||
return subprocess.check_output(f"mmcli -m any --timeout 30 --command='{cmd}'", shell=True, encoding='utf8')
|
return subprocess.check_output(f"mmcli -m any --timeout 30 --command='{cmd}'", shell=True, encoding='utf8')
|
||||||
|
|
||||||
def gps_enabled() -> bool:
|
def gps_enabled() -> bool:
|
||||||
|
@ -342,7 +342,7 @@ def main() -> NoReturn:
|
||||||
gps.bearingDeg = report["q_FltHeadingRad"] * 180/math.pi
|
gps.bearingDeg = report["q_FltHeadingRad"] * 180/math.pi
|
||||||
|
|
||||||
# TODO needs update if there is another leap second, after june 2024?
|
# TODO needs update if there is another leap second, after june 2024?
|
||||||
dt_timestamp = (datetime.datetime(1980, 1, 6, 0, 0, 0, 0, datetime.timezone.utc) +
|
dt_timestamp = (datetime.datetime(1980, 1, 6, 0, 0, 0, 0, datetime.UTC) +
|
||||||
datetime.timedelta(weeks=report['w_GpsWeekNumber']) +
|
datetime.timedelta(weeks=report['w_GpsWeekNumber']) +
|
||||||
datetime.timedelta(seconds=(1e-3*report['q_GpsFixTimeMs'] - 18)))
|
datetime.timedelta(seconds=(1e-3*report['q_GpsFixTimeMs'] - 18)))
|
||||||
gps.unixTimestampMillis = dt_timestamp.timestamp()*1e3
|
gps.unixTimestampMillis = dt_timestamp.timestamp()*1e3
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue