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) <noreply@anthropic.com>
This commit is contained in:
30
xvf3800.py
30
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("<HH", data, 1) # skip 1-byte header
|
||||
angle, vad = struct.unpack_from("<HH", data, 1) # skip status byte
|
||||
return angle % 360, bool(vad)
|
||||
|
||||
# --- LEDs ---
|
||||
|
||||
Reference in New Issue
Block a user