From 413eb916e43e174ac8d4465b05d9d998658c6bdc Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Wed, 19 Dec 2018 22:25:13 +0100 Subject: [PATCH] docs --- build/skiller-sgk3.pdf | Bin 0 -> 27781 bytes doc/color-keyboard.tex | 125 +++++++++++++++++++++++++++++++++++ doc/random.txt | 111 ------------------------------- doc/skiller-sgk3.tex | 144 ++++++++++++++++++++++++++++++++++++++++- "src/\\" | 50 -------------- src/keys.h | 1 + src/usb.c | 19 ++++-- src/usb.h | 5 ++ src/utils.h | 16 +++++ 9 files changed, 301 insertions(+), 170 deletions(-) create mode 100644 build/skiller-sgk3.pdf create mode 100644 doc/color-keyboard.tex delete mode 100644 doc/random.txt delete mode 100644 "src/\\" diff --git a/build/skiller-sgk3.pdf b/build/skiller-sgk3.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d81190354e55203a8e25d3e843cc8c3f1552cdfd GIT binary patch literal 27781 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 literal 0 HcmV?d00001 diff --git a/doc/color-keyboard.tex b/doc/color-keyboard.tex new file mode 100644 index 0000000..61bfe9a --- /dev/null +++ b/doc/color-keyboard.tex @@ -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}; diff --git a/doc/random.txt b/doc/random.txt deleted file mode 100644 index 144407a..0000000 --- a/doc/random.txt +++ /dev/null @@ -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 - diff --git a/doc/skiller-sgk3.tex b/doc/skiller-sgk3.tex index 11c80fe..886440d 100644 --- a/doc/skiller-sgk3.tex +++ b/doc/skiller-sgk3.tex @@ -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 } +\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} diff --git "a/src/\\" "b/src/\\" deleted file mode 100644 index efe5286..0000000 --- "a/src/\\" +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef KEYS_H -#define KEYS_H - -#include - -#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 */ - diff --git a/src/keys.h b/src/keys.h index 42c606b..bfa6173 100644 --- a/src/keys.h +++ b/src/keys.h @@ -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 */ diff --git a/src/usb.c b/src/usb.c index 8b798d2..cd5f3c0 100644 --- a/src/usb.c +++ b/src/usb.c @@ -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); } diff --git a/src/usb.h b/src/usb.h index c0fc658..a5b2b7f 100644 --- a/src/usb.h +++ b/src/usb.h @@ -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); diff --git a/src/utils.h b/src/utils.h index aaffe17..ceb3efa 100644 --- a/src/utils.h +++ b/src/utils.h @@ -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 + void hexdump(void* bytes, size_t length); #endif