aboutsummaryrefslogtreecommitdiffstats
path: root/quantum/rgblight.c
diff options
context:
space:
mode:
authorNathan Gray <n8gray@n8gray.org>2020-03-10 12:50:01 -0700
committerGitHub <noreply@github.com>2020-03-10 12:50:01 -0700
commit2ffb08843ba59f0af0870335934bdb277fc85620 (patch)
treef38f760dd73bca0f7089ff8751eecc03a95f7256 /quantum/rgblight.c
parent2a8ccafe6e704eced2d383810e1061613871433e (diff)
downloadfirmware-2ffb08843ba59f0af0870335934bdb277fc85620.tar.gz
firmware-2ffb08843ba59f0af0870335934bdb277fc85620.tar.bz2
firmware-2ffb08843ba59f0af0870335934bdb277fc85620.zip
Feature: RGBLight layers (#7768)
* New feature: RGBLIGHT_LAYERS This feature allows users to define multiple independent layers of lighting that can be toggled on and off individually, making it easy to use your RGB lighting to indicate things like active keyboard layer & modifier state. * Demonstrate built in functions for layer state checking Also link the video in the docs. * Follow existing pattern for setting rgblight_status flags * Eliminate rgblight_is_static_mode since it's not needed Just check to see if the timer is enabled directly.
Diffstat (limited to 'quantum/rgblight.c')
-rw-r--r--quantum/rgblight.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/quantum/rgblight.c b/quantum/rgblight.c
index f072ae8ca..b3f0f18d4 100644
--- a/quantum/rgblight.c
+++ b/quantum/rgblight.c
@@ -38,17 +38,23 @@
# include "velocikey.h"
#endif
+#ifndef MIN
+# define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
#ifdef RGBLIGHT_SPLIT
/* for split keyboard */
# define RGBLIGHT_SPLIT_SET_CHANGE_MODE rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_MODE
# define RGBLIGHT_SPLIT_SET_CHANGE_HSVS rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_HSVS
# define RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS rgblight_status.change_flags |= (RGBLIGHT_STATUS_CHANGE_MODE | RGBLIGHT_STATUS_CHANGE_HSVS)
+# define RGBLIGHT_SPLIT_SET_CHANGE_LAYERS rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_LAYERS
# define RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_TIMER
# define RGBLIGHT_SPLIT_ANIMATION_TICK rgblight_status.change_flags |= RGBLIGHT_STATUS_ANIMATION_TICK
#else
# define RGBLIGHT_SPLIT_SET_CHANGE_MODE
# define RGBLIGHT_SPLIT_SET_CHANGE_HSVS
# define RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS
+# define RGBLIGHT_SPLIT_SET_CHANGE_LAYERS
# define RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE
# define RGBLIGHT_SPLIT_ANIMATION_TICK
#endif
@@ -97,6 +103,10 @@ LED_TYPE led[RGBLED_NUM];
# define LED_ARRAY led
#endif
+#ifdef RGBLIGHT_LAYERS
+rgblight_segment_t const * const *rgblight_layers = NULL;
+#endif
+
static uint8_t clipping_start_pos = 0;
static uint8_t clipping_num_leds = RGBLED_NUM;
static uint8_t effect_start_pos = 0;
@@ -604,11 +614,67 @@ void rgblight_sethsv_master(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_se
void rgblight_sethsv_slave(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_range(hue, sat, val, (uint8_t)RGBLED_NUM / 2, (uint8_t)RGBLED_NUM); }
#endif // ifndef RGBLIGHT_SPLIT
+#ifdef RGBLIGHT_LAYERS
+void rgblight_set_layer_state(uint8_t layer, bool enabled) {
+ uint8_t mask = 1 << layer;
+ if (enabled) {
+ rgblight_status.enabled_layer_mask |= mask;
+ } else {
+ rgblight_status.enabled_layer_mask &= ~mask;
+ }
+ RGBLIGHT_SPLIT_SET_CHANGE_LAYERS;
+ // Static modes don't have a ticker running to update the LEDs
+ if (rgblight_status.timer_enabled == false) {
+ rgblight_mode_noeeprom(rgblight_config.mode);
+ }
+}
+
+bool rgblight_get_layer_state(uint8_t layer) {
+ uint8_t mask = 1 << layer;
+ return (rgblight_status.enabled_layer_mask & mask) != 0;
+}
+
+// Write any enabled LED layers into the buffer
+static void rgblight_layers_write(void) {
+ uint8_t i = 0;
+ // For each layer
+ for (const rgblight_segment_t * const *layer_ptr = rgblight_layers; i < RGBLIGHT_MAX_LAYERS; layer_ptr++, i++) {
+ if (!rgblight_get_layer_state(i)) {
+ continue; // Layer is disabled
+ }
+ const rgblight_segment_t * segment_ptr = pgm_read_ptr(layer_ptr);
+ if (segment_ptr == NULL) {
+ break; // No more layers
+ }
+ // For each segment
+ while (1) {
+ rgblight_segment_t segment;
+ memcpy_P(&segment, segment_ptr, sizeof(rgblight_segment_t));
+ if (segment.index == RGBLIGHT_END_SEGMENT_INDEX) {
+ break; // No more segments
+ }
+ // Write segment.count LEDs
+ LED_TYPE * const limit = &led[MIN(segment.index + segment.count, RGBLED_NUM)];
+ for (LED_TYPE *led_ptr = &led[segment.index]; led_ptr < limit; led_ptr++) {
+ sethsv(segment.hue, segment.sat, segment.val, led_ptr);
+ }
+ segment_ptr++;
+ }
+ }
+}
+#endif
+
#ifndef RGBLIGHT_CUSTOM_DRIVER
void rgblight_set(void) {
LED_TYPE *start_led;
uint16_t num_leds = clipping_num_leds;
+# ifdef RGBLIGHT_LAYERS
+ if (rgblight_layers != NULL) {
+ rgblight_layers_write();
+ }
+# endif
+
if (!rgblight_config.enable) {
for (uint8_t i = effect_start_pos; i < effect_end_pos; i++) {
led[i].r = 0;
@@ -652,6 +718,11 @@ void rgblight_get_syncinfo(rgblight_syncinfo_t *syncinfo) {
/* for split keyboard slave side */
void rgblight_update_sync(rgblight_syncinfo_t *syncinfo, bool write_to_eeprom) {
+# ifdef RGBLIGHT_LAYERS
+ if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_LAYERS) {
+ rgblight_status.enabled_layer_mask = syncinfo->status.enabled_layer_mask;
+ }
+# endif
if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_MODE) {
if (syncinfo->config.enable) {
rgblight_config.enable = 1; // == rgblight_enable_noeeprom();