[Keymap] Drashna's OLED rewrite (#15981)

master
Drashna Jaelre 2022-01-21 19:36:52 -08:00 committed by GitHub
parent 8901c9eca1
commit b090ff03ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 1776 additions and 295 deletions

View File

@ -50,7 +50,5 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define NO_ACTION_MACRO
#define NO_ACTION_FUNCTION
#define OLED_DISPLAY_128X64
#define POINTING_DEVICE_TASK_THROTTLE
#define POINTING_DEVICE_RIGHT

View File

@ -35,7 +35,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define RGBLED_SPLIT \
{ 10, 10 }
#define RGBLIGHT_LIMIT_VAL 80
#define OLED_BRIGHTNESS 50
#define AUDIO_PIN C6

View File

@ -43,12 +43,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
//#define WS2812_PWM_COMPLEMENTARY_OUTPUT // Define for a complementary timer output (TIMx_CHyN); omit for a normal timer output (TIMx_CHy).
#define WS2812_DMA_STREAM STM32_DMA1_STREAM7 // DMA Stream for TIMx_UP, see the respective reference manual for the appropriate values for your MCU.
#define WS2812_DMA_CHANNEL 3 // DMA Channel for TIMx_UP, see the respective reference manual for the appropriate values for your MCU.
#define WS2812_PWM_TARGET_PERIOD 800000
#define RGBLED_NUM 52
#define RGBLIGHT_SPLIT
#define RGBLED_SPLIT \
{ 26, 26 }
#define RGBLIGHT_LIMIT_VAL 150
#define DEBUG_LED_PIN C13
@ -68,6 +69,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define SERIAL_USART_RX_PAL_MODE 7 // Pin "alternate function", see the respective datasheet for the appropriate values for your MCU. default: 7
#define SERIAL_USART_TIMEOUT 100 // USART driver timeout. default 100
#define CRC8_USE_TABLE
#define CRC8_OPTIMIZE_SPEED
/* i2c config for oleds */
#define I2C_DRIVER I2CD1
#define I2C1_SCL_PIN B8
@ -75,9 +80,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define I2C1_SCL_PAL_MODE 4
#define I2C1_SDA_PAL_MODE 4
// #define I2C1_CLOCK_SPEED 400000
/* For Legacy Compatibility: */
#define I2C1_SCL 8
#define I2C1_SDA 9
/* encoder config */
#define ENCODERS_PAD_A \
@ -110,3 +112,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define PMW3360_CS_PIN B0
#define PMW3360_SPI_MODE 3
#define PMW3360_SPI_DIVISOR 64
#define PMW3360_FIRMWARE_UPLOAD_FAST

View File

@ -0,0 +1,20 @@
// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#ifndef RGBLIGHT_LIMIT_VAL
# if defined(OLED_ENABLE)
# define RGBLIGHT_LIMIT_VAL 100
# else
# define RGBLIGHT_LIMIT_VAL 150
# endif
#endif
#ifndef OLED_BRIGHTNESS
# ifdef RGBLIGHT_ENABLE
# define OLED_BRIGHTNESS 80
# else
# define OLED_BRIGHTNESS 150
# endif
#endif

View File

@ -18,5 +18,9 @@
#define TRACKBALL_DPI_OPTIONS { 1200, 1800, 2600, 3400 }
#define DEBOUNCE 45
#define DEBOUNCE 60
#define ENCODER_DEFAULT_POS 0x3
#ifdef OLED_DRIVER_SH1107
# undef OLED_DISPLAY_128X64
#endif

View File

@ -125,7 +125,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
KEYLOCK, _________________ADJUST_L2_________________, _________________ADJUST_R2_________________, TG_MODS,
UC_MOD, _________________ADJUST_L3_________________, _________________ADJUST_R3_________________, KC_MPLY,
TG(_DIABLOII), AUTO_CTN, TG_GAME, TG_DBLO,
_______, _______, KC_NUKE,
_______, REBOOT, KC_NUKE,
_______, _______, _______,
_______, _______, KC_NUKE, _______
),
@ -145,7 +145,7 @@ const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
[_MEDIA] = { { _______, _______ }, { _______, _______ } },
[_RAISE] = { { _______, _______ }, { KC_PGDN, KC_PGUP } },
[_LOWER] = { { RGB_MOD, RGB_RMOD}, { RGB_HUD, RGB_HUI } },
[_ADJUST] = { { CK_DOWN, CK_UP }, { _______, _______ } },
[_ADJUST] = { { CK_DOWN, CK_UP }, { _______, _F______ } },
};
// clang-format on
#else
@ -165,144 +165,5 @@ bool encoder_update_user(uint8_t index, bool clockwise) {
#endif
#ifdef OLED_ENABLE
// WPM-responsive animation stuff here
# define SLEEP_FRAMES 2
# define SLEEP_SPEED 10 // below this wpm value your animation will idle
# define WAKE_FRAMES 2 // uncomment if >1
# define KAKI_FRAMES 3
# define KAKI_SPEED 40 // above this wpm value typing animation to triggere
# define RTOGI_FRAMES 2
//#define LTOGI_FRAMES 2
//#define ANIM_FRAME_DURATION 500 // how long each frame lasts in ms
// #define SLEEP_TIMER 60000 // should sleep after this period of 0 wpm, needs fixing
# define ANIM_SIZE 512 // number of bytes in array, minimize for adequate firmware size, max is 1024
uint32_t anim_timer = 0;
uint32_t anim_frame_duration = 500;
uint8_t current_sleep_frame = 0;
uint8_t current_wake_frame = 0; // uncomment if WAKE_FRAMES >1
uint8_t current_kaki_frame = 0;
uint8_t current_rtogi_frame = 0;
// uint8_t current_ltogi_frame = 0;
void render_kitty(void) {
// Images credit j-inc(/James Incandenza) and pixelbenny. Credit to obosob for initial animation approach.
static const char PROGMEM sleep[SLEEP_FRAMES][ANIM_SIZE] = {{
// 'sleep1', 128x32px
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0xa8, 0x48, 0xa8, 0x18, 0x08, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 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, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x80, 0x44, 0x84, 0x06, 0x05, 0x04, 0x80, 0x40, 0x20, 0x10, 0xe0, 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,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x18, 0x04, 0x04, 0x02, 0x7a, 0x86, 0x01, 0x80, 0x80, 0x01, 0x03, 0x05, 0x07, 0x01, 0x00, 0x00, 0x80, 0x83, 0x45, 0xfa, 0x3c, 0xe0, 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, 0x00, 0x00, 0x07, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x33, 0x24, 0x28, 0x28, 0x29, 0x29, 0x29, 0x3a, 0x18, 0x1c, 0x39, 0x24, 0x24, 0x3a, 0x2d, 0x26, 0x31, 0x1f, 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,
},
{// 'sleep2', 128x32px
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, 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, 0x22, 0x22, 0x3a, 0x2a, 0x26, 0x22, 0x80, 0xc0, 0x80, 0x00, 0x24, 0x34, 0x2c, 0xe4, 0x60, 0x10, 0x70, 0x80, 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,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x38, 0x04, 0x02, 0x02, 0x01, 0x79, 0x87, 0x01, 0x80, 0x81, 0x83, 0x05, 0x05, 0x03, 0x01, 0x00, 0x00, 0x80, 0x43, 0x05, 0xfa, 0x3c, 0xe0, 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, 0x00, 0x00, 0x07, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x33, 0x24, 0x28, 0x28, 0x28, 0x29, 0x29, 0x3a, 0x18, 0x1c, 0x39, 0x24, 0x24, 0x3a, 0x2d, 0x26, 0x31, 0x1f, 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}};
static const char PROGMEM wake[WAKE_FRAMES][ANIM_SIZE] = {{
// 'mati2', 128x32px
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x30, 0x08, 0x10, 0x60, 0x80, 0x00, 0x80, 0x60, 0x10, 0x08, 0x30, 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, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x80, 0x40, 0x40, 0x5c, 0x00, 0x01, 0x41, 0x01, 0x00, 0x5c, 0x40, 0x40, 0x80, 0x7f, 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, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x80, 0xe1, 0x12, 0x0a, 0x06, 0x00, 0x80, 0x00, 0x06, 0x0a, 0x12, 0xe1, 0x80, 0x40, 0x40, 0x80, 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,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14, 0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18, 0x0f, 0x18, 0x10, 0x10, 0x1f, 0x11, 0x10, 0x10, 0x14, 0x14, 0x1f, 0x1c, 0x14, 0x14, 0x14, 0x08, 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,
},
{// 'mati3', 128x32px
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x30, 0x08, 0x10, 0x60, 0x80, 0x00, 0x80, 0x60, 0x10, 0x08, 0x30, 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, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x90, 0x12, 0x0a, 0x02, 0xf4, 0x09, 0x0d, 0xf1, 0x04, 0x02, 0x0a, 0x12, 0x90, 0x7f, 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, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x80, 0xe1, 0x12, 0x0a, 0x06, 0x01, 0x81, 0x00, 0x06, 0x0a, 0x12, 0xe1, 0x80, 0x40, 0x40, 0x80, 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,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14, 0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18, 0x0f, 0x18, 0x10, 0x10, 0x1f, 0x11, 0x10, 0x10, 0x14, 0x14, 0x1f, 0x1c, 0x14, 0x14, 0x14, 0x08, 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}};
static const char PROGMEM kaki[KAKI_FRAMES][ANIM_SIZE] = {{
// 'jare2', 128x32px
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x40, 0x80, 0x80, 0x80, 0x00, 0xfc, 0x84, 0x08, 0x08, 0x10, 0x20, 0x40, 0x40, 0x80, 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, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1e, 0x60, 0x80, 0x00, 0x00, 0x91, 0xa1, 0x80, 0x00, 0x00, 0x22, 0x84, 0x40, 0x50, 0x48, 0xc1, 0x3e, 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, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x41, 0x82, 0xe2, 0x12, 0x0a, 0x06, 0x00, 0x80, 0x88, 0x4f, 0x02, 0x22, 0xe2, 0x9f, 0x40, 0x40, 0x80, 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,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14, 0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18, 0x0f, 0x18, 0x14, 0x10, 0x10, 0x10, 0x10, 0x10, 0x14, 0x14, 0x1f, 0x1a, 0x0a, 0x0a, 0x04, 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,
},
{
// 'kaki1', 128x32px
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x1a, 0x22, 0xc2, 0x04, 0x04, 0x04, 0x07, 0x00, 0xc0, 0x20, 0x10, 0x80, 0x80, 0x01, 0x01, 0x02, 0xfc, 0xfe, 0x02, 0x3c, 0x20, 0x40, 0x80, 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,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0d, 0x8d, 0x55, 0x50, 0x94, 0xf0, 0x10, 0x09, 0x08, 0x00, 0x80, 0x00, 0x06, 0x09, 0x1b, 0xee, 0x00, 0x00, 0x00, 0x00, 0x81, 0xfe, 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, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14, 0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18, 0x0f, 0x18, 0x10, 0x10, 0x1f, 0x19, 0x18, 0x1c, 0x14, 0x16, 0x15, 0x14, 0x14, 0x14, 0x14, 0x08, 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,
},
{// 'kaki2', 128x32px
0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x10, 0x20, 0x40, 0x80, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x01, 0x02, 0x04, 0x04, 0x03, 0x80, 0x40, 0x40, 0x20, 0x00, 0x01, 0x02, 0x8c, 0x70, 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, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0d, 0x8d, 0x55, 0x50, 0x94, 0xf0, 0x10, 0x0a, 0x0e, 0x1d, 0x95, 0x24, 0x24, 0x27, 0x13, 0xe1, 0x01, 0x01, 0x01, 0x01, 0x02, 0xfc, 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, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14, 0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18, 0x0f, 0x18, 0x10, 0x10, 0x1f, 0x19, 0x18, 0x1c, 0x14, 0x14, 0x17, 0x14, 0x14, 0x14, 0x14, 0x08, 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}};
static const char PROGMEM rtogi[KAKI_FRAMES][ANIM_SIZE] = {{
// 'rtogi1', 128x32px
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x10, 0x10, 0x08, 0x04, 0x02, 0x01, 0x0f, 0x90, 0x10, 0x20, 0xf0, 0xf8, 0xf8, 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, 0x00, 0x80, 0x40, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x48, 0x47, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x88, 0xc7, 0xc4, 0x62, 0x23, 0x11, 0x3f, 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,
0x80, 0x40, 0x20, 0x10, 0x88, 0xcc, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc0, 0x80, 0x80, 0xc0, 0xe1, 0xfe, 0xb8, 0x88, 0x0c, 0x04, 0x03, 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,
0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x06, 0x04, 0x04, 0x04, 0x04, 0x05, 0x04, 0x04, 0x04, 0x07, 0x07, 0x07, 0x03, 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, 0x00, 0x00,
},
{// 'rtogi2', 128x32px
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x10, 0x10, 0x08, 0x04, 0x02, 0x01, 0x1f, 0xa0, 0x20, 0x40, 0x80, 0x00, 0xf0, 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, 0x00, 0x80, 0x40, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x48, 0x47, 0x88, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x28, 0x6b, 0x40, 0xa0, 0x99, 0x86, 0xff, 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,
0x0f, 0x11, 0x22, 0x44, 0x48, 0x4c, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc0, 0x80, 0x80, 0xc0, 0xe1, 0xfe, 0xb8, 0x88, 0x0c, 0x04, 0x06, 0x06, 0x06, 0x0e, 0x0e, 0x06, 0x01, 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, 0x00, 0x00, 0x01, 0x01, 0x01, 0x06, 0x04, 0x04, 0x04, 0x04, 0x05, 0x04, 0x04, 0x04, 0x07, 0x07, 0x07, 0x03, 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, 0x00, 0x00}};
// assumes 1 frame prep stage
void animation_phase(void) {
if (tap_toggling) {
anim_frame_duration = 300;
current_rtogi_frame = (current_rtogi_frame + 1) % RTOGI_FRAMES;
oled_write_raw_P(rtogi[abs((RTOGI_FRAMES - 1) - current_rtogi_frame)], ANIM_SIZE);
} else {
if (get_current_wpm() <= SLEEP_SPEED) {
anim_frame_duration = 500;
current_sleep_frame = (current_sleep_frame + 1) % SLEEP_FRAMES;
oled_write_raw_P(sleep[abs((SLEEP_FRAMES - 1) - current_sleep_frame)], ANIM_SIZE);
}
// if(get_current_wpm() >IDLE_SPEED && get_current_wpm() <TAP_SPEED){
if (get_current_wpm() > SLEEP_SPEED) {
anim_frame_duration = 800;
current_wake_frame = (current_wake_frame + 1) % WAKE_FRAMES;
oled_write_raw_P(wake[abs((WAKE_FRAMES - 1) - current_wake_frame)], ANIM_SIZE);
// oled_write_raw_P(wake[0], ANIM_SIZE); // remove if IDLE_FRAMES >1
}
if (get_current_wpm() >= KAKI_SPEED) {
anim_frame_duration = 500;
current_kaki_frame = (current_kaki_frame + 1) % KAKI_FRAMES;
oled_write_raw_P(kaki[abs((KAKI_FRAMES - 1) - current_kaki_frame)], ANIM_SIZE);
}
}
}
if (get_current_wpm() != 000) {
// if(timer_elapsed32(anim_timer) > ANIM_FRAME_DURATION) {
if (timer_elapsed32(anim_timer) > anim_frame_duration) {
anim_timer = timer_read32();
animation_phase();
}
} else {
// if(timer_elapsed32(anim_timer) > ANIM_FRAME_DURATION) {
if (timer_elapsed32(anim_timer) > anim_frame_duration) {
anim_timer = timer_read32();
animation_phase();
}
}
}
void oled_driver_render_logo_left(void) {
render_kitty();
oled_set_cursor(6, 0);
oled_write_P(PSTR(" Tractyl "), false);
oled_set_cursor(6, 1);
oled_write_P(PSTR(" Manuform "), false);
oled_set_cursor(6, 2);
# if defined(WPM_ENABLE)
render_wpm(1);
# endif
oled_set_cursor(6, 3);
# if defined(KEYBOARD_handwired_tractyl_manuform_5x6_right)
render_pointing_dpi_status(0);
# endif
oled_set_cursor(0, 4);
}
oled_rotation_t oled_init_keymap(oled_rotation_t rotation) { return OLED_ROTATION_180; }
#endif

View File

@ -32,3 +32,5 @@ ifeq ($(strip $(KEYBOARD)), handwired/tractyl_manuform/5x6_right/teensy2pp)
CAPS_WORD_ENABLE = yes
endif
# DEBOUNCE_TYPE = sym_eager_pk
OLED_DRIVER = custom

View File

@ -43,6 +43,8 @@ typedef struct {
uint16_t device_cpi;
} kb_config_data_t;
extern kb_config_data_t kb_config;
void trackball_set_cpi(uint16_t cpi);
void matrix_init_sub_kb(void);
void matrix_scan_sub_kb(void);

View File

@ -111,7 +111,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
KEYLOCK, _________________ADJUST_L2_________________, _______, _______, _________________ADJUST_R2_________________, RGB_IDL,
UC_MOD, _________________ADJUST_L3_________________, _________________ADJUST_R3_________________, TG_MODS,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, AUTO_CTN,
_______, _______, _______, _______, _______, _______
REBOOT, _______, _______, _______, _______, _______
),
};

