This commit is contained in:
Kacper Donat 2018-12-19 22:25:13 +01:00
parent 0b99c6028d
commit 413eb916e4
9 changed files with 301 additions and 170 deletions

BIN
build/skiller-sgk3.pdf Normal file

Binary file not shown.

125
doc/color-keyboard.tex Normal file
View File

@ -0,0 +1,125 @@
\def\row{0}
\node[key] at (0,\row) {00\\00};
\node[key] at (2,\row) {00\\03};
\node[key] at (3,\row) {00\\06};
\node[key] at (4,\row) {00\\09};
\node[key] at (5,\row) {00\\0C};
\node[key] at (6.5,\row) {00\\0F};
\node[key] at (7.5,\row) {00\\12};
\node[key] at (8.5,\row) {00\\15};
\node[key] at (9.5,\row) {00\\18};
\node[key] at (11,\row) {00\\1B};
\node[key] at (12,\row) {00\\1E};
\node[key] at (13,\row) {00\\21};
\node[key] at (14,\row) {00\\24};
\node[key] at (15.25,\row) {00\\2a};
\node[key] at (16.25,\row) {00\\2d};
\node[key] at (17.25,\row) {00\\30};
\def\row{1.5}
\node[key] at (0,\row) {00\\3f};
\node[key] at (1,\row) {00\\42};
\node[key] at (2,\row) {00\\45};
\node[key] at (3,\row) {00\\48};
\node[key] at (4,\row) {00\\4b};
\node[key] at (5,\row) {00\\4e};
\node[key] at (6,\row) {00\\51};
\node[key] at (7,\row) {00\\54};
\node[key] at (8,\row) {00\\57};
\node[key] at (9,\row) {00\\5A};
\node[key] at (10,\row) {00\\5D};
\node[key] at (11,\row) {00\\60};
\node[key] at (12,\row) {00\\63};
\node[key, text width=14.5mm] at (13,\row) {00\\66};
\node[key] at (15.25,\row) {F12};
\node[key] at (16.25,\row) {F12};
\node[key] at (17.25,\row) {F12};
\node[key] at (18.5,\row) {F12};
\node[key] at (19.5,\row) {F12};
\node[key] at (20.5,\row) {F12};
\node[key] at (21.5,\row) {F12};
\def\row{2.5}
\node[key, text width=10.75mm] at (0,\row) {0000};
\node[key] at (1.5,\row) {0000};
\node[key] at (2.5,\row) {0003};
\node[key] at (3.5,\row) {0006};
\node[key] at (4.5,\row) {0009};
\node[key] at (5.5,\row) {000C};
\node[key] at (6.5,\row) {000F};
\node[key] at (7.5,\row) {F6};
\node[key] at (8.5,\row) {F7};
\node[key] at (9.5,\row) {F8};
\node[key] at (10.5,\row) {F9};
\node[key] at (11.5,\row) {F10};
\node[key] at (12.5,\row) {F11};
\node[key, text width=10.75mm] at (13.5,\row) {F12};
\node[key] at (15.25,\row) {F12};
\node[key] at (16.25,\row) {F12};
\node[key] at (17.25,\row) {F12};
\node[key] at (18.5,\row) {F12};
\node[key] at (19.5,\row) {F12};
\node[key] at (20.5,\row) {F12};
\node[key, minimum height=12.5mm] at (21.5,\row) {F12};
\def\row{3.5}
\node[key, text width=13.0mm] at (0,\row) {0000};
\node[key] at (1.8,\row) {0000};
\node[key] at (2.8,\row) {0003};
\node[key] at (3.8,\row) {0006};
\node[key] at (4.8,\row) {0009};
\node[key] at (5.8,\row) {000C};
\node[key] at (6.8,\row) {000F};
\node[key] at (7.8,\row) {F6};
\node[key] at (8.8,\row) {F7};
\node[key] at (9.8,\row) {F8};
\node[key] at (10.8,\row) {F9};
\node[key] at (11.8,\row) {F10};
\node[key, text width=16mm] at (12.8,\row) {F12};
\node[key] at (18.5,\row) {F12};
\node[key] at (19.5,\row) {F12};
\node[key] at (20.5,\row) {F12};
\def\row{4.5}
\node[key, text width=16.75mm] at (0,\row) {0000};
\node[key] at (2.3,\row) {0000};
\node[key] at (3.3,\row) {0003};
\node[key] at (4.3,\row) {0006};
\node[key] at (5.3,\row) {0009};
\node[key] at (6.3,\row) {000C};
\node[key] at (7.3,\row) {000F};
\node[key] at (8.3,\row) {F6};
\node[key] at (9.3,\row) {F7};
\node[key] at (10.3,\row) {F8};
\node[key] at (11.3,\row) {F9};
\node[key, text width=19.75mm] at (12.3,\row) {F12};
\node[key] at (16.25,\row) {F12};
\node[key] at (18.5,\row) {F12};
\node[key] at (19.5,\row) {F12};
\node[key] at (20.5,\row) {F12};
\node[key, minimum height=12.5mm] at (21.5,\row) {F12};
\def\row{5.5}
\node[key, text width=8.875mm] at (0,\row) {0000};
\node[key, text width=8.875mm] at (1.25,\row) {0000};
\node[key, text width=8.875mm] at (2.5,\row) {0003};
\node[key, text width=46.375mm] at (3.75,\row) {0006};
\node[key, text width=8.875mm] at (10,\row) {F12};
\node[key, text width=8.875mm] at (11.25,\row) {F12};
\node[key, text width=8.875mm] at (12.5,\row) {F12};
\node[key, text width=8.875mm] at (13.75,\row) {F12};
\node[key] at (15.25,\row) {F12};
\node[key] at (16.25,\row) {F12};
\node[key] at (17.25,\row) {F12};
\node[key] at (18.5,\row) {F12};
\node[key] at (19.5,\row) {F12};
\node[key] at (20.5,\row) {F12};

