rgb_matrix_effects.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // Copyright 2021 Victor Toni (@vitoni)
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "rgb_matrix_effects.h"
  4. #include <rgb_matrix.h>
  5. #include <lib/lib8tion/lib8tion.h>
  6. #include "utils.h"
  7. /*
  8. Offset used to start at the right point in th curve to avoid big jumps in brightness
  9. 0 => 0% (signed) => 50% (unsigned)
  10. 64 => 100% (signed) => 100% (unsigned)
  11. 128 => 0% (signed) => 50% (unsigned)
  12. 192 => -100% (signed) => 0% (unsigned)
  13. */
  14. enum PHASE {
  15. PHASE_ZERO_RAISING
  16. ,PHASE_HIGH
  17. ,PHASE_ZERO_FALLING
  18. ,PHASE_LOW
  19. };
  20. /**
  21. * @brief Calculates the offset so that a specific time is aligned to a specific point in the sine curve.
  22. * @param[in] time The time for which the offset shopuld be calculated.
  23. * @param[in] phase Phase which should be reached with the offset
  24. * @see PHASE
  25. */
  26. uint8_t offset_for_time(const uint8_t time, const uint8_t phase) {
  27. switch (phase) {
  28. case PHASE_ZERO_RAISING:
  29. return 0 - time;
  30. case PHASE_HIGH:
  31. return 64 - time;
  32. case PHASE_ZERO_FALLING:
  33. return 128 - time;
  34. case PHASE_LOW:
  35. return 192 - time;
  36. default:
  37. return 0;
  38. }
  39. }
  40. /**
  41. * @brief Scales down `g_rgb_timer` so that it can be used for RGB effects.
  42. * @return scaled down timer
  43. * @see rgb_time_2_scale_w_factor()
  44. */
  45. uint8_t rgb_time_2_scale(void) {
  46. static const uint8_t factor = 1;
  47. return rgb_time_2_scale_w_factor(factor);
  48. }
  49. /*
  50. * Used to slow down RGB speed.
  51. */
  52. static const uint8_t rgb_speed_divisor = 8;
  53. /**
  54. * @brief Scales down `g_rgb_timer` so that it can be used for RGB effects.
  55. * @details Usually these calculations aredone internally by some RGB effects.
  56. This method exposed to scaling so that all effects to have same timebase. If `rgb_matrix_config.speed` all effects are affected the same.
  57. * @param[in] factor The factor can be used to speed up some operations in relation to others.
  58. * @return scaled down timer taking into account the given factor
  59. * @see g_rgb_timer
  60. * @see rgb_matrix_config.speed
  61. */
  62. uint8_t rgb_time_2_scale_w_factor(const uint8_t rgb_speed_factor) {
  63. const uint8_t scaled_time = scale16by8(g_rgb_timer, rgb_matrix_config.speed * rgb_speed_factor / rgb_speed_divisor);
  64. return scaled_time;
  65. }
  66. /**
  67. * @brief Inverse function to calculate time required to execute `timer` steps.
  68. * @details This method allows calculation of the time needed to execute N `timer`steps.
  69. Usefull when using a scaled down time but requiring the time needed to perform these steps.
  70. * @param[in] scaled_time scaled down timer to inverse to time
  71. * @return time corresponding to scaled down time
  72. * @see rgb_time_2_scale()
  73. */
  74. uint16_t scale_2_rgb_time(const uint8_t scaled_time) {
  75. const uint16_t time = scaled_time * rgb_speed_divisor * UINT8_MAX / rgb_matrix_config.speed;
  76. return time;
  77. }
  78. bool fade_in_ranged(const uint8_t time, const uint8_t range_min, const uint8_t range_max) {
  79. static const uint8_t max_delta = 1;
  80. return scaled_sin_up(time, range_min, range_max, max_delta, &(rgb_matrix_config.hsv.v));
  81. }
  82. bool fade_out_ranged(const uint8_t time, const uint8_t range_min, const uint8_t range_max) {
  83. static const uint8_t max_delta = 1;
  84. return scaled_sin_down(time, range_min, range_max, max_delta, &(rgb_matrix_config.hsv.v));
  85. }
  86. /**
  87. * @brief Convenience method to eventually skip the value part when setting HSV.
  88. * @details When setting HSV this includes the value/brightness.
  89. As changing brightness might interfer with fading or breathing effects,
  90. this method can skip the value part of HSV (depending on the preprocessor flag: RGB_FADE_IN).
  91. * @param[in] hue Hue
  92. * @param[in] sat Saturation
  93. * @param[in] hue Value (brightness)
  94. * @see rgb_matrix_sethsv_noeeprom()
  95. */
  96. void rgb_matrix_sethsv_noeeprom_user(const uint16_t hue, const uint8_t sat, const uint8_t val) {
  97. #if defined(RGB_FADE_IN) || defined(RGB_IDLE_TIMEOUT)
  98. rgb_matrix_config.hsv.h = hue;
  99. rgb_matrix_config.hsv.s = sat;
  100. // omitting setting the value to avoid interfering with effects
  101. // rgb_matrix_config.hsv.v = val;
  102. #else
  103. rgb_matrix_sethsv_noeeprom(hue, sat, val);
  104. #endif
  105. }
  106. #if defined(RGB_FADE_IN) || defined(RGB_IDLE_TIMEOUT)
  107. /**
  108. * @brief Calculates the time offset required by fade in.
  109. * @details Using an arbitrary timer any point on the sine curve might be pointed to.
  110. * The offest is calculated so that
  111. * a) the point is at the lowest point in the curve and the curve is raising
  112. * 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).
  113. * @param[in] time Current time usually represented by (usually scaled) timer
  114. * @return Offset required so that time matches the current brightness
  115. */
  116. uint8_t calc_fade_in_offset(const uint8_t time) {
  117. static const uint8_t max_steps = UINT8_MAX/2;
  118. static const uint8_t range_min = 0;
  119. static const uint8_t range_max = RGB_MATRIX_MAXIMUM_BRIGHTNESS;
  120. // start at the right point in the sine curve
  121. uint8_t time_offset = offset_for_time(time, PHASE_LOW);
  122. // find the right offset to match the current brightness
  123. for (int i = 1; i < max_steps; i++) {
  124. const uint8_t value = scaled_sin(time + time_offset + 1, range_min, range_max);
  125. if (in_range(value, range_min, range_max) && value < rgb_matrix_config.hsv.v) {
  126. time_offset++;
  127. } else {
  128. break;
  129. }
  130. }
  131. return time_offset;
  132. }
  133. /**
  134. * @brief Increases value/brightness until reaching RGB_MATRIX_MAXIMUM_BRIGHTNESS based on given timer.
  135. * @param[in] time A (usually scaled) timer
  136. * @return Returns `true` if RGB_MATRIX_MAXIMUM_BRIGHTNESS has been reached, `false` otherwise.
  137. */
  138. bool fade_in(const uint8_t time) {
  139. static const uint8_t range_min = 0;
  140. static const uint8_t range_max = RGB_MATRIX_MAXIMUM_BRIGHTNESS;
  141. return fade_in_ranged(time, range_min, range_max);
  142. }
  143. #endif
  144. #if defined(RGB_DISABLE_WITH_FADE_OUT) || defined(RGB_IDLE_TIMEOUT)
  145. /**
  146. * @brief Calculates the time offset required by fade out.
  147. * @details Using an arbitrary timer any point on the Sinus curve might be pointed to.
  148. * The offest is calculated so that
  149. * a) the point is at the highest point in the curve and the curve is failing
  150. * b) the point is near the current brightness (eg. fade out might be called while on breath effect).
  151. * @param[in] time Current time usually represented by a(usually scaled) timer
  152. * @return Offset required so that time matches the current brightness
  153. */
  154. uint8_t calc_fade_out_offset(const uint8_t time) {
  155. static const uint8_t range_min = 0;
  156. static const uint8_t range_max = RGB_MATRIX_MAXIMUM_BRIGHTNESS;
  157. // start at the right point in the sin() curve
  158. uint8_t time_offset = offset_for_time(time, PHASE_HIGH);
  159. // find the right offset to match the current brightness
  160. for (int i = 1; i < 127; i++) {
  161. const uint8_t value = scaled_sin(time + time_offset + 1, range_min, range_max);
  162. if (in_range(value, range_min, range_max) && rgb_matrix_config.hsv.v < value) {
  163. time_offset++;
  164. } else {
  165. break;
  166. }
  167. }
  168. return time_offset;
  169. }
  170. #endif
  171. #if defined(RGB_DISABLE_WITH_FADE_OUT)
  172. /**
  173. * @brief Decreases value/brightness until reaching 0 based on given timer.
  174. * @param[in] time A (usually scaled) timer
  175. * @return Returns `true` if 0 has been reached, `false` otherwise.
  176. */
  177. bool fade_out(const uint8_t time) {
  178. static const uint8_t range_min = 0;
  179. static const uint8_t range_max = RGB_MATRIX_MAXIMUM_BRIGHTNESS;
  180. return fade_out_ranged(time, range_min, range_max);
  181. }
  182. #endif
  183. #if defined(RGB_IDLE_TIMEOUT)
  184. /**
  185. * @brief Decreases value/brightness until reaching `RGB_IDLE_MINIMUM_BRIGHTNESS` based on given timer.
  186. * @param[in] time A (usually scaled) timer
  187. * @return Returns `true` if `RGB_IDLE_MINIMUM_BRIGHTNESS` has been reached, `false` otherwise.
  188. */
  189. bool idle_fade_out(const uint8_t time) {
  190. static const uint8_t range_min = RGB_IDLE_MINIMUM_BRIGHTNESS;
  191. static const uint8_t range_max = RGB_MATRIX_MAXIMUM_BRIGHTNESS;
  192. return fade_out_ranged(time, range_min, range_max);
  193. }
  194. #if defined(RGB_IDLE_BREATHE)
  195. /**
  196. * @brief Changes value/brightness to create a breathing effect based on given timer.
  197. * @details Brightness will breathe in the range starting from `RGB_IDLE_MINIMUM_BRIGHTNESS` to `RGB_IDLE_MAXIMUM_BRIGHTNESS`.
  198. * @param[in] time A (usually scaled) timer
  199. */
  200. void idle_breathe(const uint8_t time) {
  201. static const uint8_t range_min = RGB_IDLE_MINIMUM_BRIGHTNESS;
  202. static const uint8_t range_max = RGB_IDLE_MAXIMUM_BRIGHTNESS;
  203. rgb_matrix_config.hsv.v = scaled_sin(time, range_min, range_max);
  204. }
  205. #endif // RGB_IDLE_BREATHE
  206. #endif // RGB_IDLE_TIMEOUT