View File

@ -93,7 +93,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
KC_MAKE, _________________ADJUST_L1_________________, _________________ADJUST_R1_________________, KC_RESET,
VRSN, _________________ADJUST_L2_________________, _________________ADJUST_R2_________________, EEP_RST,
UC_MOD, _________________ADJUST_L3_________________, HPT_TOG, HPT_FBK, MG_NKRO, UC_MOD, _________________ADJUST_R3_________________, TG_MODS,
_______, _______, KEYLOCK, KC_NUKE, _______, _______, _______, _______, _______, _______
REBOOT, _______, KEYLOCK, KC_NUKE, _______, _______, _______, _______, _______, AUTO_CTN
),
// [_LAYERINDEX] = LAYOUT_wrapper(
// _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,

View File

@ -16,10 +16,6 @@
#include "drashna.h"
#ifdef UNICODEMAP_ENABLE
# include "drashna_unicode.h"
#endif // UNICODEMAP_ENABLE
#include "drivers/sensors/pimoroni_trackball.h"
enum more_custom_keycodes {
KC_SWAP_NUM = NEW_SAFE_RANGE,
PM_SCROLL,

View File

@ -2,7 +2,6 @@ BOOTMAGIC_ENABLE = yes # Enable Bootmagic Lite
TAP_DANCE_ENABLE = no
COMMAND_ENABLE = no # Commands for debug and configuration
CONSOLE_ENABLE = no
SPACE_CADET_ENABLE = no
ifeq ($(strip $(KEYBOARD)), ergodox_ez)
RGBLIGHT_ENABLE = yes
@ -16,5 +15,3 @@ endif
UNICODE_ENABLE = no
UNICDOEMAP_ENABLE = no
CUSTOM_UNICODE_ENABLE = no
DEBOUNCE_TYPE = sym_eager_pr

View File

@ -106,7 +106,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
KC_MAKE, _________________ADJUST_L1_________________, _________________ADJUST_R1_________________, KC_RST,
VRSN, _________________ADJUST_L2_________________, _________________ADJUST_R2_________________, EEP_RST,
TH_LVL, _________________ADJUST_L3_________________, _________________ADJUST_R3_________________, RGB_IDL,
KEYLOCK, _______, _______, _______, _______, KC_NUKE, _______, _______, _______, _______, _______, TG_MODS
KEYLOCK, _______, _______, REBOOT, _______, KC_NUKE, _______, _______, AUTO_CTN,_______, _______, TG_MODS
)
};

View File

@ -90,7 +90,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
KC_MAKE, _________________ADJUST_L1_________________, _________________ADJUST_R1_________________, KC_RESET,
VRSN, _________________ADJUST_L2_________________, _________________ADJUST_R2_________________, EEP_RST,
KEYLOCK, _________________ADJUST_L3_________________, _________________ADJUST_R3_________________, RGB_IDL,
AUTO_CTN,KC_NUKE, _______, _______, TG_MODS, HPT_FBK
REBOOT, KC_NUKE, _______, _______, TG_MODS, AUTO_CTN
)
};
// clang-format on

View File

