From 79134158d923bb2136ae1f63737db8f135aa0810 Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Thu, 5 Feb 2026 00:04:15 -0600 Subject: [PATCH] Increase Fault Resilience --- panda/board/obj/bootstub.panda.bin | Bin 14876 -> 14876 bytes panda/board/obj/bootstub.panda_h7.bin | Bin 16944 -> 16944 bytes panda/board/obj/panda.bin.signed | Bin 61336 -> 60920 bytes panda/board/obj/panda_h7.bin.signed | Bin 70112 -> 69748 bytes panda/python/__init__.py | 34 ++++++++++++++------------ panda/python/spi.py | 13 +++++++++- 6 files changed, 31 insertions(+), 16 deletions(-) diff --git a/panda/board/obj/bootstub.panda.bin b/panda/board/obj/bootstub.panda.bin index 600dd96f51edf387cb5ab66973162d133a714d69..a3558c55b6880f1599aa744102a3a298841488ba 100755 GIT binary patch delta 21 ccmbPJGN)w2En^N#i&PVHqhyoKkBqI@0AbVz_y7O^ delta 21 ccmbPJGN)w2En^O|#8i`Hb3=p8kBqI@0Atq(82|tP diff --git a/panda/board/obj/bootstub.panda_h7.bin b/panda/board/obj/bootstub.panda_h7.bin index 858c81d5fe6bfbec5b9beea435169c21997ebb77..e79e4b844c2bcb2c94a24f230037861bb68d224c 100755 GIT binary patch delta 23 dcmdnc!ngs5X4!C9TBMqo8zq};US!k93IJzf2qypl delta 23 dcmdnc!ngs5X4!CUc;0=oe14>xrO#-q+BnT=l)fhAaQ9-SBZ&B2uP{Ex=O%QNtwN*!Z zU0bWRwY9AViWL>1E?sV~y@}Qqt5)n{6t}S5_hm`)p9yHa|Mxxr&-0wjcIM1EXU?2C zGxM_Nj*!18)D=8NXtEhG2mcp9|JUC$99sP>KX)NwvKHxhv8{ICcymPKSZ z?r)GmF$^FAKn3uOUOeQ70=xu}43G+t4nW(dK{^{?UQe0Uz5YV}4alzmCY~AFh9L^Xig)0vq)?#5b>yHR8T*sFg6Z%(Oqhqm$tS{1p6oTmBzYkA*i|xI z)EMA@6*0mBVOp^G+MK|#n!^0?s20%OYJMtJEw>q?NQLN@uI_vx$U(wF0Hd zTHFt-&enVBebc_OX6de36V`i~*u?u*b>cm%Anv|JllZ$8sVBN6lBkKOK!ZX1YK&0R!GX3s@~pdDB8ak%aL4CCDM^KmNg_p9PVR= z4h;Y{0908bF2-O1cF$t?E%b`UEIHye*iFtFd6wMvQudP6BZdV~18C|=FYm+w3W-QB z()s>S1|qRKNlmxvGXO!Tr$hbSl37oddZz>`|JM%r_2ftI<{)Zgch`e3(0@C?A%K$r zb@k*|pY_1i%w9S0d%0I6*y!V4!2)wV@$_8+RjYhe{q`*p#<*LsA}HTIN>qy=6*dT> zc#9yW)v{+kIq$0*P+$^7`C1sAlPl?(QSG7MV~8@D+AbQX-2{RyF*O3V%VkCFR+1<= z>Dd6I``$>IClQ2{PA?M1bU<><>T1p&&p}i9AzUy65=O~7bhB-CM+!D6Nz3L>y>Cc4dx=W z?Be4{sdSk~Vg?>e+d8G8;zTtbakGM!}bC?!B%jg|gtVFzy7U~+O_Ik6&M7X?Co z=iEixy74Pt_uqyi6E!%ol!xE&!&(t^KusbPqVuvixq8P7$RxOr+$&N29fK1X^+p(M zd>>%aMT(Y6`mF2qZ0J;!!F!M1>F-b2zM{X`tBma%EEH#*LAB~v5c>}@IjAolOcn

