i2c_puppet-Linux/etc/i2c_puppet.py
2022-05-22 18:23:29 +02:00

131 lines
3.6 KiB
Python

import usb
_REG_VER = 0x01 # fw version
_REG_CFG = 0x02 # config
_REG_INT = 0x03 # interrupt status
_REG_KEY = 0x04 # key status
_REG_BKL = 0x05 # backlight
_REG_DEB = 0x06 # debounce cfg
_REG_FRQ = 0x07 # poll freq cfg
_REG_RST = 0x08 # reset
_REG_FIF = 0x09 # fifo
_REG_BK2 = 0x0A # backlight 2
_REG_DIR = 0x0B # gpio direction
_REG_PUE = 0x0C # gpio input pull enable
_REG_PUD = 0x0D # gpio input pull direction
_REG_GIO = 0x0E # gpio value
_REG_GIC = 0x0F # gpio interrupt config
_REG_GIN = 0x10 # gpio interrupt status
_REG_HLD = 0x11 # key hold time cfg (in 10ms units)
_REG_ADR = 0x12 # i2c puppet address
_REG_IND = 0x13 # interrupt pin assert duration
_REG_CF2 = 0x14 # config 2
_REG_TOX = 0x15 # touch delta x since last read, at most (-128 to 127)
_REG_TOY = 0x16 # touch delta y since last read, at most (-128 to 127)
_WRITE_MASK = 1 << 7
CFG_OVERFLOW_ON = 1 << 0
CFG_OVERFLOW_INT = 1 << 1
CFG_CAPSLOCK_INT = 1 << 2
CFG_NUMLOCK_INT = 1 << 3
CFG_KEY_INT = 1 << 4
CFG_PANIC_INT = 1 << 5
CFG_REPORT_MODS = 1 << 6
CFG_USE_MODS = 1 << 7
CF2_TOUCH_INT = 1 << 0
CF2_USB_KEYB_ON = 1 << 1
CF2_USB_MOUSE_ON = 1 << 2
INT_OVERFLOW = 1 << 0
INT_CAPSLOCK = 1 << 1
INT_NUMLOCK = 1 << 2
INT_KEY = 1 << 3
INT_PANIC = 1 << 4
INT_GPIO = 1 << 5
INT_TOUCH = 1 << 6
KEY_CAPSLOCK = 1 << 5
KEY_NUMLOCK = 1 << 6
KEY_COUNT_MASK = 0x1F
DIR_OUTPUT = 0
DIR_INPUT = 1
PUD_DOWN = 0
PUD_UP = 1
class I2CPuppet:
def __init__(self, vid=0x1209, pid=0xB182):
self._buffer = bytearray(2)
self._dev = usb.core.find(idVendor=vid, idProduct=pid)
if self._dev is None:
raise Exception('Device with vid:pid %04X:%04X not found!' % (vid, pid))
conf = self._dev.get_active_configuration()
itf = usb.util.find_descriptor(conf, bInterfaceClass=usb.CLASS_VENDOR_SPEC)
self._ep_out = usb.util.find_descriptor(itf, custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT)
self._ep_in = usb.util.find_descriptor(itf, custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN)
if (self._ep_out is None) or (self._ep_in is None):
raise Exception('Vendor IN or OUT endpoint not found!')
@property
def version(self):
ver = self._read_register(_REG_VER)
return (ver >> 4, ver & 0x0F)
@property
def status(self):
return self._read_register(_REG_KEY)
@property
def backlight(self):
return self._read_register(_REG_BKL) / 255
@backlight.setter
def backlight(self, value):
self._write_register(_REG_BKL, int(255 * value))
@property
def address(self):
return self._read_register(_REG_ADR)
@address.setter
def address(self, value):
self._write_register(_REG_ADR, value)
def _read_register(self, reg):
self._buffer[0] = reg
self._dev.write(self._ep_out, self._buffer[:1])
return self._dev.read(self._ep_in, 1)[0]
def _write_register(self, reg, value):
self._buffer[0] = reg | _WRITE_MASK
self._buffer[1] = value
self._dev.write(self._ep_out, self._buffer)
def _update_register_bit(self, reg, bit, value):
reg_val = self._read_register(reg)
old_val = reg_val
if value:
reg_val |= (1 << bit)
else:
reg_val &= ~(1 << bit)
if reg_val != old_val:
self._write_register(reg, reg_val)
def _get_register_bit(self, reg, bit):
return self._read_register(reg) & (1 << bit) != 0
keyboard_backlight = backlight