qmk_firmware

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

theme_djinn_default.c (9821B)


      1 // Copyright 2018-2022 Nick Brassel (@tzarc)
      2 // SPDX-License-Identifier: GPL-2.0-or-later
      3 #include <hal.h>
      4 #include <string.h>
      5 #include <ctype.h>
      6 #include <printf.h>
      7 #include "qp.h"
      8 #include "backlight.h"
      9 #include "transactions.h"
     10 #include "split_util.h"
     11 
     12 #include "djinn.h"
     13 #include "theme_djinn_default.h"
     14 
     15 #include "djinn.qgf.h"
     16 #include "lock-caps-ON.qgf.h"
     17 #include "lock-scrl-ON.qgf.h"
     18 #include "lock-num-ON.qgf.h"
     19 #include "lock-caps-OFF.qgf.h"
     20 #include "lock-scrl-OFF.qgf.h"
     21 #include "lock-num-OFF.qgf.h"
     22 #include "thintel15.qff.h"
     23 
     24 static painter_image_handle_t djinn_logo;
     25 static painter_image_handle_t lock_caps_on;
     26 static painter_image_handle_t lock_caps_off;
     27 static painter_image_handle_t lock_num_on;
     28 static painter_image_handle_t lock_num_off;
     29 static painter_image_handle_t lock_scrl_on;
     30 static painter_image_handle_t lock_scrl_off;
     31 static painter_font_handle_t  thintel;
     32 
     33 //----------------------------------------------------------
     34 // UI Initialisation
     35 void keyboard_post_init_display(void) {
     36     djinn_logo    = qp_load_image_mem(gfx_djinn);
     37     lock_caps_on  = qp_load_image_mem(gfx_lock_caps_ON);
     38     lock_caps_off = qp_load_image_mem(gfx_lock_caps_OFF);
     39     lock_num_on   = qp_load_image_mem(gfx_lock_num_ON);
     40     lock_num_off  = qp_load_image_mem(gfx_lock_num_OFF);
     41     lock_scrl_on  = qp_load_image_mem(gfx_lock_scrl_ON);
     42     lock_scrl_off = qp_load_image_mem(gfx_lock_scrl_OFF);
     43     thintel       = qp_load_font_mem(font_thintel15);
     44 }
     45 
     46 //----------------------------------------------------------
     47 // UI Drawing
     48 void draw_ui_user(bool force_redraw) {
     49     bool            hue_redraw = force_redraw;
     50     static uint16_t last_hue   = 0xFFFF;
     51 #if defined(RGB_MATRIX_ENABLE)
     52     uint16_t curr_hue = rgb_matrix_get_hue();
     53 #else  // defined(RGB_MATRIX_ENABLE)
     54     uint16_t curr_hue = 0;
     55 #endif // defined(RGB_MATRIX_ENABLE)
     56     if (last_hue != curr_hue) {
     57         last_hue   = curr_hue;
     58         hue_redraw = true;
     59     }
     60 
     61     bool            layer_state_redraw = false;
     62     static uint32_t last_layer_state   = 0;
     63     if (last_layer_state != layer_state) {
     64         last_layer_state   = layer_state;
     65         layer_state_redraw = true;
     66     }
     67 
     68     bool                     power_state_redraw = false;
     69     static usbpd_allowance_t last_current_state = (usbpd_allowance_t)(~0);
     70     if (last_current_state != kb_state.current_setting) {
     71         last_current_state = kb_state.current_setting;
     72         power_state_redraw = true;
     73     }
     74 
     75     bool            scan_redraw      = false;
     76     static uint32_t last_scan_update = 0;
     77     if (timer_elapsed32(last_scan_update) > 125) {
     78         last_scan_update = timer_read32();
     79         scan_redraw      = true;
     80     }
     81 
     82     bool            wpm_redraw      = false;
     83     static uint32_t last_wpm_update = 0;
     84     if (timer_elapsed32(last_wpm_update) > 125) {
     85         last_wpm_update = timer_read32();
     86         wpm_redraw      = true;
     87     }
     88 
     89 #if defined(RGB_MATRIX_ENABLE)
     90     bool            rgb_effect_redraw = false;
     91     static uint16_t last_effect       = 0xFFFF;
     92     uint8_t         curr_effect       = rgb_matrix_config.mode;
     93     if (last_effect != curr_effect) {
     94         last_effect       = curr_effect;
     95         rgb_effect_redraw = true;
     96     }
     97 #endif // defined(RGB_MATRIX_ENABLE)
     98 
     99     // Show the Djinn logo and two vertical bars on both sides
    100     if (hue_redraw) {
    101         qp_drawimage_recolor(lcd, 120 - djinn_logo->width / 2, 32, djinn_logo, curr_hue, 255, 255, curr_hue, 255, 0);
    102         qp_rect(lcd, 0, 0, 8, 319, curr_hue, 255, 255, true);
    103         qp_rect(lcd, 231, 0, 239, 319, curr_hue, 255, 255, true);
    104     }
    105 
    106     int ypos = 4;
    107 
    108     // Show layer info on the left side
    109     if (is_keyboard_left()) {
    110         char buf[64] = {0};
    111         int  xpos    = 16;
    112 
    113 #if defined(RGB_MATRIX_ENABLE)
    114         if (hue_redraw || rgb_effect_redraw) {
    115             static int max_rgb_xpos = 0;
    116             xpos                    = 16;
    117             snprintf(buf, sizeof(buf), "rgb: %s", rgb_matrix_get_mode_name(curr_effect));
    118 
    119             for (int i = 5; i < sizeof(buf); ++i) {
    120                 if (buf[i] == 0)
    121                     break;
    122                 else if (buf[i] == '_')
    123                     buf[i] = ' ';
    124                 else if (buf[i - 1] == ' ')
    125                     buf[i] = toupper(buf[i]);
    126                 else if (buf[i - 1] != ' ')
    127                     buf[i] = tolower(buf[i]);
    128             }
    129 
    130             xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0);
    131             if (max_rgb_xpos < xpos) {
    132                 max_rgb_xpos = xpos;
    133             }
    134             qp_rect(lcd, xpos, ypos, max_rgb_xpos, ypos + thintel->line_height, 0, 0, 0, true);
    135         }
    136 
    137         ypos += thintel->line_height + 4;
    138 #endif // defined(RGB_MATRIX_ENABLE)
    139 
    140         if (hue_redraw || layer_state_redraw) {
    141             extern const char *current_layer_name(void);
    142             const char        *layer_name = current_layer_name();
    143 
    144             static int max_layer_xpos = 0;
    145             xpos                      = 16;
    146             snprintf(buf, sizeof(buf), "layer: %s", layer_name);
    147             xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0);
    148             if (max_layer_xpos < xpos) {
    149                 max_layer_xpos = xpos;
    150             }
    151             qp_rect(lcd, xpos, ypos, max_layer_xpos, ypos + thintel->line_height, 0, 0, 0, true);
    152         }
    153 
    154         ypos += thintel->line_height + 4;
    155 
    156         if (hue_redraw || power_state_redraw) {
    157             static int max_power_xpos = 0;
    158             xpos                      = 16;
    159             snprintf(buf, sizeof(buf), "power: %s", usbpd_str(kb_state.current_setting));
    160             xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0);
    161             if (max_power_xpos < xpos) {
    162                 max_power_xpos = xpos;
    163             }
    164             qp_rect(lcd, xpos, ypos, max_power_xpos, ypos + thintel->line_height, 0, 0, 0, true);
    165         }
    166 
    167         ypos += thintel->line_height + 4;
    168 
    169         if (hue_redraw || scan_redraw) {
    170             static int max_scans_xpos = 0;
    171             xpos                      = 16;
    172             snprintf(buf, sizeof(buf), "scans: %d", (int)theme_state.scan_rate);
    173             xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0);
    174             if (max_scans_xpos < xpos) {
    175                 max_scans_xpos = xpos;
    176             }
    177             qp_rect(lcd, xpos, ypos, max_scans_xpos, ypos + thintel->line_height, 0, 0, 0, true);
    178         }
    179 
    180         ypos += thintel->line_height + 4;
    181 
    182         if (hue_redraw || wpm_redraw) {
    183             static int max_wpm_xpos = 0;
    184             xpos                    = 16;
    185             snprintf(buf, sizeof(buf), "wpm: %d", (int)get_current_wpm());
    186             xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0);
    187             if (max_wpm_xpos < xpos) {
    188                 max_wpm_xpos = xpos;
    189             }
    190             qp_rect(lcd, xpos, ypos, max_wpm_xpos, ypos + thintel->line_height, 0, 0, 0, true);
    191         }
    192 
    193         ypos += thintel->line_height + 4;
    194     }
    195 
    196     // Show LED lock indicators on the right side
    197     if (!is_keyboard_left()) {
    198         static led_t last_led_state = {0};
    199         if (hue_redraw || last_led_state.raw != host_keyboard_led_state().raw) {
    200             last_led_state.raw = host_keyboard_led_state().raw;
    201             qp_drawimage_recolor(lcd, 239 - 12 - (32 * 3), 0, last_led_state.caps_lock ? lock_caps_on : lock_caps_off, curr_hue, 255, last_led_state.caps_lock ? 255 : 32, curr_hue, 255, 0);
    202             qp_drawimage_recolor(lcd, 239 - 12 - (32 * 2), 0, last_led_state.num_lock ? lock_num_on : lock_num_off, curr_hue, 255, last_led_state.num_lock ? 255 : 32, curr_hue, 255, 0);
    203             qp_drawimage_recolor(lcd, 239 - 12 - (32 * 1), 0, last_led_state.scroll_lock ? lock_scrl_on : lock_scrl_off, curr_hue, 255, last_led_state.scroll_lock ? 255 : 32, curr_hue, 255, 0);
    204         }
    205     }
    206 }
    207 
    208 //----------------------------------------------------------
    209 // Sync
    210 
    211 theme_runtime_config theme_state;
    212 
    213 void rpc_theme_sync_callback(uint8_t m2s_size, const void *m2s_buffer, uint8_t s2m_size, void *s2m_buffer) {
    214     if (m2s_size == sizeof(theme_state)) {
    215         memcpy(&theme_state, m2s_buffer, m2s_size);
    216     }
    217 }
    218 
    219 void theme_init(void) {
    220     // Register keyboard state sync split transaction
    221     transaction_register_rpc(THEME_DATA_SYNC, rpc_theme_sync_callback);
    222 
    223     // Reset the initial shared data value between master and slave
    224     memset(&theme_state, 0, sizeof(theme_state));
    225 }
    226 
    227 void theme_state_update(void) {
    228     if (is_keyboard_master()) {
    229         // Keep the scan rate in sync
    230         theme_state.scan_rate = get_matrix_scan_rate();
    231     }
    232 }
    233 
    234 void theme_state_sync(void) {
    235     if (!is_transport_connected()) return;
    236 
    237     if (is_keyboard_master()) {
    238         // Keep track of the last state, so that we can tell if we need to propagate to slave
    239         static theme_runtime_config last_theme_state;
    240         static uint32_t             last_sync;
    241         bool                        needs_sync = false;
    242 
    243         // Check if the state values are different
    244         if (memcmp(&theme_state, &last_theme_state, sizeof(theme_runtime_config))) {
    245             needs_sync = true;
    246             memcpy(&last_theme_state, &theme_state, sizeof(theme_runtime_config));
    247         }
    248 
    249         // Send to slave every 125ms regardless of state change
    250         if (timer_elapsed32(last_sync) > 125) {
    251             needs_sync = true;
    252         }
    253 
    254         // Perform the sync if requested
    255         if (needs_sync) {
    256             if (transaction_rpc_send(THEME_DATA_SYNC, sizeof(theme_runtime_config), &theme_state)) {
    257                 last_sync = timer_read32();
    258             } else {
    259                 dprint("Failed to perform rpc call\n");
    260             }
    261         }
    262     }
    263 }