diff options
Diffstat (limited to 'users')
-rw-r--r-- | users/cedrikl/cedrikl.c | 36 | ||||
-rw-r--r-- | users/cedrikl/cedrikl.h | 21 | ||||
-rw-r--r-- | users/cedrikl/config.h | 25 | ||||
-rw-r--r-- | users/cedrikl/rules.mk | 4 | ||||
-rw-r--r-- | users/drashna/oled/oled_stuff.c | 13 | ||||
-rw-r--r-- | users/drashna/oled/oled_stuff.h | 2 | ||||
-rw-r--r-- | users/vitoni/readme.adoc | 16 | ||||
-rw-r--r-- | users/vitoni/rgb_matrix_effects.c | 236 | ||||
-rw-r--r-- | users/vitoni/rgb_matrix_effects.h | 174 | ||||
-rw-r--r-- | users/vitoni/rules.mk | 4 | ||||
-rw-r--r-- | users/vitoni/utils.c | 129 | ||||
-rw-r--r-- | users/vitoni/utils.h | 80 | ||||
-rw-r--r-- | users/vitoni/vitoni.c | 131 | ||||
-rw-r--r-- | users/vitoni/vitoni.h | 30 | ||||
-rw-r--r-- | users/wanleg/rules.mk | 2 |
15 files changed, 894 insertions, 9 deletions
diff --git a/users/cedrikl/cedrikl.c b/users/cedrikl/cedrikl.c new file mode 100644 index 0000000000..0479e22b5d --- /dev/null +++ b/users/cedrikl/cedrikl.c @@ -0,0 +1,36 @@ +/* Copyright 2021 Cedrik Lussier @cedrikl +.* Directly inspired from the work of jonavin https://github.com/qmk/qmk_firmware/tree/master/keyboards/gmmk/pro/ansi/keymaps/jonavin + +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 <http://www.gnu.org/licenses/>. +*/ + + +#include QMK_KEYBOARD_H +#include "cedrikl.h" + +// Turn on/off NUM LOCK if current state is different +void activate_numlock(bool turn_on) { + if (host_keyboard_led_state().num_lock != turn_on) { + tap_code(KC_NUMLOCK); + } +} + + +// INITIAL STARTUP + +void keyboard_post_init_user(void) { + #ifdef STARTUP_NUMLOCK_ON + activate_numlock(true); // turn on Num lock by default so that the numpad layer always has predictable results + #endif // STARTUP_NUMLOC_ON +} diff --git a/users/cedrikl/cedrikl.h b/users/cedrikl/cedrikl.h new file mode 100644 index 0000000000..e25d274664 --- /dev/null +++ b/users/cedrikl/cedrikl.h @@ -0,0 +1,21 @@ +/* Copyright 2021 Cedrik Lussier @cedrikl +.* Directly inspired from the work of jonavin https://github.com/qmk/qmk_firmware/tree/master/keyboards/gmmk/pro/ansi/keymaps/jonavin + +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 <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +// OTHER FUNCTION PROTOTYPE +void activate_numlock(bool turn_on); diff --git a/users/cedrikl/config.h b/users/cedrikl/config.h new file mode 100644 index 0000000000..741a2fe470 --- /dev/null +++ b/users/cedrikl/config.h @@ -0,0 +1,25 @@ +/* Copyright 2021 Cedrik Lussier @cedrikl +.* Directly inspired from the work of jonavin https://github.com/qmk/qmk_firmware/tree/master/keyboards/gmmk/pro/ansi/keymaps/jonavin + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#ifdef RGB_MATRIX_ENABLE + #define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_SOLID_COLOR + //#define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_CYCLE_ALL + #define RGB_DISABLE_WHEN_USB_SUSPENDED + #define RGB_MATRIX_STARTUP_VAL 120 +#endif diff --git a/users/cedrikl/rules.mk b/users/cedrikl/rules.mk new file mode 100644 index 0000000000..b5ee62c43a --- /dev/null +++ b/users/cedrikl/rules.mk @@ -0,0 +1,4 @@ +SRC += cedrikl.c +ifeq ($(strip $(STARTUP_NUMLOCK_ON)), yes) + OPT_DEFS += -DSTARTUP_NUMLOCK_ON +endif diff --git a/users/drashna/oled/oled_stuff.c b/users/drashna/oled/oled_stuff.c index eeca010de0..440b905fd0 100644 --- a/users/drashna/oled/oled_stuff.c +++ b/users/drashna/oled/oled_stuff.c @@ -466,9 +466,8 @@ void render_wpm(uint8_t padding) { #endif } -#if defined(KEYBOARD_handwired_tractyl_manuform) || defined(KEYBOARD_bastardkb_charybdis) -extern kb_config_data_t kb_config; -void render_pointing_dpi_status(uint8_t padding) { +#if defined(POINTING_DEVICE_ENABLE) +void render_pointing_dpi_status(uint16_t cpi, uint8_t padding) { oled_write_P(PSTR("CPI:"), false); if (padding) { for (uint8_t n = padding - 1; n > 0; n--) { @@ -476,7 +475,7 @@ void render_pointing_dpi_status(uint8_t padding) { } } - oled_write(get_u16_str(kb_config.device_cpi, ' '), false); + oled_write(get_u16_str(cpi, ' '), false); } #endif @@ -827,11 +826,11 @@ void oled_driver_render_logo_left(void) { # elif defined(WPM_ENABLE) render_wpm(1); # endif - oled_set_cursor(7, 3); + oled_write_P(PSTR(" "), false); # if defined(KEYBOARD_handwired_tractyl_manuform) - render_pointing_dpi_status(0); + render_pointing_dpi_status(kb_config_data.device_cpi, 1); # elif defined(KEYBOARD_bastardkb_charybdis) - render_pointing_dpi_status(1); + render_pointing_dpi_status(, 1); # endif oled_set_cursor(0, 6); #else diff --git a/users/drashna/oled/oled_stuff.h b/users/drashna/oled/oled_stuff.h index 985153c2ff..6ef2ac14cd 100644 --- a/users/drashna/oled/oled_stuff.h +++ b/users/drashna/oled/oled_stuff.h @@ -34,7 +34,7 @@ void render_bootmagic_status(void); void render_user_status(void); void oled_driver_render_logo(void); void render_wpm(uint8_t padding); -void render_pointing_dpi_status(uint8_t padding); +void render_pointing_dpi_status(uint16_t cpi, uint8_t padding); void oled_driver_render_logo_left(void); void oled_driver_render_logo_right(void); diff --git a/users/vitoni/readme.adoc b/users/vitoni/readme.adoc new file mode 100644 index 0000000000..acf65793d2 --- /dev/null +++ b/users/vitoni/readme.adoc @@ -0,0 +1,16 @@ += User functions + +Functions are mostly related to changing the RGB lights depending on user interaction and when idling. + +== utils.h + +Common functions are declared in link:utils.h[]. These function are not directly RGB related but used to modify state and calculate values. + +== rgb_matrix_effects.h + +Functions in link:rgb_matrix_effects.h[] make use of common function in `utils.h` and are used to create to RGB matrix effects such as fading or breathing. + +== vitoni.h + +The functions declared in link:vitoni.h[] are used as entry points for usage of RGB effects. +One entry point is `matrix_scan` based for regular task while the other is `process_record` based for user activity tasks. diff --git a/users/vitoni/rgb_matrix_effects.c b/users/vitoni/rgb_matrix_effects.c new file mode 100644 index 0000000000..3a13e99bc7 --- /dev/null +++ b/users/vitoni/rgb_matrix_effects.c @@ -0,0 +1,236 @@ +// Copyright 2021 Victor Toni (@vitoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "rgb_matrix_effects.h" + +#include <rgb_matrix.h> +#include <lib/lib8tion/lib8tion.h> + +#include "utils.h" + +/* + Offset used to start at the right point in th curve to avoid big jumps in brightness + 0 => 0% (signed) => 50% (unsigned) + 64 => 100% (signed) => 100% (unsigned) + 128 => 0% (signed) => 50% (unsigned) + 192 => -100% (signed) => 0% (unsigned) +*/ +enum PHASE { + PHASE_ZERO_RAISING + ,PHASE_HIGH + ,PHASE_ZERO_FALLING + ,PHASE_LOW +}; + +/** + * @brief Calculates the offset so that a specific time is aligned to a specific point in the sine curve. + * @param[in] time The time for which the offset shopuld be calculated. + * @param[in] phase Phase which should be reached with the offset + * @see PHASE + */ +uint8_t offset_for_time(const uint8_t time, const uint8_t phase) { + switch (phase) { + case PHASE_ZERO_RAISING: + return 0 - time; + case PHASE_HIGH: + return 64 - time; + case PHASE_ZERO_FALLING: + return 128 - time; + case PHASE_LOW: + return 192 - time; + default: + return 0; + } +} + +/** + * @brief Scales down `g_rgb_timer` so that it can be used for RGB effects. + * @return scaled down timer + * @see rgb_time_2_scale_w_factor() + */ +uint8_t rgb_time_2_scale(void) { + static const uint8_t factor = 1; + return rgb_time_2_scale_w_factor(factor); +} + +/* + * Used to slow down RGB speed. + */ +static const uint8_t rgb_speed_divisor = 8; + +/** + * @brief Scales down `g_rgb_timer` so that it can be used for RGB effects. + * @details Usually these calculations aredone internally by some RGB effects. + This method exposed to scaling so that all effects to have same timebase. If `rgb_matrix_config.speed` all effects are affected the same. + * @param[in] factor The factor can be used to speed up some operations in relation to others. + * @return scaled down timer taking into account the given factor + * @see g_rgb_timer + * @see rgb_matrix_config.speed + */ +uint8_t rgb_time_2_scale_w_factor(const uint8_t rgb_speed_factor) { + const uint8_t scaled_time = scale16by8(g_rgb_timer, rgb_matrix_config.speed * rgb_speed_factor / rgb_speed_divisor); + + return scaled_time; +} + +/** + * @brief Inverse function to calculate time required to execute `timer` steps. + * @details This method allows calculation of the time needed to execute N `timer`steps. + Usefull when using a scaled down time but requiring the time needed to perform these steps. + * @param[in] scaled_time scaled down timer to inverse to time + * @return time corresponding to scaled down time + * @see rgb_time_2_scale() + */ +uint16_t scale_2_rgb_time(const uint8_t scaled_time) { + const uint16_t time = scaled_time * rgb_speed_divisor * UINT8_MAX / rgb_matrix_config.speed; + + return time; +} + +bool fade_in_ranged(const uint8_t time, const uint8_t range_min, const uint8_t range_max) { + static const uint8_t max_delta = 1; + return scaled_sin_up(time, range_min, range_max, max_delta, &(rgb_matrix_config.hsv.v)); +} + +bool fade_out_ranged(const uint8_t time, const uint8_t range_min, const uint8_t range_max) { + static const uint8_t max_delta = 1; + return scaled_sin_down(time, range_min, range_max, max_delta, &(rgb_matrix_config.hsv.v)); +} + +/** + * @brief Convenience method to eventually skip the value part when setting HSV. + * @details When setting HSV this includes the value/brightness. + As changing brightness might interfer with fading or breathing effects, + this method can skip the value part of HSV (depending on the preprocessor flag: RGB_FADE_IN). + * @param[in] hue Hue + * @param[in] sat Saturation + * @param[in] hue Value (brightness) + * @see rgb_matrix_sethsv_noeeprom() + */ +void rgb_matrix_sethsv_noeeprom_user(const uint16_t hue, const uint8_t sat, const uint8_t val) { +#if defined(RGB_FADE_IN) || defined(RGB_IDLE_TIMEOUT) + rgb_matrix_config.hsv.h = hue; + rgb_matrix_config.hsv.s = sat; + // omitting setting the value to avoid interfering with effects +// rgb_matrix_config.hsv.v = val; +#else + rgb_matrix_sethsv_noeeprom(hue, sat, val); +#endif +} + +#if defined(RGB_FADE_IN) || defined(RGB_IDLE_TIMEOUT) +/** + * @brief Calculates the time offset required by fade in. + * @details Using an arbitrary timer any point on the sine curve might be pointed to. + * The offest is calculated so that + * a) the point is at the lowest point in the curve and the curve is raising + * b) the point is near the current brightness (eg. fade in might be called while fading out and the lowest value has not yet been reached). + * @param[in] time Current time usually represented by (usually scaled) timer + * @return Offset required so that time matches the current brightness + */ +uint8_t calc_fade_in_offset(const uint8_t time) { + static const uint8_t max_steps = UINT8_MAX/2; + static const uint8_t range_min = 0; + static const uint8_t range_max = RGB_MATRIX_MAXIMUM_BRIGHTNESS; + + // start at the right point in the sine curve + uint8_t time_offset = offset_for_time(time, PHASE_LOW); + + // find the right offset to match the current brightness + for (int i = 1; i < max_steps; i++) { + const uint8_t value = scaled_sin(time + time_offset + 1, range_min, range_max); + if (in_range(value, range_min, range_max) && value < rgb_matrix_config.hsv.v) { + time_offset++; + } else { + break; + } + } + + return time_offset; +} + +/** + * @brief Increases value/brightness until reaching RGB_MATRIX_MAXIMUM_BRIGHTNESS based on given timer. + * @param[in] time A (usually scaled) timer + * @return Returns `true` if RGB_MATRIX_MAXIMUM_BRIGHTNESS has been reached, `false` otherwise. + */ +bool fade_in(const uint8_t time) { + static const uint8_t range_min = 0; + static const uint8_t range_max = RGB_MATRIX_MAXIMUM_BRIGHTNESS; + + return fade_in_ranged(time, range_min, range_max); +} +#endif + +#if defined(RGB_DISABLE_WITH_FADE_OUT) || defined(RGB_IDLE_TIMEOUT) +/** + * @brief Calculates the time offset required by fade out. + * @details Using an arbitrary timer any point on the Sinus curve might be pointed to. + * The offest is calculated so that + * a) the point is at the highest point in the curve and the curve is failing + * b) the point is near the current brightness (eg. fade out might be called while on breath effect). + * @param[in] time Current time usually represented by a(usually scaled) timer + * @return Offset required so that time matches the current brightness + */ +uint8_t calc_fade_out_offset(const uint8_t time) { + static const uint8_t range_min = 0; + static const uint8_t range_max = RGB_MATRIX_MAXIMUM_BRIGHTNESS; + + // start at the right point in the sin() curve + uint8_t time_offset = offset_for_time(time, PHASE_HIGH); + + // find the right offset to match the current brightness + for (int i = 1; i < 127; i++) { + const uint8_t value = scaled_sin(time + time_offset + 1, range_min, range_max); + if (in_range(value, range_min, range_max) && rgb_matrix_config.hsv.v < value) { + time_offset++; + } else { + break; + } + } + + return time_offset; +} +#endif + +#if defined(RGB_DISABLE_WITH_FADE_OUT) +/** + * @brief Decreases value/brightness until reaching 0 based on given timer. + * @param[in] time A (usually scaled) timer + * @return Returns `true` if 0 has been reached, `false` otherwise. + */ +bool fade_out(const uint8_t time) { + static const uint8_t range_min = 0; + static const uint8_t range_max = RGB_MATRIX_MAXIMUM_BRIGHTNESS; + + return fade_out_ranged(time, range_min, range_max); +} +#endif + +#if defined(RGB_IDLE_TIMEOUT) +/** + * @brief Decreases value/brightness until reaching `RGB_IDLE_MINIMUM_BRIGHTNESS` based on given timer. + * @param[in] time A (usually scaled) timer + * @return Returns `true` if `RGB_IDLE_MINIMUM_BRIGHTNESS` has been reached, `false` otherwise. + */ +bool idle_fade_out(const uint8_t time) { + static const uint8_t range_min = RGB_IDLE_MINIMUM_BRIGHTNESS; + static const uint8_t range_max = RGB_MATRIX_MAXIMUM_BRIGHTNESS; + + return fade_out_ranged(time, range_min, range_max); +} + +#if defined(RGB_IDLE_BREATHE) +/** + * @brief Changes value/brightness to create a breathing effect based on given timer. + * @details Brightness will breathe in the range starting from `RGB_IDLE_MINIMUM_BRIGHTNESS` to `RGB_IDLE_MAXIMUM_BRIGHTNESS`. + * @param[in] time A (usually scaled) timer + */ +void idle_breathe(const uint8_t time) { + static const uint8_t range_min = RGB_IDLE_MINIMUM_BRIGHTNESS; + static const uint8_t range_max = RGB_IDLE_MAXIMUM_BRIGHTNESS; + + rgb_matrix_config.hsv.v = scaled_sin(time, range_min, range_max); +} +#endif // RGB_IDLE_BREATHE +#endif // RGB_IDLE_TIMEOUT diff --git a/users/vitoni/rgb_matrix_effects.h b/users/vitoni/rgb_matrix_effects.h new file mode 100644 index 0000000000..ed74500b18 --- /dev/null +++ b/users/vitoni/rgb_matrix_effects.h @@ -0,0 +1,174 @@ +// Copyright 2021 Victor Toni (@vitoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <stdint.h> +#include <stdbool.h> + +/** + * States reflecting the state of the keyboard. + * Dependeing on these states various effects can set for the RGB matrix. + */ +enum states { + REGULAR //!< when in regular use +#if defined(RGB_IDLE_TIMEOUT) + ,IDLE_FADE_OUT //!< when started idling + ,IDLE //!< when idling +#endif +#if defined(RGB_FADE_IN) || defined(RGB_IDLE_TIMEOUT) + ,FADE_IN //!< when starting initially or before going back to REGULAR +#endif +#if defined(RGB_DISABLE_WITH_FADE_OUT) + ,FADE_OUT //!< before supending +#endif + ,SUSPENDED //!< expecting to be suspended by RGB_DISABLE_TIMEOUT any time +}; + +/** + * @brief Scales down `g_rgb_timer` so that it can be used for RGB effects. + * @details Usually these calculations aredone internally by some RGB effects. + This method exposed to scaling so that all effects to have same timebase. If `rgb_matrix_config.speed` all effects are affected the same. + * @param[in] factor The factor can be used to speed up some operations in relation to others. + * @return scaled down timer taking into account the given factor + * @see g_rgb_timer + * @see rgb_matrix_config.speed + */ +uint8_t rgb_time_2_scale_w_factor(const uint8_t factor); + +/** + * @brief Scales down `g_rgb_timer` so that it can be used for RGB effects. + * @return scaled down timer + * @see rgb_time_2_scale_w_factor() + */ +uint8_t rgb_time_2_scale(void); + +/** + * @brief Inverse function to calculate time required to execute `timer` steps. + * @details This method allows calculation of the time needed to execute N `timer`steps. + Usefull when using a scaled down time but requiring the time needed to perform these steps. + * @param[in] scaled_time scaled down timer to inverse to time + * @return time corresponding to scaled down time + * @see rgb_time_2_scale() + */ +uint16_t scale_2_rgb_time(const uint8_t scaled_time); + +/** + * @brief Convenience method to eventually skip the value part when setting HSV. + * @details When setting HSV this includes the value/brightness. + As changing brightness might interfer with fading or breathing effects, + this method can skip the value part of HSV (depending on the preprocessor flag: RGB_FADE_IN). + * @param[in] hue Hue + * @param[in] sat Saturation + * @param[in] hue Value (brightness) + * @see rgb_matrix_sethsv_noeeprom() + */ +void rgb_matrix_sethsv_noeeprom_user(const uint16_t hue, const uint8_t sat, const uint8_t val); + +#if defined(RGB_FADE_IN) || defined(RGB_DISABLE_WITH_FADE_OUT) || defined(RGB_IDLE_TIMEOUT) +# if defined(RGB_MATRIX_MAXIMUM_BRIGHTNESS) +# if (RGB_MATRIX_MAXIMUM_BRIGHTNESS) < 1 +# error "RGB_MATRIX_MAXIMUM_BRIGHTNESS must not be less than ONE" +# endif +# if UINT8_MAX < (RGB_MATRIX_MAXIMUM_BRIGHTNESS) +# error "RGB_MATRIX_MAXIMUM_BRIGHTNESS must not be larger than UINT8_MAX" +# endif +# else +# define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200 +# endif +#endif + +#if defined(RGB_FADE_IN) || defined(RGB_IDLE_TIMEOUT) +/** + * @brief Calculates the time offset required by fade in. + * @details Using an arbitrary timer any point on the sine curve might be pointed to. + * The offset is calculated so that + * a) the point is at the lowest point in the curve and the curve is raising + * b) the point is near the current brightness (eg. fade in might be called while fading out and the lowest value has not yet been reached). + * @param[in] time Current time usually represented by a(usually scaled) timer + * @return Offset required so that time matches the current brightness + */ +uint8_t calc_fade_in_offset(const uint8_t time); + +/** + * @brief Increases value/brightness until reaching RGB_MATRIX_MAXIMUM_BRIGHTNESS based on given timer. + * @param[in] time A (usually scaled) timer + * @return Returns `true` if RGB_MATRIX_MAXIMUM_BRIGHTNESS has been reached, `false` otherwise. + */ +bool fade_in(const uint8_t time); +#endif + +#if defined(RGB_DISABLE_WITH_FADE_OUT) +# if !defined(RGB_DISABLE_TIMEOUT) +# warning "RGB_DISABLE_WITH_FADE_OUT expects RGB_DISABLE_TIMEOUT to be defined" +# endif +#endif + +#if defined(RGB_DISABLE_WITH_FADE_OUT) || defined(RGB_IDLE_TIMEOUT) +/** + * @brief Calculates the time offset required by fade out. + * @details Using an arbitrary timer any point on the Sinus curve might be pointed to. + * The offest is calculated so that + * a) the point is at the highest point in the curve and the curve is failing + * b) the point is near the current brightness (eg. fade out might be called while on breath effect). + * @param[in] time Current time usually represented by a(usually scaled) timer + * @return Offset required so that time matches the current brightness + */ +uint8_t calc_fade_out_offset(const uint8_t time); +#endif + +#if defined(RGB_DISABLE_WITH_FADE_OUT) +/** + * @brief Decreases value/brightness until reaching 0 based on given timer. + * @param[in] time A (usually scaled) timer + * @return Returns `true` if 0 has been reached, `false` otherwise. + */ +bool fade_out(const uint8_t time); +#endif + +#if defined(RGB_IDLE_TIMEOUT) +# if RGB_IDLE_TIMEOUT < 0 +# error "RGB_IDLE_TIMEOUT must not be less than ZERO" +# endif +# if !defined(RGB_IDLE_MINIMUM_BRIGHTNESS) + // minimum brightness when idling +# define RGB_IDLE_MINIMUM_BRIGHTNESS (RGB_MATRIX_MAXIMUM_BRIGHTNESS/5) +# endif +# if RGB_IDLE_MINIMUM_BRIGHTNESS < 0 +# error "RGB_IDLE_MINIMUM_BRIGHTNESS must not be less than ZERO" +# endif // RGB_IDLE_MINIMUM_BRIGHTNESS < 0 +# if RGB_MATRIX_MAXIMUM_BRIGHTNESS <= RGB_IDLE_MINIMUM_BRIGHTNESS +# error "RGB_IDLE_MINIMUM_BRIGHTNESS must be less than RGB_MATRIX_MAXIMUM_BRIGHTNESS" +# endif // RGB_MATRIX_MAXIMUM_BRIGHTNESS <= RGB_IDLE_MINIMUM_BRIGHTNESS + +/** + * @brief Decreases value/brightness until reaching `RGB_IDLE_MINIMUM_BRIGHTNESS` based on given timer. + * @param[in] time A (usually scaled) timer + * @return Returns `true` if `RGB_IDLE_MINIMUM_BRIGHTNESS` has been reached, `false` otherwise. + */ +bool idle_fade_out(const uint8_t time); + +#if defined(RGB_IDLE_BREATHE) +# if !defined(RGB_IDLE_MAXIMUM_BRIGHTNESS) + // maximum brightness when idling +# define RGB_IDLE_MAXIMUM_BRIGHTNESS (RGB_MATRIX_MAXIMUM_BRIGHTNESS*3/5) +# endif +# if !(0 <= RGB_IDLE_MAXIMUM_BRIGHTNESS) +# error "RGB_IDLE_MINIMUM_BRIGHTNESS must not be less than ZERO, was: " RGB_IDLE_MAXIMUM_BRIGHTNESS +# endif // RGB_IDLE_MAXIMUM_BRIGHTNESS < 0 +# if !(RGB_IDLE_MINIMUM_BRIGHTNESS < RGB_IDLE_MAXIMUM_BRIGHTNESS) +# error "RGB_IDLE_MINIMUM_BRIGHTNESS must be less than RGB_IDLE_MAXIMUM_BRIGHTNESS" +# endif // RGB_IDLE_MAXIMUM_BRIGHTNESS <= RGB_IDLE_MINIMUM_BRIGHTNESS +# if !(RGB_IDLE_MAXIMUM_BRIGHTNESS <= RGB_MATRIX_MAXIMUM_BRIGHTNESS) +# error "RGB_IDLE_MAXIMUM_BRIGHTNESS must be less than or equal to RGB_MATRIX_MAXIMUM_BRIGHTNESS" +# endif // RGB_MATRIX_MAXIMUM_BRIGHTNESS <= RGB_IDLE_MAXIMUM_BRIGHTNESS + +/** + * @brief Changes value/brightness to create a breathing effect based on given timer. + * @details Brightness will breathe in the range starting from `RGB_IDLE_MINIMUM_BRIGHTNESS` to `RGB_IDLE_MAXIMUM_BRIGHTNESS`. + * @param[in] time A (usually scaled) timer + */ +void idle_breathe(const uint8_t time); +#endif // RGB_IDLE_BREATHE + +#endif // RGB_IDLE_TIMEOUT diff --git a/users/vitoni/rules.mk b/users/vitoni/rules.mk new file mode 100644 index 0000000000..2f3b0d15e5 --- /dev/null +++ b/users/vitoni/rules.mk @@ -0,0 +1,4 @@ +SRC += \ + vitoni.c \ + utils.c \ + rgb_matrix_effects.c diff --git a/users/vitoni/utils.c b/users/vitoni/utils.c new file mode 100644 index 0000000000..fb011570e4 --- /dev/null +++ b/users/vitoni/utils.c @@ -0,0 +1,129 @@ +// Copyright 2021 Victor Toni (@vitoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "utils.h" + +#include <lib/lib8tion/lib8tion.h> + +/** +* @brief Changes `*value` to `new_value`. +* @param[in,out] value Pointer to variable to be changed. +* @param[in] new_value Value to be changed. +* @param[in,out] changed Flag indicating `*value` and `new_value` were different. +*/ +void update_value(uint8_t *value, const uint8_t new_value, bool *changed) { + if (new_value != (*value)) { + (*changed) = true; + (*value) = new_value; + } +} + +/** +* @brief Checks whether a value is in the given range. +* @param[in] value Value to be checked. +* @param[in] range_min Lower bound of range (inclusive). +* @param[in] range_max Upper bound of range (inclusive). +* @return `true` if (range_min <= value <= range_max), `false` otherwise +*/ +bool in_range(const uint8_t value, const uint8_t range_min, const uint8_t range_max) { + return range_min <= value && value <= range_max; +} + +/** +* @brief Calculates the sine value based on sin8() and scales it to the given range (unsigned). +* +* Table of values for unscaled sin8() eg. a theta of 0 results to 128 and a theta of 255 (240+15) results to 125. + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + +---------------------------------------------------------------- + 0: 128 131 134 137 140 143 146 149 152 155 158 161 164 167 170 173 + 16: 177 179 182 184 187 189 192 194 197 200 202 205 207 210 212 215 + 32: 218 219 221 223 224 226 228 229 231 233 234 236 238 239 241 243 + 48: 245 245 246 246 247 248 248 249 250 250 251 251 252 253 253 254 + 64: 255 254 253 253 252 251 251 250 250 249 248 248 247 246 246 245 + 80: 245 243 241 239 238 236 234 233 231 229 228 226 224 223 221 219 + 96: 218 215 212 210 207 205 202 200 197 194 192 189 187 184 182 179 + 112: 177 173 170 167 164 161 158 155 152 149 146 143 140 137 134 131 + 128: 128 125 122 119 116 113 110 107 104 101 98 95 92 89 86 83 + 144: 79 77 74 72 69 67 64 62 59 56 54 51 49 46 44 41 + 160: 38 37 35 33 32 30 28 27 25 23 22 20 18 17 15 13 + 176: 11 11 10 10 9 8 8 7 6 6 5 5 4 3 3 2 + 192: 1 2 3 3 4 5 5 6 6 7 8 8 9 10 10 11 + 208: 11 13 15 17 18 20 22 23 25 27 28 30 32 33 35 37 + 224: 38 41 44 46 49 51 54 56 59 62 64 67 69 72 74 77 + 240: 79 83 86 89 92 95 98 101 104 107 110 113 116 119 122 125 +* +* @param[in] theta Angle (a full circle mapped to 0-255) used as input for sine calculation. +* @param[in] range_min Lower bound of range (inclusive). +* @param[in] range_max Upper bound of range (inclusive). +* @return Calculated sine value mapped to the given range. +*/ +uint8_t scaled_sin(const uint8_t theta, const uint8_t range_min, const uint8_t range_max) { + const uint8_t range = range_max - range_min; + return scale8(sin8(theta), range) + range_min; +} + +/** +* @brief Increases the given value until reaching range_max. +* The increments occur following an upwards sine wave (scaled from range_min to range_max). +* @param[in] theta Angle (a full circle mapped to 0-255) used as input for sine calculation. +* @param[in] range_min Lower bound of range (inclusive). +* @param[in] range_max Upper bound of range (inclusive). +* @param[in] max_delta Maximum delta between value and range_max (due to values being integers and eventually not fully matching). +* @param[in,out] value Reference of variable to be increased +* @return `true` if value and range_max are within a delta of 3 (chosen by fair dice rolling), `false` otherwise +* @see scaled_sin() +*/ +bool scaled_sin_up(const uint8_t theta, const uint8_t range_min, const uint8_t range_max, const uint8_t max_delta, uint8_t *value) { + // ensure upper range bound + if (range_max <= (*value)) { + (*value) = range_max; + return true; + } + + const uint8_t new_value = scaled_sin(theta, range_min, range_max); + if (in_range(new_value, range_min, range_max) && (*value) < new_value) { + (*value) = new_value; + + return range_max == (*value); + } + + const uint8_t delta = range_max - (*value); + if (delta <= max_delta) { + (*value) = range_max; + } + + return delta <= max_delta; +} + +/** +* @brief Decreases the given value until reaching range_min. +* The decrements occur following an downwards sinus wave (scaled from range_min to range_max). +* @param[in] theta Angle (a full circle mapped to 0-255) used as input for sinus calculation. +* @param[in] range_min Lower bound of range (inclusive). +* @param[in] range_max Upper bound of range (inclusive). +* @param[in] max_delta Maximum delta between value and range_min (due to values being integers and eventually not fully matching). +* @param[in,out] value Reference of variable to be decreased +* @return `true` if value and range_max are within a delta of 3 (chosen by fair dice rolling), `false` otherwise +* @see scaled_sin() +*/ +bool scaled_sin_down(const uint8_t theta, const uint8_t range_min, const uint8_t range_max, const uint8_t max_delta, uint8_t *value) { + // ensure lower range bound + if ((*value) <= range_min) { + (*value) = range_min; + return true; + } + + const uint8_t new_value = scaled_sin(theta, range_min, range_max); + if (in_range(new_value, range_min, range_max) && new_value < (*value)) { + (*value) = new_value; + + return range_min == (*value); + } + + const uint8_t delta = (*value) - range_min; + if (delta <= max_delta) { + (*value) = range_min; + } + + return delta <= max_delta; +} diff --git a/users/vitoni/utils.h b/users/vitoni/utils.h new file mode 100644 index 0000000000..987b612d58 --- /dev/null +++ b/users/vitoni/utils.h @@ -0,0 +1,80 @@ +// Copyright 2021 Victor Toni (@vitoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <stdint.h> +#include <stdbool.h> + +/** +* @brief Changes `*value` to `new_value`. +* @param[in,out] value Pointer to variable to be changed. +* @param[in] new_value Value to be changed. +* @param[in,out] changed Flag indicating `*value` and `new_value` were different. +*/ +void update_value(uint8_t *value, const uint8_t new_value, bool *changed); + +/** +* @brief Checks whether a value is in the given range. +* @param[in] value Value to be checked. +* @param[in] range_min Lower bound of range (inclusive). +* @param[in] range_max Upper bound of range (inclusive). +* @return `true` if (range_min <= value <= range_max), `false` otherwise +*/ +bool in_range(const uint8_t value, const uint8_t range_min, const uint8_t range_max); + +/** +* @brief Calculates the sine value based on sin8() and scales it to the given range (unsigned). +* +* Table of values for unscaled sin8() eg. a theta of 0 results to 128 and a theta of 255 (240+15) results to 125. + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + +---------------------------------------------------------------- + 0: 128 131 134 137 140 143 146 149 152 155 158 161 164 167 170 173 + 16: 177 179 182 184 187 189 192 194 197 200 202 205 207 210 212 215 + 32: 218 219 221 223 224 226 228 229 231 233 234 236 238 239 241 243 + 48: 245 245 246 246 247 248 248 249 250 250 251 251 252 253 253 254 + 64: 255 254 253 253 252 251 251 250 250 249 248 248 247 246 246 245 + 80: 245 243 241 239 238 236 234 233 231 229 228 226 224 223 221 219 + 96: 218 215 212 210 207 205 202 200 197 194 192 189 187 184 182 179 + 112: 177 173 170 167 164 161 158 155 152 149 146 143 140 137 134 131 + 128: 128 125 122 119 116 113 110 107 104 101 98 95 92 89 86 83 + 144: 79 77 74 72 69 67 64 62 59 56 54 51 49 46 44 41 + 160: 38 37 35 33 32 30 28 27 25 23 22 20 18 17 15 13 + 176: 11 11 10 10 9 8 8 7 6 6 5 5 4 3 3 2 + 192: 1 2 3 3 4 5 5 6 6 7 8 8 9 10 10 11 + 208: 11 13 15 17 18 20 22 23 25 27 28 30 32 33 35 37 + 224: 38 41 44 46 49 51 54 56 59 62 64 67 69 72 74 77 + 240: 79 83 86 89 92 95 98 101 104 107 110 113 116 119 122 125 +* +* @param[in] theta Angle (a full circle mapped to 0-255) used as input for sine calculation. +* @param[in] range_min Lower bound of range (inclusive). +* @param[in] range_max Upper bound of range (inclusive). +* @return Calculated sine value mapped to the given range. +*/ +uint8_t scaled_sin(const uint8_t theta, const uint8_t range_min, const uint8_t range_max); + +/** +* @brief Increases the given value until reaching range_max. +* The increments occur following an upwards sine wave (scaled from range_min to range_max). +* @param[in] theta Angle (a full circle mapped to 0-255) used as input for sine calculation. +* @param[in] range_min Lower bound of range (inclusive). +* @param[in] range_max Upper bound of range (inclusive). +* @param[in] max_delta Maximum delta between value and range_max (due to values being integers and eventually not fully matching). +* @param[in,out] value Reference of variable to be increased +* @return `true` if value and range_max are within a delta of 3 (chosen by fair dice rolling), `false` otherwise +* @see scaled_sin() +*/ +bool scaled_sin_up(const uint8_t thea, const uint8_t range_min, const uint8_t range_max, const uint8_t max_delta, uint8_t *value); + +/** +* @brief Decreases the given value until reaching range_min. +* The decrements occur following an downwards sinus wave (scaled from range_min to range_max). +* @param[in] theta Angle (a full circle mapped to 0-255) used as input for sinus calculation. +* @param[in] range_min Lower bound of range (inclusive). +* @param[in] range_max Upper bound of range (inclusive). +* @param[in] max_delta Maximum delta between value and range_min (due to values being integers and eventually not fully matching). +* @param[in,out] value Reference of variable to be decreased +* @return `true` if value and range_max are within a delta of 3 (chosen by fair dice rolling), `false` otherwise +* @see scaled_sin() +*/ +bool scaled_sin_down(const uint8_t theta, const uint8_t range_min, const uint8_t range_max, const uint8_t max_delta, uint8_t *value); diff --git a/users/vitoni/vitoni.c b/users/vitoni/vitoni.c new file mode 100644 index 0000000000..2a0ff5c46f --- /dev/null +++ b/users/vitoni/vitoni.c @@ -0,0 +1,131 @@ +// Copyright 2021 Victor Toni (@vitoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "vitoni.h" + +#include <rgb_matrix.h> +#include <lib/lib8tion/lib8tion.h> + +#include "rgb_matrix_effects.h" +#include "utils.h" + +#if defined(RGB_FADE_IN) || defined(RGB_DISABLE_WITH_FADE_OUT) || defined(RGB_IDLE_TIMEOUT) +static uint8_t state; + +// flag used to indicate that offset calculation is needed to adjust the timer, +// so that it matches the index used for sine calculation +static bool calc_offset; + +void matrix_scan_user_rgb(void) { +#if defined(RGB_DISABLE_WITH_FADE_OUT) || defined(RGB_IDLE_TIMEOUT) + const uint8_t time = rgb_time_2_scale(); +#endif + static uint8_t time_offset; + + const uint32_t inactivity_millis = last_input_activity_elapsed(); + +#if defined(RGB_IDLE_TIMEOUT) + if (IDLE != state && RGB_IDLE_TIMEOUT <= inactivity_millis) { + update_value(&state, IDLE_FADE_OUT, &calc_offset); + } +#endif +#if defined(RGB_DISABLE_WITH_FADE_OUT) + const uint32_t fade_out_duration = scale_2_rgb_time(128); + const uint32_t start_fade_out_after_millis = (RGB_DISABLE_TIMEOUT) > fade_out_duration + ? (RGB_DISABLE_TIMEOUT) - fade_out_duration + : 0; + + if (start_fade_out_after_millis <= inactivity_millis) { + update_value(&state, FADE_OUT, &calc_offset); + } +#elif defined(RGB_DISABLE_TIMEOUT) + // having to set brightness "manually" to black as starting point for fade in + // for the time when returning from suspended state + if (RGB_DISABLE_TIMEOUT <= inactivity_millis + 15) { + rgb_matrix_config.hsv.v = 0; + state = SUSPENDED; + } +#endif + + switch(state) { +#if defined(RGB_IDLE_TIMEOUT) + case IDLE_FADE_OUT: + if (calc_offset) { + time_offset = calc_fade_out_offset(time); + + // resetting flag for subsequent calls + calc_offset = false; + } + if (idle_fade_out(time + time_offset)) { + update_value(&state, IDLE, &calc_offset); + } + break; + case IDLE: +#if defined(RGB_IDLE_BREATHE) + if (calc_offset) { + // no need to calculate time_offset since we are aligned already due to IDLE_FADE_OUT + // resetting flag for subsequent calls + calc_offset = false; + } + idle_breathe(time + time_offset); +#endif + break; +#endif +#if defined(RGB_DISABLE_WITH_FADE_OUT) + case FADE_OUT: + if (calc_offset) { + time_offset = calc_fade_out_offset(time); + + // resetting flag for subsequent calls + calc_offset = false; + } + if (fade_out(time + time_offset)) { + update_value(&state, SUSPENDED, &calc_offset); + } + break; +#endif +#if defined(RGB_FADE_IN) || defined(RGB_IDLE_TIMEOUT) + case FADE_IN: + { + // since we want to be active, fade in should be faster than e.g. fading out + const uint8_t fade_in_time = rgb_time_2_scale_w_factor(4); + if (calc_offset) { + time_offset = calc_fade_in_offset(fade_in_time); + + // resetting flag for subsequent calls + calc_offset = false; + } + if (fade_in(fade_in_time + time_offset)) { + update_value(&state, REGULAR, &calc_offset); + } + } + break; +#endif + default: + break; + } +} + +#if defined(RGB_FADE_IN) || defined(RGB_IDLE_TIMEOUT) +bool process_record_user_rgb(const uint16_t keycode, const keyrecord_t *record) { + // if we are in a non regular state we might have faded out (eventually partially) + // so we restore brightness (to max as we don't keep track of manually changed brightness) + // if (REGULAR != state && FADE_IN != state) { + if (FADE_IN != state && REGULAR != state) { + update_value(&state, FADE_IN, &calc_offset); + } + + return true; // Process all other keycodes normally +} + +void suspend_wakeup_init_user(void) { + if (FADE_IN != state) { + // setting brightness to black as starting point for fade in + rgb_matrix_config.hsv.v = 0; + + update_value(&state, FADE_IN, &calc_offset); + } +} +#endif // defined(RGB_FADE_IN) + +#endif // defined(RGB_FADE_IN) || defined(RGB_DISABLE_WITH_FADE_OUT) diff --git a/users/vitoni/vitoni.h b/users/vitoni/vitoni.h new file mode 100644 index 0000000000..1f26037135 --- /dev/null +++ b/users/vitoni/vitoni.h @@ -0,0 +1,30 @@ +// Copyright 2021 Victor Toni (@vitoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <stdint.h> +#include <stdbool.h> + +#include <quantum/action.h> + +#include "rgb_matrix_effects.h" + +/** + * @brief Executes periodic tasks, eg. fading or checking for upcoming supend. + * @details Function declaration as weak as the implementation might "disappear" depending on the RGB settings used. + * The weak declaration avoids having to change `keymap.c`. + */ +__attribute__((weak)) +void matrix_scan_user_rgb(void); + +/** + * @brief Executes tasks based on user activity, eg. fading in. + * @details Function declaration as weak as the implementation might "disappear" depending on the RGB settings used. + * The weak declaration avoids having to change `keymap.c`. + * @param[in] keycode + * @param[in] record + * @return `false` if further processing should be stopped, `true` otherwise + */ +__attribute__((weak)) +bool process_record_user_rgb(const uint16_t keycode, const keyrecord_t *record); diff --git a/users/wanleg/rules.mk b/users/wanleg/rules.mk index 410803512d..de4decf78a 100644 --- a/users/wanleg/rules.mk +++ b/users/wanleg/rules.mk @@ -22,7 +22,7 @@ ifeq ($(strip $(BT)), yes) OPT_DEFS += -DBLUEFRUIT #Adafruit Bluefruit controller settings BLUETOOTH_ENABLE = yes - BLUETOOTH_DRIVER = AdafruitBLE + BLUETOOTH_DRIVER = BluefruitLE F_CPU = 8000000 CONSOLE_ENABLE = no # Console for debug(+400) COMMAND_ENABLE = no # Commands for debug and configuration |