View File

@ -1,111 +0,0 @@
?? ?? ?? ???? ?? ?? rrggbb
04 79 01 1103 65 0100 ff0000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
04 fa 00 1103 65 0100 008000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
04 7c 01 1103 68 0100 ff0000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
?? ???? com? keyc ?? rrggbb
04 0100 0100 0000 00 000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
04 be03 1103 c000 00 fffbf0 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ; a
04 0200 0200 0000 00 000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
04 0d03 11 03 0e01 00 fffbf0 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ; b
04 0703 11 03 0801 00 fffbf0 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ; c
04 c403 11 03 c600 00 fffbf0 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ; d
04 9703 11 03 9900 00 fffbf0 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ; o
04 d202 11 03 c000 00 ffff00 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ; a
04 5401 11 03 c000 00 000080 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
04 9700 11 03 0201 00 000080 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
04 5701 11 03 c300 00 000080 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
04 d000 11 03 3b01 00 000080 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
04 9400 11 03 0000 00 000080 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
04 4409 11 36 0000 00 0000fe 00800000800000800000800000800000800000800000800000800000800000800000800000000000800000800000ff000000000000
04 1800 06 01 0f00 00 020000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
04 4402 04 2c 0000 00 aa5502150000000000000050000000000102030405060708090a0b0c0d0e0f00101214000000000000000000000000000000000000000000
esc == 00, left to right, top to bottom.
Magic Number: 0x04
Control sum: Sum of all the other bytes
Some kind of command: 0x0311
Some kind of address: 0x0000
Some kind of 0x00: 0x00
Payload:
bbggrr: 0x800000
Command types:
- 0x01 - lights off
- 0x02 - lights on
- 0x06 - change settings
- 0x00 - mode
- 0x01 - brightness
- 0x02 - pulse speed
- 0x03 - direction
- 0x04 - Is RGB
- 0x05 - color (3 bytes)
- 0x11 - change color
02 // number of repetitions
03 // a chuj wie
delay ?? ?? Key code
05 A0 02 0F
05 20 02 0F
05 A0 02 12
05 20 02 12
05 A0 02 0F
00 20 02 0F
6D 00 65 00 68 00 // meh
0000 AA 55 34 00 01 00 01 00 00 00 00 00 00 00 00 00
0010 12 00 06 00 01 03 05 A0 02 0F 05 20 02 0F 05 A0
0020 02 12 05 20 02 12 05 A0 02 0F 00 20 02 0F 6D 00
0030 65 00 68 00
0000 AA 55
60 00 // długość
02 00 // ilość wpisów ?
01 00
0E 00
00 0E
32 76
03 00
14 00
36 00
06 00
06 00 // number of keystrokes
02 // number of repetitions
03 // ??
05 A0 02 0F
05 20 02 0F
05 A0 02 12
05 20 02 12
05 A0 02 0F
00 20 02 0F
6D 00 65 00 68 00 // name: meh
08 00
01
03
05 A0 01 20 // 05 = delay, 05*10ms A0 - press, 0x01 - modifier 0x20 - keycode
05 A0 02 0F
05 20 02 0F
05 A0 02 12
05 20 02 12
05 A0 02 0F
05 20 02 0F
00 20 01 20
6B 00 65 00 6B 00

