''' Extension handles usage of AS5013 by AMS ''' from supervisor import ticks_ms from kmk.keys import AX from kmk.modules import Module I2C_ADDRESS = 0x40 I2X_ALT_ADDRESS = 0x41 X = 0x10 Y_RES_INT = 0x11 XP = 0x12 XN = 0x13 YP = 0x14 YN = 0x15 M_CTRL = 0x2B T_CTRL = 0x2D Y_OFFSET = 17 X_OFFSET = 7 DEAD_X = 5 DEAD_Y = 5 class Easypoint(Module): '''Module handles usage of AS5013 by AMS''' def __init__( self, i2c, address=I2C_ADDRESS, y_offset=Y_OFFSET, x_offset=X_OFFSET, dead_x=DEAD_X, dead_y=DEAD_Y, ): self._i2c_address = address self._i2c_bus = i2c # HID parameters self.polling_interval = 20 self.last_tick = ticks_ms() # Offsets for poor soldering self.y_offset = y_offset self.x_offset = x_offset # Deadzone self.dead_x = DEAD_X self.dead_y = DEAD_Y def during_bootup(self, keyboard): return def before_matrix_scan(self, keyboard): ''' Return value will be injected as an extra matrix update ''' now = ticks_ms() if now - self.last_tick < self.polling_interval: return self.last_tick = now x, y = self._read_raw_state() # I'm a shit coder, so offset is handled in software side s_x = self.getSignedNumber(x, 8) - self.x_offset s_y = self.getSignedNumber(y, 8) - self.y_offset # Evaluate Deadzone if s_x in range(-self.dead_x, self.dead_x) and s_y in range( -self.dead_y, self.dead_y ): # Within bounds, just die return else: # Set the X/Y from easypoint AX.X.move(keyboard, x) AX.Y.move(keyboard, y) def after_matrix_scan(self, keyboard): return def before_hid_send(self, keyboard): return def after_hid_send(self, keyboard): return def on_powersave_enable(self, keyboard): return def on_powersave_disable(self, keyboard): return def _read_raw_state(self): '''Read data from AS5013''' x, y = self._i2c_rdwr([X], length=2) return x, y def getSignedNumber(self, number, bitLength=8): mask = (2**bitLength) - 1 if number & (1 << (bitLength - 1)): return number | ~mask else: return number & mask def _i2c_rdwr(self, data, length=1): '''Write and optionally read I2C data.''' while not self._i2c_bus.try_lock(): pass try: if length > 0: result = bytearray(length) self._i2c_bus.writeto_then_readfrom( self._i2c_address, bytes(data), result ) return result else: self._i2c_bus.writeto(self._i2c_address, bytes(data)) return [] finally: self._i2c_bus.unlock()