I'm working on building a python library for manipulating the lighting and programmability features of my cheap Chinese iGK64 mechanical keyboard, because the Windows driver app doesn't work on Linux.
I've run the manufacturer's driver app in a Windows VM and captured USB packets for analysis. Over the last couple of days in my free time I've been breaking down the contents of these packets to determine what the different parts are, and what they do.
So far I've determined these facts:
reg:{} instr: {} addr: {} len: {} checksum: {} payload: {}
Here's an example of a packet:
Raw:
0x220200003800E670FFFFFFFFFFFFFFFF010000020200000204000002080000021000000220000002FFFFFFFFFFFFFFFF00040002000500020006000200070002
Deconstructed:
reg: 0x22 instr: 0x02 addr: 0x0000 len: 56 (0x3800) sum: 0xE670
payload: 0xFFFFFFFFFFFFFFFF010000020200000204000002080000021000000220000002FFFFFFFFFFFFFFFF00040002000500020006000200070002
I'm stuck at determining the algorithm used to calculate the Checksum. I've tried some basic xoring sequences, and some add/substract methods, but none are correct.
Hes an example of two nearly identical packets, both to same register, and payload length of zero, Only difference is the instruction and addr. But see checksums are different.
Raw1:
0x210201000000B63D0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deconstructed1:
reg: 0x21 instr: 0x02 addr: 0x0100 len: 00 (0x0000) sum: 0xB63D
payload: 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Raw2:
0x21000000000092610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deconstructed2:
reg: 0x21 instr: 0x00 addr: 0x0000 len: 00 (0x0000) sum: 0x9261
payload: 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
In this case, this is a communication from the host to the peripheral (write tr register 0x21, addr 0x100, zero payload), then from the peripheral to the host (register 0x21 "ack").
I'm pretty sure every property of the packet is used in the calculation of the checksum, including reg id, instr, addr, len, and the whole payload.
Here's some more examples which might help shed light on how the checksum is calculated:
Raw3 (this is a PING, or "alive" packet sent several times per second between host and peripheral):
0x0C0000000000A70D0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deconstructed3:
reg: 0x0C instr: 0x00 addr: 0x0000 len: 00 (0x0000) sum: 0xA70D
payload: 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Raw4 (one with a payload of all 0xFF):
0x220288013800BC74FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
Deconstructed4:
reg: 0x22 instr: 0x02 addr: 0x8801 len: 56 (0x3800) sum: 0xBC74
payload 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
I have a couple of larger raw communication dumps, but they are probably not useful for determining the checksum algorithm anymore than the examples provided here.
Any help would be greatly appreciated!
To help others, I added here how Ashley came up with the correct checksum for the raw data
2202880138000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
Came up with 0x74BC
2202000038000000FFFFFFFFFFFFFFFF010000020200000204000002080000021000000220000002FFFFFFFFFFFFFFFF00040002000500020006000200070002
Came up with 0x70E6 on CRC-CCITT (0xFFFF) 0x70E6
on site https://www.lammertbies.nl/comm/info/crc-calculation.html
To get the correct checksum in a raw data packet, just remove the checksum from the raw data packet and enter it into the crc-calculation site to find the checksum type.
Here is code to determine the checksum, courtesy falsetru of stackoverflow: ( you need to (pip) or pip3 install crc16)
import binascii
import crc16
def crccitt(hex_string):
byte_seq = binascii.unhexlify(hex_string)
crc = crc16.crc16xmodem(byte_seq, 0xffff)
return '{:04X}'.format(crc & 0xffff)
#In [387]: #crccitt('21020100000000000000000000000000000000000000000000000000000000000#000000000000000000000000000000000000000000000000000000000000000')
#Out[387]: '3DB6'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With