gh60 Rev C with LED controls (#289) * gh60_rev_c * gh60 Rev C Support for WASD, Poker, Esc, FN LED clusters * clean up spacing * Update README.md * Added image and pinout * PCB image
8 files changed, 592 insertions(+), 0 deletions(-) A keyboard/gh60_rev_c/Makefile A keyboard/gh60_rev_c/README.md A keyboard/gh60_rev_c/config.h A keyboard/gh60_rev_c/gh60.c A keyboard/gh60_rev_c/gh60.h A keyboard/gh60_rev_c/gh60revc.jpg A keyboard/gh60_rev_c/keymaps/default.c A keyboard/gh60_rev_c/pinout.txt
A keyboard/gh60_rev_c/Makefile => keyboard/gh60_rev_c/Makefile +140 -0
@@ 0,0 1,140 @@ #---------------------------------------------------------------------------- # On command line: # # make all = Make software. # # make clean = Clean out built project files. # # make coff = Convert ELF to AVR COFF. # # make extcoff = Convert ELF to AVR Extended COFF. # # make program = Download the hex file to the device. # Please customize your programmer settings(PROGRAM_CMD) # # make teensy = Download the hex file to the device, using teensy_loader_cli. # (must have teensy_loader_cli installed). # # make dfu = Download the hex file to the device, using dfu-programmer (must # have dfu-programmer installed). # # make flip = Download the hex file to the device, using Atmel FLIP (must # have Atmel FLIP installed). # # make dfu-ee = Download the eeprom file to the device, using dfu-programmer # (must have dfu-programmer installed). # # make flip-ee = Download the eeprom file to the device, using Atmel FLIP # (must have Atmel FLIP installed). # # make debug = Start either simulavr or avarice as specified for debugging, # with avr-gdb or avr-insight as the front end for debugging. # # make filename.s = Just compile filename.c into the assembler code only. # # make filename.i = Create a preprocessed source file for use in submitting # bug reports to the GCC project. # # To rebuild project do "make clean" then "make all". #---------------------------------------------------------------------------- # Target file name (without extension). TARGET = gh60 # Directory common source filess exist TOP_DIR = ../.. TMK_DIR = ../../tmk_core # Directory keyboard dependent files exist TARGET_DIR = . # # project specific files SRC = gh60.c ifdef KEYMAP SRC := keymaps/$(KEYMAP).c $(SRC) else SRC := keymaps/default.c $(SRC) endif CONFIG_H = config.h # MCU name #MCU = at90usb1287 MCU = atmega32u4 # Processor frequency. # This will define a symbol, F_CPU, in all source code files equal to the # processor frequency in Hz. You can then use this symbol in your source code to # calculate timings. Do NOT tack on a 'UL' at the end, this will be done # automatically to create a 32-bit value in your source code. # # This will be an integer division of F_USB below, as it is sourced by # F_USB after it has run through any CPU prescalers. Note that this value # does not *change* the processor frequency - it should merely be updated to # reflect the processor speed set externally so that the code can use accurate # software delays. F_CPU = 16000000 # # LUFA specific # # Target architecture (see library "Board Types" documentation). ARCH = AVR8 # Input clock frequency. # This will define a symbol, F_USB, in all source code files equal to the # input clock frequency (before any prescaling is performed) in Hz. This value may # differ from F_CPU if prescaling is used on the latter, and is required as the # raw input clock is fed directly to the PLL sections of the AVR for high speed # clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' # at the end, this will be done automatically to create a 32-bit value in your # source code. # # If no clock division is performed on the input clock inside the AVR (via the # CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. F_USB = $(F_CPU) # Interrupt driven control endpoint task(+60) OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT # Boot Section Size in *bytes* # Teensy halfKay 512 # Teensy++ halfKay 1024 # Atmel DFU loader 4096 # LUFA bootloader 4096 # USBaspLoader 2048 OPT_DEFS += -DBOOTLOADER_SIZE=4096 # Build Options # comment out to disable the options. # BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) MOUSEKEY_ENABLE = yes # Mouse keys(+4700) EXTRAKEY_ENABLE = yes # Audio control and System control(+450) # CONSOLE_ENABLE = yes # Console for debug(+400) # COMMAND_ENABLE = yes # Commands for debug and configuration KEYBOARD_LOCK_ENABLE = yes # Allow locking of keyboard via magic key # Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE # SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend NKRO_ENABLE = yes # USB Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work # BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality # MIDI_ENABLE = YES # MIDI controls # UNICODE_ENABLE = YES # Unicode # BLUETOOTH_ENABLE = yes # Enable Bluetooth with the Adafruit EZ-Key HID # Optimize size but this may cause error "relocation truncated to fit" #EXTRALDFLAGS = -Wl,--relax # Search Path VPATH += $(TARGET_DIR) VPATH += $(TOP_DIR) VPATH += $(TMK_DIR) include $(TOP_DIR)/quantum/quantum.mk
A keyboard/gh60_rev_c/README.md => keyboard/gh60_rev_c/README.md +60 -0
@@ 0,0 1,60 @@ ## gh60 Rev C keyboard firmware  /* Column pin configuration * col: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 * pin: F0 F1 E6 C7 C6 B6 D4 B1 B7 B5 B4 D7 D6 B3 (Rev.C) */ /* Row pin configuration * row: 0 1 2 3 4 * pin: D0 D1 D2 D3 D5 */ GPIO pads 0 F7 WASD LEDs 1 F6 ESC LED 2 F5 FN LED 3 F4 POKER Arrow LEDs B2 Capslock LED B0 not connected Functions to controls LED clusters gh60_caps_led_on() gh60_poker_leds_on() gh60_fn_led_on() gh60_esc_led_on() gh60_wasd_leds_on() gh60_caps_led_off() gh60_poker_leds_off() gh60_fn_led_off() gh60_esc_led_off() gh60_wasd_leds_off() ====================== ## Quantum MK Firmware For the full Quantum feature list, see [the parent README.md](/README.md). ## Building Download or clone the whole firmware and navigate to the keyboard/gh60_rev_c folder. Once your dev env is setup, you'll be able to type `make` to generate your .hex - you can then use the Teensy Loader to program your .hex file. Depending on which keymap you would like to use, you will have to compile slightly differently. ### Default To build with the default keymap, simply run `make`. ### Other Keymaps Several version of keymap are available in advance but you are recommended to define your favorite layout yourself. To define your own keymap create file named `<name>.c` in the keymaps folder, and see keymap document (you can find in top README.md) and existent keymap files. To build the firmware binary hex file with a keymap just do `make` with `KEYMAP` option like: ``` $ make KEYMAP=[default|jack|<name>] ``` Keymaps follow the format **__\<name\>.c__** and are stored in the `keymaps` folder.
A keyboard/gh60_rev_c/config.h => keyboard/gh60_rev_c/config.h +157 -0
@@ 0,0 1,157 @@ /* Copyright 2012 Jun Wako <wakojun@gmail.com> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef CONFIG_H #define CONFIG_H #include "config_common.h" /* USB Device descriptor parameter */ #define VENDOR_ID 0xFEED #define PRODUCT_ID 0x6060 #define DEVICE_VER 0x0001 #define MANUFACTURER You #define PRODUCT gh60 #define DESCRIPTION A custom keyboard /* key matrix size */ #define MATRIX_ROWS 5 #define MATRIX_COLS 14 /* * Keyboard Matrix Assignments * * Change this to how you wired your keyboard * COLS: AVR pins used for columns, left to right * ROWS: AVR pins used for rows, top to bottom * DIODE_DIRECTION: COL2ROW = COL = Anode (+), ROW = Cathode (-, marked on diode) * ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode) * */ #define COLS (int []){ F0, F1, E6, C7, C6, B6, D4, B1, B7, B5, B4, D7, D6, B3 } #define ROWS (int []){ D0, D1, D2, D3, D5 } /* COL2ROW or ROW2COL */ #define DIODE_DIRECTION COL2ROW /* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */ #define DEBOUNCE 5 /* define if matrix has ghost (lacks anti-ghosting diodes) */ //#define MATRIX_HAS_GHOST /* number of backlight levels */ #define BACKLIGHT_LEVELS 3 /* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ #define LOCKING_SUPPORT_ENABLE /* Locking resynchronize hack */ #define LOCKING_RESYNC_ENABLE /* * Force NKRO * * Force NKRO (nKey Rollover) to be enabled by default, regardless of the saved * state in the bootmagic EEPROM settings. (Note that NKRO must be enabled in the * makefile for this to work.) * * If forced on, NKRO can be disabled via magic key (default = LShift+RShift+N) * until the next keyboard reset. * * NKRO may prevent your keystrokes from being detected in the BIOS, but it is * fully operational during normal computer usage. * * For a less heavy-handed approach, enable NKRO via magic key (LShift+RShift+N) * or via bootmagic (hold SPACE+N while plugging in the keyboard). Once set by * bootmagic, NKRO mode will always be enabled until it is toggled again during a * power-up. * */ //#define FORCE_NKRO /* * Magic Key Options * * Magic keys are hotkey commands that allow control over firmware functions of * the keyboard. They are best used in combination with the HID Listen program, * found here: https://www.pjrc.com/teensy/hid_listen.html * * The options below allow the magic key functionality to be changed. This is * useful if your keyboard/keypad is missing keys and you want magic key support. * */ /* key combination for magic key command */ #define IS_COMMAND() ( \ keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ ) /* control how magic key switches layers */ //#define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS true //#define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS true //#define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM false /* override magic key keymap */ //#define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS //#define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS //#define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM //#define MAGIC_KEY_HELP1 H //#define MAGIC_KEY_HELP2 SLASH //#define MAGIC_KEY_DEBUG D //#define MAGIC_KEY_DEBUG_MATRIX X //#define MAGIC_KEY_DEBUG_KBD K //#define MAGIC_KEY_DEBUG_MOUSE M //#define MAGIC_KEY_VERSION V //#define MAGIC_KEY_STATUS S //#define MAGIC_KEY_CONSOLE C //#define MAGIC_KEY_LAYER0_ALT1 ESC //#define MAGIC_KEY_LAYER0_ALT2 GRAVE //#define MAGIC_KEY_LAYER0 0 //#define MAGIC_KEY_LAYER1 1 //#define MAGIC_KEY_LAYER2 2 //#define MAGIC_KEY_LAYER3 3 //#define MAGIC_KEY_LAYER4 4 //#define MAGIC_KEY_LAYER5 5 //#define MAGIC_KEY_LAYER6 6 //#define MAGIC_KEY_LAYER7 7 //#define MAGIC_KEY_LAYER8 8 //#define MAGIC_KEY_LAYER9 9 //#define MAGIC_KEY_BOOTLOADER PAUSE //#define MAGIC_KEY_LOCK CAPS //#define MAGIC_KEY_EEPROM E //#define MAGIC_KEY_NKRO N //#define MAGIC_KEY_SLEEP_LED Z /* * Feature disable options * These options are also useful to firmware size reduction. */ /* disable debug print */ //#define NO_DEBUG /* disable print */ //#define NO_PRINT /* disable action features */ //#define NO_ACTION_LAYER //#define NO_ACTION_TAPPING //#define NO_ACTION_ONESHOT //#define NO_ACTION_MACRO //#define NO_ACTION_FUNCTION #endif
A keyboard/gh60_rev_c/gh60.c => keyboard/gh60_rev_c/gh60.c +67 -0
@@ 0,0 1,67 @@ #include "gh60.h" #include "led.h" __attribute__ ((weak)) void matrix_init_user(void) { // leave this function blank - it can be defined in a keymap file }; __attribute__ ((weak)) void matrix_scan_user(void) { // leave this function blank - it can be defined in a keymap file } __attribute__ ((weak)) void process_action_user(keyrecord_t *record) { // leave this function blank - it can be defined in a keymap file } __attribute__ ((weak)) void led_set_user(uint8_t usb_led) { // leave this function blank - it can be defined in a keymap file } void matrix_init_kb(void) { // put your keyboard start-up code here // runs once when the firmware starts up matrix_init_user(); } void matrix_scan_kb(void) { // put your looping keyboard code here // runs every cycle (a lot) matrix_scan_user(); } void process_action_kb(keyrecord_t *record) { // put your per-action keyboard code here // runs for every action, just before processing by the firmware process_action_user(record); } void led_set_kb(uint8_t usb_led) { // put your keyboard LED indicator (ex: Caps Lock LED) toggling code here if (usb_led & (1<<USB_LED_CAPS_LOCK)) { gh60_caps_led_on(); } else { gh60_caps_led_off(); } // if (usb_led & (1<<USB_LED_NUM_LOCK)) { // gh60_esc_led_on(); // } else { // gh60_esc_led_off(); // } // if (usb_led & (1<<USB_LED_SCROLL_LOCK)) { // gh60_fn_led_on(); // } else { // gh60_fn_led_off(); // } led_set_user(usb_led); }
A keyboard/gh60_rev_c/gh60.h => keyboard/gh60_rev_c/gh60.h +81 -0
@@ 0,0 1,81 @@ #ifndef GH60_H #define GH60_H #include "matrix.h" #include "keymap_common.h" #include "backlight.h" #include <stddef.h> /* GH60 LEDs * GPIO pads * 0 F7 WASD LEDs * 1 F6 ESC LED * 2 F5 FN LED * 3 F4 POKER Arrow LEDs * B2 Capslock LED * B0 not connected */ inline void gh60_caps_led_on(void) { DDRB |= (1<<2); PORTB &= ~(1<<2); } inline void gh60_poker_leds_on(void) { DDRF |= (1<<4); PORTF &= ~(1<<4); } inline void gh60_fn_led_on(void) { DDRF |= (1<<5); PORTF &= ~(1<<5); } inline void gh60_esc_led_on(void) { DDRF |= (1<<6); PORTF &= ~(1<<6); } inline void gh60_wasd_leds_on(void) { DDRF |= (1<<7); PORTF &= ~(1<<7); } inline void gh60_caps_led_off(void) { DDRB &= ~(1<<2); PORTB &= ~(1<<2); } inline void gh60_poker_leds_off(void) { DDRF &= ~(1<<4); PORTF &= ~(1<<4); } inline void gh60_fn_led_off(void) { DDRF &= ~(1<<5); PORTF &= ~(1<<5); } inline void gh60_esc_led_off(void) { DDRF &= ~(1<<6); PORTF &= ~(1<<6); } inline void gh60_wasd_leds_off(void) { DDRF &= ~(1<<7); PORTF &= ~(1<<7); } /* GH60 keymap definition macro * K2C, K31 and K3C are extra keys for ISO */ #define KEYMAP( \ K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, \ K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \ K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, K2D, \ K30, K31, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3C, K3D, \ K40, K41, K42, K45, K49, K4A, K4B, K4C, K4D \ ) { \ { KC_##K00, KC_##K01, KC_##K02, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07, KC_##K08, KC_##K09, KC_##K0A, KC_##K0B, KC_##K0C, KC_##K0D }, \ { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17, KC_##K18, KC_##K19, KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D }, \ { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27, KC_##K28, KC_##K29, KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D }, \ { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_##K37, KC_##K38, KC_##K39, KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D }, \ { KC_##K40, KC_##K41, KC_##K42, KC_NO, KC_NO, KC_##K45, KC_NO, KC_NO, KC_NO, KC_##K49, KC_##K4A, KC_##K4B, KC_##K4C, KC_##K4D } \ } /* ANSI valiant. No extra keys for ISO */ #define KEYMAP_ANSI( \ K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, \ K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \ K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2D, \ K30, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3D, \ K40, K41, K42, K45, K4A, K4B, K4C, K4D \ ) KEYMAP( \ K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, \ K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \ K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, NO, K2D, \ K30, NO, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, NO, K3D, \ K40, K41, K42, K45, NO, K4A, K4B, K4C, K4D \ ) #define KEYMAP_HHKB( \ K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, K49,\ K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \ K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2D, \ K30, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3D, K3C, \ K40, K41, K42, K45, K4A, K4B, K4C, K4D \ ) KEYMAP( \ K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, \ K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \ K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, NO, K2D, \ K30, NO, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3C, K3D, \ K40, K41, K42, K45, K49, K4A, K4B, K4C, K4D \ ) void matrix_init_user(void); void matrix_scan_user(void); void process_action_user(keyrecord_t *record); void led_set_user(uint8_t usb_led); #endif
A keyboard/gh60_rev_c/gh60revc.jpg => keyboard/gh60_rev_c/gh60revc.jpg +0 -0
A keyboard/gh60_rev_c/keymaps/default.c => keyboard/gh60_rev_c/keymaps/default.c +69 -0
@@ 0,0 1,69 @@ #include "gh60.h" #include "action_layer.h" const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { /* 0: qwerty */ KEYMAP( ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, GRV, \ TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSPC, \ CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT,NO, ENT, \ LSFT,FN1, Z, X, C, V, B, N, M, COMM,DOT, SLSH,FN0, RSFT, \ LCTL,LGUI,LALT, SPC, BSLS,RALT,RGUI,APP, RCTL), /* 1: fn */ KEYMAP( ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, TRNS, \ TRNS,TRNS,UP, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, \ TRNS,LEFT,DOWN,RGHT,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, \ TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, \ TRNS,TRNS,TRNS, TRNS, TRNS,TRNS,TRNS,TRNS,TRNS), /* 2: arrows */ KEYMAP( TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, \ TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, \ TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, \ TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,UP, \ TRNS,TRNS,TRNS, TRNS, TRNS,TRNS,LEFT,DOWN,RGHT), }; const uint16_t PROGMEM fn_actions[] = { [0] = ACTION_LAYER_MOMENTARY(1), // to Fn overlay [1] = ACTION_LAYER_TOGGLE(2), // toggle arrow overlay }; const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) { // MACRODOWN only works in this function switch(id) { case 0: if (record->event.pressed) { register_code(KC_RSFT); } else { unregister_code(KC_RSFT); } break; } return MACRO_NONE; }; void matrix_scan_user(void) { //Layer LED indicators uint32_t layer = layer_state; if (layer & (1<<1)) { gh60_wasd_leds_on(); gh60_fn_led_on(); } else { gh60_wasd_leds_off(); gh60_fn_led_off(); } if (layer & (1<<2)) { gh60_poker_leds_on(); gh60_esc_led_on(); } else { gh60_poker_leds_off(); gh60_esc_led_off(); } };
A keyboard/gh60_rev_c/pinout.txt => keyboard/gh60_rev_c/pinout.txt +18 -0
@@ 0,0 1,18 @@ /* Column pin configuration * col: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 * pin: F0 F1 E6 C7 C6 B6 D4 B1 B7 B5 B4 D7 D6 B3 (Rev.C) */ /* Row pin configuration * row: 0 1 2 3 4 * pin: D0 D1 D2 D3 D5 */ GPIO pads 0 F7 WASD LEDs 1 F6 ESC LED 2 F5 FN LED 3 F4 POKER Arrow LEDs B2 Capslock LED B0 not connected \ No newline at end of file