Skip to content

Commit 87ea231

Browse files
georgevigeletteebrahimebrahim
authored andcommitted
Update uart handling and version string Fixes #357
1 parent 71e4e83 commit 87ea231

4 files changed

Lines changed: 38 additions & 10 deletions

File tree

src/openlifu/io/LIFUDFU.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -308,18 +308,20 @@ def _recover_idle(self) -> None:
308308
else:
309309
break
310310

311-
def _wait_while_busy(self) -> dict:
311+
def _wait_while_busy(self, timeout_s: float = 30.0) -> dict:
312312
busy = {
313313
self.STATE_DFU_DNLOAD_SYNC,
314314
self.STATE_DFU_DNLOAD_BUSY,
315315
self.STATE_DFU_MANIFEST_SYNC,
316316
self.STATE_DFU_MANIFEST,
317317
}
318-
while True:
318+
deadline = time.monotonic() + timeout_s
319+
while time.monotonic() < deadline:
319320
st = self.get_status()
320321
if st["state"] not in busy:
321322
return st
322323
time.sleep(max(st["poll_timeout_ms"] / 1000.0, 0.005))
324+
raise TimeoutError(f"USB DFU device stuck in busy state after {timeout_s:.0f} s")
323325

324326
def _dnload(self, block_num: int, payload: bytes) -> dict:
325327
self._recover_idle()
@@ -328,8 +330,10 @@ def _dnload(self, block_num: int, payload: bytes) -> dict:
328330
self.DFU_DNLOAD, block_num, bytes(payload) if payload else b""
329331
)
330332
except _usb_core.USBError as e:
331-
if "timeout" not in str(e).lower():
333+
# errno 110 = ETIMEDOUT (libusb); swallow only genuine transfer timeouts
334+
if e.errno != 110:
332335
raise
336+
logger.debug("_dnload timeout on block %d, polling status anyway: %s", block_num, e)
333337
return self._wait_while_busy()
334338

335339
def _set_address(self, address: int) -> None:
@@ -456,8 +460,14 @@ def _exchange(self, payload: bytes, read_len: int,
456460
f"I2C passthrough exchange failed (addr=0x{self._addr:02X}, "
457461
f"want_rx={read_len})"
458462
)
459-
return bytes(r.data[:read_len]) if (r.data and len(r.data) >= read_len) \
460-
else bytes(read_len)
463+
actual = len(r.data) if r.data else 0
464+
if actual < read_len:
465+
raise RuntimeError(
466+
f"I2C passthrough exchange returned too few bytes: "
467+
f"expected {read_len}, got {actual} "
468+
f"(addr=0x{self._addr:02X})"
469+
)
470+
return bytes(r.data[:read_len])
461471

462472
# --- DFU protocol commands ---
463473

src/openlifu/io/LIFUHVController.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,11 @@ def get_version(self) -> str:
133133
# r.print_packet()
134134
if r.data_len == 3:
135135
ver = f"v{r.data[0]}.{r.data[1]}.{r.data[2]}"
136-
else:
137-
ver = "v0.0.0"
136+
elif r.data_len and r.data:
137+
# Decode only the valid length, strip trailing NULs and whitespace
138+
ver_str = r.data[:r.data_len].decode('utf-8', errors='ignore').rstrip('\x00').strip()
139+
ver = ver_str if ver_str else 'v0.0.0'
140+
138141
logger.info(ver)
139142
return ver
140143

src/openlifu/io/LIFUTXDevice.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,7 +1363,11 @@ def read_block(self, identifier: int, start_address: int, count: int) -> Optiona
13631363
raise ValueError(f"count must be 1-62, got {count}")
13641364

13651365
# Request payload: uint16_t start_addr, uint8_t count, uint8_t reserved
1366-
data = struct.pack('<HBB', start_address, count, 0)
1366+
try:
1367+
data = struct.pack('<HBB', start_address, count, 0)
1368+
except struct.error as e:
1369+
logger.error(f"Error packing read_block request: {e}")
1370+
raise ValueError("Invalid start_address or count format") from e
13671371

13681372
r = self.uart.send_packet(
13691373
id=None,
@@ -1383,7 +1387,12 @@ def read_block(self, identifier: int, start_address: int, count: int) -> Optiona
13831387
logger.error(f"Unexpected data length: {r.data_len}, expected {expected_len}")
13841388
return None
13851389

1386-
values = list(struct.unpack(f'<{count}I', r.data))
1390+
try:
1391+
values = list(struct.unpack(f'<{count}I', r.data[:expected_len]))
1392+
except struct.error as e:
1393+
logger.error(f"Failed to unpack read_block response ({len(r.data)} bytes): {e}")
1394+
return None
1395+
13871396
logger.debug(f"read_block: {count} regs from 0x{start_address:04X} on tx {identifier}")
13881397
return values
13891398

src/openlifu/io/LIFUUart.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ def disconnect(self):
228228
return
229229

230230
if self.read_thread:
231-
self.read_thread.join()
231+
self.read_thread.join(timeout=5)
232232
if self.serial and self.serial.is_open:
233233
self.serial.close()
234234
self.serial = None
@@ -367,8 +367,14 @@ def _read_data(self, timeout=20):
367367
else:
368368
time.sleep(0.05) # Brief sleep to avoid a busy loop
369369
except serial.SerialException as e:
370+
if "ClearCommError" in str(e):
371+
log.warning("Serial _read_data ClearCommError on %s (ignoring): %s", self.descriptor, e)
372+
time.sleep(0.1)
373+
continue
370374
log.error("Serial _read_data error on %s: %s", self.descriptor, e)
371375
self.running = False
376+
self.signal_disconnect.emit(self.descriptor, self.port)
377+
self.port = None
372378

373379
def _tx(self, data: bytes):
374380
"""Send data over UART."""

0 commit comments

Comments
 (0)