@ -0,0 +1 @@ | |||||
/.ccls-cache |
@ -0,0 +1,169 @@ | |||||
// Copyright 2022 Andrew Dunai (@and3rson) | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#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 Andrew Dunai | |||||
#define PRODUCT Endgame48 (v2) | |||||
#define DESCRIPTION A 12x4 split ortholinear keyboard with encoder | |||||
/* | |||||
┌────────┐ | |||||
╭──────┤ ├──────╮ | |||||
RGB> ┿ D3 │ │ RAW ┿ | |||||
│ │ │ │ | |||||
PS2D> ┿ D2 └────────┘ GND ┿ | |||||
│ │ | |||||
┿ GND RST ┿ | |||||
│ [] [] │ | |||||
┿ GND VCC ┿ | |||||
│ │ | |||||
I2C> ┿ D1 ||| || || F4 ┿ <ROW5 | |||||
│ │ | |||||
I2C> ┿ D0 F5 ┿ <COL1 | |||||
│ ╱╲ │ | |||||
ROW1> ┿ D4 ╱ ╲ F6 ┿ <COL2 | |||||
│ ╱ ╲ │ | |||||
ROW3> ┿ C6 ╲ ╱ F7 ┿ <COL3 | |||||
│ ╲ ╱ │ | |||||
COL7> ┿ D7 ╲╱ B1 ┿ <COL4 | |||||
│ │ | |||||
ENCA> ┿ E6 B3 ┿ <COL5 | |||||
│ │ | |||||
ENCB> ┿ B4 B2 ┿ <COL6 | |||||
│ │ | |||||
ROW2> │ B5 B7 D5 C7 F1 F0 B6 ┿ <ROW6 | |||||
╰────╂──╂──╂──╂──╂─────╯ | |||||
┃ ┃ ┃ ┃ | |||||
ROW4 ┛ ┃ ┃ ┗ ROW8 | |||||
┃ ┃ | |||||
PS2C ┛ ┗ ROW7 | |||||
*/ | |||||
/* key matrix size */ | |||||
#define MATRIX_ROWS 8 | |||||
#define MATRIX_COLS 7 | |||||
/* key matrix pins */ | |||||
#define MATRIX_ROW_PINS { \ | |||||
D4, B5, C6, B7, \ | |||||
F4, B6, F1, F0 \ | |||||
} | |||||
#define MATRIX_COL_PINS { \ | |||||
F5, F6, F7, B1, B3, B2, \ | |||||
D7 \ | |||||
} | |||||
#define UNUSED_PINS | |||||
/* COL2ROW or ROW2COL */ | |||||
#define DIODE_DIRECTION ROW2COL | |||||
/* Set 0 if debouncing isn't needed */ | |||||
#define DEBOUNCE 20 | |||||
/* 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 | |||||
/* key combination for command */ | |||||
#define IS_COMMAND() ( \ | |||||
keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ | |||||
) | |||||
/* prevent stuck modifiers */ | |||||
#define PREVENT_STUCK_MODIFIERS | |||||
/* RGB underglow */ | |||||
#define RGB_DI_PIN D3 | |||||
#ifdef RGB_DI_PIN | |||||
#define RGBLED_NUM 12 | |||||
#define RGBLIGHT_HUE_STEP 8 | |||||
#define RGBLIGHT_SAT_STEP 8 | |||||
#define RGBLIGHT_VAL_STEP 8 | |||||
#define RGBLIGHT_DEFAULT_VAL 0 | |||||
#endif | |||||
/* Encoders */ | |||||
#define ENCODERS_PAD_A { E6 } | |||||
#define ENCODERS_PAD_B { B4 } | |||||
#define ENCODER_RESOLUTION 4 | |||||
/* Tapping config */ | |||||
#define TAPPING_TERM 90 | |||||
#define PERMISSIVE_HOLD | |||||
#define TAPPING_FORCE_HOLD | |||||
/* Reduce firmware size */ | |||||
#define NO_ACTION_ONESHOT | |||||
/* Font */ | |||||
#define OLED_FONT_H "glcdfont_48_v2.c" | |||||
/* Trackpoint */ | |||||
#define PS2_MOUSE_INIT_DELAY 200 | |||||
#ifdef PS2_USE_USART | |||||
#define PS2_CLOCK_PIN D5 | |||||
#define PS2_DATA_PIN D2 | |||||
/* synchronous, odd parity, 1-bit stop, 8-bit data, sample at falling edge */ | |||||
/* set DDR of CLOCK as input to be slave */ | |||||
#define PS2_USART_INIT() do { \ | |||||
PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT); \ | |||||
PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT); \ | |||||
UCSR1C = ((1 << UMSEL10) | \ | |||||
(3 << UPM10) | \ | |||||
(0 << USBS1) | \ | |||||
(3 << UCSZ10) | \ | |||||
(0 << UCPOL1)); \ | |||||
UCSR1A = 0; \ | |||||
UBRR1H = 0; \ | |||||
UBRR1L = 0; \ | |||||
} while (0) | |||||
#define PS2_USART_RX_INT_ON() do { \ | |||||
UCSR1B = ((1 << RXCIE1) | \ | |||||
(1 << RXEN1)); \ | |||||
} while (0) | |||||
#define PS2_USART_RX_POLL_ON() do { \ | |||||
UCSR1B = (1 << RXEN1); \ | |||||
} while (0) | |||||
#define PS2_USART_OFF() do { \ | |||||
UCSR1C = 0; \ | |||||
UCSR1B &= ~((1 << RXEN1) | \ | |||||
(1 << TXEN1)); \ | |||||
} while (0) | |||||
#define PS2_USART_RX_READY (UCSR1A & (1<<RXC1)) | |||||
#define PS2_USART_RX_DATA UDR1 | |||||
#define PS2_USART_ERROR (UCSR1A & ((1<<FE1) | (1<<DOR1) | (1<<UPE1))) | |||||
#define PS2_USART_RX_VECT USART1_RX_vect | |||||
#endif | |||||
#ifdef PS2_USE_INT | |||||
/* Note: pins are swapped, so re-soldering is needed to test both modes */ | |||||
#define PS2_CLOCK_PIN D2 | |||||
#define PS2_DATA_PIN D5 | |||||
#define PS2_INT_INIT() do { \ | |||||
EICRA |= ((1<<ISC21) | \ | |||||
(0<<ISC20)); \ | |||||
} while (0) | |||||
#define PS2_INT_ON() do { \ | |||||
EIMSK |= (1<<INT2); \ | |||||
} while (0) | |||||
#define PS2_INT_OFF() do { \ | |||||
EIMSK &= ~(1<<INT2); \ | |||||
} while (0) | |||||
#define PS2_INT_VECT INT2_vect | |||||
#endif | |||||
#endif |
@ -0,0 +1,110 @@ | |||||
// Copyright 2022 Andrew Dunai (@and3rson) | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#include "endgame48.h" | |||||
#include "quantum.h" | |||||
#include "raw_hid.h" | |||||
#include "bitwise.h" | |||||
#include "oled/oled_driver.h" | |||||
#include "symbols.h" | |||||
#include "string.h" | |||||
#include "stdio.h" | |||||
#include "eeprom.h" | |||||
#include "encoder.h" | |||||
#include "menu.h" | |||||
#include "rgblight.h" | |||||
volatile static uint32_t reset_requested = 0; | |||||
void oled_paint(void); | |||||
void request_reset(void) { | |||||
reset_requested = timer_read32(); | |||||
oled_clear(); | |||||
oled_write_P(logo, false); | |||||
oled_write_P(resetIcon, false); | |||||
oled_write("\nREADY\n FOR \nFLASH", false); | |||||
for (int i = 0; i < 16; i++) { | |||||
oled_render(); | |||||
} | |||||
rgblight_setrgb((DEBUG_COLOR >> 16) & 0xFF, (DEBUG_COLOR >> 8) & 0xFF, DEBUG_COLOR & 0xFF); | |||||
reset_keyboard(); | |||||
} | |||||
void mute(void) { | |||||
tap_code(KC_MUTE); | |||||
} | |||||
void init_eeprom_menu(menu_t *this) { | |||||
for (uint16_t i = 0; i < this->count; i++) { | |||||
uint8_t b = eeprom_read_byte((uint8_t *)i); | |||||
sprintf(this->items[i].title, "%02X:%02X", i, b); | |||||
} | |||||
} | |||||
static menu_t list_eeprom_menu = { | |||||
.title = "EEPRM", | |||||
.count = 64, | |||||
.items = (menu_item_t[64]){}, | |||||
.opened = init_eeprom_menu, | |||||
}; | |||||
menu_t main_menu = { | |||||
.title = "CFG", | |||||
.count = 5, | |||||
.items = | |||||
(menu_item_t[]){ | |||||
{ | |||||
.title = "Mute", | |||||
.func = mute, | |||||
}, | |||||
{ | |||||
.title = "RGB", | |||||
.func = rgblight_toggle_noeeprom, | |||||
}, | |||||
{ | |||||
.title = "Reset", | |||||
.func = request_reset, | |||||
}, | |||||
{ | |||||
.title = "LsEE", | |||||
.submenu = &list_eeprom_menu, | |||||
}, | |||||
{ | |||||
.title = "DelEE", | |||||
.func = eeconfig_init, | |||||
}, | |||||
}, | |||||
}; | |||||
bool process_record_kb(uint16_t keycode, keyrecord_t *record) { | |||||
if (!menu_process_record(keycode, record)) { | |||||
return false; | |||||
} | |||||
return process_record_user(keycode, record); | |||||
} | |||||
bool encoder_update_kb(uint8_t index, bool clockwise) { | |||||
if (!menu_encoder_update(index, clockwise)) { | |||||
return false; | |||||
} | |||||
return encoder_update_user(index, clockwise); | |||||
} | |||||
oled_rotation_t oled_init_kb(oled_rotation_t rotation) { | |||||
return OLED_ROTATION_270; | |||||
} | |||||
static uint32_t last_render = 0; | |||||
bool oled_task_kb(void) { | |||||
if (timer_elapsed32(last_render) > 100) { | |||||
last_render = timer_read32(); | |||||
if (!menu_oled_task()) { | |||||
return false; | |||||
} | |||||
oled_task_user(); | |||||
} | |||||
return false; | |||||
} |
@ -0,0 +1,37 @@ | |||||
// Copyright 2022 Andrew Dunai (@and3rson) | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#ifndef ENDGAME48_H | |||||
#define ENDGAME48_H | |||||
#include "quantum.h" | |||||
#include "config.h" | |||||
#define DEBUG_COLOR 0xFFFF00 | |||||
#define NOPE KC_NO | |||||
enum eg_custom_keycodes { | |||||
KC_EGMENU = SAFE_RANGE, | |||||
EG_SAFE_RANGE, | |||||
}; | |||||
#define LAYOUT( \ | |||||
K00, K01, K02, K03, K04, K05, K40, K41, K42, K43, K44, K45, \ | |||||
K10, K11, K12, K13, K14, K15, K50, K51, K52, K53, K54, K55, \ | |||||
K20, K21, K22, K23, K24, K25, K60, K61, K62, K63, K64, K65, \ | |||||
K30, K31, K32, K33, K34, K35, K76, K70, K71, K72, K73, K74, K75 \ | |||||
) { \ | |||||
{K00, K01, K02, K03, K04, K05, NOPE}, \ | |||||
{K10, K11, K12, K13, K14, K15, NOPE}, \ | |||||
{K20, K21, K22, K23, K24, K25, NOPE}, \ | |||||
{K30, K31, K32, K33, K34, K35, NOPE}, \ | |||||
{K40, K41, K42, K43, K44, K45, NOPE}, \ | |||||
{K50, K51, K52, K53, K54, K55, NOPE}, \ | |||||
{K60, K61, K62, K63, K64, K65, NOPE}, \ | |||||
{K70, K71, K72, K73, K74, K75, K76} \ | |||||
} | |||||
void request_reset(void); | |||||
#endif |
@ -0,0 +1,240 @@ | |||||
#pragma once | |||||
#ifdef __AVR__ | |||||
#include <avr/io.h> | |||||
#include <avr/pgmspace.h> | |||||
#elif defined(ESP8266) | |||||
#include <pgmspace.h> | |||||
#else | |||||
#define PROGMEM | |||||
#endif | |||||
// Helidox 8x6 font with QMK Firmware Logo | |||||
// Online editor: http://teripom.x0.com/ | |||||
// New online editor: https://joric.github.io/qle/ | |||||
static const unsigned char PROGMEM font[] = { | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x00, | |||||
0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 0x00, | |||||
0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x00, | |||||
0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x00, | |||||
0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x00, | |||||
0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00, | |||||
0x00, 0x00, 0x08, 0x08, 0x00, 0x00, | |||||
0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00, | |||||
0x00, 0x18, 0x24, 0x18, 0x00, 0x00, | |||||
0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x00, | |||||
0x30, 0x48, 0x3A, 0x06, 0x0E, 0x00, | |||||
0x26, 0x29, 0x79, 0x29, 0x26, 0x00, | |||||
0x40, 0x7F, 0x05, 0x05, 0x07, 0x00, | |||||
0x40, 0x7F, 0x05, 0x25, 0x3F, 0x00, | |||||
0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x00, | |||||
0x7F, 0x3E, 0x1C, 0x1C, 0x08, 0x00, | |||||
0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x00, | |||||
0x14, 0x22, 0x7F, 0x22, 0x14, 0x00, | |||||
0x5F, 0x5F, 0x00, 0x5F, 0x5F, 0x00, | |||||
0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00, | |||||
0x00, 0x66, 0x89, 0x95, 0x6A, 0x00, | |||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x00, | |||||
0x94, 0xA2, 0xFF, 0xA2, 0x94, 0x00, | |||||
0x08, 0x04, 0x7E, 0x04, 0x08, 0x00, | |||||
0x10, 0x20, 0x7E, 0x20, 0x10, 0x00, | |||||
0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, | |||||
0x08, 0x1C, 0x2A, 0x08, 0x08, 0x00, | |||||
0x1E, 0x10, 0x10, 0x10, 0x10, 0x00, | |||||
0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x00, | |||||
0x30, 0x38, 0x3E, 0x38, 0x30, 0x00, | |||||
0x06, 0x0E, 0x3E, 0x0E, 0x06, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, | |||||
0x00, 0x07, 0x00, 0x07, 0x00, 0x00, | |||||
0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, | |||||
0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, | |||||
0x23, 0x13, 0x08, 0x64, 0x62, 0x00, | |||||
0x36, 0x49, 0x56, 0x20, 0x50, 0x00, | |||||
0x00, 0x08, 0x07, 0x03, 0x00, 0x00, | |||||
0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, | |||||
0x00, 0x41, 0x22, 0x1C, 0x00, 0x00, | |||||
0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00, | |||||
0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, | |||||
0x00, 0x80, 0x70, 0x30, 0x00, 0x00, | |||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x00, | |||||
0x00, 0x00, 0x60, 0x60, 0x00, 0x00, | |||||
0x20, 0x10, 0x08, 0x04, 0x02, 0x00, | |||||
0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, | |||||
0x00, 0x42, 0x7F, 0x40, 0x00, 0x00, | |||||
0x72, 0x49, 0x49, 0x49, 0x46, 0x00, | |||||
0x21, 0x41, 0x49, 0x4D, 0x33, 0x00, | |||||
0x18, 0x14, 0x12, 0x7F, 0x10, 0x00, | |||||
0x27, 0x45, 0x45, 0x45, 0x39, 0x00, | |||||
0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00, | |||||
0x41, 0x21, 0x11, 0x09, 0x07, 0x00, | |||||
0x36, 0x49, 0x49, 0x49, 0x36, 0x00, | |||||
0x46, 0x49, 0x49, 0x29, 0x1E, 0x00, | |||||
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | |||||
0x00, 0x40, 0x34, 0x00, 0x00, 0x00, | |||||
0x00, 0x08, 0x14, 0x22, 0x41, 0x00, | |||||
0x14, 0x14, 0x14, 0x14, 0x14, 0x00, | |||||
0x00, 0x41, 0x22, 0x14, 0x08, 0x00, | |||||
0x02, 0x01, 0x59, 0x09, 0x06, 0x00, | |||||
0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00, | |||||
0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00, | |||||
0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, | |||||
0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, | |||||
0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00, | |||||
0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, | |||||
0x7F, 0x09, 0x09, 0x09, 0x01, 0x00, | |||||
0x3E, 0x41, 0x41, 0x51, 0x73, 0x00, | |||||
0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, | |||||
0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, | |||||
0x20, 0x40, 0x41, 0x3F, 0x01, 0x00, | |||||
0x7F, 0x08, 0x14, 0x22, 0x41, 0x00, | |||||
0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, | |||||
0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00, | |||||
0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, | |||||
0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, | |||||
0x7F, 0x09, 0x09, 0x09, 0x06, 0x00, | |||||
0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00, | |||||
0x7F, 0x09, 0x19, 0x29, 0x46, 0x00, | |||||
0x26, 0x49, 0x49, 0x49, 0x32, 0x00, | |||||
0x03, 0x01, 0x7F, 0x01, 0x03, 0x00, | |||||
0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00, | |||||
0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, | |||||
0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00, | |||||
0x63, 0x14, 0x08, 0x14, 0x63, 0x00, | |||||
0x03, 0x04, 0x78, 0x04, 0x03, 0x00, | |||||
0x61, 0x59, 0x49, 0x4D, 0x43, 0x00, | |||||
0x00, 0x7F, 0x41, 0x41, 0x41, 0x00, | |||||
0x02, 0x04, 0x08, 0x10, 0x20, 0x00, | |||||
0x00, 0x41, 0x41, 0x41, 0x7F, 0x00, | |||||
0x04, 0x02, 0x01, 0x02, 0x04, 0x00, | |||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x00, | |||||
0x00, 0x03, 0x07, 0x08, 0x00, 0x00, | |||||
0x20, 0x54, 0x54, 0x78, 0x40, 0x00, | |||||
0x7F, 0x28, 0x44, 0x44, 0x38, 0x00, | |||||
0x38, 0x44, 0x44, 0x44, 0x28, 0x00, | |||||
0x38, 0x44, 0x44, 0x28, 0x7F, 0x00, | |||||
0x38, 0x54, 0x54, 0x54, 0x18, 0x00, | |||||
0x00, 0x08, 0x7E, 0x09, 0x02, 0x00, | |||||
0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x00, | |||||
0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, | |||||
0x00, 0x44, 0x7D, 0x40, 0x00, 0x00, | |||||
0x20, 0x40, 0x40, 0x3D, 0x00, 0x00, | |||||
0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, | |||||
0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, | |||||
0x7C, 0x04, 0x78, 0x04, 0x78, 0x00, | |||||
0x7C, 0x08, 0x04, 0x04, 0x78, 0x00, | |||||
0x38, 0x44, 0x44, 0x44, 0x38, 0x00, | |||||
0xFC, 0x18, 0x24, 0x24, 0x18, 0x00, | |||||
0x18, 0x24, 0x24, 0x18, 0xFC, 0x00, | |||||
0x7C, 0x08, 0x04, 0x04, 0x08, 0x00, | |||||
0x48, 0x54, 0x54, 0x54, 0x24, 0x00, | |||||
0x04, 0x04, 0x3F, 0x44, 0x24, 0x00, | |||||
0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00, | |||||
0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, | |||||
0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00, | |||||
0x44, 0x28, 0x10, 0x28, 0x44, 0x00, | |||||
0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00, | |||||
0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, | |||||
0x00, 0x08, 0x36, 0x41, 0x00, 0x00, | |||||
0x00, 0x00, 0x77, 0x00, 0x00, 0x00, | |||||
0x00, 0x41, 0x36, 0x08, 0x00, 0x00, | |||||
0x02, 0x01, 0x02, 0x04, 0x02, 0x00, | |||||
0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00, | |||||
0x00, 0xF0, 0xFC, 0xFE, 0xFE, 0x3F, | |||||
0x1F, 0x0F, 0x0F, 0x0F, 0x0F, 0x9F, | |||||
0xFF, 0xFE, 0xFE, 0xFC, 0xF0, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, | |||||
0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, | |||||
0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, | |||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x0F, | |||||
0x1F, 0xFE, 0xFE, 0xF8, 0x00, 0x00, | |||||
0x00, 0xF0, 0xFC, 0xFE, 0xFE, 0x3F, | |||||
0x1F, 0x0F, 0x0F, 0x0F, 0x0F, 0x1F, | |||||
0x3F, 0xFE, 0xFE, 0xFC, 0xF0, 0x00, | |||||
0x03, 0x0F, 0x3F, 0xFF, 0xFF, 0xFC, | |||||
0xF0, 0xC0, 0x00, 0x00, 0xC0, 0xF0, | |||||
0xFC, 0xFF, 0xFF, 0x3F, 0x0F, 0x03, | |||||
0x3E, 0x2A, 0x22, 0x00, 0x3E, 0x0C, | |||||
0x18, 0x3E, 0x00, 0x3E, 0x22, 0x1C, | |||||
0x00, 0x1C, 0x22, 0x32, 0x00, 0x3C, | |||||
0x0A, 0x3C, 0x00, 0x3E, 0x04, 0x08, | |||||
0x04, 0x3E, 0x00, 0x3E, 0x2A, 0x22, | |||||
0x00, 0x3E, 0x22, 0x22, 0x00, 0x02, | |||||
0x3E, 0x02, 0x00, 0x3E, 0x20, 0x20, | |||||
0x00, 0x3C, 0x0A, 0x3C, 0x00, 0x3E, | |||||
0x20, 0x20, 0x02, 0x3E, 0x02, 0x00, | |||||
0x00, 0x24, 0x2A, 0x12, 0x00, 0x3E, | |||||
0x0A, 0x02, 0x00, 0x02, 0x3E, 0x02, | |||||
0x00, 0x3E, 0x22, 0x32, 0x00, 0x3E, | |||||
0x20, 0x3E, 0x00, 0x3E, 0x00, 0x00, | |||||
0x00, 0x00, 0x08, 0x08, 0x08, 0x08, | |||||
0x08, 0x08, 0x08, 0x08, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, | |||||
0xF0, 0xF8, 0x7C, 0x3E, 0x1F, 0x0F, | |||||
0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, | |||||
0x00, 0x00, 0xC0, 0xF8, 0xFF, 0xFF, | |||||
0xFF, 0xE7, 0xE0, 0xE0, 0xE7, 0xFF, | |||||
0xFF, 0xFF, 0xF8, 0xC0, 0x00, 0x00, | |||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, | |||||
0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x7E, | |||||
0xFF, 0xE7, 0xE7, 0x81, 0x00, 0x00, | |||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0xC3, 0xFF, | |||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |||||
0xFF, 0xC3, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x07, 0x04, 0x1F, 0x00, 0x1F, 0x15, | |||||
0x1F, 0x00, 0x00, 0x00, 0x00, 0x0C, | |||||
0x10, 0x0C, 0x00, 0x1D, 0x15, 0x17, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x0F, 0x3F, 0x7F, 0x7F, 0xFF, | |||||
0xF9, 0xF0, 0xF0, 0xF0, 0xF0, 0xF8, | |||||
0xFC, 0x7F, 0x7F, 0x3F, 0x0F, 0x00, | |||||
0xF0, 0xFE, 0xFF, 0xFF, 0x0F, 0x01, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x01, 0x0F, 0xFF, 0xFF, 0xFE, 0xF0, | |||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, | |||||
0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xF0, | |||||
0xF8, 0x7F, 0x7F, 0x1F, 0x00, 0x00, | |||||
0x00, 0x0F, 0x3F, 0x7F, 0x7F, 0xFC, | |||||
0xF8, 0xF0, 0xF0, 0xF0, 0xF0, 0xF8, | |||||
0xFC, 0x7F, 0x7F, 0x3F, 0x0F, 0x00, | |||||
0xC0, 0xF0, 0xFC, 0xFF, 0xFF, 0x3F, | |||||
0x0F, 0x03, 0x00, 0x00, 0x03, 0x0F, | |||||
0x3F, 0xFF, 0xFF, 0xFC, 0xF0, 0xC0, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
}; |
@ -0,0 +1,60 @@ | |||||
{ | |||||
"keyboard_name": "Endgame48", | |||||
"url": "", | |||||
"maintainer": "and3rson", | |||||
"layouts": { | |||||
"LAYOUT": { | |||||
"layout": [ | |||||
{ "w": 1, "x": 0, "y": 0 }, | |||||
{ "w": 1, "x": 1, "y": 0 }, | |||||
{ "w": 1, "x": 2, "y": 0 }, | |||||
{ "w": 1, "x": 3, "y": 0 }, | |||||
{ "w": 1, "x": 4, "y": 0 }, | |||||
{ "w": 1, "x": 5, "y": 0 }, | |||||
{ "w": 1, "x": 7, "y": 0 }, | |||||
{ "w": 1, "x": 8, "y": 0 }, | |||||
{ "w": 1, "x": 9, "y": 0 }, | |||||
{ "w": 1, "x": 10, "y": 0 }, | |||||
{ "w": 1, "x": 11, "y": 0 }, | |||||
{ "w": 1, "x": 12, "y": 0 }, | |||||
{ "w": 1, "x": 0, "y": 1 }, | |||||
{ "w": 1, "x": 1, "y": 1 }, | |||||
{ "w": 1, "x": 2, "y": 1 }, | |||||
{ "w": 1, "x": 3, "y": 1 }, | |||||
{ "w": 1, "x": 4, "y": 1 }, | |||||
{ "w": 1, "x": 5, "y": 1 }, | |||||
{ "w": 1, "x": 7, "y": 1 }, | |||||
{ "w": 1, "x": 8, "y": 1 }, | |||||
{ "w": 1, "x": 9, "y": 1 }, | |||||
{ "w": 1, "x": 10, "y": 1 }, | |||||
{ "w": 1, "x": 11, "y": 1 }, | |||||
{ "w": 1, "x": 12, "y": 1 }, | |||||
{ "w": 1, "x": 0, "y": 2 }, | |||||
{ "w": 1, "x": 1, "y": 2 }, | |||||
{ "w": 1, "x": 2, "y": 2 }, | |||||
{ "w": 1, "x": 3, "y": 2 }, | |||||
{ "w": 1, "x": 4, "y": 2 }, | |||||
{ "w": 1, "x": 5, "y": 2 }, | |||||
{ "w": 1, "x": 7, "y": 2 }, | |||||
{ "w": 1, "x": 8, "y": 2 }, | |||||
{ "w": 1, "x": 9, "y": 2 }, | |||||
{ "w": 1, "x": 10, "y": 2 }, | |||||
{ "w": 1, "x": 11, "y": 2 }, | |||||
{ "w": 1, "x": 12, "y": 2 }, | |||||
{ "w": 1, "x": 0, "y": 3 }, | |||||
{ "w": 1, "x": 1, "y": 3 }, | |||||
{ "w": 1, "x": 2, "y": 3 }, | |||||
{ "w": 1, "x": 3, "y": 3 }, | |||||
{ "w": 1, "x": 4, "y": 3 }, | |||||
{ "w": 1, "x": 5, "y": 3 }, | |||||
{ "w": 1, "x": 6, "y": 3 }, | |||||
{ "w": 1, "x": 7, "y": 3 }, | |||||
{ "w": 1, "x": 8, "y": 3 }, | |||||
{ "w": 1, "x": 9, "y": 3 }, | |||||
{ "w": 1, "x": 10, "y": 3 }, | |||||
{ "w": 1, "x": 11, "y": 3 }, | |||||
{ "w": 1, "x": 12, "y": 3 } ] | |||||
} | |||||
} | |||||
} | |||||
@ -0,0 +1,4 @@ | |||||
// Copyright 2022 Andrew Dunai (@and3rson) | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#define OLED_TIMEOUT 30000 |
@ -0,0 +1,221 @@ | |||||
// Copyright 2022 Andrew Dunai (@and3rson) | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#include "endgame48.h" | |||||
#include "config.h" | |||||
#include "taphold.h" | |||||
#include "rgblight.h" | |||||
#include "oled/oled_driver.h" | |||||
#include "smoothled.h" | |||||
#include "stdio.h" | |||||
#include "string.h" | |||||
#include "symbols.h" | |||||
#define ________ KC_TRNS | |||||
#define _MAIN 0 | |||||
#define _ALPHA 1 | |||||
#define _BETA 2 | |||||
#define _SIGMA 3 | |||||
#define F_DASH "\x9c\x9d" | |||||
uint32_t layer_colors[4] = { | |||||
0x4020FF, | |||||
0xFF0010, | |||||
0x20FF00, | |||||
0x40FFFF | |||||
}; | |||||
enum custom_keycodes { | |||||
KC_MAIN = EG_SAFE_RANGE, | |||||
KC_ALPHA, | |||||
KC_BETA, | |||||
}; | |||||
/* TapHold is my own implementation of the `LT` macro. It's processed in `process_record_user()`. */ | |||||
uint16_t taphold_config_size = 3; | |||||
taphold_t taphold_config[] = { | |||||
{.key=KC_ALPHA, .mode=TAPHOLD_LAYER, .shortAction=KC_ESC, .longAction=_ALPHA}, | |||||
{.key=KC_BETA, .mode=TAPHOLD_LAYER, .shortAction=KC_EQL, .longAction=_BETA}, | |||||
{.key=KC_LCTRL, .mode=TAPHOLD_MOD, .shortAction=KC_MINS, .longAction=KC_LCTRL}, | |||||
}; | |||||
uint32_t taphold_timeout = 100; | |||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||||
/* Main layer | |||||
┏━━━━━┳━━━━━┯━━━━━┯━━━━━┯━━━━━┯━━━━━┓┏┳━┳┓┏━━━━━┯━━━━━┯━━━━━┯━━━━━┯━━━━━┳━━━━━┓ | |||||
┃ TAB ┃ Q │ W │ E │ R │ T ┃┃┃ ┃┃┃ Y │ U │ I │ O │ P ┃ BSP ┃ | |||||
┣━━━━━╉─────┼─────┼─────┼─────┼─────┨┃┃ ┃┃┣─────┼─────┼─────┼─────┼─────╊━━━━━┫ | |||||
┃𝛼/ESC┃ A │ S │ D │ F │ G ┃┃┃ ┃┃┃ H │ J │ K │ L │ ; ┃ RET ┃ | |||||
┣━━━━━╉─────┼─────┼─────┼─────┼─────┨┗┻━┻┛┣─────┼─────┼─────┼─────┼─────╊━━━━━┫ | |||||
┃SHIFT┃ Z │ X │ C │ V │ B ┃ ┃ N │ M │ , │ . │ / ┃LCTRL┃ | |||||
┣━━━━━╉─────┼─────┼─────┼─────┼─────┨ ┣─────┼─────┼─────┼─────┼─────╊━━━━━┫ | |||||
┃CTRL ┃ │ │ ALT │ GUI │SPACE┃ (o) ┃SPACE│ 𝛽/= │ ' │ │ ┃ ┃ | |||||
┗━━━━━┻━━━━━┷━━━━━┷━━━━━┷━━━━━┷━━━━━┛ ┗━━━━━┷━━━━━┷━━━━━┷━━━━━┷━━━━━┻━━━━━┛ | |||||
*/ | |||||
[_MAIN] = LAYOUT( \ | |||||
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC, \ | |||||
KC_ALPHA,KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_ENT, \ | |||||
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_LCTRL,\ | |||||
KC_LCTRL,________,________,KC_LALT, KC_LGUI, KC_SPC, KC_EGMENU,KC_SPC, KC_BETA, KC_QUOT, ________,________,________\ | |||||
), | |||||
/* 𝛼 layer | |||||
┏━━━━━┳━━━━━┯━━━━━┯━━━━━┯━━━━━┯━━━━━┓┏┳━┳┓┏━━━━━┯━━━━━┯━━━━━┯━━━━━┯━━━━━┳━━━━━┓ | |||||
┃ ┃PREV │PLAY │NEXT │ │ ┃┃┃ ┃┃┃ - │ ^^^ │ ^ │ vvv │ ~ ┃ DEL ┃ | |||||
┣━━━━━╉─────┼─────┼─────┼─────┼─────┨┃┃ ┃┃┣─────┼─────┼─────┼─────┼─────╊━━━━━┫ | |||||
┃ ┃ │VOL -│VOL +│ │ ┃┃┃ ┃┃┃HOME │ <-- │ v │ --> │ ` ┃ \ ┃ | |||||
┣━━━━━╉─────┼─────┼─────┼─────┼─────┨┗┻━┻┛┣─────┼─────┼─────┼─────┼─────╊━━━━━┫ | |||||
┃ ┃ │ │ │ │ ┃ ┃ END │ = │ [ │ ] │ ( ┃ ) ┃ | |||||
┣━━━━━╉─────┼─────┼─────┼─────┼─────┨ ┣─────┼─────┼─────┼─────┼─────╊━━━━━┫ | |||||
┃ ┃ │ │ │ │ ┃ (o) ┃ │ │ │ │ ┃ ┃ | |||||
┗━━━━━┻━━━━━┷━━━━━┷━━━━━┷━━━━━┷━━━━━┛ ┗━━━━━┷━━━━━┷━━━━━┷━━━━━┷━━━━━┻━━━━━┛ | |||||
*/ | |||||
[_ALPHA] = LAYOUT( \ | |||||
________,KC_MPRV, KC_MPLY, KC_MNXT, ________,________, KC_MINS, KC_PGUP, KC_UP, KC_PGDN, KC_TILD, KC_DEL, \ | |||||
________,________,KC_VOLD, KC_VOLU, ________,________, KC_HOME, KC_LEFT, KC_DOWN, KC_RIGHT,KC_GRV, KC_BSLS, \ | |||||
________,________,________,________,________,________, KC_END, KC_EQL, KC_LBRC, KC_RBRC, LSFT(KC_9),LSFT(KC_0),\ | |||||
________,________,________,________,________,________,________,________,________,________,________,________,________\ | |||||
), | |||||
/* 𝛽 layer | |||||
┏━━━━━┳━━━━━┯━━━━━┯━━━━━┯━━━━━┯━━━━━┓┏┳━┳┓┏━━━━━┯━━━━━┯━━━━━┯━━━━━┯━━━━━┳━━━━━┓ | |||||
┃ RGB ┃ 1 │ 2 │ 3 │ 4 │ 5 ┃┃┃ ┃┃┃ 6 │ 7 │ 8 │ 9 │ 0 ┃ F12 ┃ | |||||
┣━━━━━╉─────┼─────┼─────┼─────┼─────┨┃┃ ┃┃┣─────┼─────┼─────┼─────┼─────╊━━━━━┫ | |||||
┃ ┃ F1 │ F2 │ F3 │ F4 │ F5 ┃┃┃ ┃┃┃ F6 │ F7 │ F8 │ F9 │ F10 ┃ F11 ┃ | |||||
┣━━━━━╉─────┼─────┼─────┼─────┼─────┨┗┻━┻┛┣─────┼─────┼─────┼─────┼─────╊━━━━━┫ | |||||
┃ ┃RESET│DEBUG│SLEEP│WAKE │EGMNU ┃ ┃ │ │ { │ } │ ┃ ┃ | |||||
┣━━━━━╉─────┼─────┼─────┼─────┼─────┨ ┣─────┼─────┼─────┼─────┼─────╊━━━━━┫ | |||||
┃ ┃ │ │ │ │ ┃ (o) ┃PTSCR│ │ │ │ ┃ ┃ | |||||
┗━━━━━┻━━━━━┷━━━━━┷━━━━━┷━━━━━┷━━━━━┛ ┗━━━━━┷━━━━━┷━━━━━┷━━━━━┷━━━━━┻━━━━━┛ | |||||
*/ | |||||
[_BETA] = LAYOUT( \ | |||||
RGB_TOG, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_F12, \ | |||||
________,KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, \ | |||||
________,RESET, DEBUG, KC_PWR, KC_WAKE, KC_EGMENU, ________,________,KC_LCBR, KC_RCBR, ________,________,\ | |||||
________,________,________,________,________,KC_MUTE, ________,KC_PSCR, ________,________,________,________,________\ | |||||
), | |||||
/* Σ layer | |||||
┏━━━━━┳━━━━━┯━━━━━┯━━━━━┯━━━━━┯━━━━━┓┏┳━┳┓┏━━━━━┯━━━━━┯━━━━━┯━━━━━┯━━━━━┳━━━━━┓ | |||||
┃ ┃ │ │ │ │ ┃┃┃ ┃┃┃ │ │ │ │ ┃ ┃ | |||||
┣━━━━━╉─────┼─────┼─────┼─────┼─────┨┃┃ ┃┃┣─────┼─────┼─────┼─────┼─────╊━━━━━┫ | |||||
┃ ┃ │ │ │ │ ┃┃┃ ┃┃┃ │ │ │ │ ┃ ┃ | |||||
┣━━━━━╉─────┼─────┼─────┼─────┼─────┨┗┻━┻┛┣─────┼─────┼─────┼─────┼─────╊━━━━━┫ | |||||
┃ ┃ │ │ │ │ ┃ ┃ │ │ │ │ ┃ ┃ | |||||
┣━━━━━╉─────┼─────┼─────┼─────┼─────┨ ┣─────┼─────┼─────┼─────┼─────╊━━━━━┫ | |||||
┃ ┃ │ │ │ │ ┃ (o) ┃ │ │ │ │ ┃ ┃ | |||||
┗━━━━━┻━━━━━┷━━━━━┷━━━━━┷━━━━━┷━━━━━┛ ┗━━━━━┷━━━━━┷━━━━━┷━━━━━┷━━━━━┻━━━━━┛ | |||||
*/ | |||||
[_SIGMA] = LAYOUT( \ | |||||
________,________,________,________,________,________, ________,________,________,________,________,________,\ | |||||
________,________,________,________,________,________, ________,________,________,________,________,________,\ | |||||
________,________,________,________,________,________, ________,________,________,________,________,________,\ | |||||
________,________,________,________,________,________,________,________,________,________,________,________,________\ | |||||
), | |||||
}; | |||||
static bool alpha_pressed = false; | |||||
static bool beta_pressed = false; | |||||
static bool ctrl_pressed = false; | |||||
static bool alt_pressed = false; | |||||
static bool shift_pressed = false; | |||||
static bool gui_pressed = false; | |||||
static volatile uint32_t last_scan; | |||||
static volatile uint32_t scan_interval; | |||||
void matrix_init_user(void) { | |||||
smoothled_set(layer_colors[0], 1500, swimOut); | |||||
} | |||||
void matrix_scan_user(void) { | |||||
uint32_t now = timer_read32(); | |||||
scan_interval = now - last_scan; | |||||
last_scan = now; | |||||
smoothled_process(); | |||||
} | |||||
void suspend_power_down_user(void) { | |||||
smoothled_set(0, 0, swimIn); | |||||
} | |||||
void suspend_wakeup_init_user(void) { | |||||
smoothled_set(layer_colors[_MAIN], 1500, swimOut); | |||||
} | |||||
layer_state_t layer_state_set_user(layer_state_t state) { | |||||
layer_state_t prevState = update_tri_layer_state(layer_state, _ALPHA, _BETA, _SIGMA); | |||||
state = update_tri_layer_state(state, _ALPHA, _BETA, _SIGMA); | |||||
uint8_t prevLayer = biton32(prevState); | |||||
uint8_t layer = biton32(state); | |||||
smoothled_set(layer_colors[layer], 250, prevLayer < layer ? swimOut : swimIn); | |||||
return state; | |||||
} | |||||
bool process_record_user(uint16_t keycode, keyrecord_t *record) { | |||||
if (keycode == KC_LCTRL) ctrl_pressed = record->event.pressed; | |||||
if (keycode == KC_LALT) alt_pressed = record->event.pressed; | |||||
if (keycode == KC_LSFT) shift_pressed = record->event.pressed; | |||||
if (keycode == KC_LGUI) gui_pressed = record->event.pressed; | |||||
if (keycode == RESET) { | |||||
request_reset(); | |||||
return false; | |||||
} | |||||
if (keycode == KC_ALPHA) alpha_pressed = record->event.pressed; | |||||
if (keycode == KC_BETA) beta_pressed = record->event.pressed; | |||||
return taphold_process(keycode, record); | |||||
} | |||||
bool encoder_update_user(uint8_t index, bool clockwise) { | |||||
if (index == 0) { | |||||
if (alpha_pressed) { | |||||
if (clockwise) { | |||||
tap_code(KC_VOLU); | |||||
} else { | |||||
tap_code(KC_VOLD); | |||||
} | |||||
} else if (beta_pressed) { | |||||
if (clockwise) { | |||||
tap_code(KC_PGDN); | |||||
} else { | |||||
tap_code(KC_PGUP); | |||||
} | |||||
} else { | |||||
if (clockwise) { | |||||
tap_code(KC_MS_WH_DOWN); | |||||
} else { | |||||
tap_code(KC_MS_WH_UP); | |||||
} | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
bool oled_task_user(void) { | |||||
oled_write_P(logo, false); | |||||
uint8_t current_layer = biton32(layer_state); | |||||
oled_write_P(layerIcons[current_layer], current_layer != _MAIN); | |||||
oled_write_P(PSTR("\n\n"), false); | |||||
char mod_data[12] = F_DASH " " F_DASH F_DASH " " F_DASH "\n\0"; | |||||
if (ctrl_pressed) memcpy(mod_data, mods[0], 2); | |||||
if (alt_pressed) memcpy(mod_data +3, mods[1], 2); | |||||
if (shift_pressed) memcpy(mod_data + 5, mods[2], 2); | |||||
if (gui_pressed) memcpy(mod_data + 8, mods[3], 2); | |||||
oled_write(mod_data, false); | |||||
char buf[10] = " "; | |||||
buf[sprintf(buf, "%2lums", scan_interval ? scan_interval : 1L)] = ' '; | |||||
buf[5] = 0; | |||||
oled_write(buf, false); | |||||
return false; | |||||
} |
@ -0,0 +1,5 @@ | |||||
ifndef QUANTUM_DIR | |||||
include ../../../../Makefile | |||||
endif | |||||
SRC += smoothled.c |
@ -0,0 +1,80 @@ | |||||
// Copyright 2022 Andrew Dunai (@and3rson) | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#include "endgame48.h" | |||||
#include "smoothled.h" | |||||
#include "math.h" | |||||
#include "string.h" | |||||
static LED_TYPE source[RGBLED_NUM] = {}; | |||||
static LED_TYPE current[RGBLED_NUM] = {}; | |||||
static LED_TYPE target[RGBLED_NUM] = {}; | |||||
static uint32_t duration = 1500; | |||||
static int32_t smoothledTimer = -1; | |||||
static animFunc_t animFunc; | |||||
const float RGBLED_STEP = 1.0f / ((float)RGBLED_NUM); | |||||
void smoothled_set(uint32_t color, uint32_t newDuration, animFunc_t newAnimFunc) { | |||||
smoothledTimer = timer_read32(); | |||||
LED_TYPE next = {.r = (color >> 16) & 0xFF, .g = (color >> 8) & 0xFF, .b = color & 0xFF}; | |||||
for (uint8_t p = 0; p < RGBLED_NUM; p++) { | |||||
source[p] = current[p]; | |||||
target[p] = next; | |||||
} | |||||
duration = newDuration; | |||||
animFunc = newAnimFunc; | |||||
} | |||||
LED_TYPE swimOut(LED_TYPE a, LED_TYPE b, float k, uint8_t x) { | |||||
k = pow(k, 2); | |||||
/* Center */ | |||||
x = fabs(5.5 - ((float)x)); | |||||
/* Time range for current LED */ | |||||
float start = RGBLED_STEP * x; | |||||
float end = RGBLED_STEP * (x + 1); | |||||
if (k <= start) { | |||||
k = 0; | |||||
} else if (k >= end) { | |||||
k = 1; | |||||
} else { | |||||
k = (k - start) / RGBLED_STEP; | |||||
} | |||||
float rk = 1.0f - k; | |||||
return (LED_TYPE){ | |||||
.r = rk * a.r + k * b.r, | |||||
.g = rk * a.g + k * b.g, | |||||
.b = rk * a.b + k * b.b, | |||||
}; | |||||
} | |||||
LED_TYPE swimIn(LED_TYPE a, LED_TYPE b, float k, uint8_t x) { | |||||
if (x < RGBLED_NUM / 2) { | |||||
x = RGBLED_NUM / 2 - x - 1; | |||||
} else { | |||||
x = RGBLED_NUM - (x - RGBLED_NUM / 2 - 1); | |||||
} | |||||
return swimOut(a, b, k, x); | |||||
} | |||||
void smoothled_process(void) { | |||||
if (smoothledTimer == -1) { | |||||
return; | |||||
} | |||||
smoothled_render(); | |||||
} | |||||
void smoothled_render(void) { | |||||
uint32_t passed = timer_elapsed32(smoothledTimer); | |||||
if (passed > duration) { | |||||
passed = duration; | |||||
smoothledTimer = -1; | |||||
} | |||||
float k = ((float)passed) / duration; | |||||
for (uint8_t p = 0; p < RGBLED_NUM; p++) { | |||||
current[p] = animFunc(source[p], target[p], k, p); | |||||
/* This is much faster than calling rgblight_setrgb_at every iteration */ | |||||
led[p] = current[p]; | |||||
} | |||||
rgblight_set(); | |||||
} |
@ -0,0 +1,15 @@ | |||||
// Copyright 2022 Andrew Dunai (@and3rson) | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#include "quantum.h" | |||||
#include "config.h" | |||||
#include "rgblight.h" | |||||
typedef LED_TYPE (*animFunc_t)(LED_TYPE, LED_TYPE, float, uint8_t); | |||||
LED_TYPE swimIn(LED_TYPE, LED_TYPE, float, uint8_t); | |||||
LED_TYPE swimOut(LED_TYPE, LED_TYPE, float, uint8_t); | |||||
void smoothled_set(uint32_t color, uint32_t newDuration, animFunc_t newAnimFunc); | |||||
void smoothled_process(void); | |||||
void smoothled_render(void); |
@ -0,0 +1,86 @@ | |||||
// Copyright 2022 Andrew Dunai (@and3rson) | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#include "menu.h" | |||||
static int8_t menu_depth = -1; | |||||
static menu_t *menus[8]; | |||||
#define MENU_OPENED menu_depth != -1 | |||||
#define MENU_CURRENT menus[menu_depth] | |||||
#define MENU_MAX_ITEMS 10 | |||||
bool menu_process_record(uint16_t keycode, keyrecord_t *record) { | |||||
if (MENU_OPENED) { | |||||
/* Menu is open */ | |||||
if (record->event.pressed) { | |||||
if (keycode == KC_EGMENU) { | |||||
menu_t *menu = MENU_CURRENT; | |||||
menu_item_t item = menu->items[menu->current]; | |||||
if (item.submenu != NULL) { | |||||
item.submenu->current = 0; | |||||
item.submenu->scroll = 0; | |||||
menus[++menu_depth] = item.submenu; | |||||
item.submenu->opened(item.submenu); | |||||
} else if (item.func != NULL) { | |||||
item.func(); | |||||
menu_depth = -1; | |||||
} | |||||
} else { | |||||
menu_depth--; | |||||
} | |||||
} | |||||
return false; | |||||
} else if (keycode == KC_EGMENU) { | |||||
/* Menu is not open, KC_EGMENU pressed */ | |||||
if (record->event.pressed) { | |||||
main_menu.current = 0; | |||||
main_menu.scroll = 0; | |||||
menus[++menu_depth] = &main_menu; | |||||
} | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
bool menu_encoder_update(uint8_t index, bool clockwise) { | |||||
if (MENU_OPENED) { | |||||
menu_t *menu = MENU_CURRENT; | |||||
if (clockwise) { | |||||
if (menu->current < menu->count - 1) { | |||||
menu->current++; | |||||
} | |||||
if (menu->current - menu->scroll >= MENU_MAX_ITEMS) { | |||||
menu->scroll++; | |||||
} | |||||
} else { | |||||
if (menu->current) { | |||||
menu->current--; | |||||
} | |||||
if (menu->current < menu->scroll) { | |||||
menu->scroll--; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
bool menu_oled_task(void) { | |||||
if (MENU_OPENED) { | |||||
oled_clear(); | |||||
oled_write_P(logo, false); | |||||
menu_t *menu = MENU_CURRENT; | |||||
char title[7] = " \0\0"; | |||||
sprintf(title, "%-5s", menu->title); | |||||
title[5] = '\n'; | |||||
oled_write(title, false); | |||||
for (uint8_t i = menu->scroll; i < (menu->count >= MENU_MAX_ITEMS ? menu->scroll + MENU_MAX_ITEMS : menu->count); i++) { | |||||
char buf[6] = " \0"; | |||||
sprintf(buf, "%-5s", menu->items[i].title); | |||||
oled_write(buf, menu->current == i); | |||||
} | |||||
return false; | |||||
} | |||||
return true; | |||||
} |
@ -0,0 +1,30 @@ | |||||
// Copyright 2022 Andrew Dunai (@and3rson) | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#include "quantum.h" | |||||
#include "stdint.h" | |||||
#include "endgame48.h" | |||||
#include "symbols.h" | |||||
#include "oled/oled_driver.h" | |||||
#include "stdio.h" | |||||
typedef struct menu_item_t { | |||||
char title[6]; | |||||
void (*func)(void); | |||||
struct menu_t *submenu; | |||||
} menu_item_t; | |||||
typedef struct menu_t { | |||||
char *title; | |||||
uint8_t count; | |||||
uint8_t current; | |||||
uint8_t scroll; | |||||
void (*opened)(struct menu_t *); | |||||
menu_item_t *items; | |||||
} menu_t; | |||||
extern menu_t main_menu; | |||||
bool menu_process_record(uint16_t keycode, keyrecord_t *record); | |||||
bool menu_encoder_update(uint8_t index, bool clockwise); | |||||
bool menu_oled_task(void); |
@ -0,0 +1,64 @@ | |||||
# Endgame48 | |||||
![Endgame48](https://i.imgur.com/asU6f9G.jpeg) | |||||
Puchi-C based 40% keyboard with rotary encoder and I2C OLED. | |||||
* Keyboard Maintainer: Andrew Dunai | |||||
* Hardware Supported: Puchi-C handwired | |||||
* Hardware Availability: [Keycapsss.com](https://keycapsss.com) | |||||
Make example for this keyboard (after setting up your build environment): | |||||
make handwired/endgame48:default:dfu | |||||
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs). | |||||
## Details | |||||
- Puchi-C based handwired keyboard | |||||
- 2x custom 1.25mm stainless steel plates | |||||
- Kailh Choc White (clicky) | |||||
- Rotary encoder | |||||
- 0.91" 128x32 I<sup>2</sup>C OLED | |||||
- WS2812 strip (12 LEDs) | |||||
- OLED menu (triggered with encoder press) which allows you to view EEPROM, reset keyboard, toggle RGB, etc. | |||||
- Handwiring is fun! | |||||
## Pinout | |||||
`PS2D` and `PS2C` are PS/2 `DATA` & `CLOCK` lines. They are not used in this revision but are reserved for future. | |||||
``` | |||||
┌────────┐ | |||||
╭──────┤ ├──────╮ | |||||
RGB> ┿ D3 │ │ RAW ┿ | |||||
│ │ │ │ | |||||
PS2D> ┿ D2 └────────┘ GND ┿ | |||||
│ │ | |||||
┿ GND RST ┿ | |||||
│ [] [] │ | |||||
┿ GND VCC ┿ | |||||
│ │ | |||||
I2C> ┿ D1 ||| || || F4 ┿ <ROW5 | |||||
│ │ | |||||
I2C> ┿ D0 F5 ┿ <COL1 | |||||
│ ╱╲ │ | |||||
ROW1> ┿ D4 ╱ ╲ F6 ┿ <COL2 | |||||
│ ╱ ╲ │ | |||||
ROW3> ┿ C6 ╲ ╱ F7 ┿ <COL3 | |||||
│ ╲ ╱ │ | |||||
COL7> ┿ D7 ╲╱ B1 ┿ <COL4 | |||||
│ │ | |||||
ENCA> ┿ E6 B3 ┿ <COL5 | |||||
│ │ | |||||
ENCB> ┿ B4 B2 ┿ <COL6 | |||||
│ │ | |||||
ROW2> │ B5 B7 D5 C7 F1 F0 B6 ┿ <ROW6 | |||||
╰────╂──╂──╂──╂──╂─────╯ | |||||
┃ ┃ ┃ ┃ | |||||
ROW4 ┛ ┃ ┃ ┗ ROW8 | |||||
┃ ┃ | |||||
PS2C ┛ ┗ ROW7 | |||||
``` |
@ -0,0 +1,29 @@ | |||||
# MCU name | |||||
MCU = atmega32u4 | |||||
BOOTLOADER = atmel-dfu | |||||
BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration | |||||
MOUSEKEY_ENABLE = yes # Mouse keys | |||||
EXTRAKEY_ENABLE = yes # Audio control and System control | |||||
CONSOLE_ENABLE = no # Console for debug | |||||
# https://github.com/qmk/qmk_firmware/blob/master/docs/faq_debug.md | |||||
DEBUG_ENABLE = no # HID prints | |||||
COMMAND_ENABLE = no # Commands for debug and configuration | |||||
SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend | |||||
NKRO_ENABLE = no # USB Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work | |||||
BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality | |||||
AUDIO_ENABLE = no | |||||
RGBLIGHT_ENABLE = yes | |||||
ENCODER_ENABLE = yes | |||||
OLED_ENABLE = yes | |||||
PS2_MOUSE_ENABLE = no | |||||
# PS2_USE_USART = yes | |||||
# PS2_USE_INT = yes | |||||
DEBOUNCE_TYPE = sym_eager_pk | |||||
SRC += taphold.c symbols.c menu.c | |||||
# https://thomasbaart.nl/2018/12/01/reducing-firmware-size-in-qmk/ | |||||
EXTRAFLAGS += -flto |
@ -0,0 +1,58 @@ | |||||
// Copyright 2022 Andrew Dunai (@and3rson) | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#include "symbols.h" | |||||
const char PROGMEM logo[12] = { | |||||
0x8f, 0x90, 0x91, 0x92, 0x93, | |||||
0xaf, 0xb0, 0xb1, 0xb2, 0xb3, | |||||
/* '4', '8', ' ', 'v', '2', */ | |||||
'\n', | |||||
0 | |||||
}; | |||||
const char PROGMEM layerIcons[4][26] = { | |||||
{ | |||||
' ', ' ', ' ', ' ', ' ', | |||||
0x20, 0x80, 0x81, 0x82, 0x20, | |||||
0x20, 0xa0, 0xa1, 0xa2, 0x20, | |||||
0x20, 0xc0, 0xc1, 0xc2, 0x20, | |||||
' ', ' ', ' ', ' ', ' ', 0 | |||||
}, | |||||
{ | |||||
' ', ' ', ' ', ' ', ' ', | |||||
0x20, 0x83, 0x84, 0x85, 0x20, | |||||
0x20, 0xa3, 0xa4, 0xa5, 0x20, | |||||
0x20, 0xc3, 0xc4, 0xc5, 0x20, | |||||
' ', ' ', ' ', ' ', ' ', 0 | |||||
}, | |||||
{ | |||||
' ', ' ', ' ', ' ', ' ', | |||||
0x20, 0x86, 0x87, 0x88, 0x20, | |||||
0x20, 0xa6, 0xa7, 0xa8, 0x20, | |||||
0x20, 0xc6, 0xc7, 0xc8, 0x20, | |||||
' ', ' ', ' ', ' ', ' ', 0 | |||||
}, | |||||
{ | |||||
' ', ' ', ' ', ' ', ' ', | |||||
0x20, 0x89, 0x8a, 0x8b, 0x20, | |||||
0x20, 0xa9, 0xaa, 0xab, 0x20, | |||||
0x20, 0xc9, 0xca, 0xcb, 0x20, | |||||
' ', ' ', ' ', ' ', ' ', 0 | |||||
}, | |||||
}; | |||||
const char PROGMEM resetIcon[26] = { | |||||
' ', ' ', ' ', ' ', ' ', | |||||
' ', 0x8c, 0x8d, 0x8e, ' ', | |||||
' ', 0xac, 0xad, 0xae, ' ', | |||||
' ', 0xcc, 0xcd, 0xce, ' ', | |||||
' ', ' ', ' ', ' ', ' ', 0 | |||||
}; | |||||
const char PROGMEM mods[4][3] = { | |||||
{0x94, 0x95}, | |||||
{0x96, 0x97}, | |||||
{0x98, 0x99}, | |||||
{0x9a, 0x9b}, | |||||
}; |
@ -0,0 +1,9 @@ | |||||
// Copyright 2022 Andrew Dunai (@and3rson) | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#include "endgame48.h" | |||||
extern const char PROGMEM logo[12]; | |||||
extern const char PROGMEM layerIcons[4][26]; | |||||
extern const char PROGMEM resetIcon[26]; | |||||
extern const char PROGMEM mods[4][3]; |
@ -0,0 +1,33 @@ | |||||
// Copyright 2022 Andrew Dunai (@and3rson) | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#include "taphold.h" | |||||
bool taphold_process(uint16_t keycode, keyrecord_t *record) { | |||||
for (int i = 0; i < taphold_config_size; i++) { | |||||
taphold_t *config = &taphold_config[i]; | |||||
if (config->key == keycode && record->event.pressed) { | |||||
if (config->mode == TAPHOLD_LAYER) { | |||||
layer_on(config->longAction); | |||||
} else { | |||||
register_code(config->longAction); | |||||
} | |||||
config->time = timer_read32(); | |||||
config->keypos = record->event.key; | |||||
return false; | |||||
} else if (KEYEQ(record->event.key, config->keypos) && !record->event.pressed) { | |||||
if (config->mode == TAPHOLD_LAYER) { | |||||
layer_off(config->longAction); | |||||
} else { | |||||
unregister_code(config->longAction); | |||||
} | |||||
if (timer_elapsed32(config->time) < taphold_timeout) { | |||||
register_code(config->shortAction); | |||||
unregister_code(config->shortAction); | |||||
} | |||||
config->keypos.row = 255; | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} |
@ -0,0 +1,28 @@ | |||||
// Copyright 2022 Andrew Dunai (@and3rson) | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#include "quantum.h" | |||||
typedef enum taphold_mode_t { | |||||
TAPHOLD_LAYER, | |||||
TAPHOLD_MOD | |||||
} taphold_mode_t; | |||||
typedef struct taphold_t { | |||||
uint16_t key; | |||||
uint32_t time; | |||||
taphold_mode_t mode; | |||||
uint16_t shortAction; | |||||
uint16_t longAction; | |||||
keypos_t keypos; | |||||
/* We store key pos to properly release the key */ | |||||
/* even when a different layer is active and the key has a different action now */ | |||||
} taphold_t; | |||||
extern taphold_t taphold_config[]; | |||||
extern uint16_t taphold_config_size; | |||||
/* Dual keys tap/hold timeout. */ | |||||
/* If key is tapped for less than this value, send key in addition to primary action after completing the action. */ | |||||
extern uint32_t taphold_timeout; | |||||
bool taphold_process(uint16_t keycode, keyrecord_t *record); |