From fd698c43d78ebbc42c1eb2bec74078b791616ad1 Mon Sep 17 00:00:00 2001 From: skullY Date: Wed, 23 Jan 2019 15:43:48 -0800 Subject: The beginning of a simple led matrix driver for is31fl3731 --- quantum/led_matrix.c | 404 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 404 insertions(+) create mode 100644 quantum/led_matrix.c (limited to 'quantum/led_matrix.c') diff --git a/quantum/led_matrix.c b/quantum/led_matrix.c new file mode 100644 index 000000000..9a0aa6acd --- /dev/null +++ b/quantum/led_matrix.c @@ -0,0 +1,404 @@ +/* Copyright 2017 Jason Williams + * Copyright 2017 Jack Humbert + * Copyright 2018 Yiancar + * Copyright 2019 Clueboard + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include "quantum.h" +#include "led_matrix.h" +#include "progmem.h" +#include "config.h" +#include "eeprom.h" +#include +#include + +led_config_t led_matrix_config; + +#ifndef MAX + #define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) +#endif + +#ifndef MIN + #define MIN(a,b) ((a) < (b)? (a): (b)) +#endif + +#ifndef LED_DISABLE_AFTER_TIMEOUT + #define LED_DISABLE_AFTER_TIMEOUT 0 +#endif + +#ifndef LED_DISABLE_WHEN_USB_SUSPENDED + #define LED_DISABLE_WHEN_USB_SUSPENDED false +#endif + +#ifndef EECONFIG_LED_MATRIX + #define EECONFIG_LED_MATRIX EECONFIG_RGBLIGHT +#endif + +#if !defined(LED_MATRIX_MAXIMUM_BRIGHTNESS) || LED_MATRIX_MAXIMUM_BRIGHTNESS > 255 + #define LED_MATRIX_MAXIMUM_BRIGHTNESS 255 +#endif + +bool g_suspend_state = false; + +// Global tick at 20 Hz +uint32_t g_tick = 0; + +// Ticks since this key was last hit. +uint8_t g_key_hit[DRIVER_LED_TOTAL]; + +// Ticks since any key was last hit. +uint32_t g_any_key_hit = 0; + +uint32_t eeconfig_read_led_matrix(void) { + return eeprom_read_dword(EECONFIG_LED_MATRIX); +} +void eeconfig_update_led_matrix(uint32_t config_value) { + eeprom_update_dword(EECONFIG_LED_MATRIX, config_value); +} +void eeconfig_update_led_matrix_default(void) { + dprintf("eeconfig_update_led_matrix_default\n"); + led_matrix_config.enable = 1; + led_matrix_config.mode = LED_MATRIX_UNIFORM_BRIGHTNESS; + led_matrix_config.val = 128; + led_matrix_config.speed = 0; + eeconfig_update_led_matrix(led_matrix_config.raw); +} +void eeconfig_debug_led_matrix(void) { + dprintf("led_matrix_config eprom\n"); + dprintf("led_matrix_config.enable = %d\n", led_matrix_config.enable); + dprintf("led_matrix_config.mode = %d\n", led_matrix_config.mode); + dprintf("led_matrix_config.val = %d\n", led_matrix_config.val); + dprintf("led_matrix_config.speed = %d\n", led_matrix_config.speed); +} + +// Last led hit +#define LED_HITS_TO_REMEMBER 8 +uint8_t g_last_led_hit[LED_HITS_TO_REMEMBER] = {255}; +uint8_t g_last_led_count = 0; + +void map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *led_i, uint8_t *led_count) { + led_matrix led; + *led_count = 0; + + for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) { + // map_index_to_led(i, &led); + led = g_leds[i]; + if (row == led.matrix_co.row && column == led.matrix_co.col) { + led_i[*led_count] = i; + (*led_count)++; + } + } +} + +void led_matrix_update_pwm_buffers(void) { + led_matrix_driver.flush(); +} + +void led_matrix_set_index_value(int index, uint8_t value) { + led_matrix_driver.set_value(index, value); +} + +void led_matrix_set_index_value_all(uint8_t value) { + led_matrix_driver.set_value_all(value); +} + +bool process_led_matrix(uint16_t keycode, keyrecord_t *record) { + if (record->event.pressed) { + uint8_t led[8], led_count; + map_row_column_to_led(record->event.key.row, record->event.key.col, led, &led_count); + if (led_count > 0) { + for (uint8_t i = LED_HITS_TO_REMEMBER; i > 1; i--) { + g_last_led_hit[i - 1] = g_last_led_hit[i - 2]; + } + g_last_led_hit[0] = led[0]; + g_last_led_count = MIN(LED_HITS_TO_REMEMBER, g_last_led_count + 1); + } + for(uint8_t i = 0; i < led_count; i++) + g_key_hit[led[i]] = 0; + g_any_key_hit = 0; + } else { + #ifdef LED_MATRIX_KEYRELEASES + uint8_t led[8], led_count; + map_row_column_to_led(record->event.key.row, record->event.key.col, led, &led_count); + for(uint8_t i = 0; i < led_count; i++) + g_key_hit[led[i]] = 255; + + g_any_key_hit = 255; + #endif + } + return true; +} + +void led_matrix_set_suspend_state(bool state) { + g_suspend_state = state; +} + +// All LEDs off +void led_matrix_all_off(void) { + led_matrix_set_index_value_all(0); +} + +// Uniform brightness +void led_matrix_uniform_brightness(void) { + led_matrix_set_index_value_all(led_matrix_config.val); +} + +void led_matrix_custom(void) {} + +void led_matrix_task(void) { + #ifdef TRACK_PREVIOUS_EFFECT + static uint8_t toggle_enable_last = 255; + #endif + if (!led_matrix_config.enable) { + led_matrix_all_off(); + led_matrix_indicators(); + #ifdef TRACK_PREVIOUS_EFFECT + toggle_enable_last = led_matrix_config.enable; + #endif + return; + } + + // delay 1 second before driving LEDs or doing anything else + // FIXME: Can't we use wait_ms() here? + static uint8_t startup_tick = 0; + if (startup_tick < 20) { + startup_tick++; + return; + } + + g_tick++; + + if (g_any_key_hit < 0xFFFFFFFF) { + g_any_key_hit++; + } + + for (int led = 0; led < DRIVER_LED_TOTAL; led++) { + if (g_key_hit[led] < 255) { + if (g_key_hit[led] == 254) + g_last_led_count = MAX(g_last_led_count - 1, 0); + g_key_hit[led]++; + } + } + + // Factory default magic value + if (led_matrix_config.mode == 255) { + led_matrix_uniform_brightness(); + return; + } + + // Ideally we would also stop sending zeros to the LED driver PWM buffers + // while suspended and just do a software shutdown. This is a cheap hack for now. + 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)); + uint8_t effect = suspend_backlight ? 0 : led_matrix_config.mode; + + #ifdef TRACK_PREVIOUS_EFFECT + // Keep track of the effect used last time, + // detect change in effect, so each effect can + // have an optional initialization. + + static uint8_t effect_last = 255; + bool initialize = (effect != effect_last) || (led_matrix_config.enable != toggle_enable_last); + effect_last = effect; + toggle_enable_last = led_matrix_config.enable; + #endif + + // this gets ticked at 20 Hz. + // each effect can opt to do calculations + // and/or request PWM buffer updates. + switch (effect) { + case LED_MATRIX_UNIFORM_BRIGHTNESS: + led_matrix_uniform_brightness(); + break; + default: + led_matrix_custom(); + break; + } + + if (! suspend_backlight) { + led_matrix_indicators(); + } + +} + +void led_matrix_indicators(void) { + led_matrix_indicators_kb(); + led_matrix_indicators_user(); +} + +__attribute__((weak)) +void led_matrix_indicators_kb(void) {} + +__attribute__((weak)) +void led_matrix_indicators_user(void) {} + + +// void led_matrix_set_indicator_index(uint8_t *index, uint8_t row, uint8_t column) +// { +// if (row >= MATRIX_ROWS) +// { +// // Special value, 255=none, 254=all +// *index = row; +// } +// else +// { +// // This needs updated to something like +// // uint8_t led[8], led_count; +// // map_row_column_to_led(row,column,led,&led_count); +// // for(uint8_t i = 0; i < led_count; i++) +// map_row_column_to_led(row, column, index); +// } +// } + +void led_matrix_init(void) { + led_matrix_driver.init(); + + // TODO: put the 1 second startup delay here? + + // clear the key hits + for (int led=0; led= LED_MATRIX_EFFECT_MAX) + led_matrix_config.mode = 1; + eeconfig_update_led_matrix(led_matrix_config.raw); +} + +void led_matrix_step_reverse(void) { + led_matrix_config.mode--; + if (led_matrix_config.mode < 1) + led_matrix_config.mode = LED_MATRIX_EFFECT_MAX - 1; + eeconfig_update_led_matrix(led_matrix_config.raw); +} + +void led_matrix_increase_val(void) { + led_matrix_config.val = increment(led_matrix_config.val, 8, 0, LED_MATRIX_MAXIMUM_BRIGHTNESS); + eeconfig_update_led_matrix(led_matrix_config.raw); +} + +void led_matrix_decrease_val(void) { + led_matrix_config.val = decrement(led_matrix_config.val, 8, 0, LED_MATRIX_MAXIMUM_BRIGHTNESS); + eeconfig_update_led_matrix(led_matrix_config.raw); +} + +void led_matrix_increase_speed(void) { + led_matrix_config.speed = increment(led_matrix_config.speed, 1, 0, 3); + eeconfig_update_led_matrix(led_matrix_config.raw);//EECONFIG needs to be increased to support this +} + +void led_matrix_decrease_speed(void) { + led_matrix_config.speed = decrement(led_matrix_config.speed, 1, 0, 3); + eeconfig_update_led_matrix(led_matrix_config.raw);//EECONFIG needs to be increased to support this +} + +void led_matrix_mode(uint8_t mode, bool eeprom_write) { + led_matrix_config.mode = mode; + if (eeprom_write) { + eeconfig_update_led_matrix(led_matrix_config.raw); + } +} + +uint8_t led_matrix_get_mode(void) { + return led_matrix_config.mode; +} + +void led_matrix_set_value(uint8_t val, bool eeprom_write) { + led_matrix_config.val = val; + if (eeprom_write) { + eeconfig_update_led_matrix(led_matrix_config.raw); + } +} -- cgit v1.2.3-24-g4f1b