From 4b7354a34299d0027543b30d516a6fa15bdde342 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sun, 20 Nov 2016 17:35:11 +0100 Subject: [PATCH] Split out LED effects into smaller "plugins" Recreate LEDControl as a class with pluggable parts, similar in vein to the event handler and loop hooks. Except in this case, only the current effect runs at any one time, the current one. All existing effects were separated out into plugins, and the default firmware example was updated too. All of them were pretty trivial, save the special NumLock effect: that one also installs a loop hook, and switches the LED mode if need be. Its setup function also skips to the next effect, if the mode was selected manually. Behaviour should be the same as before, but LED effects are now pluggable, at the cost of some code and data size increase. Signed-off-by: Gergely Nagy --- .../KeyboardioFirmware/KeyboardioFirmware.ino | 27 +- src/KeyboardioFirmware.cpp | 9 +- src/KeyboardioFirmware.h | 2 +- src/LED-BootAnimation.cpp | 35 ++ src/LED-BootAnimation.h | 10 + src/LED-BreatheEffect.cpp | 14 + src/LED-BreatheEffect.h | 14 + src/LED-ChaseEffect.cpp | 22 ++ src/LED-ChaseEffect.h | 18 + src/LED-Numlock.cpp | 50 +++ src/LED-Numlock.h | 17 + src/LED-RainbowEffect.cpp | 50 +++ src/LED-RainbowEffect.h | 39 ++ src/LED-SolidColor.cpp | 13 + src/LED-SolidColor.h | 13 + src/LEDControl.cpp | 347 +++--------------- src/LEDControl.h | 95 +---- src/LEDUtils.cpp | 78 ++++ src/LEDUtils.h | 11 + src/TestMode.cpp | 5 +- 20 files changed, 488 insertions(+), 381 deletions(-) create mode 100644 src/LED-BootAnimation.cpp create mode 100644 src/LED-BootAnimation.h create mode 100644 src/LED-BreatheEffect.cpp create mode 100644 src/LED-BreatheEffect.h create mode 100644 src/LED-ChaseEffect.cpp create mode 100644 src/LED-ChaseEffect.h create mode 100644 src/LED-Numlock.cpp create mode 100644 src/LED-Numlock.h create mode 100644 src/LED-RainbowEffect.cpp create mode 100644 src/LED-RainbowEffect.h create mode 100644 src/LED-SolidColor.cpp create mode 100644 src/LED-SolidColor.h create mode 100644 src/LEDUtils.cpp create mode 100644 src/LEDUtils.h diff --git a/examples/KeyboardioFirmware/KeyboardioFirmware.ino b/examples/KeyboardioFirmware/KeyboardioFirmware.ino index 274f4243..9f342368 100644 --- a/examples/KeyboardioFirmware/KeyboardioFirmware.ino +++ b/examples/KeyboardioFirmware/KeyboardioFirmware.ino @@ -7,6 +7,13 @@ #include "KeyboardioFirmware.h" #include "generated/keymaps.h" +#include "LED-BootAnimation.h" +#include "LED-SolidColor.h" +#include "LED-Numlock.h" +#include "LED-BreatheEffect.h" +#include "LED-ChaseEffect.h" +#include "LED-RainbowEffect.h" + uint8_t primary_keymap = 0; uint8_t temporary_keymap = 0; @@ -16,13 +23,27 @@ uint8_t temporary_keymap = 0; const Key keymaps[][ROWS][COLS] PROGMEM = { KEYMAP_LIST }; +static LEDBootAnimation bootAnimation; +static LEDSolidColor solidRed (100, 0, 0); +static LEDSolidColor solidOrange (100, 30, 0); +static LEDSolidColor solidYellow (90, 70, 0); +static LEDSolidColor solidGreen (0, 200, 0); +static LEDSolidColor solidBlue (0, 30, 200); +static LEDSolidColor solidIndigo (0, 0, 200); +static LEDSolidColor solidViolet (100, 0, 120); + +static LEDBreatheEffect breatheEffect; +static LEDRainbowEffect rainbowEffect; +static LEDRainbowWaveEffect rainbowWaveEffect; +static LEDChaseEffect chaseEffect; + +static LEDNumlock numLockEffect (NUMPAD_KEYMAP); + void setup() { - Keyboardio.setup(KEYMAPS, NUMPAD_KEYMAP); + Keyboardio.setup(KEYMAPS); } void loop() { Keyboardio.loop(); } - - diff --git a/src/KeyboardioFirmware.cpp b/src/KeyboardioFirmware.cpp index 6909c0df..7193d4e4 100644 --- a/src/KeyboardioFirmware.cpp +++ b/src/KeyboardioFirmware.cpp @@ -1,12 +1,10 @@ #include "KeyboardioFirmware.h" -byte NUMPAD_KEYMAP = 0; - Keyboardio_::Keyboardio_(void) { } void -Keyboardio_::setup(const byte keymap_count, const byte numpad_layer) { +Keyboardio_::setup(const byte keymap_count) { event_handler_hook_add (handle_key_event_default); wdt_disable(); delay(100); @@ -14,9 +12,8 @@ Keyboardio_::setup(const byte keymap_count, const byte numpad_layer) { Mouse.begin(); AbsoluteMouse.begin(); KeyboardHardware.setup(); - LEDControl.boot_animation(); + LEDControl.setup(); - NUMPAD_KEYMAP = numpad_layer; temporary_keymap = primary_keymap = Storage.load_primary_keymap(keymap_count); } @@ -30,7 +27,7 @@ Keyboardio_::loop(void) { } KeyboardHardware.scan_matrix(); - LEDControl.update(temporary_keymap); + LEDControl.update(); Keyboard.sendReport(); Keyboard.releaseAll(); } diff --git a/src/KeyboardioFirmware.h b/src/KeyboardioFirmware.h index 3cbe9de4..e476fe03 100644 --- a/src/KeyboardioFirmware.h +++ b/src/KeyboardioFirmware.h @@ -37,7 +37,7 @@ class Keyboardio_ { public: Keyboardio_(void); - void setup(const byte keymap_count, const byte numpad_layer); + void setup(const byte keymap_count); void loop(void); }; diff --git a/src/LED-BootAnimation.cpp b/src/LED-BootAnimation.cpp new file mode 100644 index 00000000..728c4eb1 --- /dev/null +++ b/src/LED-BootAnimation.cpp @@ -0,0 +1,35 @@ +#include "LED-BootAnimation.h" + +static void +type_letter(uint8_t letter) { + led_set_crgb_at(letter, {255, 0, 0}); + led_sync(); + delay(250); + led_set_crgb_at(letter, {0, 0, 0}); + led_sync(); + delay(10); +} + +LEDBootAnimation::LEDBootAnimation (void) { + LEDControl.mode_add (this); +} + +void +LEDBootAnimation::setup (void) { + LEDControl.set_all_leds_to(0, 0, 0); + + type_letter(LED_K); + type_letter(LED_E); + type_letter(LED_Y); + type_letter(LED_B); + type_letter(LED_O); + type_letter(LED_A); + type_letter(LED_R); + type_letter(LED_D); + type_letter(LED_I); + type_letter(LED_O); + type_letter(LED_SPACE); + type_letter(LED_0); + type_letter(LED_PERIOD); + type_letter(LED_9); +} diff --git a/src/LED-BootAnimation.h b/src/LED-BootAnimation.h new file mode 100644 index 00000000..dcd4f616 --- /dev/null +++ b/src/LED-BootAnimation.h @@ -0,0 +1,10 @@ +#pragma once + +#include "LEDControl.h" + +class LEDBootAnimation : LEDMode { + public: + LEDBootAnimation (void); + + virtual void setup (void) final; +}; diff --git a/src/LED-BreatheEffect.cpp b/src/LED-BreatheEffect.cpp new file mode 100644 index 00000000..69928d77 --- /dev/null +++ b/src/LED-BreatheEffect.cpp @@ -0,0 +1,14 @@ +#include "LED-BreatheEffect.h" + +LEDBreatheEffect::LEDBreatheEffect (void) { + state.brightness = 0; + state.fadeAmount = 1; + + LEDControl.mode_add (this); +} + +void +LEDBreatheEffect::update (void) { + cRGB color = breath_compute (&state); + LEDControl.set_all_leds_to (color); +} diff --git a/src/LED-BreatheEffect.h b/src/LED-BreatheEffect.h new file mode 100644 index 00000000..67b0c48c --- /dev/null +++ b/src/LED-BreatheEffect.h @@ -0,0 +1,14 @@ +#pragma once + +#include "LEDControl.h" +#include "LEDUtils.h" + +class LEDBreatheEffect : LEDMode { + public: + LEDBreatheEffect (void); + + virtual void update (void) final; + + private: + BreathState state; +}; diff --git a/src/LED-ChaseEffect.cpp b/src/LED-ChaseEffect.cpp new file mode 100644 index 00000000..8a212e37 --- /dev/null +++ b/src/LED-ChaseEffect.cpp @@ -0,0 +1,22 @@ +#include "LED-ChaseEffect.h" + +LEDChaseEffect::LEDChaseEffect (void) { + LEDControl.mode_add (this); +} + +void +LEDChaseEffect::update (void) { + if (current_chase_counter++ < chase_threshold) { + return; + } + current_chase_counter = 0; + led_set_crgb_at(pos - (chase_sign* chase_pixels), {0, 0, 0}); + led_set_crgb_at(pos, {0, 0, 0}); + + pos += chase_sign; + if (pos >= LED_COUNT || pos <= 0) { + chase_sign = -chase_sign; + } + led_set_crgb_at(pos, {0, 0, 255}); + led_set_crgb_at(pos - (chase_sign * chase_pixels), {255, 0, 0}); +} diff --git a/src/LED-ChaseEffect.h b/src/LED-ChaseEffect.h new file mode 100644 index 00000000..54f81a08 --- /dev/null +++ b/src/LED-ChaseEffect.h @@ -0,0 +1,18 @@ +#pragma once + +#include "LEDControl.h" +#include "LEDUtils.h" + +class LEDChaseEffect : LEDMode { + public: + LEDChaseEffect (void); + + virtual void update (void) final; + + private: + uint8_t pos = 0; + int8_t chase_sign = 1; //negative values when it's going backwar + uint8_t chase_pixels = 5; + uint8_t current_chase_counter = 0; + static const uint8_t chase_threshold = 20; +}; diff --git a/src/LED-Numlock.cpp b/src/LED-Numlock.cpp new file mode 100644 index 00000000..78c110c6 --- /dev/null +++ b/src/LED-Numlock.cpp @@ -0,0 +1,50 @@ +#include "LED-Numlock.h" +#include "LEDUtils.h" + +static uint8_t numpadIndex; +static uint8_t storedLEDMode; +static uint8_t us; + +LEDNumlock::LEDNumlock (uint8_t numpadIdx) { + numpadIndex = numpadIdx; + us = LEDControl.mode_add (this); + loop_hook_add (this->loopHook); + + breathState.brightness = 0; + breathState.fadeAmount = 1; +} + +void +LEDNumlock::setup (void) { + if (temporary_keymap != numpadIndex) { + LEDControl.next_mode (); + } +} + +void +LEDNumlock::update (void) { + for (uint8_t i = 0; i < 44; i++) { + led_set_crgb_at(i, {0, 0, 0}); + } + for (uint8_t i = 44; i < LED_COUNT; i++) { + led_set_crgb_at(i, {255, 0, 0}); + } + + cRGB color = breath_compute (&breathState); + led_set_crgb_at (60, color); +} + +void +LEDNumlock::loopHook (void) { + if (temporary_keymap == numpadIndex) { + if (storedLEDMode != us) { + storedLEDMode = LEDControl.get_mode (); + } + LEDControl.set_mode (us); + } + + if (temporary_keymap != numpadIndex && + LEDControl.get_mode () == us) { + LEDControl.set_mode (storedLEDMode); + } +} diff --git a/src/LED-Numlock.h b/src/LED-Numlock.h new file mode 100644 index 00000000..29826924 --- /dev/null +++ b/src/LED-Numlock.h @@ -0,0 +1,17 @@ +#pragma once + +#include "LEDControl.h" +#include "LEDUtils.h" + +class LEDNumlock : LEDMode { + public: + LEDNumlock (uint8_t numpadIndex); + + virtual void update (void) final; + virtual void setup (void) final; + + private: + static void loopHook (void); + + BreathState breathState; +}; diff --git a/src/LED-RainbowEffect.cpp b/src/LED-RainbowEffect.cpp new file mode 100644 index 00000000..5b5653ae --- /dev/null +++ b/src/LED-RainbowEffect.cpp @@ -0,0 +1,50 @@ +#include "LED-RainbowEffect.h" + +LEDRainbowEffect::LEDRainbowEffect (void) { + LEDControl.mode_add (this); +} + +void +LEDRainbowEffect::update (void) { + if (rainbow_current_ticks++ < rainbow_ticks) { + return; + } else { + rainbow_current_ticks = 0; + } + + cRGB rainbow = hsv_to_rgb(rainbow_hue, rainbow_saturation, rainbow_value); + + rainbow_hue += rainbow_steps; + if (rainbow_hue >= 255) { + rainbow_hue -= 255; + } + LEDControl.set_all_leds_to(rainbow); +} + +// --------- + +LEDRainbowWaveEffect::LEDRainbowWaveEffect (void) { + LEDControl.mode_add (this); +} + +void +LEDRainbowWaveEffect::update (void) { + if (rainbow_current_ticks++ < rainbow_wave_ticks) { + return; + } else { + rainbow_current_ticks = 0; + } + + for (uint8_t i = 0; i < LED_COUNT; i++) { + uint16_t key_hue = rainbow_hue +16*(i/4); + if (key_hue >= 255) { + key_hue -= 255; + } + cRGB rainbow = hsv_to_rgb(key_hue, rainbow_saturation, rainbow_value); + led_set_crgb_at (i, rainbow); + } + rainbow_hue += rainbow_wave_steps; + if (rainbow_hue >= 255) { + rainbow_hue -= 255; + } +} diff --git a/src/LED-RainbowEffect.h b/src/LED-RainbowEffect.h new file mode 100644 index 00000000..ae02d5b6 --- /dev/null +++ b/src/LED-RainbowEffect.h @@ -0,0 +1,39 @@ +#pragma once + +#include "LEDControl.h" +#include "LEDUtils.h" + +class LEDRainbowEffect : LEDMode { + public: + LEDRainbowEffect (void); + + virtual void update (void) final; + + private: + uint16_t rainbow_hue = 0; //stores 0 to 614 + + static const uint8_t rainbow_steps = 1; //number of hues we skip in a 360 range per update + long rainbow_current_ticks = 0; + static const long rainbow_ticks = 10; //delays between update + + static const byte rainbow_saturation = 255; + static const byte rainbow_value = 50; + +}; + +class LEDRainbowWaveEffect : LEDMode { + public: + LEDRainbowWaveEffect (void); + + virtual void update (void) final; + + private: + uint16_t rainbow_hue = 0; //stores 0 to 614 + + static const uint8_t rainbow_wave_steps = 1; //number of hues we skip in a 360 range per update + long rainbow_current_ticks = 0; + static const long rainbow_wave_ticks = 10; //delays between update + + static const byte rainbow_saturation = 255; + static const byte rainbow_value = 50; +}; diff --git a/src/LED-SolidColor.cpp b/src/LED-SolidColor.cpp new file mode 100644 index 00000000..84a57126 --- /dev/null +++ b/src/LED-SolidColor.cpp @@ -0,0 +1,13 @@ +#include "LED-SolidColor.h" + +LEDSolidColor::LEDSolidColor (uint8_t r, uint8_t g, uint8_t b) { + this->r = r; + this->g = g; + this->b = b; + LEDControl.mode_add (this); +} + +void +LEDSolidColor::init (void) { + LEDControl.set_all_leds_to (r, g, b); +} diff --git a/src/LED-SolidColor.h b/src/LED-SolidColor.h new file mode 100644 index 00000000..562a02d1 --- /dev/null +++ b/src/LED-SolidColor.h @@ -0,0 +1,13 @@ +#pragma once + +#include "LEDControl.h" + +class LEDSolidColor : LEDMode { + public: + LEDSolidColor (uint8_t r, uint8_t g, uint8_t b); + + virtual void init (void) final; + + private: + uint8_t r, g, b; +}; diff --git a/src/LEDControl.cpp b/src/LEDControl.cpp index b0321a3e..cdc2f650 100644 --- a/src/LEDControl.cpp +++ b/src/LEDControl.cpp @@ -1,322 +1,85 @@ #include "LEDControl.h" - - LEDControl_::LEDControl_(void) { - led_off.r = 0; - led_off.g = 0; - led_off.b = 0; - led_steady.r = 0; - led_steady.g = 255; - led_steady.b = 0; - led_blue.r = 0; - led_blue.g = 0; - led_blue.b = 255; - led_dark_blue.r = 0; - led_dark_blue.g = 0; - led_dark_blue.b = 127; - led_red.r = 255; - led_red.g = 0; - led_red.b = 0; - led_dark_red.r = 127; - led_dark_red.g = 0; - led_dark_red.b = 0; - -} - - -void LEDControl_::initialize_led_mode(uint8_t mode) { - set_all_leds_to(led_off); - - switch (mode) { - - case LED_MODE_RED: - set_all_leds_to(100,0,0) ; - break; - case LED_MODE_ORANGE: - set_all_leds_to(100,30,0) ; - break; - case LED_MODE_YELLOW: - set_all_leds_to(90,70,0) ; - break; - - case LED_MODE_GREEN: - set_all_leds_to(0,200,0) ; - break; - - case LED_MODE_BLUE: - set_all_leds_to(0,30,160) ; - break; - case LED_MODE_INDIGO: - set_all_leds_to(0,0,200) ; - break; - case LED_MODE_VIOLET: - set_all_leds_to(100,0,120) ; - break; - case LED_MODE_OFF: - break; - case LED_MODE_BREATHE: - break; - - case LED_MODE_RAINBOW: - break; - case LED_MODE_RAINBOW_WAVE: - break; - case LED_MODE_CHASE: - break; - default: - break; - } + memset (modes, 0, LED_MAX_MODES * sizeof (modes[0])); } -void LEDControl_::set_all_leds_to(uint8_t r, uint8_t g, uint8_t b) { - cRGB color; - color.r=r; - color.g=g; - color.b=b; - set_all_leds_to(color); -} -void LEDControl_::set_all_leds_to(cRGB color) { - for (uint8_t i = 0; i < LED_COUNT; i++) { - led_set_crgb_at(i, color); - } -} - - -void LEDControl_::next_mode() { - if (led_mode++ >= LED_MODES) { - led_mode = 0; - } -} - -void LEDControl_::set_mode(uint8_t mode) { - led_mode = mode; -} - - - - -void LEDControl_::update(uint8_t current_keymap) { - if (current_keymap == NUMPAD_KEYMAP) { - if (led_mode != LED_SPECIAL_MODE_NUMLOCK) { - stored_led_mode = led_mode; - } - led_mode = LED_SPECIAL_MODE_NUMLOCK; - } - if (current_keymap != NUMPAD_KEYMAP && - led_mode == LED_SPECIAL_MODE_NUMLOCK - ) { - led_mode = stored_led_mode; - } - +void +LEDControl_::next_mode (void) { + mode++; - if (led_mode != last_led_mode) { - initialize_led_mode(led_mode); - } - switch (led_mode) { + if (mode >= LED_MAX_MODES) { + mode = 0; + return; + } - case LED_MODE_OFF: - break; - case LED_MODE_BREATHE: - effect_breathe_update(); - break; - case LED_MODE_RAINBOW: - effect_rainbow_update(); - break; - case LED_MODE_RAINBOW_WAVE: - effect_rainbow_wave_update(); - break; - case LED_MODE_CHASE: - effect_chase_update(); - break; - case LED_SPECIAL_MODE_NUMLOCK: - effect_numlock_update(); - break; - default: - break; - } + if (modes[mode]) + return; - led_sync(); - last_led_mode = led_mode; + mode = 0; } +void +LEDControl_::setup (void) { + set_all_leds_to ({0, 0, 0}); - -void LEDControl_::effect_numlock_update() { - for (uint8_t i = 0; i < 44; i++) { - led_set_crgb_at(i, led_off); - } - for (uint8_t i = 44; i < LED_COUNT; i++) { - led_set_crgb_at(i, led_red); - } - led_compute_breath(); - led_set_crgb_at(60, led_breathe); // make numlock breathe + for (uint8_t i = 0; i < LED_MAX_MODES; i++) { + if (modes[i]) + (modes[i]->setup) (); + } } +void +LEDControl_::update (void) { + if (previousMode != mode) { + set_all_leds_to ({0, 0, 0}); + (modes[mode]->init) (); + } -void LEDControl_::led_compute_breath() { - // algorithm from http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/ - breathe_brightness = (exp(sin(millis()/2000.0*PI)) - 0.36787944)*108.0; - // change the brightness for next time through the loop: - //breathe_brightness = breathe_brightness + breathe_fadeAmount; + (modes[mode]->update) (); - // reverse the direction of the fading at the ends of the fade: - if (breathe_brightness == 0 || breathe_brightness == 150) { - breathe_fadeAmount = -breathe_fadeAmount ; - } + led_sync (); - - hsv_to_rgb(&led_breathe,200, 255, breathe_brightness); + previousMode = mode; } -void LEDControl_::effect_breathe_update() { - led_compute_breath(); - set_all_leds_to(led_breathe); +void +LEDControl_::set_mode (uint8_t mode) { + if (mode < LED_MAX_MODES) + this->mode = mode; } -void LEDControl_::effect_chase_update() { - if (current_chase_counter++ < chase_threshold) { - return; - } - current_chase_counter = 0; - led_set_crgb_at(pos - (chase_sign* chase_pixels), led_off); - led_set_crgb_at(pos, led_off); - - pos += chase_sign; - if (pos >= LED_COUNT || pos <= 0) { - chase_sign = -chase_sign; - } - led_set_crgb_at(pos, led_blue); - led_set_crgb_at(pos - (chase_sign * chase_pixels), led_red); +uint8_t +LEDControl_::get_mode (void) { + return mode; } -void LEDControl_::effect_rainbow_update() { - if (rainbow_current_ticks++ < rainbow_ticks) { - return; - } else { - rainbow_current_ticks = 0; - } - hsv_to_rgb( &rainbow, rainbow_hue, rainbow_saturation, rainbow_value); - rainbow_hue += rainbow_steps; - if (rainbow_hue >= 255) { - rainbow_hue -= 255; - } - set_all_leds_to(rainbow); -} - -void LEDControl_::effect_rainbow_wave_update() { - if (rainbow_current_ticks++ < rainbow_wave_ticks) { - return; - } else { - rainbow_current_ticks = 0; - } - - for (uint8_t i = 0; i < LED_COUNT; i++) { - uint16_t key_hue = rainbow_hue +16*(i/4); - if (key_hue >= 255) { - key_hue -= 255; - } - hsv_to_rgb(&rainbow, key_hue, rainbow_saturation, rainbow_value); - led_set_crgb_at(i,rainbow); - } - rainbow_hue += rainbow_wave_steps; - if (rainbow_hue >= 255) { - rainbow_hue -= 255; - } -} - -void LEDControl_::boot_animation() { - set_all_leds_to(led_off); - - type_letter(LED_K); - type_letter(LED_E); - type_letter(LED_Y); - type_letter(LED_B); - type_letter(LED_O); - type_letter(LED_A); - type_letter(LED_R); - type_letter(LED_D); - type_letter(LED_I); - type_letter(LED_O); - type_letter(LED_SPACE); - type_letter(LED_0); - type_letter(LED_PERIOD); - type_letter(LED_9); - led_mode = LED_MODE_RAINBOW; - +int8_t +LEDControl_::mode_add (LEDMode *mode) { + for (int i = 0; i < LED_MAX_MODES; i++) { + if (modes[i]) + continue; + modes[i] = mode; + return i; + } + return -1; } -void LEDControl_::type_letter(uint8_t letter) { - led_set_crgb_at(letter,led_red); - led_sync(); - delay(250); - led_set_crgb_at(letter,led_off); - led_sync(); - delay(10); - +void +LEDControl_::set_all_leds_to(uint8_t r, uint8_t g, uint8_t b) { + cRGB color; + color.r=r; + color.g=g; + color.b=b; + set_all_leds_to(color); } - -// From http://web.mit.edu/storborg/Public/hsvtorgb.c - talk to Scott about licensing -void LEDControl_::hsv_to_rgb(cRGB *cRGB, uint16_t h, uint16_t s, uint16_t v) { - /* HSV to RGB conversion function with only integer - * math */ - uint16_t region, fpart, p, q, t; - - if(s == 0) { - /* color is grayscale */ - cRGB->r = cRGB->g = cRGB->b = v; - return; - } - - /* make hue 0-5 */ - region = (h *6) >> 8; - /* find remainder part, make it from 0-255 */ - fpart = (h*6) - (region <<8); - - /* calculate temp vars, doing integer multiplication */ - p = (v * (255 - s)) >> 8; - q = (v * (255 - ((s * fpart) >> 8))) >> 8; - t = (v * (255 - ((s * (255 - fpart)) >> 8))) >> 8; - - /* assign temp vars based on color cone region */ - switch(region) { - case 0: - cRGB->r = v; - cRGB->g = t; - cRGB->b = p; - break; - case 1: - cRGB->r = q; - cRGB->g = v; - cRGB->b = p; - break; - case 2: - cRGB->r = p; - cRGB->g = v; - cRGB->b = t; - break; - case 3: - cRGB->r = p; - cRGB->g = q; - cRGB->b = v; - break; - case 4: - cRGB->r = t; - cRGB->g = p; - cRGB->b = v; - break; - default: - cRGB->r = v; - cRGB->g = p; - cRGB->b = q; - break; - } - - return; +void +LEDControl_::set_all_leds_to(cRGB color) { + for (uint8_t i = 0; i < LED_COUNT; i++) { + led_set_crgb_at(i, color); + } } - - LEDControl_ LEDControl; diff --git a/src/LEDControl.h b/src/LEDControl.h index bea7be8d..c18cc045 100644 --- a/src/LEDControl.h +++ b/src/LEDControl.h @@ -3,93 +3,32 @@ #include #include "KeyboardConfig.h" +#define LED_MAX_MODES 24 -#define LED_MODES 12 -#define LED_MODE_OFF 0 - -#define LED_MODE_RED 1 -#define LED_MODE_ORANGE 2 -#define LED_MODE_YELLOW 3 -#define LED_MODE_GREEN 4 -#define LED_MODE_BLUE 5 -#define LED_MODE_INDIGO 6 -#define LED_MODE_VIOLET 7 - - -#define LED_MODE_BREATHE 8 -#define LED_MODE_RAINBOW 9 -#define LED_MODE_RAINBOW_WAVE 10 -#define LED_MODE_CHASE 11 - - - - -#define LED_SPECIAL_MODE_NUMLOCK 100 - +class LEDMode { + public: + virtual void setup (void) {}; + virtual void init (void) {}; + virtual void update (void) {}; +}; class LEDControl_ { public: LEDControl_(void); - void next_mode(); - void boot_animation(); - void update(uint8_t current_keymap); - void type_letter(uint8_t letter); + void next_mode(void); + void setup(void); + void update(void); void set_mode(uint8_t mode); - void set_all_leds_to(uint8_t r, uint8_t g, uint8_t b); - void effect_rainbow_update(); + uint8_t get_mode(); - private: - uint8_t led_mode = 0; - uint8_t last_led_mode = 0; - uint8_t stored_led_mode = 0; - uint8_t pos = 0; - void hsv_to_rgb(cRGB *cRGB, uint16_t h, uint16_t s, uint16_t v); + int8_t mode_add (LEDMode *mode); - cRGB led_off; - cRGB led_steady; - cRGB led_blue; - cRGB led_dark_blue; - cRGB led_red; - cRGB led_dark_red; - cRGB led_breathe; - cRGB rainbow; - - uint16_t rainbow_hue = 0; //stores 0 to 614 - - static const uint8_t rainbow_steps = 1; //number of hues we skip in a 360 range per update - static const uint8_t rainbow_wave_steps=1; //number of hues we skip in a 360 range per update - - static const byte rainbow_saturation = 255; - static const byte rainbow_value = 50; - - static const long rainbow_wave_ticks = 10; //delays between update - static const long rainbow_ticks = 10; //delays between update - long rainbow_current_ticks=0; - - uint8_t breathe_brightness = 0; // how bright the LED is - int8_t breathe_fadeAmount=1; // how many points to fade the LED by (can be negative) - int8_t chase_sign =1; //negative values when it's going backwar - uint8_t chase_pixels=5; - uint8_t current_chase_counter = 0; - static const uint8_t chase_threshold = 20; -// End RGB stuff - void led_compute_breath(); - void effect_breathe_init(); - void effect_rainbow_init(); - void effect_chase_init(); - void effect_steady_init(); - void effect_heatmap_init(); - - void effect_breathe_update(); - void effect_rainbow_wave_update(); - void effect_chase_update(); - void effect_steady_update(); - void effect_heatmap_update(); - void effect_numlock_update(); + void set_all_leds_to(uint8_t r, uint8_t g, uint8_t b); void set_all_leds_to(cRGB color); - void initialize_led_mode(uint8_t mode); + + private: + LEDMode *modes[LED_MAX_MODES]; + uint8_t previousMode, mode; }; extern LEDControl_ LEDControl; - -extern byte NUMPAD_KEYMAP; diff --git a/src/LEDUtils.cpp b/src/LEDUtils.cpp new file mode 100644 index 00000000..458c8705 --- /dev/null +++ b/src/LEDUtils.cpp @@ -0,0 +1,78 @@ +#include "LEDUtils.h" + +cRGB +breath_compute (BreathState *state) { + // algorithm from http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/ + state->brightness = (exp(sin(millis()/2000.0*PI)) - 0.36787944)*108.0; + // change the brightness for next time through the loop: + //state->brightness = state->brightness + state->fadeAmount; + + // reverse the direction of the fading at the ends of the fade: + if (state->brightness == 0 || state->brightness == 150) { + state->fadeAmount = -state->fadeAmount ; + } + + return hsv_to_rgb(200, 255, state->brightness); +} + +// From http://web.mit.edu/storborg/Public/hsvtorgb.c - talk to Scott about licensing +cRGB +hsv_to_rgb(uint16_t h, uint16_t s, uint16_t v) { + cRGB color; + + /* HSV to RGB conversion function with only integer + * math */ + uint16_t region, fpart, p, q, t; + + if(s == 0) { + /* color is grayscale */ + color.r = color.g = color.b = v; + return color; + } + + /* make hue 0-5 */ + region = (h *6) >> 8; + /* find remainder part, make it from 0-255 */ + fpart = (h*6) - (region <<8); + + /* calculate temp vars, doing integer multiplication */ + p = (v * (255 - s)) >> 8; + q = (v * (255 - ((s * fpart) >> 8))) >> 8; + t = (v * (255 - ((s * (255 - fpart)) >> 8))) >> 8; + + /* assign temp vars based on color cone region */ + switch(region) { + case 0: + color.r = v; + color.g = t; + color.b = p; + break; + case 1: + color.r = q; + color.g = v; + color.b = p; + break; + case 2: + color.r = p; + color.g = v; + color.b = t; + break; + case 3: + color.r = p; + color.g = q; + color.b = v; + break; + case 4: + color.r = t; + color.g = p; + color.b = v; + break; + default: + color.r = v; + color.g = p; + color.b = q; + break; + } + + return color; +} diff --git a/src/LEDUtils.h b/src/LEDUtils.h new file mode 100644 index 00000000..184388f6 --- /dev/null +++ b/src/LEDUtils.h @@ -0,0 +1,11 @@ +#pragma once + +#include "KeyboardConfig.h" + +typedef struct BreathState { + uint8_t brightness = 0; // how bright the LED is + int8_t fadeAmount = 1; // how many points to fade the LED by (can be negative) +}; + +cRGB breath_compute (BreathState *state); +cRGB hsv_to_rgb(uint16_t h, uint16_t s, uint16_t v); diff --git a/src/TestMode.cpp b/src/TestMode.cpp index 4edc0239..1de2c6c1 100644 --- a/src/TestMode.cpp +++ b/src/TestMode.cpp @@ -1,5 +1,8 @@ #include "KeyboardioFirmware.h" #include "TestMode.h" +#include "LED-RainbowEffect.h" + +static LEDRainbowEffect testRainbowEffect; TestMode_::TestMode_(void) { } @@ -39,7 +42,7 @@ void TestMode_::TestLEDs(void) { delay(1000); // rainbow for 10 seconds for(auto i=0; i<10000; i++ ) { - LEDControl.effect_rainbow_update(); + testRainbowEffect.update(); led_sync(); delay(1); }