import errno import struct import usb.core import usb.util from usb.core import USBError VENDOR_ID = 0x191A PRODUCT_ID = 0x8003 ENDPOINT = 1 class PatliteDevice: def __init__(self): self._dev = None def connect(self): dev = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID) if dev is None: raise RuntimeError( f"Patlite not found (vendor={VENDOR_ID:#06x}, product={PRODUCT_ID:#06x})" ) try: if dev.is_kernel_driver_active(0): dev.detach_kernel_driver(0) dev.set_configuration() except USBError as exc: if exc.errno == errno.EACCES: raise RuntimeError( "USB access denied. On headless hosts, run ./scripts/install-udev.sh, " "then 'newgrp patlite' (or re-login), unplug/replug the Patlite, and retry." ) from exc raise self._dev = dev def close(self): if self._dev is not None: self.send(0x00, 0x00, 0x00) usb.util.dispose_resources(self._dev) self._dev = None def send(self, ry: int, gb: int, w: int): if self._dev is None: return data = struct.pack( "BBBBBBBx", 0x00, 0x00, 0x0F, 0x00, ry & 0xFF, gb & 0xFF, w & 0xFF, ) self._dev.write(ENDPOINT, data)