From deaad254d9ae75c1b9c0b28ced14d2c4bfc903ca Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 7 Mar 2023 14:44:10 -0800 Subject: [PATCH] python: non-zero default timeout (#1279) * non-zero default timeout * respect timeout in spi --- python/base.py | 10 ++++++---- python/spi.py | 34 ++++++++++++++++++---------------- python/usb.py | 10 +++++----- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/python/base.py b/python/base.py index 7c8789e1f..5bfa56489 100644 --- a/python/base.py +++ b/python/base.py @@ -3,30 +3,32 @@ from typing import List from .constants import McuType +TIMEOUT = int(15 * 1e3) # default timeout, in milliseconds class BaseHandle(ABC): """ A handle to talk to a panda. Borrows heavily from the libusb1 handle API. """ + @abstractmethod def close(self) -> None: ... @abstractmethod - def controlWrite(self, request_type: int, request: int, value: int, index: int, data, timeout: int = 0) -> int: + def controlWrite(self, request_type: int, request: int, value: int, index: int, data, timeout: int = TIMEOUT) -> int: ... @abstractmethod - def controlRead(self, request_type: int, request: int, value: int, index: int, length: int, timeout: int = 0) -> bytes: + def controlRead(self, request_type: int, request: int, value: int, index: int, length: int, timeout: int = TIMEOUT) -> bytes: ... @abstractmethod - def bulkWrite(self, endpoint: int, data: List[int], timeout: int = 0) -> int: + def bulkWrite(self, endpoint: int, data: List[int], timeout: int = TIMEOUT) -> int: ... @abstractmethod - def bulkRead(self, endpoint: int, length: int, timeout: int = 0) -> bytes: + def bulkRead(self, endpoint: int, length: int, timeout: int = TIMEOUT) -> bytes: ... diff --git a/python/spi.py b/python/spi.py index af719704f..7a4a48804 100644 --- a/python/spi.py +++ b/python/spi.py @@ -10,7 +10,7 @@ from contextlib import contextmanager from functools import reduce from typing import List, Optional -from .base import BaseHandle, BaseSTBootloaderHandle +from .base import BaseHandle, BaseSTBootloaderHandle, TIMEOUT from .constants import McuType, MCU_TYPE_BY_IDCODE try: @@ -25,7 +25,7 @@ DACK = 0x85 NACK = 0x1F CHECKSUM_START = 0xAB -ACK_TIMEOUT_SECONDS = 0.1 +MIN_ACK_TIMEOUT_MS = 100 MAX_XFER_RETRY_COUNT = 5 USB_MAX_SIZE = 0x40 @@ -96,9 +96,11 @@ class PandaSpiHandle(BaseHandle): cksum ^= b return cksum - def _wait_for_ack(self, spi, ack_val: int) -> None: + def _wait_for_ack(self, spi, ack_val: int, timeout: int) -> None: + timeout_s = max(MIN_ACK_TIMEOUT_MS, timeout) * 1e-3 + start = time.monotonic() - while (time.monotonic() - start) < ACK_TIMEOUT_SECONDS: + while (timeout == 0) or ((time.monotonic() - start) < timeout_s): dat = spi.xfer2(b"\x12")[0] if dat == NACK: raise PandaSpiNackResponse @@ -107,7 +109,7 @@ class PandaSpiHandle(BaseHandle): raise PandaSpiMissingAck - def _transfer(self, spi, endpoint: int, data, max_rx_len: int = 1000) -> bytes: + def _transfer(self, spi, endpoint: int, data, timeout: int, max_rx_len: int = 1000) -> bytes: logging.debug("starting transfer: endpoint=%d, max_rx_len=%d", endpoint, max_rx_len) logging.debug("==============================================") @@ -121,7 +123,7 @@ class PandaSpiHandle(BaseHandle): spi.xfer2(packet) logging.debug("- waiting for header ACK") - self._wait_for_ack(spi, HACK) + self._wait_for_ack(spi, HACK, timeout) # send data logging.debug("- sending data") @@ -129,7 +131,7 @@ class PandaSpiHandle(BaseHandle): spi.xfer2(packet) logging.debug("- waiting for data ACK") - self._wait_for_ack(spi, DACK) + self._wait_for_ack(spi, DACK, timeout) # get response length, then response response_len_bytes = bytes(spi.xfer2(b"\x00" * 2)) @@ -150,26 +152,26 @@ class PandaSpiHandle(BaseHandle): def close(self): self.dev.close() - def controlWrite(self, request_type: int, request: int, value: int, index: int, data, timeout: int = 0): + def controlWrite(self, request_type: int, request: int, value: int, index: int, data, timeout: int = TIMEOUT): with self.dev.acquire() as spi: - return self._transfer(spi, 0, struct.pack(" int: + def bulkWrite(self, endpoint: int, data: List[int], timeout: int = TIMEOUT) -> int: with self.dev.acquire() as spi: for x in range(math.ceil(len(data) / USB_MAX_SIZE)): - self._transfer(spi, endpoint, data[USB_MAX_SIZE*x:USB_MAX_SIZE*(x+1)]) + self._transfer(spi, endpoint, data[USB_MAX_SIZE*x:USB_MAX_SIZE*(x+1)], timeout) return len(data) - def bulkRead(self, endpoint: int, length: int, timeout: int = 0) -> bytes: + def bulkRead(self, endpoint: int, length: int, timeout: int = TIMEOUT) -> bytes: ret: List[int] = [] with self.dev.acquire() as spi: for _ in range(math.ceil(length / USB_MAX_SIZE)): - d = self._transfer(spi, endpoint, [], max_rx_len=USB_MAX_SIZE) + d = self._transfer(spi, endpoint, [], timeout, max_rx_len=USB_MAX_SIZE) ret += d if len(d) < USB_MAX_SIZE: break @@ -216,7 +218,7 @@ class STBootloaderSPIHandle(BaseSTBootloaderHandle): elif data != self.ACK: raise PandaSpiMissingAck - def _cmd(self, cmd: int, data: Optional[List[bytes]] = None, read_bytes: int = 0, predata=None) -> bytes: + def _cmd(self, cmd: int, data: Optional[List[bytes]] = None, read_bytes: int = TIMEOUT, predata=None) -> bytes: ret = b"" with self.dev.acquire() as spi: # sync + command diff --git a/python/usb.py b/python/usb.py index a869cee16..2e236a999 100644 --- a/python/usb.py +++ b/python/usb.py @@ -1,7 +1,7 @@ import struct from typing import List -from .base import BaseHandle, BaseSTBootloaderHandle +from .base import BaseHandle, BaseSTBootloaderHandle, TIMEOUT from .constants import McuType class PandaUsbHandle(BaseHandle): @@ -11,16 +11,16 @@ class PandaUsbHandle(BaseHandle): def close(self): self._libusb_handle.close() - def controlWrite(self, request_type: int, request: int, value: int, index: int, data, timeout: int = 0): + def controlWrite(self, request_type: int, request: int, value: int, index: int, data, timeout: int = TIMEOUT): return self._libusb_handle.controlWrite(request_type, request, value, index, data, timeout) - def controlRead(self, request_type: int, request: int, value: int, index: int, length: int, timeout: int = 0): + def controlRead(self, request_type: int, request: int, value: int, index: int, length: int, timeout: int = TIMEOUT): return self._libusb_handle.controlRead(request_type, request, value, index, length, timeout) - def bulkWrite(self, endpoint: int, data: List[int], timeout: int = 0) -> int: + def bulkWrite(self, endpoint: int, data: List[int], timeout: int = TIMEOUT) -> int: return self._libusb_handle.bulkWrite(endpoint, data, timeout) # type: ignore - def bulkRead(self, endpoint: int, length: int, timeout: int = 0) -> bytes: + def bulkRead(self, endpoint: int, length: int, timeout: int = TIMEOUT) -> bytes: return self._libusb_handle.bulkRead(endpoint, length, timeout) # type: ignore