qmk_firmware

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

sugarglider.c (15225B)


      1 // Copyright 2023 Kyle McCreery
      2 // SPDX-License-Identifier: GPL-2.0-or-later
      3 
      4 #include "sugarglider.h"
      5 
      6 #ifndef GLIDEPOINT_DPI_OPTIONS
      7 #    define GLIDEPOINT_DPI_OPTIONS \
      8         { 400, 800, 1200, 1600, 2000, 2400, 2800, 3200, 3600, 4000 }
      9 #endif
     10 
     11 #ifndef GLIDEPOINT_DPI_DEFAULT
     12 #    define GLIDEPOINT_DPI_DEFAULT 1
     13 #endif
     14 
     15 keyboard_config_t keyboard_config;
     16 uint16_t          dpi_array[] = GLIDEPOINT_DPI_OPTIONS;
     17 #define DPI_OPTION_SIZE (sizeof(dpi_array) / sizeof(uint16_t))
     18 
     19 void board_init(void) {
     20     // B9 is configured as I2C1_SDA in the board file; that function must be
     21     // disabled before using B7 as I2C1_SDA.
     22     gpio_set_pin_input_high(B9);
     23     gpio_set_pin_output(B12);
     24     gpio_set_pin_output(B13);
     25     gpio_set_pin_output(B14);
     26     gpio_write_pin_low(B12);
     27     gpio_write_pin_low(B13);
     28     gpio_write_pin_low(B14);
     29     gpio_set_pin_output(C13);
     30 }
     31 
     32 #ifdef DYNAMIC_TAPPING_TERM_ENABLE
     33 void tap_modify(int change_value, bool tap_status) {
     34     if (keyboard_config.dt_term_config < 0) {
     35         keyboard_config.dt_term_config *= -1;
     36     }
     37 
     38     keyboard_config.dt_term_config += change_value;
     39 
     40     if (tap_status == false ) {
     41         keyboard_config.dt_term_config *= -1;
     42         g_tapping_term = 0;
     43     } else {
     44         g_tapping_term = keyboard_config.dt_term_config;
     45     }
     46     eeconfig_update_kb(keyboard_config.raw);
     47 }
     48 
     49 void tap_toggle(void) {
     50     keyboard_config.dt_term_config *= -1;
     51     if (keyboard_config.dt_term_config > 0) {
     52         g_tapping_term = keyboard_config.dt_term_config;
     53     } else {
     54         g_tapping_term = 0;
     55     }
     56     eeconfig_update_kb(keyboard_config.raw);
     57 }
     58 #endif  // ifdef DYNAMIC_TAPPING_TERM_ENABLE
     59 
     60 #ifdef DIP_SWITCH_ENABLE
     61 bool dip_switch_update_kb(uint8_t index, bool active) {
     62     if (!dip_switch_update_user(index, active)) { return false; }
     63     switch (index) {
     64         case 0:
     65             if(active != host_keyboard_led_state().caps_lock) { tap_code(KC_CAPS); }
     66             break;
     67         break;
     68     }
     69     return true;
     70 }
     71 #endif
     72 
     73 #if defined(ENCODER_ENABLE) && ! defined(ENCODER_MAP_ENABLE)
     74 bool encoder_update_kb(uint8_t index, bool clockwise) {
     75     if (!encoder_update_user(index, clockwise)) { return false; }
     76     switch (index) {
     77         case 0:
     78             if (clockwise) {
     79                 tap_code(KC_VOLU);
     80             } else {
     81                 tap_code(KC_VOLD);
     82             }
     83         break;
     84         case 1:
     85             if (clockwise) {
     86                 tap_code(KC_VOLU);
     87             } else {
     88                 tap_code(KC_VOLD);
     89             }
     90         break;
     91         case 2:
     92             if (clockwise) {
     93                 tap_code(KC_PGUP);
     94             } else {
     95                 tap_code(KC_PGDN);
     96             }
     97         break;
     98         case 3:
     99             if (clockwise) {
    100                 tap_code(MS_WHLU);
    101             } else {
    102                 tap_code(MS_WHLD);
    103             }
    104         break;
    105     }
    106     return true;
    107 }
    108 #endif
    109 
    110 bool led_update_kb(led_t led_state) {
    111     bool res = led_update_user(led_state);
    112     if(res) {
    113         gpio_write_pin(B12, led_state.num_lock);     // Updates status LEDs
    114         gpio_write_pin(B13, led_state.caps_lock);    // Updates status LEDs
    115         gpio_write_pin(B14, led_state.scroll_lock);  // Updates status LEDs
    116         gpio_write_pin(C13, !led_state.caps_lock);   // Updates status LEDs, this is the LED on the blackpill itself
    117     }
    118     return res;
    119 }
    120 
    121 #ifdef OLED_ENABLE
    122 static void render_logo(void) {     // Render MechWild "MW" Logo
    123     static const char PROGMEM logo_1[] = {0xCC, 0xCD, 0xCE, 0xCF, 0x00};
    124     static const char PROGMEM logo_2[] = {0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0x00};
    125     static const char PROGMEM logo_3[] = {0xD5, 0xD6, 0xD7, 0xD8, 0x00};
    126     static const char PROGMEM logo_4[] = {0xDE, 0xD9, 0xDA, 0xDB, 0x00};
    127     
    128     oled_write_P(logo_1, false);
    129     oled_set_cursor(0,1);
    130     oled_write_P(logo_2, false);
    131     oled_set_cursor(0,2);
    132     oled_write_P(logo_3, false);
    133     oled_set_cursor(0,3);
    134     oled_write_P(logo_4, false);
    135 }
    136 
    137 #ifdef OLED_DISPLAY_128X64 // Wide OLED Functionality
    138 oled_rotation_t oled_init_kb(oled_rotation_t rotation) {
    139     return OLED_ROTATION_180;       // flips the display 180 degrees
    140 }
    141 
    142 bool clear_screen = true;           // used to manage singular screen clears to prevent display glitch
    143 bool clear_screen_art = true;       // used to manage singular screen clears to prevent display glitch
    144 static void render_sugarglider_wide(void) {     // Render sugarglider logo
    145     static const char PROGMEM sgl_1[] = {0xDE, 0xDE, 0xDE, 0x98, 0x99, 0xDE, 0x9A, 0x9B, 0x9C, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xCC, 0xCD, 0xCE, 0xCF, 0x00};
    146     static const char PROGMEM sgl_2[] = {0x9D, 0x9E, 0xDE, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xDE, 0xDE, 0xDE, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0x00};
    147     static const char PROGMEM sgl_3[] = {0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xDE, 0xDE, 0xDE, 0xD5, 0xD6, 0xD7, 0xD8, 0x00};
    148     static const char PROGMEM sgl_4[] = {0xDE, 0xB2, 0xDE, 0xB3, 0xB4, 0xB5, 0xB6, 0xDE, 0xDE, 0xB7, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xD9, 0xDA, 0xDB, 0x00};
    149     static const char PROGMEM sgl_5[] = {0xDE, 0xB8, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xB9, 0x00};
    150     static const char PROGMEM sgl_6[] = {0xDE, 0xBA, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xBB, 0xBC, 0x00};
    151     static const char PROGMEM sgl_7[] = {0xDE, 0xBD, 0xBE, 0xDE, 0xDE, 0xBF, 0xDE, 0xDE, 0xC0, 0xC1, 0x00};
    152     static const char PROGMEM sgl_8[] = {0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0x00};
    153 
    154     oled_write_P(sgl_1, false);
    155     oled_set_cursor(0,1);
    156     oled_write_P(sgl_2, false);
    157     oled_set_cursor(0,2);
    158     oled_write_P(sgl_3, false);
    159     oled_set_cursor(0,3);
    160     oled_write_P(sgl_4, false);
    161     oled_set_cursor(0,4);
    162     oled_write_P(sgl_5, false);
    163     oled_set_cursor(0,5);
    164     oled_write_P(sgl_6, false);
    165     oled_set_cursor(0,6);
    166     oled_write_P(sgl_7, false);
    167     oled_set_cursor(0,7);
    168     oled_write_P(sgl_8, false);
    169 }
    170 
    171 bool oled_task_kb(void) {
    172     if(!oled_task_user()) {
    173         return false;
    174     }
    175     if ( !(host_keyboard_led_state().num_lock || host_keyboard_led_state().caps_lock || host_keyboard_led_state().scroll_lock ) && get_highest_layer(layer_state) == 0 ) {      // If none of the status LEDs are active and also the active layer is the base layer
    176         if (clear_screen_art == true) {
    177             oled_clear();
    178             oled_render();
    179             clear_screen_art = false;
    180         }
    181         render_sugarglider_wide();
    182 #ifdef POINTING_DEVICE_ENABLE                           // only display dpi and tap info if pointing devices are active
    183         oled_set_cursor(10,5);
    184         oled_write_P(PSTR(" DPI:"), false);
    185         oled_write(get_u16_str(dpi_array[keyboard_config.dpi_config], ' '), false);
    186 #ifdef DYNAMIC_TAPPING_TERM_ENABLE                      // only display tap info if it is being configured dynamically
    187         oled_set_cursor(10,6);
    188         oled_write_P(PSTR(" TAP:"), false);
    189         if (keyboard_config.dt_term_config < 0) {
    190             oled_write_P(PSTR("Off  "), false);
    191         } else {
    192             oled_write(get_u16_str(g_tapping_term, ' '), false);
    193         }
    194 #endif
    195 #endif
    196         clear_screen = true;
    197     } else {        // If any of the status LEDs are active or if the active layer is not the base layer
    198         if (clear_screen == true) {
    199             oled_clear();
    200             oled_render();
    201             clear_screen = false;
    202         }
    203         render_logo();
    204         oled_set_cursor(8,1);
    205         switch (get_highest_layer(layer_state)) {
    206             case 0:
    207                 oled_write_P(PSTR("Base  "), false);
    208                 break;
    209             case 1:
    210                 oled_write_P(PSTR("Lower "), false);
    211                 break;
    212             case 2:
    213                 oled_write_P(PSTR("Raise "), false);
    214                 break;
    215             case 3:
    216                 oled_write_P(PSTR("Adjust"), false);
    217                 break;
    218             case 4:
    219                 oled_write_P(PSTR("Mouse "), false);
    220                 break;
    221 #ifdef STENO_ENABLE
    222             case 5:
    223                 oled_write_P(PSTR("Steno Layer"), false);
    224                 break;
    225 #endif
    226             default:
    227                 oled_write_P(PSTR("Layer ?"), false);    // Should never display, here as a catchall
    228         }
    229         led_t led_state = host_keyboard_led_state();
    230         oled_set_cursor(8,0);
    231         oled_write_P(led_state.num_lock ? PSTR("NUM ") : PSTR("    "), false);
    232         oled_write_P(led_state.caps_lock ? PSTR("CAP ") : PSTR("    "), false);
    233         oled_write_P(led_state.scroll_lock ? PSTR("SCR") : PSTR("    "), false);
    234 #ifdef POINTING_DEVICE_ENABLE                   // only display dpi and tap info if pointing devices are active
    235         oled_set_cursor(8,2);
    236         oled_write_P(PSTR("DPI:"), false);
    237         oled_write(get_u16_str(dpi_array[keyboard_config.dpi_config], ' '), false);
    238 #ifdef DYNAMIC_TAPPING_TERM_ENABLE              // only display tap info if it is being configured dynamically
    239         oled_set_cursor(8,3);
    240         oled_write_P(PSTR("TAP:"), false);
    241         if (keyboard_config.dt_term_config < 0) {
    242             oled_write_P(PSTR("Off  "), false);
    243         } else {
    244             oled_write(get_u16_str(g_tapping_term, ' '), false);
    245         }
    246 #endif
    247 #endif
    248         clear_screen_art = true;
    249     }
    250     return true;
    251 }
    252 #else  // Using an OLED but not the wide OLED
    253 oled_rotation_t oled_init_kb(oled_rotation_t rotation) {
    254     return OLED_ROTATION_270;       // flips the display 270 degrees
    255 }
    256 
    257 
    258 bool oled_task_kb(void) {
    259     if(!oled_task_user()) {
    260         return false;
    261     }
    262     render_logo();
    263 
    264     oled_set_cursor(0,5);
    265     switch (get_highest_layer(layer_state)) {
    266         case 0:
    267             oled_write_P(PSTR("Base "), false);
    268             break;
    269         case 1:
    270             oled_write_P(PSTR("Lower"), false);
    271             break;
    272         case 2:
    273             oled_write_P(PSTR("Raise"), false);
    274             break;
    275         case 3:
    276             oled_write_P(PSTR("Adjst"), false);
    277             break;
    278         case 4:
    279             oled_write_P(PSTR("Mouse"), false);
    280             break;
    281 #ifdef STENO_ENABLE
    282         case 5:
    283             oled_write_P(PSTR("Steno"), false);
    284             break;
    285 #endif
    286         default:
    287             oled_write_P(PSTR("?????"), false);    // Should never display, here as a catchall
    288     }
    289         led_t led_state = host_keyboard_led_state();
    290         oled_set_cursor(0,6);
    291         oled_write_P(led_state.num_lock ? PSTR("NUM  ") : PSTR("     "), false);
    292         oled_write_P(led_state.caps_lock ? PSTR("CAP  ") : PSTR("     "), false);
    293         oled_write_P(led_state.scroll_lock ? PSTR("SCR  ") : PSTR("     "), false);
    294 #ifdef POINTING_DEVICE_ENABLE
    295         oled_set_cursor(0,11);
    296         oled_write_P(PSTR("DPI: "), false);
    297         oled_write(get_u16_str(dpi_array[keyboard_config.dpi_config], ' '), false);
    298 #endif
    299 #ifdef DYNAMIC_TAPPING_TERM_ENABLE              // only display tap info if it is being configured dynamically
    300         oled_set_cursor(0,13);
    301         oled_write_P(PSTR("TAP: "), false);
    302         if (keyboard_config.dt_term_config < 0) {
    303             oled_write_P(PSTR("Off  "), false);
    304         } else {
    305             oled_write(get_u16_str(g_tapping_term, ' '), false);
    306         }
    307 #endif
    308     return true;
    309 }
    310 #endif // Not using wide OLED
    311 #endif // ifdef OLED_ENABLE
    312 
    313 bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
    314     switch(keycode) {
    315 #ifdef POINTING_DEVICE_ENABLE
    316         case DPI_UP:
    317             if (record->event.pressed) {
    318                 keyboard_config.dpi_config = (keyboard_config.dpi_config + 1) % DPI_OPTION_SIZE;
    319                 eeconfig_update_kb(keyboard_config.raw);
    320                 pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
    321             }
    322             return false;
    323         case DPI_DN:
    324             if (record->event.pressed) {
    325                 if (keyboard_config.dpi_config > 0) {
    326                     keyboard_config.dpi_config = (keyboard_config.dpi_config - 1) % DPI_OPTION_SIZE;
    327                 } else {
    328                     keyboard_config.dpi_config = DPI_OPTION_SIZE - 1;
    329                 }
    330                 eeconfig_update_kb(keyboard_config.raw);
    331                 pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
    332             }
    333             return false;
    334         case DPI_FINE:
    335             if (record->event.pressed) {
    336                 pointing_device_set_cpi(dpi_array[0]);
    337             } else {
    338                 pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
    339             }
    340             return false;
    341 #endif
    342 #ifdef DYNAMIC_TAPPING_TERM_ENABLE // only include tap info keycodes if it is being configured dynamically
    343         case TAP_UP:
    344             if (record->event.pressed) {
    345                 if (keyboard_config.dt_term_config < 5000) {
    346                     tap_modify(DYNAMIC_TAPPING_TERM_INCREMENT, true);
    347                 }
    348             }
    349             return false;
    350         case TAP_DN:
    351             if (record->event.pressed) {
    352                 if (keyboard_config.dt_term_config > 0) {
    353                     tap_modify(-1 * DYNAMIC_TAPPING_TERM_INCREMENT, true);
    354                 }
    355             }
    356             return false;
    357         case TAP_ON:
    358             if (record->event.pressed) {
    359                 tap_modify(0, true);
    360             }
    361             return false;
    362         case TAP_OFF:
    363             if (record->event.pressed) {
    364                 tap_modify(0, false);
    365             }
    366             return false;
    367         case TAP_TOG:
    368             if (record->event.pressed) {
    369                 tap_toggle();
    370             }
    371             return false;
    372 #endif // ifdef 
    373     }
    374     return process_record_user(keycode, record);
    375 }
    376 
    377 void pointing_device_init_kb(void) {
    378 #ifdef POINTING_DEVICE_ENABLE
    379     pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
    380 #endif
    381 }
    382 
    383 void eeconfig_init_kb(void) {
    384 #ifdef POINTING_DEVICE_ENABLE
    385     keyboard_config.dpi_config = GLIDEPOINT_DPI_DEFAULT;
    386 #endif
    387 #ifdef DYNAMIC_TAPPING_TERM_ENABLE // only set tap term from eeprom if it is being configured dynamically
    388     keyboard_config.dt_term_config = TAPPING_TERM;
    389 #endif
    390     eeconfig_update_kb(keyboard_config.raw);
    391 #ifdef STENO_ENABLE
    392     steno_set_mode(STENO_MODE_GEMINI); // or STENO_MODE_BOLT
    393 #endif
    394     eeconfig_init_user();
    395 }
    396 
    397 void matrix_init_kb(void) {
    398     // is safe to just read DPI setting since matrix init
    399     // comes before pointing device init.
    400     keyboard_config.raw = eeconfig_read_kb();
    401 #ifdef POINTING_DEVICE_ENABLE
    402     if (keyboard_config.dpi_config > DPI_OPTION_SIZE) {
    403         eeconfig_init_kb();
    404     }
    405 #endif
    406     matrix_init_user();
    407 }
    408 
    409 void keyboard_post_init_kb(void) {
    410 #ifdef POINTING_DEVICE_ENABLE
    411     pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
    412 #endif
    413 #ifdef RGBLIGHT_ENABLE
    414     rgblight_toggle_noeeprom();     //double toggle post init removes the weirdness with rgb strips having a yellow first LED
    415     rgblight_toggle_noeeprom();
    416 #endif
    417 #ifdef DYNAMIC_TAPPING_TERM_ENABLE
    418     tap_toggle();   // Need it to reevaluate this setting after initiating so that it is current after init
    419     tap_toggle();
    420 #endif
    421     keyboard_post_init_user();
    422 #ifdef OLED_ENABLE  // purposefully after user post init to allow the RGB to startup first
    423     wait_ms(200);   // Avoids a startup issue where the oled renders and then turns off with blackpill
    424     oled_on();
    425 #endif
    426 }