qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

evo70.c (25881B)


      1 /* Copyright 2021 customMK
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 2 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     15  */
     16 
     17 #include "quantum.h"
     18 #include <stdbool.h>
     19 #include "matrix.h"
     20 #include OLED_FONT_H
     21 
     22 //If Bongo cat not undefined, Scroll wheel will be enabled,
     23 //but for scroll wheel to work, you must also set MOUSEKEY_ENABLE = yes
     24 //in rules.mk 
     25 #define BONGOCAT
     26 
     27 /* Placement information for display elements */
     28 #define ENC_DISPLAY_X 0
     29 #define ENC_DISPLAY_Y 0
     30 
     31 #define LAYER_DISPLAY_X 5
     32 #define LAYER_DISPLAY_Y 19
     33 
     34 #define CAPSLOCK_DISPLAY_X 80
     35 #define CAPSLOCK_DISPLAY_Y 19
     36 
     37 #define NUMLOCK_DISPLAY_X 105
     38 #define NUMLOCK_DISPLAY_Y 19
     39 
     40 /* Encoder Parameters */
     41 static bool OLED_awakened = false;
     42 static bool OLED_redraw = false;
     43 static bool startup_complete = false;
     44 static bool startup_delay = false;
     45 static bool starting_up = false;
     46 
     47 #define ENCODER_MATRIX_ROW 5
     48 #define ENCODER_MATRIX_COL 6
     49 
     50 #define ENC_SPLASH 0
     51 #define ENC_VOLUME 1
     52 #define ENC_MEDIA 2
     53 #define ENC_CUSTOM 3
     54 #define ENC_BL_BRIGHT 4
     55 #define ENC_BL_BREATH 5
     56 #define ENC_RGB_BRIGHT 6
     57 #define ENC_RGB_MODE 7
     58 #define ENC_RGB_COLOR 8
     59 #define ENC_SCROLL 9
     60 #ifdef BONGOCAT
     61 #define ENC_BONGO 9
     62 #endif //bongocat
     63 
     64 
     65 extern matrix_row_t matrix[MATRIX_ROWS];
     66 
     67 char* enc_mode_str[] = {
     68 #ifdef BONGOCAT
     69     /* Splash */ "",
     70     "Volume",
     71     "Media Control",
     72     "Custom",
     73     "Backlight Brightness",
     74     "Backlight Breathing",
     75     "Underglow Brightness",
     76     "Underglow Mode",
     77     "Underglow Color",
     78     "" // Bongo Cat
     79 };
     80 
     81 uint16_t enc_cw[] =  { KC_VOLU, KC_VOLU, KC_MEDIA_NEXT_TRACK, KC_VOLU, 0, 0, 0, 0, 0, KC_VOLU };
     82 uint16_t enc_ccw[] = { KC_VOLD, KC_VOLD, KC_MEDIA_PREV_TRACK, KC_VOLD, 0, 0, 0, 0, 0, KC_VOLD };
     83 #else
     84     /* Splash */ "",
     85     "Volume",
     86     "Media Control",
     87     "Custom",
     88     "Backlight Brightness",
     89     "Backlight Breathing",
     90     "Underglow Brightness",
     91     "Underglow Mode",
     92     "Underglow Color",
     93     "Scroll Wheel"
     94 };
     95 
     96 uint16_t enc_cw[] =  { KC_VOLU, KC_VOLU, KC_MEDIA_NEXT_TRACK, KC_VOLU, 0, 0, 0, 0, 0, MS_WHLU };
     97 uint16_t enc_ccw[] = { KC_VOLD, KC_VOLD, KC_MEDIA_PREV_TRACK, KC_VOLD, 0, 0, 0, 0, 0, MS_WHLD };
     98 #endif //bongocat
     99 
    100 uint8_t num_enc_modes = 10;
    101 
    102 uint8_t enc_mode_str_startpos[] = {0, 49, 28, 49, 7, 10, 7, 25, 22, 31};
    103 
    104 uint8_t prev_layer = 255;
    105 uint8_t prev_capslock = 255;
    106 uint8_t prev_numlock = 255;
    107 
    108 typedef union {
    109     uint32_t raw;
    110     struct {
    111         uint8_t enc_mode;
    112         uint8_t breathingperiod;
    113         bool oled_is_on : 1;
    114     };
    115 } user_config_t;
    116 
    117 user_config_t user_config;
    118 
    119 
    120 
    121 /* OLED Draw Functions */
    122 /* TODO: Reimplement using Quantum Painter when available  */
    123 
    124 static void draw_line_h(uint8_t x, uint8_t y, uint8_t len, bool on) {
    125      for (uint8_t i = 0; i < len; i++) {
    126          oled_write_pixel(i + x, y, on);
    127      }
    128  }
    129 
    130  static void draw_line_v(uint8_t x, uint8_t y, uint8_t len, bool on) {
    131      for (uint8_t i = 0; i < len; i++) {
    132          oled_write_pixel(x, i + y, on);
    133      }
    134  }
    135 
    136 void draw_rect_soft(uint8_t x, uint8_t y, uint8_t width, uint8_t height, bool on) {
    137     uint8_t tempHeight;
    138 
    139     draw_line_h(x + 1, y, width - 2, on);
    140     draw_line_h(x + 1, y + height - 1, width - 2, on);
    141 
    142     tempHeight = height - 2;
    143 
    144     if (tempHeight < 1) return;
    145 
    146     draw_line_v(x, y + 1, tempHeight, on);
    147     draw_line_v(x + width - 1, y + 1, tempHeight, on);
    148 }
    149 
    150 void write_char_at_pixel_xy(uint8_t x, uint8_t y, const char data, bool invert) {
    151     uint8_t i, j, temp;
    152     uint8_t cast_data = (uint8_t)data;
    153     
    154     const uint8_t *glyph = &font[((uint8_t)cast_data - OLED_FONT_START) * OLED_FONT_WIDTH];
    155     temp = pgm_read_byte(glyph);
    156     for (i = 0; i < OLED_FONT_WIDTH ; i++) {
    157         for (j = 0; j < OLED_FONT_HEIGHT; j++) {
    158             if (temp & 0x01) {
    159                 oled_write_pixel(x + i, y + j, !invert);
    160             } else {
    161                 oled_write_pixel(x + i, y + j, invert);
    162             }
    163             temp >>= 1;
    164         }
    165         temp = pgm_read_byte(++glyph);
    166     }
    167 }
    168 
    169 void write_chars_at_pixel_xy(uint8_t x, uint8_t y, const char *data, bool invert) {
    170     uint8_t c = data[0];
    171     uint8_t offset = 0;
    172     while (c != 0) {
    173         write_char_at_pixel_xy(x + offset, y, c, invert);
    174         data++;
    175         c = data[0];
    176         offset += 6;
    177     }
    178 }
    179 
    180 
    181 void draw_rect_filled_soft(uint8_t x, uint8_t y, uint8_t width, uint8_t height, bool on) {
    182     for (int i = x; i < x + width; i++) {
    183         if (i == x || i == (x + width - 1))
    184             draw_line_v(i, y + 1, height - 2, on);
    185         else
    186             draw_line_v(i, y, height, on);
    187     }
    188 }
    189 
    190 void draw_text_rectangle(uint8_t x, uint8_t y, uint8_t width, char* str, bool filled) {
    191     if (filled) {
    192         draw_rect_filled_soft(x, y, width, 11, true);
    193         write_chars_at_pixel_xy(x+3, y+2, str, true);
    194     } else {
    195         draw_rect_soft(x, y, width, 11, true);
    196         write_chars_at_pixel_xy(x+3, y+2, str, false);
    197     }
    198 }
    199 
    200 void draw_keyboard_layer(void){
    201     uint8_t highest_layer;
    202     highest_layer = get_highest_layer(layer_state);
    203     draw_rect_filled_soft(LAYER_DISPLAY_X + highest_layer*12, LAYER_DISPLAY_Y, 11, 11, true);
    204 
    205     write_char_at_pixel_xy(LAYER_DISPLAY_X+3,  LAYER_DISPLAY_Y+2, '0', highest_layer == 0);
    206     write_char_at_pixel_xy(LAYER_DISPLAY_X+3+12, LAYER_DISPLAY_Y+2, '1', highest_layer == 1);
    207     write_char_at_pixel_xy(LAYER_DISPLAY_X+3+24, LAYER_DISPLAY_Y+2, '2', highest_layer == 2);
    208     write_char_at_pixel_xy(LAYER_DISPLAY_X+3+36, LAYER_DISPLAY_Y+2, '3', highest_layer == 3);
    209 
    210     draw_line_h(0, 14, 128, true);
    211 }
    212 
    213 
    214 static const uint8_t splash[] PROGMEM = {
    215     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    216     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    217     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,
    218     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    219     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1c, 0x06, 0x02, 0x02,
    220     0x03, 0x03, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x03, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03,
    221     0x03, 0x03, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x83, 0x83, 0x83, 0x83, 0x03,
    222     0x02, 0x02, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    223     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    224     0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
    225     0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0xf8, 0xfe, 0x87, 0xe1, 0xbf, 0x9f, 0x00, 0x00,
    226     0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
    227     0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
    228     0x00, 0x00, 0xff, 0xff, 0xff, 0x3f, 0xfc, 0xe0, 0xc0, 0xf8, 0x7f, 0x0f, 0xff, 0xff, 0x00, 0x00,
    229     0x00, 0x00, 0xff, 0xff, 0xff, 0x80, 0xc0, 0xf0, 0xf8, 0x3c, 0x1f, 0x0f, 0x03, 0x01, 0x00, 0x00,
    230     0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    231     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe, 0xc7, 0x83,
    232     0x83, 0x8f, 0xc6, 0xc0, 0xfe, 0xff, 0xc7, 0xc0, 0xf0, 0xff, 0xff, 0x81, 0xc0, 0xe0, 0x70, 0x9e,
    233     0x8f, 0xbf, 0xf8, 0xf0, 0x80, 0xc1, 0xe3, 0x7f, 0xff, 0xff, 0x83, 0x83, 0x83, 0xc1, 0xfc, 0xfe,
    234     0xff, 0x83, 0x83, 0xdf, 0xff, 0x7e, 0x18, 0x18, 0xfe, 0xff, 0xfb, 0x1c, 0x06, 0xff, 0xff, 0xff,
    235     0x3c, 0x0e, 0xe7, 0xff, 0xff, 0x80, 0xc0, 0xe0, 0x60, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
    236     0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x01, 0x0f, 0x0f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
    237     0x00, 0x00, 0xff, 0xff, 0xff, 0x07, 0x03, 0x03, 0x0f, 0x3f, 0x7c, 0xf8, 0xe0, 0x80, 0x00, 0x00,
    238     0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    239     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
    240     0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01,
    241     0x03, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01,
    242     0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
    243     0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x38, 0x20, 0x40, 0x40,
    244     0x40, 0x40, 0x43, 0x43, 0x43, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x43, 0x40, 0x40,
    245     0x40, 0x40, 0x43, 0x43, 0x43, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x43, 0x43, 0x43, 0x40,
    246     0x40, 0x40, 0x60, 0x30, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    247 
    248 uint16_t startup_timer = 0;
    249 bool redrawn_splash = false;
    250 
    251 
    252 #ifdef BONGOCAT
    253 
    254 
    255 #define ANIM_FRAME_DURATION 75
    256 #define IDLE_FRAMES 5
    257 #define IDLE_TIMEOUT 750
    258 #define SLEEP_TIMEOUT 15000
    259 
    260 
    261 static const uint8_t bongofont[] PROGMEM = {
    262     0xC1, 0xC1, 0xC2, 0x04, 0x08, 0x10,
    263     0xC0, 0x38, 0x04, 0x03, 0x00, 0x00,
    264     0xA0, 0x22, 0x24, 0x14, 0x12, 0x12,
    265     0xA0, 0x21, 0x22, 0x12, 0x11, 0x11,
    266     0x83, 0x7C, 0x41, 0x41, 0x40, 0x40,
    267     0x82, 0x82, 0x84, 0x08, 0x10, 0x20,
    268     0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
    269     0x80, 0x70, 0x19, 0x06, 0x00, 0x00,
    270     0x80, 0x70, 0x0C, 0x03, 0x00, 0x00,
    271     0x80, 0x00, 0x30, 0x30, 0x00, 0xC0,
    272     0x80, 0x00, 0x30, 0x30, 0x00, 0x00,
    273     0x49, 0x88, 0x08, 0x08, 0x08, 0x00,
    274     0x44, 0x84, 0x04, 0x04, 0x00, 0x00,
    275     0x40, 0x80, 0x00, 0x00, 0x00, 0x00,
    276     0x40, 0x40, 0x20, 0x20, 0x20, 0x20,
    277     0x3C, 0xC2, 0x01, 0x01, 0x02, 0x02,
    278     0x35, 0x01, 0x8A, 0x7C, 0x00, 0x00,
    279     0x20, 0x40, 0x80, 0x00, 0x00, 0x00,
    280     0x20, 0x21, 0x22, 0x12, 0x11, 0x11,
    281     0x20, 0x20, 0x10, 0x10, 0x10, 0x10,
    282     0x1E, 0xE1, 0x00, 0x00, 0x01, 0x01,
    283     0x1C, 0xE2, 0x01, 0x01, 0x02, 0x02,
    284     0x18, 0x64, 0x82, 0x02, 0x02, 0x02,
    285     0x18, 0x60, 0x80, 0x00, 0x00, 0x00,
    286     0x18, 0x18, 0x1B, 0x03, 0x00, 0x40,
    287     0x18, 0x06, 0x05, 0x98, 0x99, 0x84,
    288     0x12, 0x0B, 0x08, 0x08, 0x08, 0x08,
    289     0x11, 0x09, 0x08, 0x08, 0x08, 0x08,
    290     0x10, 0x10, 0xD0, 0x11, 0x0F, 0x21,
    291     0x10, 0x10, 0x10, 0x11, 0x0F, 0x01,
    292     0x10, 0x08, 0x08, 0x04, 0x04, 0x04,
    293     0x10, 0x08, 0x04, 0x02, 0x02, 0x04,
    294     0x0C, 0x30, 0x40, 0x80, 0x00, 0x00,
    295     0x0C, 0x0C, 0x0D, 0x01, 0x00, 0x40,
    296     0x08, 0xE8, 0x08, 0x07, 0x10, 0x24,
    297     0x08, 0x30, 0x40, 0x80, 0x00, 0x00,
    298     0x08, 0x08, 0x08, 0x07, 0x00, 0x00,
    299     0x08, 0x08, 0x04, 0x02, 0x02, 0x02,
    300     0x08, 0x04, 0x02, 0x01, 0x01, 0x02,
    301     0x05, 0x05, 0x09, 0x09, 0x10, 0x10,
    302     0x04, 0x38, 0x40, 0x80, 0x00, 0x00,
    303     0x04, 0x04, 0x08, 0x08, 0x10, 0x10,
    304     0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
    305     0x04, 0x04, 0x02, 0x01, 0x00, 0x00,
    306     0x02, 0x02, 0x81, 0x80, 0x80, 0x00,
    307     0x02, 0x02, 0x04, 0x04, 0x08, 0x08,
    308     0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
    309     0x02, 0x02, 0x01, 0x00, 0x00, 0x00,
    310     0x01, 0xE1, 0x1A, 0x06, 0x09, 0x31,
    311     0x01, 0x01, 0x02, 0x04, 0x08, 0x10,
    312     0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
    313     0x00, 0x80, 0x80, 0x00, 0x00, 0x00,
    314     0x00, 0x80, 0x40, 0x40, 0x20, 0x20,
    315     0x00, 0x00, 0x80, 0x80, 0x40, 0x40,
    316     0x00, 0x00, 0x60, 0x60, 0x00, 0x81,
    317     0x00, 0x00, 0x01, 0x01, 0x00, 0x40,
    318     0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
    319     0x00, 0x00, 0x00, 0x00, 0x00, 0x0C,
    320     0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
    321     0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    322     0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 
    323 
    324 
    325 static const uint8_t bongo_line_x[] = {51, 49, 48, 57};
    326 static const uint8_t bongo_line_y[] = {0, 8, 16, 24};
    327 static const uint8_t bongo_line_len[] = {5, 7, 8, 6};
    328 
    329 const uint8_t bongo_line_data[8][26] PROGMEM = {
    330     { //idle1
    331     60, 52, 19, 30, 35,
    332     22, 47, 51, 60, 9, 0, 17,
    333     1, 57, 33, 3, 27, 41, 29, 50,
    334     45, 36, 60, 60, 60, 60},
    335     { //idle2
    336     60, 52, 19, 30, 35,
    337     22, 47, 51, 60, 9, 0, 17,
    338     1, 57, 33, 3, 27, 41, 29, 50,
    339     45, 36, 60, 60, 60, 60},
    340     { //idle3
    341     60, 53, 14, 31, 23,
    342     15, 43, 60, 60, 54, 5, 13,
    343     7, 56, 24, 2, 26, 39, 29, 50,
    344     45, 36, 60, 60, 60, 60},
    345     { //idle4
    346     6, 52, 19, 38, 32,
    347     20, 47, 51, 60, 9, 0, 17,
    348     8, 57, 33, 3, 27, 41, 29, 50,
    349     45, 36, 60, 60, 60, 60},
    350     { //idle5
    351     60, 52, 19, 37, 40,
    352     21, 47, 51, 60, 9, 0, 17,
    353     8, 57, 33, 3, 27, 41, 29, 50,
    354     45, 36, 60, 60, 60, 60},
    355     { //prep
    356     6, 52, 19, 38, 32,
    357     20, 44, 51, 60, 10, 48, 16,
    358     8, 25, 4, 18, 27, 42, 46, 50,
    359     60, 60, 60, 60, 60, 60},
    360     { //tap1
    361     6, 52, 19, 38, 32,
    362     20, 44, 51, 60, 10, 49, 17,
    363     8, 25, 4, 18, 27, 41, 28, 11,
    364     60, 60, 60, 60, 58, 59},
    365     { //tap2
    366     6, 52, 19, 38, 32,
    367     20, 47, 51, 60, 10, 48, 16,
    368     8, 60, 55, 3, 27, 42, 46, 50,
    369     45, 34, 12, 60, 60, 60}
    370 };
    371 
    372 enum anin_states { sleep, idle, prep, tap };
    373 uint8_t anim_state = idle;
    374 uint32_t idle_timeout_timer = 0;
    375 uint32_t anim_timer = 0;
    376 uint8_t current_idle_frame = 0;
    377 uint8_t current_tap_frame = 6;
    378 uint8_t last_bongo_frame = 12;
    379 
    380 void write_bongochar_at_pixel_xy(uint8_t x, uint8_t y, uint8_t data, bool invert) {
    381     uint8_t i, j, temp;
    382     for (i = 0; i < 6 ; i++) { // 6 = font width
    383         temp = pgm_read_byte(&bongofont[data * 6]+i);
    384         for (j = 0; j < 8; j++) {  // 8 = font height
    385             if (temp & 0x01) {
    386                 oled_write_pixel(x + i, y + j, !invert);
    387             } else {
    388                 oled_write_pixel(x + i, y + j, invert);
    389             }
    390             temp >>= 1;
    391         }
    392     }
    393 }
    394 
    395 bool is_key_down(void) {
    396     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
    397         if (matrix[i] > 0) {
    398             return true;
    399         }
    400     }
    401     return false;
    402 }
    403 
    404 void eval_anim_state(void) {
    405     bool key_down;
    406     key_down = is_key_down();
    407 
    408     switch (anim_state) {
    409         case sleep:
    410             if(key_down) { anim_state = tap; }
    411             break; 
    412         case idle:
    413             if(key_down) { anim_state = tap; }
    414             else if (timer_elapsed32(idle_timeout_timer) >= SLEEP_TIMEOUT) //prep to idle
    415                 {
    416                     anim_state = sleep;
    417                     current_idle_frame = 0;
    418                 }
    419             break;
    420         case prep:
    421             if(key_down) { anim_state = tap; }
    422             else if (timer_elapsed32(idle_timeout_timer) >= IDLE_TIMEOUT) //prep to idle
    423                 {
    424                     anim_state = idle;
    425                     current_idle_frame = 0;
    426                 }
    427             break;
    428         case tap:
    429             if (!key_down)
    430             {
    431                 anim_state = prep;
    432                 idle_timeout_timer = timer_read32();
    433             }
    434             break;
    435         default:
    436             break;
    437     }
    438 }
    439 
    440 void draw_bongo_table(void) {
    441     //draws the table edge for bongocat, this edge doesn't change during the animation
    442     uint8_t i;
    443     uint8_t y = 31;
    444     uint8_t j = 0;
    445     for (i = 17; i < 57; i++) {
    446         oled_write_pixel(i, y, true); //every five horizontal pixels, move up one pixel to make a diagonal line
    447         if (j == 4) {
    448             --y;
    449             j=0;
    450         } else {
    451             j++;
    452         }
    453     }
    454 
    455     y=15;
    456     j=0;
    457     for (i = 91; i < 128; i++) {
    458 
    459         oled_write_pixel(i, y, true); //every four horizontal pixels, move up one pixel to make a diagonal line
    460         if (j == 3) {
    461             --y;
    462             j=0;
    463         } else {
    464             j++;
    465         }
    466     }
    467 
    468 
    469 }
    470 
    471 
    472 void draw_bongocat_frame(int framenumber) {
    473     //only redraw if the animation frame has changed
    474     if (framenumber != last_bongo_frame) {
    475         last_bongo_frame = framenumber;
    476         uint8_t i, j, current_bongochar = 0;
    477         for (i = 0; i < 4; i++) {
    478             for (j = 0; j < bongo_line_len[i]; j++) {
    479                 write_bongochar_at_pixel_xy(bongo_line_x[i] + j*6, bongo_line_y[i], pgm_read_byte(&bongo_line_data[framenumber][current_bongochar]), false);
    480                 current_bongochar++;
    481             }
    482         }
    483     }
    484     
    485 }
    486 
    487 bool is_new_tap(void) {
    488     static matrix_row_t old_matrix[] = { 0, 0, 0, 0, 0, 0 };
    489     bool new_tap = false;
    490     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
    491         if (matrix[i] > old_matrix[i]) { // more 1's detected, there was a new tap
    492             new_tap = true;
    493         }
    494         old_matrix[i] = matrix[i];
    495     }
    496     return new_tap;
    497 }
    498 
    499 void draw_bongocat(void) {
    500     static bool already_tapped = false;
    501     if (is_new_tap()) {
    502         already_tapped = false;
    503     };
    504     eval_anim_state();
    505     switch (anim_state) {
    506         case sleep:
    507             draw_bongocat_frame(4);
    508             break;
    509         case idle:       
    510             draw_bongocat_frame(4 - current_idle_frame);
    511             if (timer_elapsed32(anim_timer) > ANIM_FRAME_DURATION) {
    512                 current_idle_frame = (current_idle_frame + 1) % 5;
    513                 anim_timer = timer_read32();
    514             }
    515             break;
    516         case prep:
    517             draw_bongocat_frame(5);
    518             already_tapped = false;
    519             break;
    520         case tap:
    521             draw_bongocat_frame(current_tap_frame);
    522             if (already_tapped == false) {
    523                 if (current_tap_frame == 6) {
    524                     current_tap_frame = 7;
    525                 }
    526                 else {
    527                     current_tap_frame = 6;
    528                 }
    529             }
    530             already_tapped = true;
    531             break;
    532         default:
    533             draw_bongocat_frame(4);
    534             already_tapped = false;
    535             break;
    536 
    537     }
    538 }
    539 
    540 #endif //BONGOCAT
    541 
    542 void draw_splash(void) {
    543     uint8_t i, j, k, temp;
    544     uint16_t count;
    545     count = 0;
    546     temp = pgm_read_byte(&splash[count]);
    547     for (i = 0; i < 4 ; i++) {
    548         for (j = 0; j < 128; j++) {
    549             for (k = 0; k < 8; k++) {
    550                 if (temp & 0x01) {
    551                     oled_write_pixel(j, (i * 8) + k, true);
    552                 } else {
    553                     oled_write_pixel(j, (i * 8) + k, false);
    554                 }
    555                 temp >>= 1;
    556                 
    557             }
    558             temp = pgm_read_byte(&splash[++count]);
    559         }
    560     }
    561 }
    562 
    563 void draw_media_arrow(uint8_t x, uint8_t y, bool fwd) {
    564     draw_line_v(x, y, 7, true);
    565     draw_line_v(x+4, y, 7, true);
    566     draw_line_v(x+2, y+2, 3, true);
    567     if (fwd) {
    568         draw_line_v(x+1, y+1, 5, true);
    569         oled_write_pixel(x+3, y+3, true);
    570     } else {
    571         draw_line_v(x+3, y+1, 5, true);
    572         oled_write_pixel(x+1, y+3, true);
    573     }
    574 }
    575 
    576 void draw_enc_mode(void){
    577     write_chars_at_pixel_xy(enc_mode_str_startpos[user_config.enc_mode], ENC_DISPLAY_Y + 2, enc_mode_str[user_config.enc_mode], false);
    578     if (user_config.enc_mode == ENC_MEDIA) {
    579         draw_media_arrow(enc_mode_str_startpos[user_config.enc_mode] - 16, ENC_DISPLAY_Y + 2, false);
    580         draw_media_arrow(enc_mode_str_startpos[user_config.enc_mode] + 88, ENC_DISPLAY_Y + 2, true);
    581     }
    582 }
    583 
    584 void draw_keyboard_locks(void) {
    585     led_t led_state = host_keyboard_led_state();
    586     draw_text_rectangle(CAPSLOCK_DISPLAY_X, CAPSLOCK_DISPLAY_Y, 5 + (3 * 6), "CAP", led_state.caps_lock);
    587     draw_text_rectangle(NUMLOCK_DISPLAY_X, NUMLOCK_DISPLAY_Y, 5 + (3 * 6), "NUM", led_state.num_lock);
    588 }
    589 
    590 
    591 /* Encoder handling functions */
    592 
    593 __attribute__((weak)) void set_custom_encoder_mode_user(bool custom_encoder_mode) {}
    594 
    595 void update_custom_encoder_mode_user(void) {
    596 #ifdef BONGOCAT
    597     set_custom_encoder_mode_user((user_config.enc_mode == ENC_CUSTOM) || (user_config.enc_mode == ENC_SPLASH) || (user_config.enc_mode == ENC_BONGO));
    598 #else
    599     set_custom_encoder_mode_user((user_config.enc_mode == ENC_CUSTOM) || (user_config.enc_mode == ENC_SPLASH));
    600 #endif
    601 }
    602 
    603 void update_kb_eeprom(void) {
    604     eeconfig_update_kb(user_config.raw);
    605 }
    606 
    607 void update_breathing(void);
    608 void matrix_init_kb(void) {
    609 
    610     user_config.raw = eeconfig_read_kb();
    611     if (user_config.enc_mode == 0xFF) { //EEPROM was cleared
    612         user_config.enc_mode = 0;
    613         user_config.oled_is_on = true;
    614         user_config.breathingperiod = 1;
    615         update_kb_eeprom();
    616 
    617     }
    618     startup_delay = true;
    619     update_custom_encoder_mode_user();
    620     matrix_init_user();
    621 }
    622 
    623 void handle_encoder_switch_process_record(keyrecord_t *record) {
    624 
    625     static uint32_t encoder_press_timer = 0;
    626     if (record->event.pressed) {
    627         if (!user_config.oled_is_on) {
    628             oled_on();
    629             user_config.oled_is_on = true;
    630             OLED_awakened = true;
    631             OLED_redraw = true;
    632             update_kb_eeprom();
    633         }
    634         encoder_press_timer = timer_read32();
    635     } else {
    636         if (OLED_awakened == true) {
    637             OLED_awakened = false;
    638         } else {
    639             if (timer_elapsed32(encoder_press_timer) < 300) {
    640 
    641                 if (get_mods() & MOD_MASK_SHIFT) {
    642                     user_config.enc_mode = (user_config.enc_mode + (num_enc_modes- 1)) % num_enc_modes;
    643                 } else {
    644                     user_config.enc_mode = (user_config.enc_mode + 1) % num_enc_modes;
    645                 }
    646                 OLED_redraw = true;
    647                 update_custom_encoder_mode_user();
    648                 update_kb_eeprom();
    649             } else {
    650                 OLED_redraw = false;
    651                 oled_clear();
    652                 user_config.oled_is_on = false;
    653                 update_kb_eeprom();
    654             }
    655         }
    656     }
    657 
    658 }
    659 
    660 bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
    661     if (record->event.key.row == ENCODER_MATRIX_ROW && record->event.key.col == ENCODER_MATRIX_COL){
    662         handle_encoder_switch_process_record(record);
    663     }
    664     return process_record_user(keycode, record);
    665 }
    666 
    667 void update_breathing(void) {
    668     if (user_config.breathingperiod == 1) {
    669         breathing_disable();
    670     }
    671     else {
    672         breathing_period_set(user_config.breathingperiod);
    673         breathing_enable();
    674     }
    675     update_kb_eeprom();
    676 }
    677 
    678 
    679 void backlight_breath_change(bool increase) { //increase period or decrease period
    680     if ((increase) && (user_config.breathingperiod < 15)) {
    681         user_config.breathingperiod++;
    682         update_breathing();
    683     }
    684     if (!increase) {
    685         if (user_config.breathingperiod > 2) {
    686             user_config.breathingperiod--;
    687             update_breathing();
    688         } 
    689         else {
    690             user_config.breathingperiod = 1;
    691             update_breathing();
    692 
    693             
    694         }
    695     }
    696 }
    697 
    698 bool encoder_update_kb(uint8_t index, bool clockwise) {
    699     if (!encoder_update_user(index, clockwise)) return false;
    700     switch (user_config.enc_mode) {
    701         case ENC_RGB_MODE :
    702             if (clockwise) {
    703                 rgblight_step();
    704             } else {
    705                 rgblight_step_reverse();
    706             }
    707             break;
    708         case ENC_RGB_BRIGHT :
    709             if (clockwise) {
    710                 rgblight_increase_val();
    711             } else {
    712                 rgblight_decrease_val();
    713             }
    714             break;
    715         case ENC_BL_BRIGHT :
    716             if (clockwise) {
    717                 backlight_increase();
    718             } else {
    719                 backlight_decrease();
    720             }
    721             break;
    722         case ENC_BL_BREATH :
    723             backlight_breath_change(clockwise);
    724             break;
    725         case ENC_RGB_COLOR :
    726             if (clockwise) {
    727                 rgblight_increase_hue();
    728             } else {
    729                 rgblight_decrease_hue();
    730             }
    731             break;
    732         default:
    733             if (clockwise) {
    734                 tap_code(enc_cw[user_config.enc_mode]);
    735             } else {
    736                 tap_code(enc_ccw[user_config.enc_mode]);
    737             }
    738     }
    739     return true;
    740 }
    741 
    742 
    743 void housekeeping_task_kb(void) {
    744     led_t current_led_state = host_keyboard_led_state();
    745     uint8_t current_layer = get_highest_layer(layer_state);
    746     if (startup_delay) {
    747         startup_timer = timer_read();
    748         startup_delay = false;
    749         startup_complete = false;
    750         starting_up = true;
    751         OLED_redraw = false;
    752     }
    753     else if (starting_up) {
    754         if (timer_elapsed(startup_timer) >= 200) {
    755             update_breathing();
    756             startup_complete = true;
    757             starting_up = false;
    758             if (user_config.oled_is_on) {
    759                 oled_on();
    760                 OLED_redraw = true;
    761             } else
    762             {
    763                 oled_clear();
    764                 user_config.oled_is_on = false;
    765             }
    766         }
    767     }
    768     if (startup_complete) {
    769         if (user_config.enc_mode == ENC_SPLASH) {
    770             if (user_config.oled_is_on && OLED_redraw) {
    771                 draw_splash();
    772             }
    773         }
    774     #ifdef BONGOCAT
    775         else if (user_config.enc_mode == ENC_BONGO) {
    776             if (user_config.oled_is_on) {
    777                 if (OLED_redraw) {
    778                     oled_clear();
    779                     last_bongo_frame = 12; //force a redraw
    780                     draw_bongo_table();
    781                     OLED_redraw = false;
    782                 }
    783                 draw_bongocat();
    784 
    785             }
    786 
    787         }
    788     #endif //BONGOCAT
    789         else  {        
    790             if (user_config.oled_is_on && (
    791                     OLED_redraw
    792                     || (prev_layer != current_layer)
    793                     || (prev_capslock != current_led_state.caps_lock)
    794                     || (prev_numlock != current_led_state.num_lock))) {
    795 
    796                 prev_layer = current_layer;
    797                 prev_capslock = current_led_state.caps_lock;
    798                 prev_numlock = current_led_state.num_lock;
    799 
    800                 oled_clear();
    801                 draw_keyboard_layer();
    802                 draw_keyboard_locks();
    803                 draw_enc_mode();
    804             }
    805         }
    806         OLED_redraw = false;
    807     }
    808     
    809 }
    810