1
0
Fork 0

[Keymap] Add vitoni keymap for GMMK Pro (ISO) (#15006)

* [Keymap] Add vitoni layout for GMMK Pro (ISO)

Keymap has layered cursor keys similar to laptop keyboards.

* Configure RGB defaults for startup

* Configure encoder to change value/brightness on FN layer

* Remove FN layer and add dedicated RGB layer

* Make RGB layer sticky (using TG) to avoid holding FN while configuring RGB

* Add RGB indicators for active layers

* Add RGB indicator for active RESET mode

Signed-off-by: Victor Toni <victor.toni@gmail.com>

* Configure idle / USB suspend settings

* Add RGB fade in when resuming after suspend

* Add RGB fade out before suspend

* Add fade out before idle

* Add breathe effect when idle
This commit is contained in:
Victor Toni 2021-12-27 11:13:12 +01:00 committed by GitHub
parent 6bc870d899
commit 6209122213
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 1072 additions and 0 deletions

16
users/vitoni/readme.adoc Normal file
View file

@ -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.

View file

@ -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

View file

@ -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

4
users/vitoni/rules.mk Normal file
View file

@ -0,0 +1,4 @@
SRC += \
vitoni.c \
utils.c \
rgb_matrix_effects.c

129
users/vitoni/utils.c Normal file
View file

@ -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;
}

80
users/vitoni/utils.h Normal file
View file

@ -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);

131
users/vitoni/vitoni.c Normal file
View file

@ -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)

30
users/vitoni/vitoni.h Normal file
View file

@ -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);