From 10e39dd0f1de1518344f2ab0b70ae613f0f2aa63 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 11 Apr 2026 15:51:24 -0500 Subject: [PATCH] fix leds --- requirements.txt | 5 ++++ xvf3800.py | 70 ++++++++++++++++++++++++++++-------------------- 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/requirements.txt b/requirements.txt index 3dc2aec..7ceba6f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,13 +1,18 @@ # HeadMic - Vixy's Ears # For Raspberry Pi 5 (head-vixy) +# Python 3.13 compatibility +setuptools>=75.0.0 + # Web framework fastapi>=0.104.0 uvicorn>=0.24.0 +python-multipart>=0.0.6 # Audio pyaudio>=0.2.13 webrtcvad>=2.0.10 +numpy>=1.24.0 # Wake word detection pvporcupine>=3.0.0 diff --git a/xvf3800.py b/xvf3800.py index 14dd8b4..1099e93 100644 --- a/xvf3800.py +++ b/xvf3800.py @@ -28,15 +28,16 @@ PID = 0x001A CTRL_REQUEST_TYPE_OUT = usb.util.CTRL_OUT | usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_RECIPIENT_DEVICE if PYUSB_AVAILABLE else 0 CTRL_REQUEST_TYPE_IN = usb.util.CTRL_IN | usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_RECIPIENT_DEVICE if PYUSB_AVAILABLE else 0 -# Resource IDs +# Resource IDs (wIndex in USB control transfer) GPO_RESID = 20 -# Parameter indices (within resource) -DOA_VALUE_IDX = 18 # returns (angle 0-359, vad 0/1) -LED_EFFECT_IDX = 0 # 0=off, 1=breath, 2=rainbow, 3=solid, 4=doa, 5=ring -LED_BRIGHTNESS_IDX = 1 -LED_COLOR_IDX = 3 # single uint32 color -LED_RING_COLOR_IDX = 5 # 12 × uint32 +# Command IDs (wValue in USB control transfer) +DOA_VALUE_CMD = 18 # returns (angle 0-359, vad 0/1) +LED_EFFECT_CMD = 12 # 0=off, 1=breath, 2=rainbow, 3=solid, 4=doa, 5=ring +LED_BRIGHTNESS_CMD = 13 +LED_COLOR_CMD = 15 # single uint32 color +LED_DOA_COLOR_CMD = 16 # two uint32 values: base + indicator +LED_RING_COLOR_CMD = 17 # 12 × uint32 class XVF3800: @@ -48,29 +49,41 @@ class XVF3800: self.bus = usb_device.bus self.address = usb_device.address - def _read(self, resid: int, param_idx: int, length: int) -> bytes: - """Read parameter via USB control transfer.""" - wValue = (resid << 8) | param_idx + def _read(self, resid: int, cmdid: int, length: int) -> bytes: + """Read parameter via USB control transfer. + wValue = cmdid | 0x80 (read flag), wIndex = resid.""" try: - data = self.dev.ctrl_transfer(CTRL_REQUEST_TYPE_IN, 0, wValue, 0, length, timeout=1000) + 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 + ) return bytes(data) except Exception as e: - logger.debug("USB read error (resid=%d, param=%d): %s", resid, param_idx, e) + logger.debug("USB read error (resid=%d, cmd=%d): %s", resid, cmdid, e) return b"" - def _write(self, resid: int, param_idx: int, data: bytes): - """Write parameter via USB control transfer.""" - wValue = (resid << 8) | param_idx + def _write(self, resid: int, cmdid: int, data: bytes): + """Write parameter via USB control transfer. + wValue = cmdid, wIndex = resid.""" try: - self.dev.ctrl_transfer(CTRL_REQUEST_TYPE_OUT, 0, wValue, 0, data, timeout=1000) + self.dev.ctrl_transfer( + CTRL_REQUEST_TYPE_OUT, 0, + cmdid, # wValue: command ID + resid, # wIndex: resource ID + data, + timeout=1000 + ) except Exception as e: - logger.debug("USB write error (resid=%d, param=%d): %s", resid, param_idx, e) + logger.debug("USB write error (resid=%d, cmd=%d): %s", resid, cmdid, e) # --- DoA --- def read_doa(self) -> tuple[int, bool]: """Read Direction of Arrival. Returns (angle 0-359, vad True/False).""" - data = self._read(GPO_RESID, DOA_VALUE_IDX, 4) + data = self._read(GPO_RESID, DOA_VALUE_CMD, 2) # 2 uint16 words if len(data) < 4: return 0, False angle, vad = struct.unpack_from("