qmk_firmware

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

satisfaction_oled.c (7955B)


      1 // Copyright 2023 Andrew Kannan
      2 // SPDX-License-Identifier: GPL-2.0-or-later
      3 
      4 #include "satisfaction_core.h"
      5 #include "action_layer.h"
      6 #include "action_util.h"
      7 #include "timer.h"
      8 #include "matrix.h"
      9 #include "led.h"
     10 #include "host.h"
     11 #include "progmem.h"
     12 #include <stdio.h>
     13 
     14 void draw_default(void);
     15 void draw_clock(void);
     16 
     17 #ifdef OLED_ENABLE
     18 #include "oled_driver.h"
     19 
     20 oled_rotation_t oled_init_kb(oled_rotation_t rotation) { return OLED_ROTATION_0; }
     21 
     22 bool oled_task_kb(void) {
     23     if (!oled_task_user()) { return false; }
     24     if (!oled_task_needs_to_repaint()) {
     25         return false;
     26     }
     27     oled_clear();
     28     if (clock_set_mode) {
     29         draw_clock();
     30         return false;
     31     }
     32     switch (oled_mode) {
     33         default:
     34         case OLED_DEFAULT:
     35             draw_default();
     36             break;
     37         case OLED_TIME:
     38             draw_clock();
     39             break;
     40     }
     41     return false;
     42 }
     43 
     44 // Request a repaint of the OLED image without resetting the OLED sleep timer.
     45 // Used for things like clock updates that should not keep the OLED turned on
     46 // if there is no other activity.
     47 void oled_request_repaint(void) {
     48     if (is_oled_on()) {
     49         oled_repaint_requested = true;
     50     }
     51 }
     52 
     53 // Request a repaint of the OLED image and reset the OLED sleep timer.
     54 // Needs to be called after any activity that should keep the OLED turned on.
     55 void oled_request_wakeup(void) {
     56     oled_wakeup_requested = true;
     57 }
     58 
     59 // Check whether oled_task_user() needs to repaint the OLED image.  This
     60 // function should be called at the start of oled_task_user(); it also handles
     61 // the OLED sleep timer and the OLED_OFF mode.
     62 bool oled_task_needs_to_repaint(void) {
     63     // In the OLED_OFF mode the OLED is kept turned off; any wakeup requests
     64     // are ignored.
     65     if ((oled_mode == OLED_OFF) && !clock_set_mode) {
     66         oled_wakeup_requested = false;
     67         oled_repaint_requested = false;
     68         oled_off();
     69         return false;
     70     }
     71 
     72     // If OLED wakeup was requested, reset the sleep timer and do a repaint.
     73     if (oled_wakeup_requested) {
     74         oled_wakeup_requested = false;
     75         oled_repaint_requested = false;
     76         oled_sleep_timer = timer_read32() + CUSTOM_OLED_TIMEOUT;
     77         oled_on();
     78         return true;
     79     }
     80 
     81     // If OLED repaint was requested, just do a repaint without touching the
     82     // sleep timer.
     83     if (oled_repaint_requested) {
     84         oled_repaint_requested = false;
     85         return true;
     86     }
     87 
     88     // If the OLED is currently off, skip the repaint (which would turn the
     89     // OLED on if the image is changed in any way).
     90     if (!is_oled_on()) {
     91         return false;
     92     }
     93 
     94     // If the sleep timer has expired while the OLED was on, turn the OLED off.
     95     if (timer_expired32(timer_read32(), oled_sleep_timer)) {
     96         oled_off();
     97         return false;
     98     }
     99 
    100     // Always perform a repaint if the OLED is currently on.  (This can
    101     // potentially be optimized to avoid unneeded repaints if all possible
    102     // state changes are covered by oled_request_repaint() or
    103     // oled_request_wakeup(), but then any missed calls to these functions
    104     // would result in displaying a stale image.)
    105     return true;
    106 }
    107 
    108 
    109 static void draw_line_h(uint8_t x, uint8_t y, uint8_t len) {
    110     for (uint8_t i = 0; i < len; i++) {
    111         oled_write_pixel(i + x, y, true);
    112     }
    113 }
    114 
    115 static void draw_line_v(uint8_t x, uint8_t y, uint8_t len) {
    116     for (uint8_t i = 0; i < len; i++) {
    117         oled_write_pixel(x, i + y, true);
    118     }
    119 }
    120 
    121 static char* get_enc_mode(void) {
    122     switch (encoder_mode) {
    123         default:
    124         case ENC_MODE_VOLUME:
    125             return "VOL";
    126         case ENC_MODE_MEDIA:
    127             return "MED";
    128         case ENC_MODE_SCROLL:
    129             return "SCR";
    130         case ENC_MODE_BRIGHTNESS:
    131             return "BRT";
    132         case ENC_MODE_BACKLIGHT:
    133             return "BKL";
    134         case ENC_MODE_CLOCK_SET:
    135             return "CLK";
    136         case ENC_MODE_CUSTOM0:
    137             return "CS0";
    138         case ENC_MODE_CUSTOM1:
    139             return "CS1";
    140         case ENC_MODE_CUSTOM2:
    141             return "CS2";
    142     }
    143 }
    144 
    145 static char* get_time(void) {
    146     uint8_t  hour   = last_minute / 60;
    147     uint16_t minute = last_minute % 60;
    148 
    149     if (encoder_mode == ENC_MODE_CLOCK_SET) {
    150         hour   = hour_config;
    151         minute = minute_config;
    152     }
    153 
    154     bool is_pm = (hour / 12) > 0;
    155     hour       = hour % 12;
    156     if (hour == 0) {
    157         hour = 12;
    158     }
    159 
    160     static char time_str[8] = "";
    161     snprintf(time_str, sizeof(time_str), "%02hhu:%02hu%s", hour, minute, is_pm ? "pm" : "am");
    162 
    163     return time_str;
    164 }
    165 
    166 static char* get_date(void) {
    167     int16_t year  = last_timespec.year + 1980;
    168     int8_t  month = last_timespec.month;
    169     int8_t  day   = last_timespec.day;
    170 
    171     if (encoder_mode == ENC_MODE_CLOCK_SET) {
    172         year  = year_config + 1980;
    173         month = month_config;
    174         day   = day_config;
    175     }
    176 
    177     static char date_str[11] = "";
    178     snprintf(date_str, sizeof(date_str), "%04hd-%02hhd-%02hhd", year, month, day);
    179 
    180     return date_str;
    181 }
    182 
    183 void draw_default(void) {
    184     oled_write_P(PSTR("LAYER "), false);
    185     oled_write_char(get_highest_layer(layer_state) + 0x30, true);
    186 
    187     oled_write_P(PSTR(" ENC "), false);
    188     oled_write(get_enc_mode(), true);
    189 
    190     led_t led_state = host_keyboard_led_state();
    191     oled_set_cursor(18, 0);
    192     oled_write_P(PSTR("CAP"), led_state.caps_lock);
    193     oled_set_cursor(18, 1);
    194     oled_write_P(PSTR("SCR"), led_state.scroll_lock);
    195 
    196     uint8_t mod_state = get_mods();
    197     oled_set_cursor(6, 3);
    198     oled_write_P(PSTR("S"), mod_state & MOD_MASK_SHIFT);
    199     oled_advance_char();
    200     oled_write_P(PSTR("C"), mod_state & MOD_MASK_CTRL);
    201     oled_advance_char();
    202     oled_write_P(PSTR("A"), mod_state & MOD_MASK_ALT);
    203     oled_advance_char();
    204     oled_write_P(PSTR("G"), mod_state & MOD_MASK_GUI);
    205     oled_advance_char();
    206 
    207     oled_write(get_time(), false);
    208 
    209 /* Matrix display is 12 x 12 pixels */
    210 #define MATRIX_DISPLAY_X 0
    211 #define MATRIX_DISPLAY_Y 18
    212 
    213     // matrix
    214     for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
    215         for (uint8_t y = 0; y < MATRIX_COLS; y++) {
    216             bool on = (matrix_get_row(x) & (1 << y)) > 0;
    217             oled_write_pixel(MATRIX_DISPLAY_X + y + 2, MATRIX_DISPLAY_Y + x + 2, on);
    218         }
    219     }
    220 
    221     // outline
    222     draw_line_h(MATRIX_DISPLAY_X, MATRIX_DISPLAY_Y, 19);
    223     draw_line_h(MATRIX_DISPLAY_X, MATRIX_DISPLAY_Y + 9, 19);
    224     draw_line_v(MATRIX_DISPLAY_X, MATRIX_DISPLAY_Y, 9);
    225     draw_line_v(MATRIX_DISPLAY_X + 19, MATRIX_DISPLAY_Y, 9);
    226 
    227     // oled location
    228     draw_line_h(MATRIX_DISPLAY_X + 14, MATRIX_DISPLAY_Y + 2, 3);
    229 
    230     // bodge extra lines for invert layer and enc mode
    231     draw_line_v(35, 0, 8);
    232     draw_line_v(71, 0, 8);
    233 }
    234 
    235 void draw_clock(void) {
    236     oled_set_cursor(0, 0);
    237     oled_write(get_date(), false);
    238     oled_set_cursor(0, 2);
    239     oled_write(get_time(), false);
    240 
    241     oled_set_cursor(12, 0);
    242     oled_write_P(PSTR(" ENC "), false);
    243     oled_write(get_enc_mode(), true);
    244 
    245     oled_set_cursor(13, 1);
    246     oled_write_P(PSTR("LAYER "), false);
    247     oled_write_char(get_highest_layer(layer_state) + 0x30, true);
    248 
    249     led_t led_state = host_keyboard_led_state();
    250     oled_set_cursor(15, 3);
    251     oled_write_P(PSTR("CAPS"), led_state.caps_lock);
    252 
    253     if (clock_set_mode) {
    254         switch (time_config_idx) {
    255             case 0:  // hour
    256             default:
    257                 draw_line_h(0, 25, 10);
    258                 break;
    259             case 1:  // minute
    260                 draw_line_h(18, 25, 10);
    261                 break;
    262             case 2:  // year
    263                 draw_line_h(0, 9, 24);
    264                 break;
    265             case 3:  // month
    266                 draw_line_h(30, 9, 10);
    267                 break;
    268             case 4:  // day
    269                 draw_line_h(48, 9, 10);
    270                 break;
    271         }
    272     }
    273 
    274     // bodge extra lines for invert layer and enc mode
    275     draw_line_v(101, 0, 8);
    276     draw_line_v(113, 8, 8);
    277 }
    278 
    279 #else
    280 
    281 void oled_request_repaint(void){
    282 }
    283 
    284 void oled_request_wakeup(void){
    285 }
    286 
    287 #endif