From f4452865d16cd60a5aee1fecd926e96b48b39bf1 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 12 Apr 2026 17:30:29 -0500 Subject: [PATCH] Fix USB read length to match official tool protocol The XVF3800 expects exact wLength: count * type_size + 1 (status byte). Requesting wrong length caused stale/corrupted responses when polling. Split _read into _read_uint16 and _read_float matching official format. Co-Authored-By: Claude Opus 4.6 (1M context) --- xvf3800.py | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/xvf3800.py b/xvf3800.py index 1d06eea..cd98e5e 100644 --- a/xvf3800.py +++ b/xvf3800.py @@ -53,17 +53,25 @@ class XVF3800: # don't call set_configuration() or detach_kernel_driver(), # the audio driver needs to keep its interface. - def _read(self, resid: int, cmdid: int, length: int) -> bytes: - """Read parameter via USB control transfer. - wValue = cmdid | 0x80 (read flag), wIndex = resid.""" + def _read_uint16(self, resid: int, cmdid: int, count: int) -> bytes: + """Read uint16 parameters. Returns raw bytes including 1-byte status header.""" try: + length = count * 2 + 1 # +1 for status byte data = self.dev.ctrl_transfer( CTRL_REQUEST_TYPE_IN, 0, - 0x80 | cmdid, # wValue: cmdid with read bit - resid, # wIndex: resource ID - length * 4, # bytes to read (length is in words) - timeout=1000 - ) + 0x80 | cmdid, resid, length, timeout=1000) + return bytes(data) + except Exception as e: + logger.debug("USB read error (resid=%d, cmd=%d): %s", resid, cmdid, e) + return b"" + + def _read_float(self, resid: int, cmdid: int, count: int) -> bytes: + """Read float32 parameters. Returns raw bytes including 1-byte status header.""" + try: + length = count * 4 + 1 # +1 for status byte + data = self.dev.ctrl_transfer( + CTRL_REQUEST_TYPE_IN, 0, + 0x80 | cmdid, resid, length, timeout=1000) return bytes(data) except Exception as e: logger.debug("USB read error (resid=%d, cmd=%d): %s", resid, cmdid, e) @@ -88,10 +96,10 @@ class XVF3800: def read_doa(self) -> tuple[int, bool]: """Read Direction of Arrival. Returns (angle 0-359, vad True/False). Response format: 1 status byte + 2 uint16 words (angle, vad).""" - data = self._read(GPO_RESID, DOA_VALUE_CMD, 2) # 2 uint16 words - if len(data) < 5: # 1 header + 4 data bytes + data = self._read_uint16(GPO_RESID, DOA_VALUE_CMD, 2) + if len(data) < 5: return 0, False - angle, vad = struct.unpack_from("