ONLYNcM8nN*`l5hz4} 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 TRlf1??RP>mb8c|2;f((S7tUz% delta 12891 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 diff --git a/panda/python/__init__.py b/panda/python/__init__.py index 9339bfcf8..55a794d54 100644 --- a/panda/python/__init__.py +++ b/panda/python/__init__.py @@ -804,7 +804,8 @@ class Panda: # The panda will NAK CAN writes when there is CAN congestion. # libusb will try to send it again, with a max timeout. # Timeout is in ms. If set to 0, the timeout is infinite. - CAN_SEND_TIMEOUT_MS = 10 + CAN_SEND_TIMEOUT_MS = 5 + CAN_MAX_RETRIES = 3 def can_reset_communications(self): self._handle.controlWrite(Panda.REQUEST_OUT, 0xc0, 0, 0, b'') @@ -812,18 +813,18 @@ class Panda: @ensure_can_packet_version def can_send_many(self, arr, timeout=CAN_SEND_TIMEOUT_MS): snds = pack_can_buffer(arr) - while True: - try: - for tx in snds: - while True: - bs = self._handle.bulkWrite(3, tx, timeout=timeout) - tx = tx[bs:] - if len(tx) == 0: - break - logging.error("CAN: PARTIAL SEND MANY, RETRYING") - break - except (usb1.USBErrorIO, usb1.USBErrorOverflow): - logging.error("CAN: BAD SEND MANY, RETRYING") + for tx in snds: + retries = 0 + while len(tx) > 0: + bs = self._handle.bulkWrite(3, tx, timeout=timeout) + if bs == 0: + retries += 1 + if retries > self.CAN_MAX_RETRIES: + logging.warning("CAN send: no progress after retries, dropping") + break + else: + retries = 0 + tx = tx[bs:] def can_send(self, addr, dat, bus, timeout=CAN_SEND_TIMEOUT_MS): self.can_send_many([[addr, None, dat, bus]], timeout=timeout) @@ -831,13 +832,16 @@ class Panda: @ensure_can_packet_version def can_recv(self): dat = bytearray() - while True: + for _ in range(self.CAN_MAX_RETRIES): try: dat = self._handle.bulkRead(1, 16384) # Max receive batch size + 2 extra reserve frames break except (usb1.USBErrorIO, usb1.USBErrorOverflow): logging.error("CAN: BAD RECV, RETRYING") - time.sleep(0.1) + time.sleep(0.01) + else: + logging.error("CAN: recv failed after retries") + return [] msgs, self.can_rx_overflow_buffer = unpack_can_buffer(self.can_rx_overflow_buffer + dat) return msgs diff --git a/panda/python/spi.py b/panda/python/spi.py index be4f7dcf4..681f44a56 100644 --- a/panda/python/spi.py +++ b/panda/python/spi.py @@ -27,7 +27,10 @@ NACK = 0x1F CHECKSUM_START = 0xAB MIN_ACK_TIMEOUT_MS = 100 +MAX_ACK_TIMEOUT_MS = 500 # like C++ SPI_ACK_TIMEOUT +DEFAULT_TIMEOUT_MS = 500 # default when timeout=0 MAX_XFER_RETRY_COUNT = 5 +MAX_TIMEOUT_RETRIES = 5 # like C++ XFER_SIZE = 0x40*31 @@ -152,6 +155,8 @@ class PandaSpiHandle(BaseHandle): return cksum def _wait_for_ack(self, spi, ack_val: int, timeout: int, tx: int, length: int = 1) -> bytes: + # Original behavior preserved - timeout=0 means wait forever within this function + # The caller (_transfer) handles the overall timeout timeout_s = max(MIN_ACK_TIMEOUT_MS, timeout) * 1e-3 start = time.monotonic() @@ -225,10 +230,15 @@ class PandaSpiHandle(BaseHandle): logging.debug("starting transfer: endpoint=%d, max_rx_len=%d", endpoint, max_rx_len) logging.debug("==============================================") + # Fix timeout=0 infinite loop: default to DEFAULT_TIMEOUT_MS + if timeout == 0: + timeout = DEFAULT_TIMEOUT_MS + n = 0 start_time = time.monotonic() exc = PandaSpiException() - while (timeout == 0) or (time.monotonic() - start_time) < timeout*1e-3: + # Use the timeout for the overall loop, matching original behavior but with timeout=0 fixed + while (time.monotonic() - start_time) < timeout * 1e-3: n += 1 logging.debug("\ntry #%d", n) with self.dev.acquire() as spi: @@ -238,6 +248,7 @@ class PandaSpiHandle(BaseHandle): exc = e logging.debug("SPI transfer failed, retrying", exc_info=True) + logging.error("SPI transfer failed after %d tries, %.2fms", n, (time.monotonic() - start_time) * 1000) raise exc def get_protocol_version(self) -> bytes: