Adafruit_CircuitPython_Inte.../code.py
2023-07-11 14:26:21 -07:00

206 lines
5.8 KiB
Python

import usb.core
import time
import struct
import intellikeys_firmware
# There are three interfaces
# No subclass 0x81, 0x02
# Keyboard 0x83, 0x03
# Mouse 0x84
# USB defines
DIR_SHIFT = 7
DIR_OUT = 0 << DIR_SHIFT
DIR_IN = 1 << DIR_SHIFT
DESC_DEVICE = 0x01
DESC_CONFIGURATION = 0x02
DESC_STRING = 0x03
DESC_INTERFACE = 0x04
# No shift
REQ_RCPT_DEVICE = 0
REQ_RCPT_INTERFACE = 1
REQ_RCPT_ENDPOINT = 2
REQ_RCPT_OTHER = 3
REQ_TYPE_SHIFT = 5
REQ_TYPE_STANDARD = 0 << REQ_TYPE_SHIFT
REQ_TYPE_CLASS = 1 << REQ_TYPE_SHIFT
REQ_TYPE_VENDOR = 2 << REQ_TYPE_SHIFT
REQ_TYPE_INVALID = 3 << REQ_TYPE_SHIFT
REQ_GET_DESCRIPTOR = 6
REQ_SET_INTERFACE = 11
# EZUSB values
ANCHOR_LOAD_INTERNAL = 0xA0
ANCHOR_LOAD_EXTERNAL = 0xA3
# IntelliKeys values
CMD_BASE = 0
IK_CMD_GET_VERSION = (CMD_BASE + 1)
IK_CMD_LED = (CMD_BASE + 2)
IK_CMD_SCAN = (CMD_BASE + 3)
IK_CMD_TONE = (CMD_BASE + 4)
IK_CMD_GET_EVENT = (CMD_BASE + 5)
IK_CMD_INIT = (CMD_BASE + 6)
IK_CMD_EEPROM_READ = (CMD_BASE + 7)
IK_CMD_EEPROM_WRITE = (CMD_BASE + 8)
IK_CMD_ONOFFSWITCH = (CMD_BASE + 9)
IK_CMD_CORRECT = (CMD_BASE + 10)
IK_CMD_EEPROM_READBYTE = (CMD_BASE + 11)
IK_CMD_RESET_DEVICE = (CMD_BASE + 12)
IK_CMD_START_AUTO = (CMD_BASE + 13)
IK_CMD_STOP_AUTO = (CMD_BASE + 14)
IK_CMD_ALL_LEDS = (CMD_BASE + 15)
IK_CMD_START_OUTPUT = (CMD_BASE + 16)
IK_CMD_STOP_OUTPUT = (CMD_BASE + 17)
IK_CMD_ALL_SENSORS = (CMD_BASE + 18)
CPUCS_REG = 0x7F92
def ezusb_load_xfer(bRequest: int, addr: int, buf: ReadableBuffer):
device.ctrl_transfer(REQ_RCPT_DEVICE | REQ_TYPE_VENDOR | DIR_OUT, bRequest, wValue=addr, wIndex=0, data_or_wLength=buf)
def ezusb_8051_reset(reset: bool):
buf = b"\x01" if reset else b"\x00"
ezusb_load_xfer(ANCHOR_LOAD_INTERNAL, CPUCS_REG, buf)
def is_ram_address(address) -> bool:
return address <= 0x1b3f
def download_hex(buffer):
offset = 0
buffer = memoryview(buffer)
for internal_ram in (True, False):
bRequest = ANCHOR_LOAD_INTERNAL if internal_ram else ANCHOR_LOAD_EXTERNAL
while offset < len(buffer):
length, address, record_type = struct.unpack_from(">BHB", buffer, offset=offset)
if record_type != 0:
break
if is_ram_address(address) != internal_ram:
continue
offset += 4
ezusb_load_xfer(bRequest, address, buffer[offset: offset + length])
offset += length
if internal_ram:
ezusb_8051_reset(True)
def get_descriptor_into(dtype, index, language_id, buffer: ReadableBuffer):
wValue = dtype << 8 | index
wIndex = language_id
device.ctrl_transfer(REQ_RCPT_DEVICE | REQ_TYPE_STANDARD | DIR_IN, REQ_GET_DESCRIPTOR, wValue=wValue, wIndex=wIndex, data_or_wLength=buffer)
def hid_send_report(index, buffer, report_id = 0):
endpoint = 0x02 if index == 0 else 0x03
if report_id > 0:
report = bytearray(len(buffer) + 1)
report[0] = report_id
report[1:] = buffer
else:
report = buffer
print(f"send report to {endpoint:02x}")
device.write(endpoint, report)
def post_command(command, data=0):
buf = bytearray(8)
buf[0] = command
buf[1] = data
print("command", command, data)
hid_send_report(0, buf)
device.read(0x81, buf, timeout=2)
print("read", buf)
return
def tone(msLength, vol=2):
buf = bytearray(8)
buf[0] = IK_CMD_TONE
buf[1] = 247
buf[2] = vol
buf[3] = msLength // 10
hid_send_report(0, buf)
def led(index, value):
buf = bytearray(8)
buf[0] = IK_CMD_LED
buf[1] = index
buf[2] = 1 if value else 0
hid_send_report(0, buf)
print('hello')
device = None
while True:
while device is None:
for d in usb.core.find(True):
print(hex(d.idVendor), hex(d.idProduct))
if d.idVendor == 0x095e:
device = d
break
if device.idProduct == 0x0100:
device.ctrl_transfer(REQ_RCPT_DEVICE | REQ_TYPE_STANDARD | DIR_OUT, REQ_SET_INTERFACE, 0, 0)
print("Loading loader")
ezusb_8051_reset(True)
# Load the loader
download_hex(intellikeys_firmware.LOADER)
ezusb_8051_reset(False)
# Load the external firmware
print("Loading firmware")
download_hex(intellikeys_firmware.FIRMWARE)
ezusb_8051_reset(True)
ezusb_8051_reset(False)
print("firmware loaded")
device = None
time.sleep(2)
elif device.idProduct == 0x0101:
print("Re-enumerated with loaded firmware")
b = bytearray(38)
get_descriptor_into(DESC_STRING, 1, 0, b)
print(struct.unpack_from("<B", b, offset=0))
print(b[2:].decode("utf-8"))
get_descriptor_into(DESC_STRING, 2, 0, b)
print(struct.unpack_from("<B", b, offset=0))
print(b[2:32].decode("utf-8"))
get_descriptor_into(DESC_DEVICE, 0, 0, b)
print("device descriptor", b[:b[0]])
config_buf = bytearray(98)
get_descriptor_into(DESC_CONFIGURATION, 0, 0, config_buf)
print("configuration descriptor", config_buf)
mv = memoryview(bytearray(55))
print("(")
for i, l in enumerate((28, 55, 44)):
get_descriptor_into(0x22, i, 0, mv[:l])
print(bytes(mv[:l]), " + ")
device.detach_kernel_driver(0)
device.detach_kernel_driver(1)
device.detach_kernel_driver(2)
post_command(IK_CMD_INIT, 0)
post_command(IK_CMD_SCAN, 1)
time.sleep(0.25)
post_command(IK_CMD_ALL_SENSORS)
print("version")
post_command(IK_CMD_GET_VERSION)
buf = bytearray(8)
sensors = [0] * 3
while True:
device.read(0x81, buf)
if buf[0] == 55:
sensors[buf[1]] = buf[2]
print(sensors)
elif buf[0] == 52:
tone(50)
led(1, True)
elif buf[0] == 53:
led(1, False)
print(buf)