summaryrefslogtreecommitdiff
path: root/quantum
diff options
context:
space:
mode:
Diffstat (limited to 'quantum')
-rw-r--r--quantum/rgblight.c71
-rw-r--r--quantum/rgblight.h27
2 files changed, 98 insertions, 0 deletions
diff --git a/quantum/rgblight.c b/quantum/rgblight.c
index f072ae8ca9..b3f0f18d42 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();
diff --git a/quantum/rgblight.h b/quantum/rgblight.h
index 39c4c2784f..40f267daa2 100644
--- a/quantum/rgblight.h
+++ b/quantum/rgblight.h
@@ -170,6 +170,29 @@ enum RGBLIGHT_EFFECT_MODE {
# include <avr/pgmspace.h>
# endif
+# ifdef RGBLIGHT_LAYERS
+typedef struct {
+ uint8_t index; // The first LED to light
+ uint8_t count; // The number of LEDs to light
+ uint8_t hue;
+ uint8_t sat;
+ uint8_t val;
+} rgblight_segment_t;
+
+# define RGBLIGHT_END_SEGMENT_INDEX (255)
+# define RGBLIGHT_END_SEGMENTS {RGBLIGHT_END_SEGMENT_INDEX, 0, 0, 0}
+# define RGBLIGHT_MAX_LAYERS 8
+# define RGBLIGHT_LAYER_SEGMENTS(...) { __VA_ARGS__, RGBLIGHT_END_SEGMENTS }
+# define RGBLIGHT_LAYERS_LIST(...) { __VA_ARGS__, NULL }
+
+// Get/set enabled rgblight layers
+void rgblight_set_layer_state(uint8_t layer, bool enabled);
+bool rgblight_get_layer_state(uint8_t layer);
+
+// Point this to an array of rgblight_segment_t arrays in keyboard_post_init_user to use rgblight layers
+extern const rgblight_segment_t * const * rgblight_layers;
+# endif
+
extern LED_TYPE led[RGBLED_NUM];
extern const uint8_t RGBLED_BREATHING_INTERVALS[4] PROGMEM;
@@ -199,6 +222,9 @@ typedef struct _rgblight_status_t {
# ifdef RGBLIGHT_SPLIT
uint8_t change_flags;
# endif
+# ifdef RGBLIGHT_LAYERS
+ uint8_t enabled_layer_mask;
+# endif
} rgblight_status_t;
/* === Utility Functions ===*/
@@ -313,6 +339,7 @@ void rgblight_timer_toggle(void);
# define RGBLIGHT_STATUS_CHANGE_HSVS (1 << 1)
# define RGBLIGHT_STATUS_CHANGE_TIMER (1 << 2)
# define RGBLIGHT_STATUS_ANIMATION_TICK (1 << 3)
+# define RGBLIGHT_STATUS_CHANGE_LAYERS (1 << 4)
typedef struct _rgblight_syncinfo_t {
rgblight_config_t config;