qmk

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.z3bra.org/qmk.git
Log | Files | Refs | Submodules | LICENSE

led_matrix.c (11303B)


      1 /* Copyright 2017 Jason Williams
      2  * Copyright 2017 Jack Humbert
      3  * Copyright 2018 Yiancar
      4  * Copyright 2019 Clueboard
      5  *
      6  * This program is free software: you can redistribute it and/or modify
      7  * it under the terms of the GNU General Public License as published by
      8  * the Free Software Foundation, either version 2 of the License, or
      9  * (at your option) any later version.
     10  *
     11  * This program is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  * GNU General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU General Public License
     17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     18  */
     19 
     20 #include <stdint.h>
     21 #include <stdbool.h>
     22 #include "quantum.h"
     23 #include "ledmatrix.h"
     24 #include "progmem.h"
     25 #include "config.h"
     26 #include "eeprom.h"
     27 #include <string.h>
     28 #include <math.h>
     29 
     30 led_config_t led_matrix_config;
     31 
     32 #ifndef MAX
     33 #    define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
     34 #endif
     35 
     36 #ifndef MIN
     37 #    define MIN(a, b) ((a) < (b) ? (a) : (b))
     38 #endif
     39 
     40 #ifndef LED_DISABLE_AFTER_TIMEOUT
     41 #    define LED_DISABLE_AFTER_TIMEOUT 0
     42 #endif
     43 
     44 #ifndef LED_DISABLE_WHEN_USB_SUSPENDED
     45 #    define LED_DISABLE_WHEN_USB_SUSPENDED false
     46 #endif
     47 
     48 #ifndef EECONFIG_LED_MATRIX
     49 #    define EECONFIG_LED_MATRIX EECONFIG_RGBLIGHT
     50 #endif
     51 
     52 #if !defined(LED_MATRIX_MAXIMUM_BRIGHTNESS) || LED_MATRIX_MAXIMUM_BRIGHTNESS > 255
     53 #    define LED_MATRIX_MAXIMUM_BRIGHTNESS 255
     54 #endif
     55 
     56 bool g_suspend_state = false;
     57 
     58 // Global tick at 20 Hz
     59 uint32_t g_tick = 0;
     60 
     61 // Ticks since this key was last hit.
     62 uint8_t g_key_hit[LED_DRIVER_LED_COUNT];
     63 
     64 // Ticks since any key was last hit.
     65 uint32_t g_any_key_hit = 0;
     66 
     67 uint32_t eeconfig_read_led_matrix(void) { return eeprom_read_dword(EECONFIG_LED_MATRIX); }
     68 
     69 void eeconfig_update_led_matrix(uint32_t config_value) { eeprom_update_dword(EECONFIG_LED_MATRIX, config_value); }
     70 
     71 void eeconfig_update_led_matrix_default(void) {
     72     dprintf("eeconfig_update_led_matrix_default\n");
     73     led_matrix_config.enable = 1;
     74     led_matrix_config.mode   = LED_MATRIX_UNIFORM_BRIGHTNESS;
     75     led_matrix_config.val    = 128;
     76     led_matrix_config.speed  = 0;
     77     eeconfig_update_led_matrix(led_matrix_config.raw);
     78 }
     79 
     80 void eeconfig_debug_led_matrix(void) {
     81     dprintf("led_matrix_config eeprom\n");
     82     dprintf("led_matrix_config.enable = %d\n", led_matrix_config.enable);
     83     dprintf("led_matrix_config.mode = %d\n", led_matrix_config.mode);
     84     dprintf("led_matrix_config.val = %d\n", led_matrix_config.val);
     85     dprintf("led_matrix_config.speed = %d\n", led_matrix_config.speed);
     86 }
     87 
     88 // Last led hit
     89 #ifndef LED_HITS_TO_REMEMBER
     90 #    define LED_HITS_TO_REMEMBER 8
     91 #endif
     92 uint8_t g_last_led_hit[LED_HITS_TO_REMEMBER] = {255};
     93 uint8_t g_last_led_count                     = 0;
     94 
     95 void map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *led_i, uint8_t *led_count) {
     96     led_matrix led;
     97     *led_count = 0;
     98 
     99     for (uint8_t i = 0; i < LED_DRIVER_LED_COUNT; i++) {
    100         // map_index_to_led(i, &led);
    101         led = g_leds[i];
    102         if (row == led.matrix_co.row && column == led.matrix_co.col) {
    103             led_i[*led_count] = i;
    104             (*led_count)++;
    105         }
    106     }
    107 }
    108 
    109 void led_matrix_update_pwm_buffers(void) { led_matrix_driver.flush(); }
    110 
    111 void led_matrix_set_index_value(int index, uint8_t value) { led_matrix_driver.set_value(index, value); }
    112 
    113 void led_matrix_set_index_value_all(uint8_t value) { led_matrix_driver.set_value_all(value); }
    114 
    115 bool process_led_matrix(uint16_t keycode, keyrecord_t *record) {
    116     if (record->event.pressed) {
    117         uint8_t led[8], led_count;
    118         map_row_column_to_led(record->event.key.row, record->event.key.col, led, &led_count);
    119         if (led_count > 0) {
    120             for (uint8_t i = LED_HITS_TO_REMEMBER; i > 1; i--) {
    121                 g_last_led_hit[i - 1] = g_last_led_hit[i - 2];
    122             }
    123             g_last_led_hit[0] = led[0];
    124             g_last_led_count  = MIN(LED_HITS_TO_REMEMBER, g_last_led_count + 1);
    125         }
    126         for (uint8_t i = 0; i < led_count; i++) g_key_hit[led[i]] = 0;
    127         g_any_key_hit = 0;
    128     } else {
    129 #ifdef LED_MATRIX_KEYRELEASES
    130         uint8_t led[8], led_count;
    131         map_row_column_to_led(record->event.key.row, record->event.key.col, led, &led_count);
    132         for (uint8_t i = 0; i < led_count; i++) g_key_hit[led[i]] = 255;
    133 
    134         g_any_key_hit = 255;
    135 #endif
    136     }
    137     return true;
    138 }
    139 
    140 void led_matrix_set_suspend_state(bool state) { g_suspend_state = state; }
    141 
    142 // All LEDs off
    143 void led_matrix_all_off(void) { led_matrix_set_index_value_all(0); }
    144 
    145 // Uniform brightness
    146 void led_matrix_uniform_brightness(void) { led_matrix_set_index_value_all(LED_MATRIX_MAXIMUM_BRIGHTNESS / BACKLIGHT_LEVELS * led_matrix_config.val); }
    147 
    148 void led_matrix_custom(void) {}
    149 
    150 void led_matrix_task(void) {
    151     if (!led_matrix_config.enable) {
    152         led_matrix_all_off();
    153         led_matrix_indicators();
    154         return;
    155     }
    156 
    157     g_tick++;
    158 
    159     if (g_any_key_hit < 0xFFFFFFFF) {
    160         g_any_key_hit++;
    161     }
    162 
    163     for (int led = 0; led < LED_DRIVER_LED_COUNT; led++) {
    164         if (g_key_hit[led] < 255) {
    165             if (g_key_hit[led] == 254) g_last_led_count = MAX(g_last_led_count - 1, 0);
    166             g_key_hit[led]++;
    167         }
    168     }
    169 
    170     // Ideally we would also stop sending zeros to the LED driver PWM buffers
    171     // while suspended and just do a software shutdown. This is a cheap hack for now.
    172     bool    suspend_backlight = ((g_suspend_state && LED_DISABLE_WHEN_USB_SUSPENDED) || (LED_DISABLE_AFTER_TIMEOUT > 0 && g_any_key_hit > LED_DISABLE_AFTER_TIMEOUT * 60 * 20));
    173     uint8_t effect            = suspend_backlight ? 0 : led_matrix_config.mode;
    174 
    175     // this gets ticked at 20 Hz.
    176     // each effect can opt to do calculations
    177     // and/or request PWM buffer updates.
    178     switch (effect) {
    179         case LED_MATRIX_UNIFORM_BRIGHTNESS:
    180             led_matrix_uniform_brightness();
    181             break;
    182         default:
    183             led_matrix_custom();
    184             break;
    185     }
    186 
    187     if (!suspend_backlight) {
    188         led_matrix_indicators();
    189     }
    190 
    191     // Tell the LED driver to update its state
    192     led_matrix_driver.flush();
    193 }
    194 
    195 void led_matrix_indicators(void) {
    196     led_matrix_indicators_kb();
    197     led_matrix_indicators_user();
    198 }
    199 
    200 __attribute__((weak)) void led_matrix_indicators_kb(void) {}
    201 
    202 __attribute__((weak)) void led_matrix_indicators_user(void) {}
    203 
    204 // void led_matrix_set_indicator_index(uint8_t *index, uint8_t row, uint8_t column)
    205 // {
    206 //  if (row >= MATRIX_ROWS)
    207 //  {
    208 //      // Special value, 255=none, 254=all
    209 //      *index = row;
    210 //  }
    211 //  else
    212 //  {
    213 //      // This needs updated to something like
    214 //      // uint8_t led[8], led_count;
    215 //      // map_row_column_to_led(row,column,led,&led_count);
    216 //      // for(uint8_t i = 0; i < led_count; i++)
    217 //      map_row_column_to_led(row, column, index);
    218 //  }
    219 // }
    220 
    221 void led_matrix_init(void) {
    222     led_matrix_driver.init();
    223 
    224     // Wait half a second for the driver to finish initializing
    225     wait_ms(500);
    226 
    227     // clear the key hits
    228     for (int led = 0; led < LED_DRIVER_LED_COUNT; led++) {
    229         g_key_hit[led] = 255;
    230     }
    231 
    232     if (!eeconfig_is_enabled()) {
    233         dprintf("led_matrix_init_drivers eeconfig is not enabled.\n");
    234         eeconfig_init();
    235         eeconfig_update_led_matrix_default();
    236     }
    237 
    238     led_matrix_config.raw = eeconfig_read_led_matrix();
    239 
    240     if (!led_matrix_config.mode) {
    241         dprintf("led_matrix_init_drivers led_matrix_config.mode = 0. Write default values to EEPROM.\n");
    242         eeconfig_update_led_matrix_default();
    243         led_matrix_config.raw = eeconfig_read_led_matrix();
    244     }
    245 
    246     eeconfig_debug_led_matrix();  // display current eeprom values
    247 }
    248 
    249 // Deals with the messy details of incrementing an integer
    250 static uint8_t increment(uint8_t value, uint8_t step, uint8_t min, uint8_t max) {
    251     int16_t new_value = value;
    252     new_value += step;
    253     return MIN(MAX(new_value, min), max);
    254 }
    255 
    256 static uint8_t decrement(uint8_t value, uint8_t step, uint8_t min, uint8_t max) {
    257     int16_t new_value = value;
    258     new_value -= step;
    259     return MIN(MAX(new_value, min), max);
    260 }
    261 
    262 // void *backlight_get_custom_key_value_eeprom_address(uint8_t led) {
    263 //     // 3 bytes per value
    264 //     return EECONFIG_LED_MATRIX + (led * 3);
    265 // }
    266 
    267 // void backlight_get_key_value(uint8_t led, uint8_t *value) {
    268 //     void *address = backlight_get_custom_key_value_eeprom_address(led);
    269 //     value = eeprom_read_byte(address);
    270 // }
    271 
    272 // void backlight_set_key_value(uint8_t row, uint8_t column, uint8_t value) {
    273 //     uint8_t led[8], led_count;
    274 //     map_row_column_to_led(row,column,led,&led_count);
    275 //     for(uint8_t i = 0; i < led_count; i++) {
    276 //         if (led[i] < LED_DRIVER_LED_COUNT) {
    277 //             void *address = backlight_get_custom_key_value_eeprom_address(led[i]);
    278 //             eeprom_update_byte(address, value);
    279 //         }
    280 //     }
    281 // }
    282 
    283 uint32_t led_matrix_get_tick(void) { return g_tick; }
    284 
    285 void led_matrix_toggle(void) {
    286     led_matrix_config.enable ^= 1;
    287     eeconfig_update_led_matrix(led_matrix_config.raw);
    288 }
    289 
    290 void led_matrix_enable(void) {
    291     led_matrix_config.enable = 1;
    292     eeconfig_update_led_matrix(led_matrix_config.raw);
    293 }
    294 
    295 void led_matrix_enable_noeeprom(void) { led_matrix_config.enable = 1; }
    296 
    297 void led_matrix_disable(void) {
    298     led_matrix_config.enable = 0;
    299     eeconfig_update_led_matrix(led_matrix_config.raw);
    300 }
    301 
    302 void led_matrix_disable_noeeprom(void) { led_matrix_config.enable = 0; }
    303 
    304 void led_matrix_step(void) {
    305     led_matrix_config.mode++;
    306     if (led_matrix_config.mode >= LED_MATRIX_EFFECT_MAX) {
    307         led_matrix_config.mode = 1;
    308     }
    309     eeconfig_update_led_matrix(led_matrix_config.raw);
    310 }
    311 
    312 void led_matrix_step_reverse(void) {
    313     led_matrix_config.mode--;
    314     if (led_matrix_config.mode < 1) {
    315         led_matrix_config.mode = LED_MATRIX_EFFECT_MAX - 1;
    316     }
    317     eeconfig_update_led_matrix(led_matrix_config.raw);
    318 }
    319 
    320 void led_matrix_increase_val(void) {
    321     led_matrix_config.val = increment(led_matrix_config.val, 8, 0, LED_MATRIX_MAXIMUM_BRIGHTNESS);
    322     eeconfig_update_led_matrix(led_matrix_config.raw);
    323 }
    324 
    325 void led_matrix_decrease_val(void) {
    326     led_matrix_config.val = decrement(led_matrix_config.val, 8, 0, LED_MATRIX_MAXIMUM_BRIGHTNESS);
    327     eeconfig_update_led_matrix(led_matrix_config.raw);
    328 }
    329 
    330 void led_matrix_increase_speed(void) {
    331     led_matrix_config.speed = increment(led_matrix_config.speed, 1, 0, 3);
    332     eeconfig_update_led_matrix(led_matrix_config.raw);  // EECONFIG needs to be increased to support this
    333 }
    334 
    335 void led_matrix_decrease_speed(void) {
    336     led_matrix_config.speed = decrement(led_matrix_config.speed, 1, 0, 3);
    337     eeconfig_update_led_matrix(led_matrix_config.raw);  // EECONFIG needs to be increased to support this
    338 }
    339 
    340 void led_matrix_mode(uint8_t mode, bool eeprom_write) {
    341     led_matrix_config.mode = mode;
    342     if (eeprom_write) {
    343         eeconfig_update_led_matrix(led_matrix_config.raw);
    344     }
    345 }
    346 
    347 uint8_t led_matrix_get_mode(void) { return led_matrix_config.mode; }
    348 
    349 void led_matrix_set_value_noeeprom(uint8_t val) { led_matrix_config.val = val; }
    350 
    351 void led_matrix_set_value(uint8_t val) {
    352     led_matrix_set_value_noeeprom(val);
    353     eeconfig_update_led_matrix(led_matrix_config.raw);
    354 }
    355 
    356 void backlight_set(uint8_t val) { led_matrix_set_value(val); }