View File

@ -1,5 +1,5 @@
\documentclass[]{article}
\usepackage[T1]{fontenc}
\usepackage{fontspec}
\usepackage{listings}
\usepackage{titling}
\usepackage[utf8]{inputenc}
@ -12,15 +12,153 @@
\usepackage{amstext}
\usepackage{tikz}
\usepackage{pgfplots}
\usepackage{bytefield}
\usetikzlibrary{intersections,calc,positioning,arrows}
%opening
\title {Sharkoon Skiller MECH SGK3 USB control protocol}
\author {Kacper Donat <kacper@kadet.net>}
\tikzstyle{key}=[draw, rounded corners=.3mm, outer sep=2pt]
\DeclareRobustCommand{\key}[1]{\tikz[baseline={(K.base)}]{\node[key] (K) {#1}}}
\begin{document}
{\huge \noindent \textbf{\thetitle} \vspace{5mm}} \\
{\large \theauthor} \\
\section{Basic hardware information}
Port: USB, ID \texttt{0c45:8513}
\section{Basic info}
\begin{table}[H]
\begin{tabular}{l|r}
\textbf{Property} & \textbf{Value} \\ \hline
\textbf{VendorID} & 0c45\\
\textbf{ProductID} & 8513 \\
\textbf{Control Interface Index} & 1 \\ \hline
\textbf{Endianness} & Big Endian
\end{tabular}
\end{table}
\section{Protocol}
Commands are submited to keybord via USB control transfer, state updates are send by keyboard via USB interrupts.
After every command, keyboard should send state update.
Every packet has length of 64 bytes, and consist of 8 bytes header followed by payload, which can be up to 56 bytes
long. It's not possible to split packet into two, instead we should use addressing feature described later.
\begin{figure}[H]
\centering
\begin{bytefield}[bitwidth=4em]{8}
\bitheader{0-7} \\
\bitbox{1}{04h} & \bitbox{2}{checksum} & \bitbox{1}{cmd} & \bitbox{1}{len} & \bitbox{2}{addr} & \bitbox{1}{00h} \\
\wordbox{3}{payload \\ up to len bytes}
\end{bytefield}
\end{figure}
\subsection{Header}
Every packet starts with magic byte \texttt{04h}, probably used to determine control packets. Every value is written
in Big Endian manner, ie. LOW byte commes first. Header is ended with one null byte used for padding.
\subsubsection{checksum}
Magic value is followed by 2-byte long checksum. Checksum calculation method is really trivial - it's just a sum of all
bytes after checksum.
\begin{equation}
\mathtt{checksum} = \sum_{i=3}^{64} \mathtt{Byte}_i
\end{equation}
\subsubsection{command}
Command is 1-byte long identifier, which determines payload kind and action taken by keyboard. Commands can be used
to update keyboard state, or to read state.
\begin{table}[H]
\centering
\begin{tabular}{l|r|l}
\textbf{Command} & \textbf{Value} & \textbf{Description} \\ \hline
\texttt{SK\_CMD\_DISABLE\_LED} & \texttt{01h} & Disables key backlight, takes some time. \\
\texttt{SK\_CMD\_ENABLE\_LED} & \texttt{02h} & Enables key backlight, takes some time. \\
\texttt{SK\_CMD\_READ\_???} & \texttt{03h} & Reads some state. \\
\texttt{SK\_CMD\_READ\_???} & \texttt{05h} & Reads some state. \\
\texttt{SK\_CMD\_SET\_MODE} & \texttt{06h} & Changes keyboard mode or mode settings. \\
\texttt{SK\_CMD\_MAP\_KEYS} & \texttt{08h} & Writes key mapping to controller. \\
\texttt{SK\_CMD\_WRITE\_MACRO} & \texttt{0Ah} & Saves macros in controller memory. \\
\texttt{SK\_CMD\_SET\_COLOR} & \texttt{11h} & Changes LED RGB values in key given keys, or key range. \\
\end{tabular}
\end{table}
All commands will be described more precisely in later sections.
\subsubsection{len}
Length of payload, up to 56.
\subsubsection{addr}
Address of changed value/register, command specific, if not needed should be set to \texttt{0000h}.
\section{commands}
\subsection{\texttt{SK\_CMD\_DISABLE\_LED} (\texttt{01h})}
This command disables all LEDs\footnote{And maybe other things, hard to test.} on keyboard. It's useful when we
need to change few values and don't want to constantly blink diodes.
\subsection{\texttt{SK\_CMD\_ENABLE\_LED} (\texttt{02h})}
This command re-enables all LEDs on keyboard. It's useful when we need to change few values and don't want to
constantly blink diodes. Both operations are quite long to execute, they can took about 1s.
\subsection{\texttt{SK\_CMD\_SET\_COLOR} (\texttt{11h})}
This command can be used to change color of 1 or few LEDs at once. This operation takes less than 100ms, and
refreshes all diodes (in simpler words - they blink).
\subsubsection{Addressing}
The \texttt{addr} header value identifies starting address of specific LED in keyboard. Rule of thumb is that keys
are addressed from left to right, top to bottom staring with \key{Esc} addressed \texttt{0000h}. Key address map can
be seen below.
\begin{figure}[H]
\resizebox{\linewidth}{!}{
\begin{tikzpicture}[
x=.75cm, y=-.65cm,
key/.append style={
text width=.7cm,
minimum height=6mm,
inner sep=0,
align=center,
font=\scriptsize\tt,
anchor=north west
}
]
\input{color-keyboard.tex}
\end{tikzpicture}
}
\end{figure}
\subsubsection{Payload}
Payload of this command consist of consecutive RGB values, 1-byte per channel, we could describe this struct like that:
\begin{verbatim}
typedef struct {
struct {
uint8_t r;
uint8_t g;
uint8_t b;
} color[SK_MAX_PAYLOAD / 3];
} skillerctl_payload_color_t;
\end{verbatim}
\subsubsection{Examples}
\begin{figure}[h]
\begin{verbatim}
0000 04 13 01 11 03 00 00 01 ff 00 00 00 00 00 00 00
0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
\end{verbatim}
\caption{setting color of \key{Esc} to red (\texttt{ff0000h})}
\end{figure}
\begin{figure}[h]
\begin{verbatim}
0000 04 13 01 11 09 00 00 01 ff ff ff ff ff ff ff ff
0010 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
\end{verbatim}
\caption{setting color of \key{Esc}, \key{F1}, \key{F2} to white (\texttt{ffffffh})}
\end{figure}
\end{document}

50
src/\
View File

@ -1,50 +0,0 @@
#ifndef KEYS_H
#define KEYS_H
#include <inttypes.h>
#define SK_KEY_BAD 0xffff
#define SK_KEY_ESC 0x0000
#define SK_KEY_F1 0x0003
#define SK_KEY_F2 0x0006
#define SK_KEY_F3 0x0009
#define SK_KEY_F4 0x000C
#define SK_KEY_F5 0x000F
#define SK_KEY_F6 0x0012
#define SK_KEY_F7 0x0015
#define SK_KEY_F8 0x0018
#define SK_KEY_F9 0x001B
#define SK_KEY_F10 0x001E
#define SK_KEY_F11 0x0021
#define SK_KEY_F12 0x0024
#define SK_KEY_PRTSC 0x002a
#define SK_KEY_SCROLL_LOCK 0x002d
#define SK_KEY_BREAK 0x0030
#define SK_KEY_TILDE 0x003f
#define SK_KEY_1 0x003f
#define SK_KEY_2 0x003f
#define SK_KEY_3 0x003f
#define SK_KEY_4 0x003f
#define SK_KEY_5 0x003f
#define SK_KEY_6 0x003f
#define SK_KEY_7 0x003f
#define SK_KEY_8 0x003f
#define SK_KEY_9 0x003f
#define SK_KEY_0 0x003f
#define SK_KEY_MINUS 0x003f
#define SK_KEY_EQUALS 0x003f
#define SK_KEY_BACKSPACE 0x003f
#define SK_KEY_INSERT 0x003f
#define SK_KEY_HOME 0x003f
#define SK_KEY_PGUP 0x003f
#define SK_KEY_NUMLOCK 0x003f
#define SK_KEY_NUMDIV 0x003f
#define SK_KEY_NUMASTERIX 0x003f
#define SK_KEY_NUMMINUS 0x003f
typedef uint16_t skillerctl_keyaddr_t;
skillerctl_keyaddr_t skillerctl_keyaddr(const char* name);
#endif /* KEYS_H */

View File

@ -112,6 +112,7 @@
typedef uint16_t skillerctl_keyaddr_t;
skillerctl_keyaddr_t skillerctl_keyaddr(const char* name);
char* skillerctl_keystr(skillerctl_keyaddr_t key);
#endif /* KEYS_H */

View File

@ -31,12 +31,19 @@ void skillerctl_send_command(libusb_device_handle *handle, skillerctl_packet_t *
printf("Sending packet to keyboard: \n");
hexdump(buffer, SK_PACKET_SIZE);
libusb_control_transfer(handle, 0x21, 9, 0x0204, 0x0001, buffer, SK_PACKET_SIZE, 250);
libusb_interrupt_transfer(handle, SK_PORT_STATE, buffer, sizeof(buffer), &length, 250);
ASSERT(libusb_control_transfer(
handle,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
LIBUSB_REQUEST_SET_CONFIGURATION,
SK_CONFIGURATION,
SK_INTERFACE_CONTROL,
buffer, SK_PACKET_SIZE,
250
));
ASSERT(libusb_interrupt_transfer(handle, SK_PORT_STATE, buffer, sizeof(buffer), &length, 250));
printf("State from keyboard: \n");
hexdump(buffer, SK_PACKET_SIZE);
// we need to pretend that we're doing important stuff
usleep(100000);
hexdump(buffer, length);
usleep(5000);
}

View File

@ -10,6 +10,11 @@
#define SK_PORT_STATE 0x82
#define SK_PORT_HID 0x81
#define SK_INTERFACE_HID 0
#define SK_INTERFACE_CONTROL 1
#define SK_CONFIGURATION 0x0204
libusb_device* skillerctl_find_device(libusb_device **devices, size_t count);
void skillerctl_send_command(libusb_device_handle *handle, skillerctl_packet_t *packet);

View File

@ -1,8 +1,24 @@
#ifndef UTILS_H_
#define UTILS_H_
#define ASSERT(line) do { \
int r = line; \
if (r < LIBUSB_SUCCESS && r < LIBUSB_ERROR_COUNT) { \
printf("%s (%d) on %s:%d\n%s\n", libusb_error_name(r), r, __FILE__, __LINE__, #line);\
} \
} while (0)
#define ASSERT_RETURN(line, ret) do { \
int r = line; \
if (r < LIBUSB_SUCCESS) { \
printf("%s on %s:%d\n%s\n", libusb_error_name(r),__FILE__, __LINE__, #line);\
return ret;\
} \
} while (0)
#include <stdlib.h>
void hexdump(void* bytes, size_t length);
#endif