@ -70,6 +70,15 @@ void shutdown_user(void) {
__attribute__((weak)) void suspend_power_down_keymap(void) {}
void suspend_power_down_user(void) {
if (layer_state_is(_GAMEPAD)) {
layer_off(_GAMEPAD);
}
if (layer_state_is(_DIABLO)) {
layer_off(_DIABLO);
}
if (layer_state_is(_DIABLOII)) {
layer_off(_DIABLOII);
}
#ifdef OLED_ENABLE
oled_off();
#endif
@ -78,12 +87,6 @@ void suspend_power_down_user(void) {
__attribute__((weak)) void suspend_wakeup_init_keymap(void) {}
void suspend_wakeup_init_user(void) {
if (layer_state_is(_GAMEPAD)) {
layer_off(_GAMEPAD);
}
if (layer_state_is(_DIABLO)) {
layer_off(_DIABLO);
}
suspend_wakeup_init_keymap();
}

View File

@ -29,7 +29,7 @@
# define SELECT_SOFT_SERIAL_SPEED 1
# endif
# ifdef CUSTOM_SPLIT_TRANSPORT_SYNC
# define SPLIT_TRANSACTION_IDS_USER RPC_ID_USER_STATE_SYNC, RPC_ID_USER_KEYMAP_SYNC, RPC_ID_USER_CONFIG_SYNC, RPC_ID_USER_WATCHDOG_SYNC
# define SPLIT_TRANSACTION_IDS_USER RPC_ID_USER_STATE_SYNC, RPC_ID_USER_KEYMAP_SYNC, RPC_ID_USER_CONFIG_SYNC, RPC_ID_USER_WATCHDOG_SYNC, RPC_ID_USER_KEYLOG_STR
# endif
#endif
@ -271,3 +271,21 @@
# define C14 PAL_LINE(GPIOC, 14)
# define C15 PAL_LINE(GPIOC, 15)
#endif
#ifdef OLED_DRIVER_SH1107
# define OLED_DISPLAY_CUSTOM
# define OLED_IC_SH1107 2
# define OLED_DISPLAY_128X128
# define OLED_DISPLAY_WIDTH 128
# define OLED_DISPLAY_HEIGHT 128
# define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH)
# define OLED_BLOCK_TYPE uint16_t
# define OLED_SOURCE_MAP \
{ 0, 8, 16, 24, 32, 40, 48, 56 }
# define OLED_TARGET_MAP \
{ 56, 48, 40, 32, 24, 16, 8, 0 }
# define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8)
# define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT)
# define OLED_COM_PINS COM_PINS_ALT
# define OLED_IC OLED_IC_SH1107
#endif

View File

@ -2,25 +2,37 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "drashna.h"
#ifdef __AVR__
# include <avr/wdt.h>
#endif
userspace_config_t userspace_config;
/**
* @brief Handle registering a keycode, with optional modifer based on timed event
*
* @param code keycode to send to host
* @param mod_code modifier to send with code, if held for tapping term or longer
* @param pressed the press/release event (can use "record->event.pressed" for this)
* @return true exits function
* @return false exits function
*/
bool mod_key_press_timer(uint16_t code, uint16_t mod_code, bool pressed) {
static uint16_t this_timer;
if (pressed) {
this_timer = timer_read();
} else {
if (timer_elapsed(this_timer) < TAPPING_TERM) {
tap_code(code);
} else {
register_code(mod_code);
tap_code(code);
unregister_code(mod_code);
}
}
mod_key_press(code, mod_code, pressed, this_timer);
return false;
}
/**
* @brief Handle registation of keycode, with optional modifier based on custom timer
*
* @param code keycode to send to host
* @param mod_code modifier keycode to send with code, if held for tapping term or longer
* @param pressed the press/release event
* @param this_timer custom timer to use
* @return true
* @return false
*/
bool mod_key_press(uint16_t code, uint16_t mod_code, bool pressed, uint16_t this_timer) {
if (pressed) {
this_timer = timer_read();
@ -36,6 +48,14 @@ bool mod_key_press(uint16_t code, uint16_t mod_code, bool pressed, uint16_t this
return false;
}
/**
* @brief Performs exact match for modifier values
*
* @param value the modifer varible (get_mods/get_oneshot_mods/get_weak_mods)
* @param mask the modifier mask to check for
* @return true Has the exact modifiers specifed
* @return false Does not have the exact modifiers specified
*/
bool hasAllBitsInMask(uint8_t value, uint8_t mask) {
value &= 0xF;
mask &= 0xF;
@ -43,10 +63,62 @@ bool hasAllBitsInMask(uint8_t value, uint8_t mask) {
return (value & mask) == mask;
}
void tap_code16_nomods(uint8_t kc) {
/**
* @brief Tap keycode, with no mods
*
* @param kc keycode to use
*/
void tap_code16_nomods(uint16_t kc) {
uint8_t temp_mod = get_mods();
clear_mods();
clear_oneshot_mods();
tap_code16(kc);
set_mods(temp_mod);
}
/**
* @brief Run shutdown routine and soft reboot firmware.
*
*/
#ifdef HAPTIC_ENABLE
# include "haptic.h"
#endif
#ifdef AUDIO_ENABLE
# ifndef GOODBYE_SONG
# define GOODBYE_SONG SONG(GOODBYE_SOUND)
# endif
float reset_song[][2] = GOODBYE_SONG;
#endif
void software_reset(void) {
clear_keyboard();
#if defined(MIDI_ENABLE) && defined(MIDI_BASIC)
process_midi_all_notes_off();
#endif
#ifdef AUDIO_ENABLE
# ifndef NO_MUSIC_MODE
music_all_notes_off();
# endif
uint16_t timer_start = timer_read();
PLAY_SONG(reset_song);
shutdown_user();
while (timer_elapsed(timer_start) < 250) wait_ms(1);
stop_all_notes();
#else
shutdown_user();
wait_ms(250);
#endif
#ifdef HAPTIC_ENABLE
haptic_shutdown();
#endif
#if defined(PROTOCOL_LUFA)
wdt_enable(WDTO_250MS);
#elif defined(PROTOCOL_CHIBIOS)
# if defined(MCU_STM32) || defined(MCU_KINETIS)
NVIC_SystemReset();
# endif
#endif
}

View File

@ -78,7 +78,8 @@ enum userspace_layers {
bool mod_key_press_timer(uint16_t code, uint16_t mod_code, bool pressed);
bool mod_key_press(uint16_t code, uint16_t mod_code, bool pressed, uint16_t this_timer);
bool hasAllBitsInMask(uint8_t value, uint8_t mask);
void tap_code16_nomods(uint8_t kc);
void tap_code16_nomods(uint16_t kc);
void software_reset(void);
// clang-format off
typedef union {

View File

@ -17,6 +17,14 @@
# error Dictionary size excees maximum size permitted
# endif
/**
* @brief Process handler for autocorrect feature
*
* @param keycode Keycode registered by matrix press, per keymap
* @param record keyrecord_t structure
* @return true Continue processing keycodes, and send to host
* @return false Stop processing keycodes, and don't send to host
*/
bool process_autocorrection(uint16_t keycode, keyrecord_t* record) {
static uint8_t typo_buffer[AUTOCORRECTION_MAX_LENGTH] = {KC_SPC};
static uint8_t typo_buffer_size = 1;
@ -53,6 +61,14 @@ bool process_autocorrection(uint16_t keycode, keyrecord_t* record) {
keycode &= 0xFF;
break;
# endif
# ifdef SWAP_HANDS_ENABLE
case QK_SWAP_HANDS ... QK_SWAP_HANDS_MAX:
if (keycode >= 0x56F0 || record->event.pressed || !record->tap.count) {
return true;
}
keycode &= 0xFF;
break;
# endif
# ifndef NO_ACTION_ONESHOT
case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX:
if ((keycode & 0xF) == MOD_LSFT) {
@ -70,7 +86,6 @@ bool process_autocorrection(uint16_t keycode, keyrecord_t* record) {
}
}
// Subtract buffer for Backspace key, reset for other non-alpha.
if (!(KC_A <= keycode && keycode <= KC_Z)) {
if (keycode == KC_BSPC) {
@ -83,7 +98,7 @@ bool process_autocorrection(uint16_t keycode, keyrecord_t* record) {
// Set a word boundary if space, period, digit, etc. is pressed.
// Behave more conservatively for the enter key. Reset, so that enter
// can't be used on a word ending.
if (keycode == KC_ENT) {
if (keycode == KC_ENT || (keycode == KC_MINUS && (get_mods() | get_oneshot_mods()) & MOD_MASK_SHIFT)) {
typo_buffer_size = 0;
}
keycode = KC_SPC;

View File

@ -10,6 +10,16 @@
bool caps_word_enabled = false;
bool caps_word_shifted = false;
/**
* @brief Handler for Caps Word feature.
*
* This checks the keycodes, and applies shift to the correct keys, if and when needid.
*
* @param keycode Keycode from matrix
* @param record keyrecord_t data structure
* @return true Continue processing keycode and sent to host
* @return false Stop processing keycode, and do not send to host
*/
bool process_caps_word(uint16_t keycode, keyrecord_t* record) {
if (!caps_word_enabled) {
// Pressing both shift keys at the same time enables caps word.

View File

@ -18,8 +18,24 @@ bool host_driver_disabled = false;
// Defines actions tor my global custom keycodes. Defined in drashna.h file
// Then runs the _keymap's record handier if not processed here
/**
* @brief Keycode handler for keymaps
*
* This handles the keycodes at the keymap level, useful for keyboard specific customization
*/
__attribute__((weak)) bool process_record_keymap(uint16_t keycode, keyrecord_t *record) { return true; }
__attribute__((weak)) bool process_record_secrets(uint16_t keycode, keyrecord_t *record) { return true; }
/**
* @brief Main user keycode handler
*
* This handles all of the keycodes for the user, including calling feature handlers.
*
* @param keycode Keycode from matrix
* @param record keyrecord_t data structure
* @return true Continue processing keycode and send to host
* @return false Stop process keycode and do not send to host
*/
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
// If console is enabled, it will print the matrix position and status of each key pressed
#ifdef KEYLOGGER_ENABLE
@ -215,12 +231,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *re
return false;
case REBOOT:
if (record->event.pressed) {
shutdown_user();
#ifdef __AVR__
wdt_enable(WDTO_250MS);
#else
NVIC_SystemReset();
#endif
software_reset();
}
return false;

View File

@ -11,7 +11,12 @@ diablo_timer_t diablo_timer[NUM_OF_DIABLO_KEYS];
// Otherwise, you will need to hit a bunch of times, or hit the "clear" command
uint8_t diablo_times[] = {0, 1, 3, 5, 10, 30};
// Cycle through the times for the macro, starting at 0, for disabled.
/**
* @brief Main function for handling diable related tap dances.
*
* @param state Main data struction contining information about events
* @param user_data Local data for the dance. Allows customization to be passed on to function
*/
void diablo_tapdance_master(qk_tap_dance_state_t *state, void *user_data) {
diable_keys_t *diablo_keys = (diable_keys_t *)user_data;
// Sets the keycode based on the index
@ -43,7 +48,10 @@ qk_tap_dance_action_t tap_dance_actions[] = {
[TD_D3_4] = ACTION_TAP_DANCE_DIABLO(3, KC_4),
};
// Checks each of the 4 timers/keys to see if enough time has elapsed
/**
* @brief Runs check to see if timer has elapsed for each dance, and sends keycodes, if it has.
*
*/
void run_diablo_macro_check(void) {
for (uint8_t index = 0; index < NUM_OF_DIABLO_KEYS; index++) {
// if key_interval is 0, it's disabled, so only run if it's set. If it's set, check the timer.

View File

@ -8,6 +8,11 @@
uint16_t typing_mode;
/**
* @brief Registers the unicode keystrokes based on desired unicode
*
* @param glyph Unicode character, supports up to 0x1FFFF (or higher)
*/
void tap_unicode_glyph_nomods(uint32_t glyph) {
uint8_t temp_mod = get_mods();
clear_mods();
@ -43,6 +48,15 @@ typedef uint32_t (*translator_function_t)(bool is_shifted, uint32_t keycode);
return ret; \
}
/**
* @brief Handler function for outputting unicode.
*
* @param keycode Keycode from matrix.
* @param record keyrecord_t data structure
* @param translator translator lut for different unicode modes
* @return true Continue processing matrix press, and send to host
* @return false Replace keycode, and do not send to host
*/
bool process_record_glyph_replacement(uint16_t keycode, keyrecord_t *record, translator_function_t translator) {
uint8_t temp_mod = get_mods();
uint8_t temp_osm = get_oneshot_mods();
@ -182,6 +196,15 @@ bool process_record_zalgo(uint16_t keycode, keyrecord_t *record) {
return true;
}
/**
* @brief Main handler for unicode input
*
* @param keycode Keycode from switch matrix
* @param record keyrecord_t data struture
* @return true Send keycode from matrix to host
* @return false Stop processing and do not send to host
*/
bool process_record_unicode(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case UC_FLIP: // (ノಠ痊ಠ)ノ彡┻━┻
@ -265,6 +288,10 @@ bool process_record_unicode(uint16_t keycode, keyrecord_t *record) {
return process_unicode_common(keycode, record);
}
/**
* @brief Initialize the default unicode mode on firmware startu
*
*/
void matrix_init_unicode(void) {
unicode_input_mode_init();
}

View File

@ -22,17 +22,12 @@
extern bool host_driver_disabled;
#ifndef KEYLOGGER_LENGTH
// # ifdef OLED_DISPLAY_128X64
# define KEYLOGGER_LENGTH ((uint8_t)(OLED_DISPLAY_HEIGHT / OLED_FONT_WIDTH))
// # else
// # define KEYLOGGER_LENGTH (uint8_t *(OLED_DISPLAY_WIDTH / OLED_FONT_HEIGHT))
// # endif
#endif
uint32_t oled_timer = 0;
char keylog_str[OLED_KEYLOGGER_LENGTH] = {0};
static uint16_t log_timer = 0;
static const char PROGMEM display_border[3] = {0x0, 0xFF, 0x0};
uint32_t oled_timer = 0;
static char keylog_str[KEYLOGGER_LENGTH + 1] = {0};
static uint16_t log_timer = 0;
deferred_token kittoken;
// clang-format off
static const char PROGMEM code_to_name[256] = {
@ -56,10 +51,16 @@ static const char PROGMEM code_to_name[256] = {
};
// clang-format on
/**
* @brief parses pressed keycodes and saves to buffer
*
* @param keycode Keycode pressed from switch matrix
* @param record keyrecord_t data structure
*/
void add_keylog(uint16_t keycode, keyrecord_t *record) {
if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX) || (keycode >= QK_MODS && keycode <= QK_MODS_MAX)) {
if (((keycode & 0xFF) == KC_BSPC) && mod_config(get_mods() | get_oneshot_mods()) & MOD_MASK_CTRL) {
memset(keylog_str, ' ', sizeof(keylog_str) - 1);
memset(keylog_str, ' ', OLED_KEYLOGGER_LENGTH);
return;
}
if (record->tap.count) {
@ -72,23 +73,29 @@ void add_keylog(uint16_t keycode, keyrecord_t *record) {
return;
}
for (uint8_t i = 1; i < KEYLOGGER_LENGTH; i++) {
keylog_str[i - 1] = keylog_str[i];
}
memmove(keylog_str, keylog_str + 1, OLED_KEYLOGGER_LENGTH - 1);
if (keycode < (sizeof(code_to_name) / sizeof(char))) {
keylog_str[(KEYLOGGER_LENGTH - 1)] = pgm_read_byte(&code_to_name[keycode]);
keylog_str[(OLED_KEYLOGGER_LENGTH - 1)] = pgm_read_byte(&code_to_name[keycode]);
}
log_timer = timer_read();
}
/**
* @brief Keycode handler for oled display.
*
* This adds pressed keys to buffer, but also resets the oled timer
*
* @param keycode Keycode from matrix
* @param record keyrecord data struture
* @return true
* @return false
*/
bool process_record_user_oled(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) {
#ifdef OLED_ENABLE
oled_timer = timer_read32();
add_keylog(keycode, record);
#endif
}
return true;
}
@ -99,12 +106,29 @@ void update_log(void) {
}
}
/**
* @brief Renders keylogger buffer to oled
*
*/
void render_keylogger_status(void) {
#ifdef OLED_DISPLAY_VERBOSE
oled_set_cursor(1, 7);
#endif
oled_write_P(PSTR(OLED_RENDER_KEYLOGGER), false);
oled_write(keylog_str, false);
#ifdef OLED_DISPLAY_VERBOSE
oled_advance_page(true);
#endif
}
/**
* @brief Renders default layer state (aka layout) to oled
*
*/
void render_default_layer_state(void) {
#ifdef OLED_DISPLAY_VERBOSE
oled_set_cursor(5, 2);
#endif
oled_write_P(PSTR(OLED_RENDER_LAYOUT_NAME), false);
switch (get_highest_layer(default_layer_state)) {
case _QWERTY:
@ -120,46 +144,150 @@ void render_default_layer_state(void) {
oled_write_P(PSTR(OLED_RENDER_LAYOUT_DVORAK), false);
break;
}
#ifdef OLED_DISPLAY_128X64
#ifdef OLED_DISPLAY_VERBOSE
oled_advance_page(true);
#endif
}
/**
* @brief Renders the active layers to the OLED
*
*/
void render_layer_state(void) {
oled_write_P(PSTR(OLED_RENDER_LAYER_NAME), false);
#ifdef OLED_DISPLAY_128X64
#ifdef OLED_DISPLAY_VERBOSE
static const char PROGMEM tri_layer_image[4][3][18] = {
{
{
0x80, 0x80, 0x40, 0x40, 0x20, 0x20,
0x10, 0x10, 0x08, 0x08, 0x10, 0x10,
0x20, 0x20, 0x40, 0x40, 0x80, 0x80
},
{
0x88, 0x88, 0x5D, 0x5D, 0x3E, 0x3E,
0x7C, 0x7C, 0xF8, 0xF8, 0x7C, 0x7C,
0x3E, 0x3E, 0x5D, 0x5D, 0x88, 0x88
},
{
0x00, 0x00, 0x01, 0x01, 0x02, 0x02,
0x04, 0x04, 0x08, 0x08, 0x04, 0x04,
0x02, 0x02, 0x01, 0x01, 0x00, 0x00
}
},
{
{
0x80, 0x80, 0xC0, 0xC0, 0xE0, 0xE0,
0xF0, 0xF0, 0xF8, 0xF8, 0xF0, 0xF0,
0xE0, 0xE0, 0xC0, 0xC0, 0x80, 0x80
},
{
0x88, 0x88, 0x55, 0x55, 0x23, 0x23,
0x47, 0x47, 0x8F, 0x8F, 0x47, 0x47,
0x23, 0x23, 0x55, 0x55, 0x88, 0x88
},
{
0x00, 0x00, 0x01, 0x01, 0x02, 0x02,
0x04, 0x04, 0x08, 0x08, 0x04, 0x04,
0x02, 0x02, 0x01, 0x01, 0x00, 0x00
}
},
{
{
0x80, 0x80, 0x40, 0x40, 0x20, 0x20,
0x10, 0x10, 0x08, 0x08, 0x10, 0x10,
0x20, 0x20, 0x40, 0x40, 0x80, 0x80
},
{
0x88, 0x88, 0xD5, 0xD5, 0xE2, 0xE2,
0xC4, 0xC4, 0x88, 0x88, 0xC4, 0xC4,
0xE2, 0xE2, 0xD5, 0xD5, 0x88, 0x88
},
{
0x00, 0x00, 0x01, 0x01, 0x03, 0x03,
0x07, 0x07, 0x0F, 0x0F, 0x07, 0x07,
0x03, 0x03, 0x01, 0x01, 0x00, 0x00
}
},
{
{
0x80, 0x80, 0x40, 0xC0, 0x60, 0xA0,
0x50, 0xB0, 0x58, 0xA8, 0x50, 0xB0,
0x60, 0xA0, 0x40, 0xC0, 0x80, 0x80
},
{
0x88, 0x88, 0x5D, 0xD5, 0x6B, 0xB6,
0x6D, 0xD6, 0xAD, 0xDA, 0x6D, 0xD6,
0x6B, 0xB6, 0x5D, 0xD5, 0x88, 0x88
},
{
0x00, 0x00, 0x01, 0x01, 0x03, 0x02,
0x05, 0x06, 0x0D, 0x0A, 0x05, 0x06,
0x03, 0x02, 0x01, 0x01, 0x00, 0x00
}
}
};
uint8_t layer_is = 0;
if (layer_state_is(_ADJUST)) {
layer_is = 3;
} else if (layer_state_is(_RAISE)) {
layer_is = 1;
} else if (layer_state_is(_LOWER)) {
layer_is = 2;
}
oled_set_cursor(1, 2);
oled_write_raw_P(tri_layer_image[layer_is][0], sizeof(tri_layer_image[0][0]));
oled_set_cursor(5, 3);
oled_write_P(PSTR("Diablo2"), layer_state_is(_DIABLOII));
oled_write_P(PSTR(" "), false);
#endif
oled_write_P(PSTR(OLED_RENDER_LAYER_LOWER), layer_state_is(_LOWER));
#ifdef OLED_DISPLAY_128X64
oled_write_P(PSTR(" "), false);
#endif
oled_write_P(PSTR(OLED_RENDER_LAYER_RAISE), layer_state_is(_RAISE));
#ifdef OLED_DISPLAY_128X64
oled_write_P(PSTR("Diablo3"), layer_state_is(_DIABLO));
oled_advance_page(true);
oled_write_P(PSTR(" "), false);
oled_set_cursor(1, 3);
oled_write_raw_P(tri_layer_image[layer_is][1], sizeof(tri_layer_image[0][0]));
oled_set_cursor(5, 4);
oled_write_P(PSTR("GamePad"), layer_state_is(_GAMEPAD));
oled_write_P(PSTR(" "), false);
oled_write_P(PSTR("Diablo"), layer_state_is(_DIABLO));
oled_write_P(PSTR(" "), false);
oled_write_P(PSTR("Mouse"), layer_state_is(_MOUSE));
oled_advance_page(true);
oled_set_cursor(1, 4);
oled_write_raw_P(tri_layer_image[layer_is][2], sizeof(tri_layer_image[0][0]));
#else
oled_write_P(PSTR(OLED_RENDER_LAYER_NAME), false);
oled_write_P(PSTR(OLED_RENDER_LAYER_LOWER), layer_state_is(_LOWER));
oled_write_P(PSTR(OLED_RENDER_LAYER_RAISE), layer_state_is(_RAISE));
oled_advance_page(true);
#endif
}
/**
* @brief Renders the current lock status to oled
*
* @param led_usb_state Current keyboard led state
*/
void render_keylock_status(uint8_t led_usb_state) {
#if defined(OLED_DISPLAY_VERBOSE)
oled_set_cursor(1, 6);
#endif
oled_write_P(PSTR(OLED_RENDER_LOCK_NAME), false);
#if !defined(OLED_DISPLAY_128X64)
#if !defined(OLED_DISPLAY_VERBOSE)
oled_write_P(PSTR(" "), false);
#endif
oled_write_P(PSTR(OLED_RENDER_LOCK_NUML), led_usb_state & (1 << USB_LED_NUM_LOCK));
oled_write_P(PSTR(" "), false);
oled_write_P(PSTR(OLED_RENDER_LOCK_CAPS), led_usb_state & (1 << USB_LED_CAPS_LOCK));
#if defined(OLED_DISPLAY_128X64)
#if defined(OLED_DISPLAY_VERBOSE)
oled_write_P(PSTR(" "), false);
oled_write_P(PSTR(OLED_RENDER_LOCK_SCLK), led_usb_state & (1 << USB_LED_SCROLL_LOCK));
#endif
}
/**
* @brief Renders the matrix scan rate to the host system
*
*/
void render_matrix_scan_rate(void) {
#ifdef DEBUG_MATRIX_SCAN_RATE
oled_write_P(PSTR("MS:"), false);
@ -167,10 +295,18 @@ void render_matrix_scan_rate(void) {
#endif
}
/**
* @brief Renders the modifier state
*
* @param modifiers Modifiers to check against (real, weak, onesheot, etc;)
*/
void render_mod_status(uint8_t modifiers) {
static const char PROGMEM mod_status[5][3] = {{0xE8, 0xE9, 0}, {0xE4, 0xE5, 0}, {0xE6, 0xE7, 0}, {0xEA, 0xEB, 0}, {0xEC, 0xED, 0}};
#if defined(OLED_DISPLAY_VERBOSE)
oled_set_cursor(1, 5);
#endif
oled_write_P(PSTR(OLED_RENDER_MODS_NAME), false);
#if defined(OLED_DISPLAY_128X64)
#if defined(OLED_DISPLAY_VERBOSE)
oled_write_P(mod_status[0], (modifiers & MOD_BIT(KC_LSHIFT)));
oled_write_P(mod_status[!keymap_config.swap_lctl_lgui ? 3 : 4], (modifiers & MOD_BIT(KC_LGUI)));
oled_write_P(mod_status[2], (modifiers & MOD_BIT(KC_LALT)));
@ -200,26 +336,27 @@ void render_bootmagic_status(void) {
};
bool is_bootmagic_on;
#ifdef OLED_DISPLAY_128X64
#ifdef OLED_DISPLAY_VERBOSE
oled_set_cursor(7, 4);
is_bootmagic_on = !keymap_config.swap_lctl_lgui;
#else
is_bootmagic_on = keymap_config.swap_lctl_lgui;
#endif
oled_write_P(PSTR(OLED_RENDER_BOOTMAGIC_NAME), false);
#ifdef OLED_DISPLAY_128X64
#ifdef OLED_DISPLAY_VERBOSE
if (keymap_config.swap_lctl_lgui)
#else
oled_write_P(PSTR(OLED_RENDER_BOOTMAGIC_NAME), false);
oled_write_P(PSTR(" "), false);
#endif
{
oled_write_P(logo[1][0], is_bootmagic_on);
#ifdef OLED_DISPLAY_128X64
#ifdef OLED_DISPLAY_VERBOSE
} else {
#endif
oled_write_P(logo[0][0], !is_bootmagic_on);
}
#ifndef OLED_DISPLAY_128X64
#ifndef OLED_DISPLAY_VERBOSE
oled_write_P(PSTR(" "), false);
oled_write_P(logo[1][1], is_bootmagic_on);
oled_write_P(logo[0][1], !is_bootmagic_on);
@ -232,10 +369,8 @@ void render_bootmagic_status(void) {
#else
oled_write_P(PSTR(OLED_RENDER_BOOTMAGIC_NOGUI), keymap_config.no_gui);
#endif
#ifdef OLED_DISPLAY_128X64
oled_advance_page(true);
oled_write_P(PSTR("Magic"), false);
oled_write_P(PSTR(" "), false);
#ifdef OLED_DISPLAY_VERBOSE
oled_set_cursor(7, 5);
if (keymap_config.swap_lctl_lgui) {
oled_write_P(logo[1][1], is_bootmagic_on);
} else {
@ -248,9 +383,6 @@ void render_bootmagic_status(void) {
oled_write_P(PSTR(" "), false);
oled_write_P(PSTR(OLED_RENDER_BOOTMAGIC_SWAP), swap_hands);
#endif
#ifdef OLED_DISPLAY_128X64
oled_advance_page(true);
#endif
}
#if defined(POINTING_DEVICE_ENABLE)
@ -268,14 +400,17 @@ void render_user_status(void) {
is_audio_on = is_audio_on();
is_clicky_on = is_clicky_on();
# endif
#endif
#if defined(OLED_DISPLAY_VERBOSE)
oled_set_cursor(1, 6);
#endif
oled_write_P(PSTR(OLED_RENDER_USER_NAME), false);
#if !defined(OLED_DISPLAY_128X64)
#if !defined(OLED_DISPLAY_VERBOSE)
oled_write_P(PSTR(" "), false);
#endif
#if defined(RGB_MATRIX_ENABLE)
oled_write_P(PSTR(OLED_RENDER_USER_ANIM), userspace_config.rgb_matrix_idle_anim);
# if !defined(OLED_DISPLAY_128X64)
# if !defined(OLED_DISPLAY_VERBOSE)
oled_write_P(PSTR(" "), false);
# endif
#elif defined(POINTING_DEVICE_ENABLE)
@ -289,7 +424,7 @@ void render_user_status(void) {
# ifdef AUDIO_CLICKY
static const char PROGMEM audio_clicky_status[2][3] = {{0xF4, 0xF5, 0}, {0xF6, 0xF7, 0}};
oled_write_P(audio_clicky_status[is_clicky_on && is_audio_on], false);
# if !defined(OLED_DISPLAY_128X64)
# if !defined(OLED_DISPLAY_VERBOSE)
oled_write_P(PSTR(" "), false);
# endif
# endif
@ -304,30 +439,20 @@ void render_user_status(void) {
oled_write_P(uc_mod_status[get_unicode_input_mode() == UC_MAC], false);
#endif
if (userspace_config.nuke_switch) {
#if !defined(OLED_DISPLAY_128X64)
#if !defined(OLED_DISPLAY_VERBOSE)
oled_write_P(PSTR(" "), false);
#endif
static const char PROGMEM nukem_good[2] = {0xFA, 0};
oled_write_P(nukem_good, false);
#if !defined(OLED_DISPLAY_128X64)
#if !defined(OLED_DISPLAY_VERBOSE)
oled_advance_page(true);
#endif
}
#if defined(OLED_DISPLAY_128X64)
#if defined(OLED_DISPLAY_VERBOSE)
oled_advance_page(true);
#endif
}
void oled_driver_render_logo(void) {
// clang-format off
static const char PROGMEM qmk_logo[] = {
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,
0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,0};
// clang-format on
oled_write_P(qmk_logo, false);
}
void render_wpm(uint8_t padding) {
#ifdef WPM_ENABLE
@ -356,49 +481,389 @@ void render_pointing_dpi_status(uint8_t padding) {
#endif
__attribute__((weak)) void oled_driver_render_logo_right(void) {
#if defined(OLED_DISPLAY_128X64)
oled_driver_render_logo();
#if defined(OLED_DISPLAY_VERBOSE)
oled_set_cursor(0, 2);
render_default_layer_state();
oled_set_cursor(0, 4);
#else
render_default_layer_state();
#endif
}
__attribute__((weak)) void oled_driver_render_logo_left(void) {
#if defined(OLED_DISPLAY_128X64)
oled_driver_render_logo();
# ifdef DEBUG_MATRIX_SCAN_RATE
// WPM-responsive animation stuff here
#define OLED_SLEEP_FRAMES 2
#define OLED_SLEEP_SPEED 10 // below this wpm value your animation will idle
#define OLED_WAKE_FRAMES 2 // uncomment if >1
#define OLED_WAKE_SPEED OLED_SLEEP_SPEED // below this wpm value your animation will idle
#define OLED_KAKI_FRAMES 3
#define OLED_KAKI_SPEED 40 // above this wpm value typing animation to triggere
#define OLED_RTOGI_FRAMES 2
//#define OLED_LTOGI_FRAMES 2
//#define ANIM_FRAME_DURATION 500 // how long each frame lasts in ms
// #define SLEEP_TIMER 60000 // should sleep after this period of 0 wpm, needs fixing
#define OLED_ANIM_SIZE 32 // number of bytes in array, minimize for adequate firmware size, max is 1024
#define OLED_ANIM_ROWS 4
#define OLED_ANIM_MAX_FRAMES 3
#if (OLED_SLEEP_FRAMES > OLED_ANIM_MAX_FRAMES) || (OLED_WAKE_FRAMES > OLED_ANIM_MAX_FRAMES) || (OLED_KAKI_FRAMES > OLED_ANIM_MAX_FRAMES) || (OLED_RTOGI_FRAMES > OLED_ANIM_MAX_FRAMES)
# error frame size too large
#endif
static uint8_t animation_frame = 0;
static uint8_t animation_type = 0;
void render_kitty(void) {
// Images credit j-inc(/James Incandenza) and pixelbenny.
// Credit to obosob for initial animation approach.
// heavily modified by drashna because he's a glutton for punishment
// clang-format off
static const char PROGMEM animation[4][OLED_ANIM_MAX_FRAMES][OLED_ANIM_ROWS][OLED_ANIM_SIZE] = {
// sleep frames
{
{
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
0xa8, 0x48, 0xa8, 0x18, 0x08, 0x00, 0x00, 0x00,
0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03,
0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x80,
0x44, 0x84, 0x06, 0x05, 0x04, 0x80, 0x40, 0x20,
0x10, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20,
0x18, 0x04, 0x04, 0x02, 0x7a, 0x86, 0x01, 0x80,
0x80, 0x01, 0x03, 0x05, 0x07, 0x01, 0x00, 0x00,
0x80, 0x83, 0x45, 0xfa, 0x3c, 0xe0, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x08,
0x10, 0x10, 0x10, 0x10, 0x10, 0x33, 0x24, 0x28,
0x28, 0x29, 0x29, 0x29, 0x3a, 0x18, 0x1c, 0x39,
0x24, 0x24, 0x3a, 0x2d, 0x26, 0x31, 0x1f, 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,
0x22, 0x22, 0x3a, 0x2a, 0x26, 0x22, 0x80, 0xc0,
0x80, 0x00, 0x24, 0x34, 0x2c, 0xe4, 0x60, 0x10,
0x70, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x38,
0x04, 0x02, 0x02, 0x01, 0x79, 0x87, 0x01, 0x80,
0x81, 0x83, 0x05, 0x05, 0x03, 0x01, 0x00, 0x00,
0x80, 0x43, 0x05, 0xfa, 0x3c, 0xe0, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x08,
0x10, 0x10, 0x10, 0x10, 0x10, 0x33, 0x24, 0x28,
0x28, 0x28, 0x29, 0x29, 0x3a, 0x18, 0x1c, 0x39,
0x24, 0x24, 0x3a, 0x2d, 0x26, 0x31, 0x1f, 0x00
}
}
},
// wake frames
{
{
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x30, 0x08, 0x10, 0x60, 0x80,
0x00, 0x80, 0x60, 0x10, 0x08, 0x30, 0xc0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0x80, 0x40, 0x40, 0x5c, 0x00, 0x01,
0x41, 0x01, 0x00, 0x5c, 0x40, 0x40, 0x80, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0x40, 0x40, 0x80, 0xe1, 0x12, 0x0a, 0x06, 0x00,
0x80, 0x00, 0x06, 0x0a, 0x12, 0xe1, 0x80, 0x40,
0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14,
0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18,
0x0f, 0x18, 0x10, 0x10, 0x1f, 0x11, 0x10, 0x10,
0x14, 0x14, 0x1f, 0x1c, 0x14, 0x14, 0x14, 0x08
}
},
{
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x30, 0x08, 0x10, 0x60, 0x80,
0x00, 0x80, 0x60, 0x10, 0x08, 0x30, 0xc0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0x90, 0x12, 0x0a, 0x02, 0xf4, 0x09,
0x0d, 0xf1, 0x04, 0x02, 0x0a, 0x12, 0x90, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0x40, 0x40, 0x80, 0xe1, 0x12, 0x0a, 0x06, 0x01,
0x81, 0x00, 0x06, 0x0a, 0x12, 0xe1, 0x80, 0x40,
0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14,
0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18,
0x0f, 0x18, 0x10, 0x10, 0x1f, 0x11, 0x10, 0x10,
0x14, 0x14, 0x1f, 0x1c, 0x14, 0x14, 0x14, 0x08
}
}
},
// kaki frames
{
{
{
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x40,
0x80, 0x80, 0x80, 0x00, 0xfc, 0x84, 0x08, 0x08,
0x10, 0x20, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1e, 0x60,
0x80, 0x00, 0x00, 0x91, 0xa1, 0x80, 0x00, 0x00,
0x22, 0x84, 0x40, 0x50, 0x48, 0xc1, 0x3e, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0x40, 0x41, 0x82, 0xe2, 0x12, 0x0a, 0x06, 0x00,
0x80, 0x88, 0x4f, 0x02, 0x22, 0xe2, 0x9f, 0x40,
0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14,
0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18,
0x0f, 0x18, 0x14, 0x10, 0x10, 0x10, 0x10, 0x10,
0x14, 0x14, 0x1f, 0x1a, 0x0a, 0x0a, 0x04, 0x00
}
},
{
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xf0, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x06, 0x1a, 0x22, 0xc2, 0x04, 0x04,
0x04, 0x07, 0x00, 0xc0, 0x20, 0x10, 0x80, 0x80,
0x01, 0x01, 0x02, 0xfc, 0xfe, 0x02, 0x3c, 0x20,
0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0d, 0x8d,
0x55, 0x50, 0x94, 0xf0, 0x10, 0x09, 0x08, 0x00,
0x80, 0x00, 0x06, 0x09, 0x1b, 0xee, 0x00, 0x00,
0x00, 0x00, 0x81, 0xfe, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14,
0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18,
0x0f, 0x18, 0x10, 0x10, 0x1f, 0x19, 0x18, 0x1c,
0x14, 0x16, 0x15, 0x14, 0x14, 0x14, 0x14, 0x08
}
},
{
{
0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0xe0, 0x10, 0x20, 0x40,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x01,
0x02, 0x04, 0x04, 0x03, 0x80, 0x40, 0x40, 0x20,
0x00, 0x01, 0x02, 0x8c, 0x70, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0d, 0x8d,
0x55, 0x50, 0x94, 0xf0, 0x10, 0x0a, 0x0e, 0x1d,
0x95, 0x24, 0x24, 0x27, 0x13, 0xe1, 0x01, 0x01,
0x01, 0x01, 0x02, 0xfc, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14,
0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18,
0x0f, 0x18, 0x10, 0x10, 0x1f, 0x19, 0x18, 0x1c,
0x14, 0x14, 0x17, 0x14, 0x14, 0x14, 0x14, 0x08
}
}
},
// rtogi frames
{
{
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xc0, 0x20, 0x10, 0x10, 0x08, 0x04, 0x02,
0x01, 0x0f, 0x90, 0x10, 0x20, 0xf0, 0xf8, 0xf8
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0x40, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08,
0x48, 0x47, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x88, 0xc7, 0xc4, 0x62, 0x23, 0x11, 0x3f
},
{
0x80, 0x40, 0x20, 0x10, 0x88, 0xcc, 0x43, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc0,
0x80, 0x80, 0xc0, 0xe1, 0xfe, 0xb8, 0x88, 0x0c,
0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x01, 0x06, 0x04, 0x04, 0x04, 0x04,
0x05, 0x04, 0x04, 0x04, 0x07, 0x07, 0x07, 0x03,
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, 0xc0, 0x20, 0x10, 0x10, 0x08, 0x04, 0x02,
0x01, 0x1f, 0xa0, 0x20, 0x40, 0x80, 0x00, 0xf0
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0x40, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08,
0x48, 0x47, 0x88, 0x00, 0x00, 0x00, 0x00, 0x24,
0x24, 0x28, 0x6b, 0x40, 0xa0, 0x99, 0x86, 0xff
},
{
0x0f, 0x11, 0x22, 0x44, 0x48, 0x4c, 0x43, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc0,
0x80, 0x80, 0xc0, 0xe1, 0xfe, 0xb8, 0x88, 0x0c,
0x04, 0x06, 0x06, 0x06, 0x0e, 0x0e, 0x06, 0x01
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x01, 0x06, 0x04, 0x04, 0x04, 0x04,
0x05, 0x04, 0x04, 0x04, 0x07, 0x07, 0x07, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}
}
}
};
// clang-format on
for (uint8_t i = 0; i < 4; i++) {
oled_set_cursor(1, i + 2);
oled_write_raw_P(animation[animation_type][animation_frame][i], OLED_ANIM_SIZE);
}
}
uint32_t kitty_animation_phases(uint32_t triger_time, void *cb_arg) {
uint32_t anim_frame_duration = 500;
// can't change animation frame duration here, otherwise, it gets stuck.
// weirdly, it seems to work fine if it's in keymap.c but not here.
// Should move this block to the deferred execution?
#ifdef POINTING_DEVICE_ENABLE
if (tap_toggling) {
animation_frame = (animation_frame + 1) % OLED_RTOGI_FRAMES;
animation_type = 3;
anim_frame_duration = 300;
} else
#endif
{
if (get_current_wpm() <= OLED_SLEEP_SPEED) {
animation_frame = (animation_frame + 1) % OLED_SLEEP_FRAMES;
animation_type = 0;
anim_frame_duration = 500;
} else if (get_current_wpm() > OLED_WAKE_SPEED) {
animation_frame = (animation_frame + 1) % OLED_WAKE_FRAMES;
animation_type = 1;
anim_frame_duration = 800;
} else if (get_current_wpm() >= OLED_KAKI_SPEED) {
animation_frame = (animation_frame + 1) % OLED_KAKI_FRAMES;
animation_type = 2;
anim_frame_duration = 500;
}
}
return anim_frame_duration;
}
void oled_driver_render_logo_left(void) {
#if defined(OLED_DISPLAY_VERBOSE)
oled_set_cursor(0, 2);
render_kitty();
# if defined(KEYBOARD_handwired_tractyl_manuform)
oled_set_cursor(7, 0);
oled_write_P(PSTR("Tractyl"), true);
# elif defined(KEYBOARD_bastardkb_charybdis)
oled_set_cursor(6, 0);
oled_write_P(PSTR("Charybdis"), true);
# else
oled_set_cursor(8, 0);
oled_write_P(PSTR("Left"), true);
# endif
oled_set_cursor(7, 2);
# if defined(DEBUG_MATRIX_SCAN_RATE)
render_matrix_scan_rate();
# elif defined(WPM_ENABLE)
render_wpm(0);
render_wpm(1);
# endif
oled_write_P(PSTR(" "), false);
# if defined(KEYBOARD_handwired_tractyl_manuform) || defined(KEYBOARD_bastardkb_charybdis)
oled_set_cursor(7, 3);
# if defined(KEYBOARD_handwired_tractyl_manuform)
render_pointing_dpi_status(0);
# elif defined(KEYBOARD_bastardkb_charybdis)
render_pointing_dpi_status(1);
# endif
oled_set_cursor(0, 4);
oled_set_cursor(0, 6);
#else
render_default_layer_state();
#endif
}
void render_status_secondary(void) {
# if defined(KEYBOARD_handwired_tractyl_manuform)
oled_set_cursor(7, 0);
oled_write_P(PSTR("Manuform"), true);
# elif defined(KEYBOARD_bastardkb_charybdis)
oled_set_cursor(6, 0);
oled_write_P(PSTR("Charybdis"), true);
# else
oled_set_cursor(8, 0);
oled_write_P(PSTR("Right"), true);
# endif
oled_driver_render_logo_right();
/* Show Keyboard Layout */
render_layer_state();
render_mod_status(get_mods() | get_oneshot_mods());
#if !defined(OLED_DISPLAY_128X64) && defined(WPM_ENABLE) && !defined(CONVERT_TO_PROTON_C)
#if !defined(OLED_DISPLAY_VERBOSE) && defined(WPM_ENABLE) && !defined(CONVERT_TO_PROTON_C)
render_wpm(2);
#endif
// render_keylock_status(host_keyboard_leds());
render_keylock_status(host_keyboard_leds());
}
void render_status_main(void) {
oled_driver_render_logo_left();
/* Show Keyboard Layout */
// render_keylock_status(host_keyboard_leds());
render_bootmagic_status();
render_user_status();
@ -408,8 +873,14 @@ void render_status_main(void) {
__attribute__((weak)) oled_rotation_t oled_init_keymap(oled_rotation_t rotation) { return rotation; }
oled_rotation_t oled_init_user(oled_rotation_t rotation) {
memset(keylog_str, ' ', sizeof(keylog_str) - 1);
if (is_keyboard_master()) {
memset(keylog_str, ' ', OLED_KEYLOGGER_LENGTH);
}
kittoken = defer_exec(3000, kitty_animation_phases, NULL);
oled_clear();
oled_render();
return oled_init_keymap(rotation);
}
@ -417,22 +888,61 @@ bool oled_task_user(void) {
update_log();
if (is_keyboard_master()) {
#ifndef OLED_DISPLAY_TEST
if (timer_elapsed32(oled_timer) > 30000) {
oled_off();
return false;
} else {
} else
#endif
{
oled_on();
}
}
#if defined(OLED_DISPLAY_VERBOSE)
static const char PROGMEM header_image[] = {
0,192, 32, 16, 8, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 7, 15, 31, 63,127,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,127, 63, 31, 15, 7, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 8, 16, 32,192, 0,
0,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 7, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 7, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255, 0
};
static const char PROGMEM footer_image[] = {
0, 3, 4, 8, 16, 32, 64,128,128,128,128,128,128,128,192,224,240,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,240,224,192,128,128,128,128,128,128,128, 64, 32, 16, 8, 4, 3, 0
};
oled_write_raw_P(header_image, sizeof(header_image));
oled_set_cursor(0, 1);
#endif
#ifndef OLED_DISPLAY_TEST
if (is_keyboard_left()) {
#endif
render_status_main(); // Renders the current keyboard state (layer, lock, caps, scroll, etc)
#ifndef OLED_DISPLAY_TEST
} else {
render_status_secondary();
}
if (is_keyboard_master()) {
#endif
#if defined(OLED_DISPLAY_128X128)
if (is_keyboard_left()) {
render_keylogger_status();
} else {
render_keylock_status(host_keyboard_leds());
}
#endif
#if defined(OLED_DISPLAY_VERBOSE)
uint8_t num_of_rows;
# if defined(OLED_DISPLAY_128X128)
num_of_rows = 15;
# else
num_of_rows = 7;
# endif
for (uint8_t i= 1; i < num_of_rows; i++) {
oled_set_cursor(0, i);
oled_write_raw_P(display_border, sizeof(display_border));
oled_set_cursor(21, i);
oled_write_raw_P(display_border, sizeof(display_border));
}
oled_set_cursor(0, num_of_rows);
oled_write_raw_P(footer_image, sizeof(footer_image));
#endif
return false;
}

View File

@ -18,6 +18,7 @@
#include "quantum.h"
#include "oled_driver.h"
extern deferred_token kittoken;
void oled_driver_render_logo(void);
bool process_record_user_oled(uint16_t keycode, keyrecord_t *record);
@ -37,12 +38,16 @@ void render_pointing_dpi_status(uint8_t padding);
void oled_driver_render_logo_left(void);
void oled_driver_render_logo_right(void);
#ifdef OLED_DISPLAY_128X64
# define OLED_RENDER_KEYLOGGER "Keylogger: "
#if defined(OLED_DISPLAY_128X128) || defined(OLED_DISPLAY_128X64)
# define OLED_DISPLAY_VERBOSE
# define OLED_RENDER_KEYLOGGER "Keylogger: "
# ifndef OLED_KEYLOGGER_LENGTH
# define OLED_KEYLOGGER_LENGTH 9
# endif
# define OLED_RENDER_LAYOUT_NAME "Layout: "
# define OLED_RENDER_LAYOUT_QWERTY "Qwerty"
# define OLED_RENDER_LAYOUT_COLEMAK_DH "Colemak-DH"
# define OLED_RENDER_LAYOUT_COLEMAK_DH "ColemkDH"
# define OLED_RENDER_LAYOUT_COLEMAK "Colemak"
# define OLED_RENDER_LAYOUT_DVORAK "Dvorak"
# define OLED_RENDER_LAYOUT_WORKMAN "Workman"
@ -58,11 +63,11 @@ void oled_driver_render_logo_right(void);
# define OLED_RENDER_LAYER_MODS "Mods"
# define OLED_RENDER_LOCK_NAME "Lock: "
# define OLED_RENDER_LOCK_NUML "NUML"
# define OLED_RENDER_LOCK_NUML "NUM"
# define OLED_RENDER_LOCK_CAPS "CAPS"
# define OLED_RENDER_LOCK_SCLK "SCLK"
# define OLED_RENDER_MODS_NAME "Mods:"
# define OLED_RENDER_MODS_NAME "Mods"
# define OLED_RENDER_MODS_SFT "Sft"
# define OLED_RENDER_MODS_CTL "Ctl"
# define OLED_RENDER_MODS_ALT "Alt"
@ -84,6 +89,9 @@ void oled_driver_render_logo_right(void);
# define OLED_RENDER_WPM_COUNTER "WPM: "
#else
# define OLED_RENDER_KEYLOGGER "KLogr"
# ifndef OLED_KEYLOGGER_LENGTH
# define OLED_KEYLOGGER_LENGTH 5
# endif
# define OLED_RENDER_LAYOUT_NAME "Lyout"
# define OLED_RENDER_LAYOUT_QWERTY " QRTY"
@ -127,5 +135,7 @@ void oled_driver_render_logo_right(void);
# define OLED_RENDER_USER_NUKE "Nuke"
# define OLED_RENDER_WPM_COUNTER "WPM: "
#endif
extern char keylog_str[OLED_KEYLOGGER_LENGTH];

View File

@ -0,0 +1,860 @@
/*
Copyright 2019 Ryan Caltabiano <https://github.com/XScorpion2>
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/>.
*/
#include "i2c_master.h"
#include "oled_driver.h"
#include OLED_FONT_H
#include "timer.h"
#include "print.h"
#include <string.h>
#include "progmem.h"
#include "keyboard.h"
// Used commands from spec sheet: https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf
// for SH1106: https://www.velleman.eu/downloads/29/infosheets/sh1106_datasheet.pdf
// Fundamental Commands
#define CONTRAST 0x81
#define DISPLAY_ALL_ON 0xA5
#define DISPLAY_ALL_ON_RESUME 0xA4
#define NORMAL_DISPLAY 0xA6
#define INVERT_DISPLAY 0xA7
#define DISPLAY_ON 0xAF
#define DISPLAY_OFF 0xAE
#define NOP 0xE3
// Scrolling Commands
#define ACTIVATE_SCROLL 0x2F
#define DEACTIVATE_SCROLL 0x2E
#define SCROLL_RIGHT 0x26
#define SCROLL_LEFT 0x27
#define SCROLL_RIGHT_UP 0x29
#define SCROLL_LEFT_UP 0x2A
// Addressing Setting Commands
#define MEMORY_MODE 0x20
#define COLUMN_ADDR 0x21
#define PAGE_ADDR 0x22
#define PAM_SETCOLUMN_LSB 0x00
#define PAM_SETCOLUMN_MSB 0x10
#define PAM_PAGE_ADDR 0xB0 // 0xb0 -- 0xb7
// Hardware Configuration Commands
#define DISPLAY_START_LINE 0x40
#define SEGMENT_REMAP 0xA0
#define SEGMENT_REMAP_INV 0xA1
#define MULTIPLEX_RATIO 0xA8
#define COM_SCAN_INC 0xC0
#define COM_SCAN_DEC 0xC8
#define DISPLAY_OFFSET 0xD3
#define COM_PINS 0xDA
#define COM_PINS_SEQ 0x02
#define COM_PINS_ALT 0x12
#define COM_PINS_SEQ_LR 0x22
#define COM_PINS_ALT_LR 0x32
// Timing & Driving Commands
#define DISPLAY_CLOCK 0xD5
#define PRE_CHARGE_PERIOD 0xD9
#define VCOM_DETECT 0xDB
// Advance Graphic Commands
#define FADE_BLINK 0x23
#define ENABLE_FADE 0x20
#define ENABLE_BLINK 0x30
// Charge Pump Commands
#define CHARGE_PUMP 0x8D
// Commands specific to the SH1107 chip
#define SH1107_DISPLAY_START_LINE 0xDC
#define SH1107_MEMORY_MODE_PAGE 0x20
#define SH1107_MEMORY_MODE_VERTICAL 0x21
// Misc defines
#ifndef OLED_BLOCK_COUNT
# define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8)
#endif
#ifndef OLED_BLOCK_SIZE
# define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT)
#endif
#define OLED_ALL_BLOCKS_MASK (((((OLED_BLOCK_TYPE)1 << (OLED_BLOCK_COUNT - 1)) - 1) << 1) | 1)
#define OLED_IC_HAS_HORIZONTAL_MODE (OLED_IC == OLED_IC_SSD1306)
#define OLED_IC_COM_PINS_ARE_COLUMNS (OLED_IC == OLED_IC_SH1107)
#ifndef OLED_COM_PIN_COUNT
# if OLED_IC == OLED_IC_SH1106
# define OLED_COM_PIN_COUNT 64
# elif OLED_IC == OLED_IC_SH1107
# define OLED_COM_PIN_COUNT 128
# else
# error Invalid OLED_IC value
# endif
#endif
#ifndef OLED_COM_PIN_OFFSET
# define OLED_COM_PIN_OFFSET 0
#endif
// i2c defines
#define I2C_CMD 0x00
#define I2C_DATA 0x40
#if defined(__AVR__)
# define I2C_TRANSMIT_P(data) i2c_transmit_P((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), OLED_I2C_TIMEOUT)
#else // defined(__AVR__)
# define I2C_TRANSMIT_P(data) i2c_transmit((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), OLED_I2C_TIMEOUT)
#endif // defined(__AVR__)
#define I2C_TRANSMIT(data) i2c_transmit((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), OLED_I2C_TIMEOUT)
#define I2C_WRITE_REG(mode, data, size) i2c_writeReg((OLED_DISPLAY_ADDRESS << 1), mode, data, size, OLED_I2C_TIMEOUT)
#define HAS_FLAGS(bits, flags) ((bits & flags) == flags)
// Display buffer's is the same as the OLED memory layout
// this is so we don't end up with rounding errors with
// parts of the display unusable or don't get cleared correctly
// and also allows for drawing & inverting
uint8_t oled_buffer[OLED_MATRIX_SIZE];
uint8_t * oled_cursor;
OLED_BLOCK_TYPE oled_dirty = 0;
bool oled_initialized = false;
bool oled_active = false;
bool oled_scrolling = false;
bool oled_inverted = false;
uint8_t oled_brightness = OLED_BRIGHTNESS;
oled_rotation_t oled_rotation = 0;
uint8_t oled_rotation_width = 0;
uint8_t oled_scroll_speed = 0; // this holds the speed after being remapped to ssd1306 internal values
uint8_t oled_scroll_start = 0;
uint8_t oled_scroll_end = 7;
#if OLED_TIMEOUT > 0
uint32_t oled_timeout;
#endif
#if OLED_SCROLL_TIMEOUT > 0
uint32_t oled_scroll_timeout;
#endif
#if OLED_UPDATE_INTERVAL > 0
uint16_t oled_update_timeout;
#endif
// Internal variables to reduce math instructions
#if defined(__AVR__)
// identical to i2c_transmit, but for PROGMEM since all initialization is in PROGMEM arrays currently
// probably should move this into i2c_master...
static i2c_status_t i2c_transmit_P(uint8_t address, const uint8_t *data, uint16_t length, uint16_t timeout) {
i2c_status_t status = i2c_start(address | I2C_WRITE, timeout);
for (uint16_t i = 0; i < length && status >= 0; i++) {
status = i2c_write(pgm_read_byte((const char *)data++), timeout);
if (status) break;
}
i2c_stop();
return status;
}
#endif
// Flips the rendering bits for a character at the current cursor position
static void InvertCharacter(uint8_t *cursor) {
const uint8_t *end = cursor + OLED_FONT_WIDTH;
while (cursor < end) {
*cursor = ~(*cursor);
cursor++;
}
}
bool oled_init(oled_rotation_t rotation) {
#if defined(USE_I2C) && defined(SPLIT_KEYBOARD)
if (!is_keyboard_master()) {
return true;
}
#endif
oled_rotation = oled_init_user(oled_init_kb(rotation));
if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
oled_rotation_width = OLED_DISPLAY_WIDTH;
} else {
oled_rotation_width = OLED_DISPLAY_HEIGHT;
}
i2c_init();
static const uint8_t PROGMEM display_setup1[] = {
I2C_CMD,
DISPLAY_OFF,
DISPLAY_CLOCK,
0x80,
MULTIPLEX_RATIO,
#if OLED_IC_COM_PINS_ARE_COLUMNS
OLED_DISPLAY_WIDTH - 1,
#else
OLED_DISPLAY_HEIGHT - 1,
#endif
DISPLAY_OFFSET,
0x00,
DISPLAY_START_LINE | 0x00,
CHARGE_PUMP,
0x14,
#if (OLED_IC != OLED_IC_SH1106)
// MEMORY_MODE is unsupported on SH1106 (Page Addressing only)
MEMORY_MODE,
0x00, // Horizontal addressing mode
#elif OLED_IC == OLED_IC_SH1107
// Page addressing mode
SH1107_MEMORY_MODE_PAGE,
#endif
};
if (I2C_TRANSMIT_P(display_setup1) != I2C_STATUS_SUCCESS) {
print("oled_init cmd set 1 failed\n");
return false;
}
if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_180)) {
static const uint8_t PROGMEM display_normal[] = {
I2C_CMD, SEGMENT_REMAP_INV, COM_SCAN_DEC, DISPLAY_OFFSET, OLED_COM_PIN_OFFSET,
};
if (I2C_TRANSMIT_P(display_normal) != I2C_STATUS_SUCCESS) {
print("oled_init cmd normal rotation failed\n");
return false;
}
} else {
static const uint8_t PROGMEM display_flipped[] = {
I2C_CMD, SEGMENT_REMAP, COM_SCAN_INC, DISPLAY_OFFSET, (OLED_COM_PIN_COUNT - OLED_COM_PIN_OFFSET) % OLED_COM_PIN_COUNT,
};
if (I2C_TRANSMIT_P(display_flipped) != I2C_STATUS_SUCCESS) {
print("display_flipped failed\n");
return false;
}
}
static const uint8_t PROGMEM display_setup2[] = {I2C_CMD, COM_PINS, OLED_COM_PINS, CONTRAST, OLED_BRIGHTNESS, PRE_CHARGE_PERIOD, 0x22, VCOM_DETECT, 0x35, DISPLAY_ALL_ON_RESUME, NORMAL_DISPLAY, DEACTIVATE_SCROLL, DISPLAY_ON}; if (I2C_TRANSMIT_P(display_setup2) != I2C_STATUS_SUCCESS) {
print("display_setup2 failed\n");
return false;
}
#if OLED_TIMEOUT > 0
oled_timeout = timer_read32() + OLED_TIMEOUT;
#endif
#if OLED_SCROLL_TIMEOUT > 0
oled_scroll_timeout = timer_read32() + OLED_SCROLL_TIMEOUT;
#endif
oled_clear();
oled_initialized = true;
oled_active = true;
oled_scrolling = false;
return true;
}
__attribute__((weak)) oled_rotation_t oled_init_kb(oled_rotation_t rotation) { return rotation; }
__attribute__((weak)) oled_rotation_t oled_init_user(oled_rotation_t rotation) { return rotation; }
void oled_clear(void) {
memset(oled_buffer, 0, sizeof(oled_buffer));
oled_cursor = &oled_buffer[0];
oled_dirty = OLED_ALL_BLOCKS_MASK;
}
static void calc_bounds(uint8_t update_start, uint8_t *cmd_array) {
// Calculate commands to set memory addressing bounds.
uint8_t start_page = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_WIDTH;
uint8_t start_column = OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_WIDTH;
#if !OLED_IC_HAS_HORIZONTAL_MODE
// Commands for Page Addressing Mode. Sets starting page and column; has no end bound.
// Column value must be split into high and low nybble and sent as two commands.
cmd_array[0] = PAM_PAGE_ADDR | start_page;
cmd_array[1] = PAM_SETCOLUMN_LSB | ((OLED_COLUMN_OFFSET + start_column) & 0x0f);
cmd_array[2] = PAM_SETCOLUMN_MSB | ((OLED_COLUMN_OFFSET + start_column) >> 4 & 0x0f);
cmd_array[3] = NOP;
cmd_array[4] = NOP;
cmd_array[5] = NOP;
#else
// Commands for use in Horizontal Addressing mode.
cmd_array[1] = start_column + OLED_COLUMN_OFFSET;
cmd_array[4] = start_page;
cmd_array[2] = (OLED_BLOCK_SIZE + OLED_DISPLAY_WIDTH - 1) % OLED_DISPLAY_WIDTH + cmd_array[1];
cmd_array[5] = (OLED_BLOCK_SIZE + OLED_DISPLAY_WIDTH - 1) / OLED_DISPLAY_WIDTH - 1 + cmd_array[4];
#endif
}
static void calc_bounds_90(uint8_t update_start, uint8_t *cmd_array) {
// Block numbering starts from the bottom left corner, going up and then to
// the right. The controller needs the page and column numbers for the top
// left and bottom right corners of that block.
// Total number of pages across the screen height.
const uint8_t height_in_pages = OLED_DISPLAY_HEIGHT / 8;
// Difference of starting page numbers for adjacent blocks; may be 0 if
// blocks are large enough to occupy one or more whole 8px columns.
const uint8_t page_inc_per_block = OLED_BLOCK_SIZE % OLED_DISPLAY_HEIGHT / 8;
// Top page number for a block which is at the bottom edge of the screen.
const uint8_t bottom_block_top_page = (height_in_pages - page_inc_per_block) % height_in_pages;
#if !OLED_IC_HAS_HORIZONTAL_MODE
// Only the Page Addressing Mode is supported
uint8_t start_page = bottom_block_top_page - (OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_HEIGHT / 8);
uint8_t start_column = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_HEIGHT * 8;
cmd_array[0] = PAM_PAGE_ADDR | start_page;
cmd_array[1] = PAM_SETCOLUMN_LSB | ((OLED_COLUMN_OFFSET + start_column) & 0x0f);
cmd_array[2] = PAM_SETCOLUMN_MSB | ((OLED_COLUMN_OFFSET + start_column) >> 4 & 0x0f);
#else
cmd_array[1] = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_HEIGHT * 8 + OLED_COLUMN_OFFSET;
cmd_array[4] = bottom_block_top_page - (OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_HEIGHT / 8);
cmd_array[2] = (OLED_BLOCK_SIZE + OLED_DISPLAY_HEIGHT - 1) / OLED_DISPLAY_HEIGHT * 8 - 1 + cmd_array[1];
cmd_array[5] = (OLED_BLOCK_SIZE + OLED_DISPLAY_HEIGHT - 1) % OLED_DISPLAY_HEIGHT / 8 + cmd_array[4];
#endif
}
uint8_t crot(uint8_t a, int8_t n) {
const uint8_t mask = 0x7;
n &= mask;
return a << n | a >> (-n & mask);
}
static void rotate_90(const uint8_t *src, uint8_t *dest) {
for (uint8_t i = 0, shift = 7; i < 8; ++i, --shift) {
uint8_t selector = (1 << i);
for (uint8_t j = 0; j < 8; ++j) {
dest[i] |= crot(src[j] & selector, shift - (int8_t)j);
}
}
}
void oled_render(void) {
if (!oled_initialized) {
return;
}
// Do we have work to do?
oled_dirty &= OLED_ALL_BLOCKS_MASK;
if (!oled_dirty || oled_scrolling) {
return;
}
// Find first dirty block
uint8_t update_start = 0;
while (!(oled_dirty & ((OLED_BLOCK_TYPE)1 << update_start))) {
++update_start;
}
// Set column & page position
#if OLED_IC_HAS_HORIZONTAL_MODE
static uint8_t display_start[] = {I2C_CMD, COLUMN_ADDR, 0, OLED_DISPLAY_WIDTH - 1, PAGE_ADDR, 0, OLED_DISPLAY_HEIGHT / 8 - 1};
#else
static uint8_t display_start[] = {I2C_CMD, PAM_PAGE_ADDR, PAM_SETCOLUMN_LSB, PAM_SETCOLUMN_MSB};
#endif
if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
calc_bounds(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start
} else {
calc_bounds_90(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start
}
// Send column & page position
if (I2C_TRANSMIT(display_start) != I2C_STATUS_SUCCESS) {
print("oled_render offset command failed\n");
return;
}
if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
// Send render data chunk as is
if (I2C_WRITE_REG(I2C_DATA, &oled_buffer[OLED_BLOCK_SIZE * update_start], OLED_BLOCK_SIZE) != I2C_STATUS_SUCCESS) {
print("oled_render data failed\n");
return;
}
} else {
// Rotate the render chunks
const static uint8_t source_map[] = OLED_SOURCE_MAP;
const static uint8_t target_map[] = OLED_TARGET_MAP;
static uint8_t temp_buffer[OLED_BLOCK_SIZE];
memset(temp_buffer, 0, sizeof(temp_buffer));
for (uint8_t i = 0; i < sizeof(source_map); ++i) {
rotate_90(&oled_buffer[OLED_BLOCK_SIZE * update_start + source_map[i]], &temp_buffer[target_map[i]]);
}
#if OLED_IC_HAS_HORIZONTAL_MODE
// Send render data chunk after rotating
if (I2C_WRITE_REG(I2C_DATA, &temp_buffer[0], OLED_BLOCK_SIZE) != I2C_STATUS_SUCCESS) {
print("oled_render90 data failed\n");
return;
}
#else
// For SH1106 or SH1107 the data chunk must be split into separate pieces for each page
const uint8_t columns_in_block = (OLED_BLOCK_SIZE + OLED_DISPLAY_HEIGHT - 1) / OLED_DISPLAY_HEIGHT * 8;
const uint8_t num_pages = OLED_BLOCK_SIZE / columns_in_block;
for (uint8_t i = 0; i < num_pages; ++i) {
// Send column & page position for all pages except the first one
if (i > 0) {
display_start[1]++;
if (I2C_TRANSMIT(display_start) != I2C_STATUS_SUCCESS) {
print("oled_render offset command failed\n");
return;
}
}
// Send data for the page
if (I2C_WRITE_REG(I2C_DATA, &temp_buffer[columns_in_block * i], columns_in_block) != I2C_STATUS_SUCCESS) {
print("oled_render90 data failed\n");
return;
}
}
#endif
}
// Turn on display if it is off
oled_on();
// Clear dirty flag
oled_dirty &= ~((OLED_BLOCK_TYPE)1 << update_start);
}
void oled_set_cursor(uint8_t col, uint8_t line) {
uint16_t index = line * oled_rotation_width + col * OLED_FONT_WIDTH;
// Out of bounds?
if (index >= OLED_MATRIX_SIZE) {
index = 0;
}
oled_cursor = &oled_buffer[index];
}
void oled_advance_page(bool clearPageRemainder) {
uint16_t index = oled_cursor - &oled_buffer[0];
uint8_t remaining = oled_rotation_width - (index % oled_rotation_width);
if (clearPageRemainder) {
// Remaining Char count
remaining = remaining / OLED_FONT_WIDTH;
// Write empty character until next line
while (remaining--) oled_write_char(' ', false);
} else {
// Next page index out of bounds?
if (index + remaining >= OLED_MATRIX_SIZE) {
index = 0;
remaining = 0;
}
oled_cursor = &oled_buffer[index + remaining];
}
}
void oled_advance_char(void) {
uint16_t nextIndex = oled_cursor - &oled_buffer[0] + OLED_FONT_WIDTH;
uint8_t remainingSpace = oled_rotation_width - (nextIndex % oled_rotation_width);
// Do we have enough space on the current line for the next character
if (remainingSpace < OLED_FONT_WIDTH) {
nextIndex += remainingSpace;
}
// Did we go out of bounds
if (nextIndex >= OLED_MATRIX_SIZE) {
nextIndex = 0;
}
// Update cursor position
oled_cursor = &oled_buffer[nextIndex];
}
// Main handler that writes character data to the display buffer
void oled_write_char(const char data, bool invert) {
// Advance to the next line if newline
if (data == '\n') {
// Old source wrote ' ' until end of line...
oled_advance_page(true);
return;
}
if (data == '\r') {
oled_advance_page(false);
return;
}
// copy the current render buffer to check for dirty after
static uint8_t oled_temp_buffer[OLED_FONT_WIDTH];
memcpy(&oled_temp_buffer, oled_cursor, OLED_FONT_WIDTH);
_Static_assert(sizeof(font) >= ((OLED_FONT_END + 1 - OLED_FONT_START) * OLED_FONT_WIDTH), "OLED_FONT_END references outside array");
// set the reder buffer data
uint8_t cast_data = (uint8_t)data; // font based on unsigned type for index
if (cast_data < OLED_FONT_START || cast_data > OLED_FONT_END) {
memset(oled_cursor, 0x00, OLED_FONT_WIDTH);
} else {
const uint8_t *glyph = &font[(cast_data - OLED_FONT_START) * OLED_FONT_WIDTH];
memcpy_P(oled_cursor, glyph, OLED_FONT_WIDTH);
}
// Invert if needed
if (invert) {
InvertCharacter(oled_cursor);
}
// Dirty check
if (memcmp(&oled_temp_buffer, oled_cursor, OLED_FONT_WIDTH)) {
uint16_t index = oled_cursor - &oled_buffer[0];
oled_dirty |= ((OLED_BLOCK_TYPE)1 << (index / OLED_BLOCK_SIZE));
// Edgecase check if the written data spans the 2 chunks
oled_dirty |= ((OLED_BLOCK_TYPE)1 << ((index + OLED_FONT_WIDTH - 1) / OLED_BLOCK_SIZE));
}
// Finally move to the next char
oled_advance_char();
}
void oled_write(const char *data, bool invert) {
const char *end = data + strlen(data);
while (data < end) {
oled_write_char(*data, invert);
data++;
}
}
void oled_write_ln(const char *data, bool invert) {
oled_write(data, invert);
oled_advance_page(true);
}
void oled_pan(bool left) {
uint16_t i = 0;
for (uint16_t y = 0; y < OLED_DISPLAY_HEIGHT / 8; y++) {
if (left) {
for (uint16_t x = 0; x < OLED_DISPLAY_WIDTH - 1; x++) {
i = y * OLED_DISPLAY_WIDTH + x;
oled_buffer[i] = oled_buffer[i + 1];
}
} else {
for (uint16_t x = OLED_DISPLAY_WIDTH - 1; x > 0; x--) {
i = y * OLED_DISPLAY_WIDTH + x;
oled_buffer[i] = oled_buffer[i - 1];
}
}
}
oled_dirty = OLED_ALL_BLOCKS_MASK;
}
oled_buffer_reader_t oled_read_raw(uint16_t start_index) {
if (start_index > OLED_MATRIX_SIZE) start_index = OLED_MATRIX_SIZE;
oled_buffer_reader_t ret_reader;
ret_reader.current_element = &oled_buffer[start_index];
ret_reader.remaining_element_count = OLED_MATRIX_SIZE - start_index;
return ret_reader;
}
void oled_write_raw_byte(const char data, uint16_t index) {
if (index > OLED_MATRIX_SIZE) index = OLED_MATRIX_SIZE;
if (oled_buffer[index] == data) return;
oled_buffer[index] = data;
oled_dirty |= ((OLED_BLOCK_TYPE)1 << (index / OLED_BLOCK_SIZE));
}
void oled_write_raw(const char *data, uint16_t size) {
uint16_t cursor_start_index = oled_cursor - &oled_buffer[0];
if ((size + cursor_start_index) > OLED_MATRIX_SIZE) size = OLED_MATRIX_SIZE - cursor_start_index;
for (uint16_t i = cursor_start_index; i < cursor_start_index + size; i++) {
uint8_t c = *data++;
if (oled_buffer[i] == c) continue;
oled_buffer[i] = c;
oled_dirty |= ((OLED_BLOCK_TYPE)1 << (i / OLED_BLOCK_SIZE));
}
}
void oled_write_pixel(uint8_t x, uint8_t y, bool on) {
if (x >= oled_rotation_width) {
return;
}
uint16_t index = x + (y / 8) * oled_rotation_width;
if (index >= OLED_MATRIX_SIZE) {
return;
}
uint8_t data = oled_buffer[index];
if (on) {
data |= (1 << (y % 8));
} else {
data &= ~(1 << (y % 8));
}
if (oled_buffer[index] != data) {
oled_buffer[index] = data;
oled_dirty |= ((OLED_BLOCK_TYPE)1 << (index / OLED_BLOCK_SIZE));
}
}
#if defined(__AVR__)
void oled_write_P(const char *data, bool invert) {
uint8_t c = pgm_read_byte(data);
while (c != 0) {
oled_write_char(c, invert);
c = pgm_read_byte(++data);
}
}
void oled_write_ln_P(const char *data, bool invert) {
oled_write_P(data, invert);
oled_advance_page(true);
}
void oled_write_raw_P(const char *data, uint16_t size) {
uint16_t cursor_start_index = oled_cursor - &oled_buffer[0];
if ((size + cursor_start_index) > OLED_MATRIX_SIZE) size = OLED_MATRIX_SIZE - cursor_start_index;
for (uint16_t i = cursor_start_index; i < cursor_start_index + size; i++) {
uint8_t c = pgm_read_byte(data++);
if (oled_buffer[i] == c) continue;
oled_buffer[i] = c;
oled_dirty |= ((OLED_BLOCK_TYPE)1 << (i / OLED_BLOCK_SIZE));
}
}
#endif // defined(__AVR__)
bool oled_on(void) {
if (!oled_initialized) {
return oled_active;
}
#if OLED_TIMEOUT > 0
oled_timeout = timer_read32() + OLED_TIMEOUT;
#endif
static const uint8_t PROGMEM display_on[] =
#ifdef OLED_FADE_OUT
{I2C_CMD, FADE_BLINK, 0x00};
#else
{I2C_CMD, DISPLAY_ON};
#endif
if (!oled_active) {
if (I2C_TRANSMIT_P(display_on) != I2C_STATUS_SUCCESS) {
print("oled_on cmd failed\n");
return oled_active;
}
oled_active = true;
}
return oled_active;
}
bool oled_off(void) {
if (!oled_initialized) {
return !oled_active;
}
static const uint8_t PROGMEM display_off[] =
#ifdef OLED_FADE_OUT
{I2C_CMD, FADE_BLINK, ENABLE_FADE | OLED_FADE_OUT_INTERVAL};
#else
{I2C_CMD, DISPLAY_OFF};
#endif
if (oled_active) {
if (I2C_TRANSMIT_P(display_off) != I2C_STATUS_SUCCESS) {
print("oled_off cmd failed\n");
return oled_active;
}
oled_active = false;
}
return !oled_active;
}
bool is_oled_on(void) { return oled_active; }
uint8_t oled_set_brightness(uint8_t level) {
if (!oled_initialized) {
return oled_brightness;
}
uint8_t set_contrast[] = {I2C_CMD, CONTRAST, level};
if (oled_brightness != level) {
if (I2C_TRANSMIT(set_contrast) != I2C_STATUS_SUCCESS) {
print("set_brightness cmd failed\n");
return oled_brightness;
}
oled_brightness = level;
}
return oled_brightness;
}
uint8_t oled_get_brightness(void) { return oled_brightness; }
// Set the specific 8 lines rows of the screen to scroll.
// 0 is the default for start, and 7 for end, which is the entire
// height of the screen. For 128x32 screens, rows 4-7 are not used.
void oled_scroll_set_area(uint8_t start_line, uint8_t end_line) {
oled_scroll_start = start_line;
oled_scroll_end = end_line;
}
void oled_scroll_set_speed(uint8_t speed) {
// Sets the speed for scrolling... does not take effect
// until scrolling is either started or restarted
// the ssd1306 supports 8 speeds
// FrameRate2 speed = 7
// FrameRate3 speed = 4
// FrameRate4 speed = 5
// FrameRate5 speed = 0
// FrameRate25 speed = 6
// FrameRate64 speed = 1
// FrameRate128 speed = 2
// FrameRate256 speed = 3
// for ease of use these are remaped here to be in order
static const uint8_t scroll_remap[8] = {7, 4, 5, 0, 6, 1, 2, 3};
oled_scroll_speed = scroll_remap[speed];
}
bool oled_scroll_right(void) {
if (!oled_initialized) {
return oled_scrolling;
}
// Dont enable scrolling if we need to update the display
// This prevents scrolling of bad data from starting the scroll too early after init
if (!oled_dirty && !oled_scrolling) {
uint8_t display_scroll_right[] = {I2C_CMD, SCROLL_RIGHT, 0x00, oled_scroll_start, oled_scroll_speed, oled_scroll_end, 0x00, 0xFF, ACTIVATE_SCROLL};
if (I2C_TRANSMIT(display_scroll_right) != I2C_STATUS_SUCCESS) {
print("oled_scroll_right cmd failed\n");
return oled_scrolling;
}
oled_scrolling = true;
}
return oled_scrolling;
}
bool oled_scroll_left(void) {
if (!oled_initialized) {
return oled_scrolling;
}
// Dont enable scrolling if we need to update the display
// This prevents scrolling of bad data from starting the scroll too early after init
if (!oled_dirty && !oled_scrolling) {
uint8_t display_scroll_left[] = {I2C_CMD, SCROLL_LEFT, 0x00, oled_scroll_start, oled_scroll_speed, oled_scroll_end, 0x00, 0xFF, ACTIVATE_SCROLL};
if (I2C_TRANSMIT(display_scroll_left) != I2C_STATUS_SUCCESS) {
print("oled_scroll_left cmd failed\n");
return oled_scrolling;
}
oled_scrolling = true;
}
return oled_scrolling;
}
bool oled_scroll_off(void) {
if (!oled_initialized) {
return !oled_scrolling;
}
if (oled_scrolling) {
static const uint8_t PROGMEM display_scroll_off[] = {I2C_CMD, DEACTIVATE_SCROLL};
if (I2C_TRANSMIT_P(display_scroll_off) != I2C_STATUS_SUCCESS) {
print("oled_scroll_off cmd failed\n");
return oled_scrolling;
}
oled_scrolling = false;
oled_dirty = OLED_ALL_BLOCKS_MASK;
}
return !oled_scrolling;
}
bool is_oled_scrolling(void) { return oled_scrolling; }
bool oled_invert(bool invert) {
if (!oled_initialized) {
return oled_inverted;
}
if (invert && !oled_inverted) {
static const uint8_t PROGMEM display_inverted[] = {I2C_CMD, INVERT_DISPLAY};
if (I2C_TRANSMIT_P(display_inverted) != I2C_STATUS_SUCCESS) {
print("oled_invert cmd failed\n");
return oled_inverted;
}
oled_inverted = true;
} else if (!invert && oled_inverted) {
static const uint8_t PROGMEM display_normal[] = {I2C_CMD, NORMAL_DISPLAY};
if (I2C_TRANSMIT_P(display_normal) != I2C_STATUS_SUCCESS) {
print("oled_invert cmd failed\n");
return oled_inverted;
}
oled_inverted = false;
}
return oled_inverted;
}
uint8_t oled_max_chars(void) {
if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
return OLED_DISPLAY_WIDTH / OLED_FONT_WIDTH;
}
return OLED_DISPLAY_HEIGHT / OLED_FONT_WIDTH;
}
uint8_t oled_max_lines(void) {
if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
return OLED_DISPLAY_HEIGHT / OLED_FONT_HEIGHT;
}
return OLED_DISPLAY_WIDTH / OLED_FONT_HEIGHT;
}
void oled_task(void) {
if (!oled_initialized) {
return;
}
#if OLED_UPDATE_INTERVAL > 0
if (timer_elapsed(oled_update_timeout) >= OLED_UPDATE_INTERVAL) {
oled_update_timeout = timer_read();
oled_set_cursor(0, 0);
oled_task_kb();
}
#else
oled_set_cursor(0, 0);
oled_task_kb();
#endif
#if OLED_SCROLL_TIMEOUT > 0
if (oled_dirty && oled_scrolling) {
oled_scroll_timeout = timer_read32() + OLED_SCROLL_TIMEOUT;
oled_scroll_off();
}
#endif
// Smart render system, no need to check for dirty
oled_render();
// Display timeout check
#if OLED_TIMEOUT > 0
if (oled_active && timer_expired32(timer_read32(), oled_timeout)) {
oled_off();
}
#endif
#if OLED_SCROLL_TIMEOUT > 0
if (!oled_scrolling && timer_expired32(timer_read32(), oled_scroll_timeout)) {
# ifdef OLED_SCROLL_TIMEOUT_RIGHT
oled_scroll_right();
# else
oled_scroll_left();
# endif
}
#endif
}
__attribute__((weak)) bool oled_task_kb(void) { return oled_task_user(); }
__attribute__((weak)) bool oled_task_user(void) { return true; }

View File

@ -105,7 +105,7 @@ bool process_record_pointing(uint16_t keycode, keyrecord_t* record) {
mouse_timer = timer_read();
break;
}
if (layer_state_is(_MOUSE) && !mouse_keycode_tracker) {
if (layer_state_is(_MOUSE) && !mouse_keycode_tracker && !tap_toggling) {
layer_off(_MOUSE);
}
mouse_keycode_tracker = 0;

View File

@ -78,10 +78,20 @@ endif
CUSTOM_OLED_DRIVER ?= yes
ifeq ($(strip $(OLED_ENABLE)), yes)
ifeq ($(strip $(CUSTOM_OLED_DRIVER)), yes)
SRC += $(USER_PATH)/oled/oled_stuff.c
OPT_DEFS += -DCUSTOM_OLED_DRIVER_CODE
ifeq ($(strip $(OLED_DRIVER)), custom)
OPT_DEFS += -DOLED_ENABLE \
-DOLED_DRIVER_SH1107
SRC += $(USER_PATH)/oled/sh110x.c
QUANTUM_LIB_SRC += i2c_master.c
endif
ifeq ($(strip $(CUSTOM_OLED_DRIVER)), yes)
OPT_DEFS += -DCUSTOM_OLED_DRIVER_CODE
SRC += $(USER_PATH)/oled/oled_stuff.c
endif
ifeq ($(strip $(OLED_DISPLAY_TEST)), yes)
OPT_DEFS += -DOLED_DISPLAY_TEST
endif
DEFERRED_EXEC_ENABLE = yes
endif
CUSTOM_POINTING_DEVICE ?= yes
@ -97,6 +107,7 @@ ifeq ($(strip $(CUSTOM_SPLIT_TRANSPORT_SYNC)), yes)
QUANTUM_LIB_SRC += $(USER_PATH)/split/transport_sync.c
OPT_DEFS += -DCUSTOM_SPLIT_TRANSPORT_SYNC
endif
endif
AUTOCORRECTION_ENABLE ?= no

View File

@ -9,7 +9,7 @@
#endif
#ifdef CUSTOM_UNICODE_ENABLE
#include "process_unicode_common.h"
# include "process_unicode_common.h"
extern unicode_config_t unicode_config;
#endif
#ifdef AUDIO_ENABLE
@ -24,8 +24,10 @@ extern bool tap_toggling;
extern bool swap_hands;
#endif
static bool watchdog_ping_done = false;
static uint32_t watchdog_timer = 0;
#if defined(SPLIT_WATCHDOG_TIMEOUT)
static bool watchdog_ping_done = false;
static uint32_t watchdog_timer = 0;
#endif
extern userspace_config_t userspace_config;
extern bool host_driver_disabled;
@ -51,20 +53,35 @@ void user_config_sync(uint8_t initiator2target_buffer_size, const void* initiato
}
}
#if defined(SPLIT_WATCHDOG_TIMEOUT)
void watchdog_handler(uint8_t in_buflen, const void* in_data, uint8_t out_buflen, void* out_data) { watchdog_ping_done = true; }
#endif
#ifdef OLED_ENABLE
#include "oled/oled_stuff.h"
void keylogger_string_sync(uint8_t initiator2target_buffer_size, const void* initiator2target_buffer, uint8_t target2initiator_buffer_size, void* target2initiator_buffer) {
if (initiator2target_buffer_size == OLED_KEYLOGGER_LENGTH) {
memcpy(&keylog_str, initiator2target_buffer, initiator2target_buffer_size);
}
}
#endif
void keyboard_post_init_transport_sync(void) {
// Register keyboard state sync split transaction
transaction_register_rpc(RPC_ID_USER_STATE_SYNC, user_state_sync);
transaction_register_rpc(RPC_ID_USER_KEYMAP_SYNC, user_keymap_sync);
transaction_register_rpc(RPC_ID_USER_CONFIG_SYNC, user_config_sync);
#ifdef __AVR__
wdt_disable();
#ifdef OLED_ENABLE
transaction_register_rpc(RPC_ID_USER_KEYLOG_STR, keylogger_string_sync);
#endif
#if defined(SPLIT_WATCHDOG_TIMEOUT)
# if defined(PROTOCOL_LUFA)
wdt_disable();
# endif
transaction_register_rpc(RPC_ID_USER_WATCHDOG_SYNC, watchdog_handler);
watchdog_timer = timer_read32();
#endif
}
void user_transport_update(void) {
@ -107,9 +124,12 @@ void user_transport_update(void) {
void user_transport_sync(void) {
if (is_keyboard_master()) {
// Keep track of the last state, so that we can tell if we need to propagate to slave
static uint16_t last_keymap = 0;
static uint32_t last_config = 0, last_sync[3], last_user_state = 0;
bool needs_sync = false;
static uint16_t last_keymap = 0;
static uint32_t last_config = 0, last_sync[4], last_user_state = 0;
bool needs_sync = false;
#ifdef OLED_ENABLE
static char keylog_temp[OLED_KEYLOGGER_LENGTH] = { 0 };
#endif
// Check if the state values are different
if (memcmp(&transport_user_state, &last_user_state, sizeof(transport_user_state))) {
@ -164,9 +184,30 @@ void user_transport_sync(void) {
if (transaction_rpc_send(RPC_ID_USER_CONFIG_SYNC, sizeof(transport_userspace_config), &transport_userspace_config)) {
last_sync[2] = timer_read32();
}
needs_sync = false;
}
#ifdef OLED_ENABLE
// Check if the state values are different
if (memcmp(&keylog_str, &keylog_temp, OLED_KEYLOGGER_LENGTH)) {
needs_sync = true;
memcpy(&keylog_temp, &keylog_str, OLED_KEYLOGGER_LENGTH);
}
if (timer_elapsed32(last_sync[3]) > 250) {
needs_sync = true;
}
// Perform the sync if requested
if (needs_sync) {
if (transaction_rpc_send(RPC_ID_USER_KEYLOG_STR, OLED_KEYLOGGER_LENGTH, &keylog_str)) {
last_sync[3] = timer_read32();
}
needs_sync = false;
}
#endif
}
#if defined(SPLIT_WATCHDOG_TIMEOUT)
if (!watchdog_ping_done) {
if (is_keyboard_master()) {
if (timer_elapsed32(watchdog_timer) > 100) {
@ -180,16 +221,14 @@ void user_transport_sync(void) {
}
} else {
if (timer_elapsed32(watchdog_timer) > 3500) {
#ifdef __AVR__
wdt_enable(WDTO_250MS);
#else
NVIC_SystemReset();
#endif
software_reset();
while (1) {
}
}
}
}
#endif
}
void housekeeping_task_user(void) {

View File

@ -4,6 +4,10 @@
#pragma once
#include "drashna.h"
#ifdef OLED_ENABLE
# include "oled/oled_stuff.h"
extern char keylog_str[OLED_KEYLOGGER_LENGTH];
#endif
typedef union {
uint32_t raw;