GCC Code Coverage Report


Directory: ./
File: overlays/wled/lib8tion.h
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 53 67 79.1%
Functions: 10 12 83.3%
Branches: 16 18 88.9%

Line Branch Exec Source
1 #ifndef __INC_LIB8TION_H
2 #define __INC_LIB8TION_H
3
4 #include "FastLED.h"
5 #include "lib8tion/types.h"
6
7 #ifndef __INC_LED_SYSDEFS_H
8 #error WTH? led_sysdefs needs to be included first
9 #endif
10
11 /// @file lib8tion.h
12 /// Fast, efficient 8-bit math functions specifically
13 /// designed for high-performance LED programming.
14
15 #include <stdint.h>
16 #include "lib8tion/lib8static.h"
17 #include "lib8tion/qfx.h"
18
19
20 #if !defined(__AVR__)
21 #include <string.h>
22 // for memmove, memcpy, and memset if not defined here
23 #endif // end of !defined(__AVR__)
24
25 #if defined(__arm__)
26
27 #if defined(FASTLED_TEENSY3)
28 // Can use Cortex M4 DSP instructions
29 #define QADD8_C 0
30 #define QADD7_C 0
31 #define QADD8_ARM_DSP_ASM 1
32 #define QADD7_ARM_DSP_ASM 1
33 #else
34 // Generic ARM
35 #define QADD8_C 1
36 #define QADD7_C 1
37 #endif // end of defined(FASTLED_TEENSY3)
38
39 #define QSUB8_C 1
40 #define SCALE8_C 1
41 #define SCALE16BY8_C 1
42 #define SCALE16_C 1
43 #define ABS8_C 1
44 #define MUL8_C 1
45 #define QMUL8_C 1
46 #define ADD8_C 1
47 #define SUB8_C 1
48 #define EASE8_C 1
49 #define AVG8_C 1
50 #define AVG8R_C 1
51 #define AVG7_C 1
52 #define AVG16_C 1
53 #define AVG16R_C 1
54 #define AVG15_C 1
55 #define BLEND8_C 1
56
57 // end of #if defined(__arm__)
58
59 #elif defined(ARDUINO_ARCH_APOLLO3)
60
61 // Default to using the standard C functions for now
62 #define QADD8_C 1
63 #define QADD7_C 1
64 #define QSUB8_C 1
65 #define SCALE8_C 1
66 #define SCALE16BY8_C 1
67 #define SCALE16_C 1
68 #define ABS8_C 1
69 #define MUL8_C 1
70 #define QMUL8_C 1
71 #define ADD8_C 1
72 #define SUB8_C 1
73 #define EASE8_C 1
74 #define AVG8_C 1
75 #define AVG8R_C 1
76 #define AVG7_C 1
77 #define AVG16_C 1
78 #define AVG16R_C 1
79 #define AVG15_C 1
80 #define BLEND8_C 1
81
82 // end of #elif defined(ARDUINO_ARCH_APOLLO3)
83
84 #elif defined(__AVR__)
85
86 // AVR ATmega and friends Arduino
87
88 #define QADD8_C 0
89 #define QADD7_C 0
90 #define QSUB8_C 0
91 #define ABS8_C 0
92 #define ADD8_C 0
93 #define SUB8_C 0
94 #define AVG8_C 0
95 #define AVG8R_C 0
96 #define AVG7_C 0
97 #define AVG16_C 0
98 #define AVG16R_C 0
99 #define AVG15_C 0
100
101 #define QADD8_AVRASM 1
102 #define QADD7_AVRASM 1
103 #define QSUB8_AVRASM 1
104 #define ABS8_AVRASM 1
105 #define ADD8_AVRASM 1
106 #define SUB8_AVRASM 1
107 #define AVG8_AVRASM 1
108 #define AVG8R_AVRASM 1
109 #define AVG7_AVRASM 1
110 #define AVG16_AVRASM 1
111 #define AVG16R_AVRASM 1
112 #define AVG15_AVRASM 1
113
114 // Note: these require hardware MUL instruction
115 // -- sorry, ATtiny!
116 #if !defined(LIB8_ATTINY)
117 #define SCALE8_C 0
118 #define SCALE16BY8_C 0
119 #define SCALE16_C 0
120 #define MUL8_C 0
121 #define QMUL8_C 0
122 #define EASE8_C 0
123 #define BLEND8_C 0
124 #define SCALE8_AVRASM 1
125 #define SCALE16BY8_AVRASM 1
126 #define SCALE16_AVRASM 1
127 #define MUL8_AVRASM 1
128 #define QMUL8_AVRASM 1
129 #define EASE8_AVRASM 1
130 #define CLEANUP_R1_AVRASM 1
131 #define BLEND8_AVRASM 1
132 #else
133 // On ATtiny, we just use C implementations
134 #define SCALE8_C 1
135 #define SCALE16BY8_C 1
136 #define SCALE16_C 1
137 #define MUL8_C 1
138 #define QMUL8_C 1
139 #define EASE8_C 1
140 #define BLEND8_C 1
141 #define SCALE8_AVRASM 0
142 #define SCALE16BY8_AVRASM 0
143 #define SCALE16_AVRASM 0
144 #define MUL8_AVRASM 0
145 #define QMUL8_AVRASM 0
146 #define EASE8_AVRASM 0
147 #define BLEND8_AVRASM 0
148 #endif // end of !defined(LIB8_ATTINY)
149
150 // end of #elif defined(__AVR__)
151
152 #else
153
154 // Doxygen: ignore these macros
155 /// @cond
156
157 // unspecified architecture, so
158 // no ASM, everything in C
159 #define QADD8_C 1
160 #define QADD7_C 1
161 #define QSUB8_C 1
162 #define SCALE8_C 1
163 #define SCALE16BY8_C 1
164 #define SCALE16_C 1
165 #define ABS8_C 1
166 #define MUL8_C 1
167 #define QMUL8_C 1
168 #define ADD8_C 1
169 #define SUB8_C 1
170 #define EASE8_C 1
171 #define AVG8_C 1
172 #define AVG8R_C 1
173 #define AVG7_C 1
174 #define AVG16_C 1
175 #define AVG16R_C 1
176 #define AVG15_C 1
177 #define BLEND8_C 1
178
179 /// @endcond
180
181 #endif
182
183 /// @defgroup lib8tion Fast Math Functions
184 /// Fast, efficient 8-bit math functions specifically
185 /// designed for high-performance LED programming.
186 ///
187 /// Because of the AVR (Arduino) and ARM assembly language
188 /// implementations provided, using these functions often
189 /// results in smaller and faster code than the equivalent
190 /// program using plain "C" arithmetic and logic.
191 ///
192 /// Included are:
193 ///
194 /// - Saturating unsigned 8-bit add and subtract.
195 /// Instead of wrapping around if an overflow occurs,
196 /// these routines just 'clamp' the output at a maxumum
197 /// of 255, or a minimum of 0. Useful for adding pixel
198 /// values. E.g., qadd8( 200, 100) = 255.
199 /// @code
200 /// qadd8( i, j) == MIN( (i + j), 0xFF )
201 /// qsub8( i, j) == MAX( (i - j), 0 )
202 /// @endcode
203 ///
204 /// - Saturating signed 8-bit ("7-bit") add.
205 /// @code
206 /// qadd7( i, j) == MIN( (i + j), 0x7F)
207 /// @endcode
208 ///
209 /// - Scaling (down) of unsigned 8- and 16- bit values.
210 /// Scaledown value is specified in 1/256ths.
211 /// @code
212 /// scale8( i, sc) == (i * sc) / 256
213 /// scale16by8( i, sc) == (i * sc) / 256
214 /// @endcode
215 ///
216 /// Example: scaling a 0-255 value down into a
217 /// range from 0-99:
218 /// @code
219 /// downscaled = scale8( originalnumber, 100);
220 /// @endcode
221 ///
222 /// A special version of scale8 is provided for scaling
223 /// LED brightness values, to make sure that they don't
224 /// accidentally scale down to total black at low
225 /// dimming levels, since that would look wrong:
226 /// @code
227 /// scale8_video( i, sc) = ((i * sc) / 256) +? 1
228 /// @endcode
229 ///
230 /// Example: reducing an LED brightness by a
231 /// dimming factor:
232 /// @code
233 /// new_bright = scale8_video( orig_bright, dimming);
234 /// @endcode
235 ///
236 /// - Fast 8- and 16- bit unsigned random numbers.
237 /// Significantly faster than Arduino random(), but
238 /// also somewhat less random. You can add entropy.
239 /// @code
240 /// random8() == random from 0..255
241 /// random8( n) == random from 0..(N-1)
242 /// random8( n, m) == random from N..(M-1)
243 ///
244 /// random16() == random from 0..65535
245 /// random16( n) == random from 0..(N-1)
246 /// random16( n, m) == random from N..(M-1)
247 ///
248 /// random16_set_seed( k) == seed = k
249 /// random16_add_entropy( k) == seed += k
250 /// @endcode
251 ///
252 /// - Absolute value of a signed 8-bit value.
253 /// @code
254 /// abs8( i) == abs( i)
255 /// @endcode
256 ///
257 /// - 8-bit math operations which return 8-bit values.
258 /// These are provided mostly for completeness,
259 /// not particularly for performance.
260 /// @code
261 /// mul8( i, j) == (i * j) & 0xFF
262 /// add8( i, j) == (i + j) & 0xFF
263 /// sub8( i, j) == (i - j) & 0xFF
264 /// @endcode
265 ///
266 /// - Fast 16-bit approximations of sin and cos.
267 /// Input angle is a uint16_t from 0-65535.
268 /// Output is a signed int16_t from -32767 to 32767.
269 /// @code
270 /// sin16( x) == sin( (x/32768.0) * pi) * 32767
271 /// cos16( x) == cos( (x/32768.0) * pi) * 32767
272 /// @endcode
273 ///
274 /// Accurate to more than 99% in all cases.
275 ///
276 /// - Fast 8-bit approximations of sin and cos.
277 /// Input angle is a uint8_t from 0-255.
278 /// Output is an UNsigned uint8_t from 0 to 255.
279 /// @code
280 /// sin8( x) == (sin( (x/128.0) * pi) * 128) + 128
281 /// cos8( x) == (cos( (x/128.0) * pi) * 128) + 128
282 /// @endcode
283 ///
284 /// Accurate to within about 2%.
285 ///
286 /// - Fast 8-bit "easing in/out" function.
287 /// @code
288 /// ease8InOutCubic(x) == 3(x^2) - 2(x^3)
289 /// ease8InOutApprox(x) ==
290 /// faster, rougher, approximation of cubic easing
291 /// ease8InOutQuad(x) == quadratic (vs cubic) easing
292 /// @endcode
293 ///
294 /// - Cubic, Quadratic, and Triangle wave functions.
295 /// Input is a uint8_t representing phase withing the wave,
296 /// similar to how sin8 takes an angle 'theta'.
297 /// Output is a uint8_t representing the amplitude of
298 /// the wave at that point.
299 /// @code
300 /// cubicwave8( x)
301 /// quadwave8( x)
302 /// triwave8( x)
303 /// @endcode
304 ///
305 /// - Square root for 16-bit integers. About three times
306 /// faster and five times smaller than Arduino's built-in
307 /// generic 32-bit sqrt routine.
308 /// @code
309 /// sqrt16( uint16_t x ) == sqrt( x)
310 /// @endcode
311 ///
312 /// - Dimming and brightening functions for 8-bit
313 /// light values.
314 /// @code
315 /// dim8_video( x) == scale8_video( x, x)
316 /// dim8_raw( x) == scale8( x, x)
317 /// dim8_lin( x) == (x<128) ? ((x+1)/2) : scale8(x,x)
318 /// brighten8_video( x) == 255 - dim8_video( 255 - x)
319 /// brighten8_raw( x) == 255 - dim8_raw( 255 - x)
320 /// brighten8_lin( x) == 255 - dim8_lin( 255 - x)
321 /// @endcode
322 ///
323 /// The dimming functions in particular are suitable
324 /// for making LED light output appear more 'linear'.
325 ///
326 /// - Linear interpolation between two values, with the
327 /// fraction between them expressed as an 8- or 16-bit
328 /// fixed point fraction (fract8 or fract16).
329 /// @code
330 /// lerp8by8( fromU8, toU8, fract8 )
331 /// lerp16by8( fromU16, toU16, fract8 )
332 /// lerp15by8( fromS16, toS16, fract8 )
333 /// == from + (( to - from ) * fract8) / 256)
334 /// lerp16by16( fromU16, toU16, fract16 )
335 /// == from + (( to - from ) * fract16) / 65536)
336 /// map8( in, rangeStart, rangeEnd)
337 /// == map( in, 0, 255, rangeStart, rangeEnd);
338 /// @endcode
339 ///
340 /// - Optimized memmove, memcpy, and memset, that are
341 /// faster than standard avr-libc 1.8.
342 /// @code
343 /// memmove8( dest, src, bytecount)
344 /// memcpy8( dest, src, bytecount)
345 /// memset8( buf, value, bytecount)
346 /// @endcode
347 ///
348 /// - Beat generators which return sine or sawtooth
349 /// waves in a specified number of Beats Per Minute.
350 /// Sine wave beat generators can specify a low and
351 /// high range for the output. Sawtooth wave beat
352 /// generators always range 0-255 or 0-65535.
353 /// @code
354 /// beatsin8( BPM, low8, high8)
355 /// = (sine(beatphase) * (high8-low8)) + low8
356 /// beatsin16( BPM, low16, high16)
357 /// = (sine(beatphase) * (high16-low16)) + low16
358 /// beatsin88( BPM88, low16, high16)
359 /// = (sine(beatphase) * (high16-low16)) + low16
360 /// beat8( BPM) = 8-bit repeating sawtooth wave
361 /// beat16( BPM) = 16-bit repeating sawtooth wave
362 /// beat88( BPM88) = 16-bit repeating sawtooth wave
363 /// @endcode
364 ///
365 /// BPM is beats per minute in either simple form
366 /// e.g. 120, or Q8.8 fixed-point form.
367 /// BPM88 is beats per minute in ONLY Q8.8 fixed-point
368 /// form.
369 ///
370 /// Lib8tion is pronounced like 'libation': lie-BAY-shun
371 ///
372 /// @{
373
374
375
376
377 #include "lib8tion/math8.h"
378 #include "lib8tion/scale8.h"
379 #include "lib8tion/random8.h"
380 #include "lib8tion/trig8.h"
381
382 ///////////////////////////////////////////////////////////////////////
383
384
385
386
387 FASTLED_NAMESPACE_BEGIN
388
389
390 ///////////////////////////////////////////////////////////////////////
391 ///
392 /// @defgroup FloatConversions Float-to-Fixed and Fixed-to-Float Conversions
393 /// Functions to convert between floating point and fixed point types.
394 /// @note Anything involving a "float" on AVR will be slower.
395 /// @{
396
397 /// Conversion from 16-bit fixed point (::sfract15) to IEEE754 32-bit float.
398 LIB8STATIC float sfract15ToFloat( sfract15 y)
399 {
400 return y / 32768.0;
401 }
402
403 /// Conversion from IEEE754 float in the range (-1,1) to 16-bit fixed point (::sfract15).
404 /// @note The extremes of one and negative one are NOT representable! The
405 /// representable range is 0.99996948242 to -0.99996948242, in steps of 0.00003051757.
406 LIB8STATIC sfract15 floatToSfract15( float f)
407 {
408 return f * 32768.0;
409 }
410
411 /// @} FloatConversions
412
413
414
415 ///////////////////////////////////////////////////////////////////////
416 ///
417 /// @defgroup FastMemory Fast Memory Functions for AVR
418 /// Alternatives to memmove, memcpy, and memset that are
419 /// faster on AVR than standard avr-libc 1.8.
420 /// @{
421
422 #if defined(__AVR__) || defined(FASTLED_DOXYGEN)
423 extern "C" {
424 void * memmove8( void * dst, const void * src, uint16_t num ); ///< Faster alternative to memmove() on AVR
425 void * memcpy8 ( void * dst, const void * src, uint16_t num ) __attribute__ ((noinline)); ///< Faster alternative to memcpy() on AVR
426 void * memset8 ( void * ptr, uint8_t value, uint16_t num ) __attribute__ ((noinline)) ; ///< Faster alternative to memset() on AVR
427 }
428 #else
429 // on non-AVR platforms, these names just call standard libc.
430 #define memmove8 memmove
431 #define memcpy8 memcpy
432 #define memset8 memset
433 #endif
434
435 /// @} FastMemory
436
437
438 ///////////////////////////////////////////////////////////////////////
439 ///
440 /// @defgroup LinearInterpolation Linear Interpolation
441 /// Fast linear interpolation functions, such as could be used for Perlin noise, etc.
442 ///
443 /// A note on the structure of the lerp functions:
444 /// The cases for b>a and b<=a are handled separately for
445 /// speed. Without knowing the relative order of a and b,
446 /// the value (a-b) might be overflow the width of a or b,
447 /// and have to be promoted to a wider, slower type.
448 /// To avoid that, we separate the two cases, and are able
449 /// to do all the math in the same width as the arguments,
450 /// which is much faster and smaller on AVR.
451 /// @{
452
453 /// Linear interpolation between two unsigned 8-bit values,
454 /// with 8-bit fraction
455 3656 LIB8STATIC uint8_t lerp8by8( uint8_t a, uint8_t b, fract8 frac)
456 {
457 uint8_t result;
458
2/2
✓ Branch 0 taken 2232 times.
✓ Branch 1 taken 1424 times.
3656 if( b > a) {
459 2232 uint8_t delta = b - a;
460 2232 uint8_t scaled = scale8( delta, frac);
461 2232 result = a + scaled;
462 } else {
463 1424 uint8_t delta = a - b;
464 1424 uint8_t scaled = scale8( delta, frac);
465 1424 result = a - scaled;
466 }
467 3656 return result;
468 }
469
470 /// Linear interpolation between two unsigned 16-bit values,
471 /// with 16-bit fraction
472 LIB8STATIC uint16_t lerp16by16( uint16_t a, uint16_t b, fract16 frac)
473 {
474 uint16_t result;
475 if( b > a ) {
476 uint16_t delta = b - a;
477 uint16_t scaled = scale16(delta, frac);
478 result = a + scaled;
479 } else {
480 uint16_t delta = a - b;
481 uint16_t scaled = scale16( delta, frac);
482 result = a - scaled;
483 }
484 return result;
485 }
486
487 /// Linear interpolation between two unsigned 16-bit values,
488 /// with 8-bit fraction
489 LIB8STATIC uint16_t lerp16by8( uint16_t a, uint16_t b, fract8 frac)
490 {
491 uint16_t result;
492 if( b > a) {
493 uint16_t delta = b - a;
494 uint16_t scaled = scale16by8( delta, frac);
495 result = a + scaled;
496 } else {
497 uint16_t delta = a - b;
498 uint16_t scaled = scale16by8( delta, frac);
499 result = a - scaled;
500 }
501 return result;
502 }
503
504 /// Linear interpolation between two signed 15-bit values,
505 /// with 8-bit fraction
506 LIB8STATIC int16_t lerp15by8( int16_t a, int16_t b, fract8 frac)
507 {
508 int16_t result;
509 if( b > a) {
510 uint16_t delta = b - a;
511 uint16_t scaled = scale16by8( delta, frac);
512 result = a + scaled;
513 } else {
514 uint16_t delta = a - b;
515 uint16_t scaled = scale16by8( delta, frac);
516 result = a - scaled;
517 }
518 return result;
519 }
520
521 /// Linear interpolation between two signed 15-bit values,
522 /// with 8-bit fraction
523 ✗ LIB8STATIC int16_t lerp15by16( int16_t a, int16_t b, fract16 frac)
524 {
525 int16_t result;
526 ✗ if( b > a) {
527 ✗ uint16_t delta = b - a;
528 ✗ uint16_t scaled = scale16( delta, frac);
529 ✗ result = a + scaled;
530 } else {
531 ✗ uint16_t delta = a - b;
532 ✗ uint16_t scaled = scale16( delta, frac);
533 ✗ result = a - scaled;
534 }
535 ✗ return result;
536 }
537
538 /// Map from one full-range 8-bit value into a narrower
539 /// range of 8-bit values, possibly a range of hues.
540 ///
541 /// E.g. map `myValue` into a hue in the range blue..purple..pink..red
542 /// @code
543 /// hue = map8( myValue, HUE_BLUE, HUE_RED);
544 /// @endcode
545 ///
546 /// Combines nicely with the waveform functions (like sin8(), etc)
547 /// to produce continuous hue gradients back and forth:
548 /// @code
549 /// hue = map8( sin8( myValue), HUE_BLUE, HUE_RED);
550 /// @endcode
551 ///
552 /// Mathematically simiar to lerp8by8(), but arguments are more
553 /// like Arduino's "map"; this function is similar to
554 /// @code
555 /// map( in, 0, 255, rangeStart, rangeEnd)
556 /// @endcode
557 ///
558 /// but faster and specifically designed for 8-bit values.
559 ✗ LIB8STATIC uint8_t map8( uint8_t in, uint8_t rangeStart, uint8_t rangeEnd)
560 {
561 ✗ uint8_t rangeWidth = rangeEnd - rangeStart;
562 ✗ uint8_t out = scale8( in, rangeWidth);
563 ✗ out += rangeStart;
564 ✗ return out;
565 }
566
567 /// @} LinearInterpolation
568
569
570 ///////////////////////////////////////////////////////////////////////
571 ///
572 /// @defgroup Easing Easing Functions
573 /// Specify the rate of change of a parameter over time.
574 /// @see http://easings.net
575 /// @{
576
577 /// 8-bit quadratic ease-in / ease-out function.
578 /// Takes around 13 cycles on AVR.
579 #if (EASE8_C == 1) || defined(FASTLED_DOXYGEN)
580 4170 LIB8STATIC uint8_t ease8InOutQuad( uint8_t i)
581 {
582 4170 uint8_t j = i;
583
2/2
✓ Branch 0 taken 2089 times.
✓ Branch 1 taken 2081 times.
4170 if( j & 0x80 ) {
584 2089 j = 255 - j;
585 }
586 4170 uint8_t jj = scale8( j, j);
587 4170 uint8_t jj2 = jj << 1;
588
2/2
✓ Branch 0 taken 2089 times.
✓ Branch 1 taken 2081 times.
4170 if( i & 0x80 ) {
589 2089 jj2 = 255 - jj2;
590 }
591 4170 return jj2;
592 }
593
594 #elif EASE8_AVRASM == 1
595 // This AVR asm version of ease8InOutQuad preserves one more
596 // low-bit of precision than the C version, and is also slightly
597 // smaller and faster.
598 LIB8STATIC uint8_t ease8InOutQuad(uint8_t val) {
599 uint8_t j=val;
600 asm volatile (
601 "sbrc %[val], 7 \n"
602 "com %[j] \n"
603 "mul %[j], %[j] \n"
604 "add r0, %[j] \n"
605 "ldi %[j], 0 \n"
606 "adc %[j], r1 \n"
607 "lsl r0 \n" // carry = high bit of low byte of mul product
608 "rol %[j] \n" // j = (j * 2) + carry // preserve add'l bit of precision
609 "sbrc %[val], 7 \n"
610 "com %[j] \n"
611 "clr __zero_reg__ \n"
612 : [j] "+&a" (j)
613 : [val] "a" (val)
614 : "r0", "r1"
615 );
616 return j;
617 }
618
619 #else
620 #error "No implementation for ease8InOutQuad available."
621 #endif
622
623 /// 16-bit quadratic ease-in / ease-out function.
624 /// C implementation at this point.
625 LIB8STATIC uint16_t ease16InOutQuad( uint16_t i)
626 {
627 uint16_t j = i;
628 if( j & 0x8000 ) {
629 j = 65535 - j;
630 }
631 uint16_t jj = scale16( j, j);
632 uint16_t jj2 = jj << 1;
633 if( i & 0x8000 ) {
634 jj2 = 65535 - jj2;
635 }
636 return jj2;
637 }
638
639
640 /// 8-bit cubic ease-in / ease-out function.
641 /// Takes around 18 cycles on AVR.
642 46267 LIB8STATIC fract8 ease8InOutCubic( fract8 i)
643 {
644 46267 uint8_t ii = scale8_LEAVING_R1_DIRTY( i, i);
645 46267 uint8_t iii = scale8_LEAVING_R1_DIRTY( ii, i);
646
647 46267 uint16_t r1 = (3 * (uint16_t)(ii)) - ( 2 * (uint16_t)(iii));
648
649 /* the code generated for the above *'s automatically
650 cleans up R1, so there's no need to explicitily call
651 cleanup_R1(); */
652
653 46267 uint8_t result = r1;
654
655 // if we got "256", return 255:
656
2/2
✓ Branch 0 taken 1854 times.
✓ Branch 1 taken 44413 times.
46267 if( r1 & 0x100 ) {
657 1854 result = 255;
658 }
659 46267 return result;
660 }
661
662
663 /// Fast, rough 8-bit ease-in/ease-out function.
664 /// Shaped approximately like ease8InOutCubic(),
665 /// it's never off by more than a couple of percent
666 /// from the actual cubic S-curve, and it executes
667 /// more than twice as fast. Use when the cycles
668 /// are more important than visual smoothness.
669 /// Asm version takes around 7 cycles on AVR.
670 #if (EASE8_C == 1) || defined(FASTLED_DOXYGEN)
671 27044 LIB8STATIC fract8 ease8InOutApprox( fract8 i)
672 {
673
2/2
✓ Branch 0 taken 8688 times.
✓ Branch 1 taken 18356 times.
27044 if( i < 64) {
674 // start with slope 0.5
675 8688 i /= 2;
676
2/2
✓ Branch 0 taken 8688 times.
✓ Branch 1 taken 9668 times.
18356 } else if( i > (255 - 64)) {
677 // end with slope 0.5
678 8688 i = 255 - i;
679 8688 i /= 2;
680 8688 i = 255 - i;
681 } else {
682 // in the middle, use slope 192/128 = 1.5
683 9668 i -= 64;
684 9668 i += (i / 2);
685 9668 i += 32;
686 }
687
688 27044 return i;
689 }
690
691 #elif EASE8_AVRASM == 1
692 LIB8STATIC uint8_t ease8InOutApprox( fract8 i)
693 {
694 // takes around 7 cycles on AVR
695 asm volatile (
696 " subi %[i], 64 \n\t"
697 " cpi %[i], 128 \n\t"
698 " brcc Lshift_%= \n\t"
699
700 // middle case
701 " mov __tmp_reg__, %[i] \n\t"
702 " lsr __tmp_reg__ \n\t"
703 " add %[i], __tmp_reg__ \n\t"
704 " subi %[i], 224 \n\t"
705 " rjmp Ldone_%= \n\t"
706
707 // start or end case
708 "Lshift_%=: \n\t"
709 " lsr %[i] \n\t"
710 " subi %[i], 96 \n\t"
711
712 "Ldone_%=: \n\t"
713
714 : [i] "+a" (i)
715 :
716 : "r0"
717 );
718 return i;
719 }
720 #else
721 #error "No implementation for ease8 available."
722 #endif
723
724 /// @} Easing
725
726
727 ///////////////////////////////////////////////////////////////////////
728 ///
729 /// @defgroup WaveformGenerators Waveform Generators
730 /// General purpose wave generator functions.
731 ///
732 /// @{
733
734
735 /// Triangle wave generator.
736 /// Useful for turning a one-byte ever-increasing value into a
737 /// one-byte value that oscillates up and down.
738 /// @code
739 /// input output
740 /// 0..127 0..254 (positive slope)
741 /// 128..255 254..0 (negative slope)
742 /// @endcode
743 ///
744 /// On AVR this function takes just three cycles.
745 ///
746 50446 LIB8STATIC uint8_t triwave8(uint8_t in)
747 {
748
2/2
✓ Branch 0 taken 24006 times.
✓ Branch 1 taken 26440 times.
50446 if( in & 0x80) {
749 24006 in = 255 - in;
750 }
751 50446 uint8_t out = in << 1;
752 50446 return out;
753 }
754
755 /// Quadratic waveform generator. Spends just a little
756 /// more time at the limits than "sine" does.
757 ///
758 /// S-shaped wave generator (like "sine"). Useful
759 /// for turning a one-byte "counter" value into a
760 /// one-byte oscillating value that moves smoothly up and down,
761 /// with an "acceleration" and "deceleration" curve.
762 ///
763 /// This is even faster than "sin8()", and has
764 /// a slightly different curve shape.
765 4170 LIB8STATIC uint8_t quadwave8(uint8_t in)
766 {
767 4170 return ease8InOutQuad( triwave8( in));
768 }
769
770 /// Cubic waveform generator. Spends visibly more time
771 /// at the limits than "sine" does.
772 /// @copydetails quadwave8()
773 46267 LIB8STATIC uint8_t cubicwave8(uint8_t in)
774 {
775 46267 return ease8InOutCubic( triwave8( in));
776 }
777
778
779 /// Square wave generator.
780 /// Useful for turning a one-byte ever-increasing value
781 /// into a one-byte value that is either 0 or 255.
782 /// The width of the output "pulse" is determined by
783 /// the pulsewidth argument:
784 /// @code
785 /// if pulsewidth is 255, output is always 255.
786 /// if pulsewidth < 255, then
787 /// if input < pulsewidth then output is 255
788 /// if input >= pulsewidth then output is 0
789 /// @endcode
790 ///
791 /// The output looking like:
792 ///
793 /// @code
794 /// 255 +--pulsewidth--+
795 /// . | |
796 /// 0 0 +--------(256-pulsewidth)--------
797 /// @endcode
798 ///
799 /// @param in input value
800 /// @param pulsewidth width of the output pulse
801 /// @returns square wave output
802 LIB8STATIC uint8_t squarewave8( uint8_t in, uint8_t pulsewidth=128)
803 {
804 if( in < pulsewidth || (pulsewidth == 255)) {
805 return 255;
806 } else {
807 return 0;
808 }
809 }
810
811 /// @} WaveformGenerators
812
813 /// @} lib8tion (excluding the timekeeping functions from the nested group)
814
815
816 ///////////////////////////////////////////////////////////////////////
817 ///
818 /// @defgroup Timekeeping Timekeeping Functions
819 /// Tools for tracking and working with time
820 ///
821 /// @{
822
823 #if ((defined(ARDUINO) || defined(SPARK) || defined(FASTLED_HAS_MILLIS)) && !defined(USE_GET_MILLISECOND_TIMER)) || defined(FASTLED_DOXYGEN)
824 // Forward declaration of Arduino function 'millis'.
825 //uint32_t millis();
826
827 /// The a number of functions need access to a millisecond counter
828 /// in order to keep time. On Arduino, this is "millis()".
829 /// On other platforms, you'll need to provide a function with this
830 /// signature which provides similar functionality:
831 /// @code{.cpp}
832 /// uint32_t get_millisecond_timer();
833 /// @endcode
834 ///
835 /// You can also force use of the get_millisecond_timer() function
836 /// by \#defining `USE_GET_MILLISECOND_TIMER`.
837 #define GET_MILLIS millis
838 #else
839 uint32_t get_millisecond_timer();
840 #define GET_MILLIS get_millisecond_timer
841 #endif
842
843 /// @} Timekeeping
844
845
846 /// @addtogroup lib8tion
847 /// @{
848
849
850 ///////////////////////////////////////////////////////////////////////
851 ///
852 /// @defgroup BeatGenerators Waveform Beat Generators
853 /// Waveform generators that reset at a given number
854 /// of "beats per minute" (BPM).
855 ///
856 /// The standard "beat" functions generate "sawtooth" waves which rise from
857 /// 0 up to a max value and then reset, continuously repeating that cycle at
858 /// the specified frequency (BPM).
859 ///
860 /// The "sin" versions function similarly, but create an oscillating sine wave
861 /// at the specified frequency.
862 ///
863 /// BPM can be supplied two ways. The simpler way of specifying BPM is as
864 /// a simple 8-bit integer from 1-255, (e.g., "120").
865 /// The more sophisticated way of specifying BPM allows for fractional
866 /// "Q8.8" fixed point number (an ::accum88) with an 8-bit integer part and
867 /// an 8-bit fractional part. The easiest way to construct this is to multiply
868 /// a floating point BPM value (e.g. 120.3) by 256, (e.g. resulting in 30796
869 /// in this case), and pass that as the 16-bit BPM argument.
870 ///
871 /// Originally these functions were designed to make an entire animation project pulse.
872 /// with brightness. For that effect, add this line just above your existing call to
873 /// "FastLED.show()":
874 /// @code
875 /// uint8_t bright = beatsin8( 60 /*BPM*/, 192 /*dimmest*/, 255 /*brightest*/ ));
876 /// FastLED.setBrightness( bright );
877 /// FastLED.show();
878 /// @endcode
879 ///
880 /// The entire animation will now pulse between brightness 192 and 255 once per second.
881 ///
882 /// @warning Any "BPM88" parameter **MUST** always be provided in Q8.8 format!
883 /// @note The beat generators need access to a millisecond counter
884 /// to track elapsed time. See ::GET_MILLIS for reference. When using the Arduino
885 /// `millis()` function, accuracy is a bit better than one part in a thousand.
886 ///
887 /// @{
888
889
890 /// Generates a 16-bit "sawtooth" wave at a given BPM, with BPM
891 /// specified in Q8.8 fixed-point format.
892 /// @param beats_per_minute_88 the frequency of the wave, in Q8.8 format
893 /// @param timebase the time offset of the wave from the millis() timer
894 /// @warning The BPM parameter **MUST** be provided in Q8.8 format! E.g.
895 /// for 120 BPM it would be 120*256 = 30720. If you just want to specify
896 /// "120", use beat16() or beat8().
897 128508 LIB8STATIC uint16_t beat88( accum88 beats_per_minute_88, uint32_t timebase = 0)
898 {
899 // BPM is 'beats per minute', or 'beats per 60000ms'.
900 // To avoid using the (slower) division operator, we
901 // want to convert 'beats per 60000ms' to 'beats per 65536ms',
902 // and then use a simple, fast bit-shift to divide by 65536.
903 //
904 // The ratio 65536:60000 is 279.620266667:256; we'll call it 280:256.
905 // The conversion is accurate to about 0.05%, more or less,
906 // e.g. if you ask for "120 BPM", you'll get about "119.93".
907 128508 return (((GET_MILLIS()) - timebase) * beats_per_minute_88 * 280) >> 16;
908 }
909
910 /// Generates a 16-bit "sawtooth" wave at a given BPM
911 /// @param beats_per_minute the frequency of the wave, in decimal
912 /// @param timebase the time offset of the wave from the millis() timer
913 127945 LIB8STATIC uint16_t beat16( accum88 beats_per_minute, uint32_t timebase = 0)
914 {
915 // Convert simple 8-bit BPM's to full Q8.8 accum88's if needed
916
2/2
✓ Branch 0 taken 97869 times.
✓ Branch 1 taken 30076 times.
127945 if( beats_per_minute < 256) beats_per_minute <<= 8;
917 127945 return beat88(beats_per_minute, timebase);
918 }
919
920 /// Generates an 8-bit "sawtooth" wave at a given BPM
921 /// @param beats_per_minute the frequency of the wave, in decimal
922 /// @param timebase the time offset of the wave from the millis() timer
923 75856 LIB8STATIC uint8_t beat8( accum88 beats_per_minute, uint32_t timebase = 0)
924 {
925 75856 return beat16( beats_per_minute, timebase) >> 8;
926 }
927
928
929 /// Generates a 16-bit sine wave at a given BPM that oscillates within
930 /// a given range.
931 /// @param beats_per_minute_88 the frequency of the wave, in Q8.8 format
932 /// @param lowest the lowest output value of the sine wave
933 /// @param highest the highest output value of the sine wave
934 /// @param timebase the time offset of the wave from the millis() timer
935 /// @param phase_offset phase offset of the wave from the current position
936 /// @warning The BPM parameter **MUST** be provided in Q8.8 format! E.g.
937 /// for 120 BPM it would be 120*256 = 30720. If you just want to specify
938 /// "120", use beatsin16() or beatsin8().
939 LIB8STATIC uint16_t beatsin88( accum88 beats_per_minute_88, uint16_t lowest = 0, uint16_t highest = 65535,
940 uint32_t timebase = 0, uint16_t phase_offset = 0)
941 {
942 uint16_t beat = beat88( beats_per_minute_88, timebase);
943 uint16_t beatsin = (sin16( beat + phase_offset) + 32768);
944 uint16_t rangewidth = highest - lowest;
945 uint16_t scaledbeat = scale16( beatsin, rangewidth);
946 uint16_t result = lowest + scaledbeat;
947 return result;
948 }
949
950 /// Generates a 16-bit sine wave at a given BPM that oscillates within
951 /// a given range.
952 /// @param beats_per_minute the frequency of the wave, in decimal
953 /// @param lowest the lowest output value of the sine wave
954 /// @param highest the highest output value of the sine wave
955 /// @param timebase the time offset of the wave from the millis() timer
956 /// @param phase_offset phase offset of the wave from the current position
957 LIB8STATIC uint16_t beatsin16( accum88 beats_per_minute, uint16_t lowest = 0, uint16_t highest = 65535,
958 uint32_t timebase = 0, uint16_t phase_offset = 0)
959 {
960 uint16_t beat = beat16( beats_per_minute, timebase);
961 uint16_t beatsin = (sin16( beat + phase_offset) + 32768);
962 uint16_t rangewidth = highest - lowest;
963 uint16_t scaledbeat = scale16( beatsin, rangewidth);
964 uint16_t result = lowest + scaledbeat;
965 return result;
966 }
967
968 /// Generates an 8-bit sine wave at a given BPM that oscillates within
969 /// a given range.
970 /// @param beats_per_minute the frequency of the wave, in decimal
971 /// @param lowest the lowest output value of the sine wave
972 /// @param highest the highest output value of the sine wave
973 /// @param timebase the time offset of the wave from the millis() timer
974 /// @param phase_offset phase offset of the wave from the current position
975 LIB8STATIC uint8_t beatsin8( accum88 beats_per_minute, uint8_t lowest = 0, uint8_t highest = 255,
976 uint32_t timebase = 0, uint8_t phase_offset = 0)
977 {
978 uint8_t beat = beat8( beats_per_minute, timebase);
979 uint8_t beatsin = sin8( beat + phase_offset);
980 uint8_t rangewidth = highest - lowest;
981 uint8_t scaledbeat = scale8( beatsin, rangewidth);
982 uint8_t result = lowest + scaledbeat;
983 return result;
984 }
985
986 /// @} BeatGenerators
987
988 /// @} lib8tion, to exclude timekeeping functions
989
990
991 ///////////////////////////////////////////////////////////////////////
992 ///
993 /// @addtogroup Timekeeping
994 /// @{
995
996 /// Return the current seconds since boot in a 16-bit value. Used as part of the
997 /// "every N time-periods" mechanism
998 LIB8STATIC uint16_t seconds16()
999 {
1000 uint32_t ms = GET_MILLIS();
1001 uint16_t s16;
1002 s16 = ms / 1000;
1003 return s16;
1004 }
1005
1006 /// Return the current minutes since boot in a 16-bit value. Used as part of the
1007 /// "every N time-periods" mechanism
1008 LIB8STATIC uint16_t minutes16()
1009 {
1010 uint32_t ms = GET_MILLIS();
1011 uint16_t m16;
1012 m16 = (ms / (60000L)) & 0xFFFF;
1013 return m16;
1014 }
1015
1016 /// Return the current hours since boot in an 8-bit value. Used as part of the
1017 /// "every N time-periods" mechanism
1018 LIB8STATIC uint8_t hours8()
1019 {
1020 uint32_t ms = GET_MILLIS();
1021 uint8_t h8;
1022 h8 = (ms / (3600000L)) & 0xFF;
1023 return h8;
1024 }
1025
1026
1027 /// Helper routine to divide a 32-bit value by 1024, returning
1028 /// only the low 16 bits.
1029 /// You'd think this would be just
1030 /// @code
1031 /// result = (in32 >> 10) & 0xFFFF;
1032 /// @endcode
1033 /// And on ARM, that's what you want and all is well.
1034 /// But on AVR that code turns into a loop that executes
1035 /// a four-byte shift ten times: 40 shifts in all, plus loop
1036 /// overhead. This routine gets exactly the same result with
1037 /// just six shifts (vs 40), and no loop overhead.
1038 /// Used to convert millis to "binary seconds" aka bseconds:
1039 /// one bsecond == 1024 millis.
1040 LIB8STATIC uint16_t div1024_32_16( uint32_t in32)
1041 {
1042 uint16_t out16;
1043 #if defined(__AVR__)
1044 asm volatile (
1045 " lsr %D[in] \n\t"
1046 " ror %C[in] \n\t"
1047 " ror %B[in] \n\t"
1048 " lsr %D[in] \n\t"
1049 " ror %C[in] \n\t"
1050 " ror %B[in] \n\t"
1051 " mov %B[out],%C[in] \n\t"
1052 " mov %A[out],%B[in] \n\t"
1053 : [in] "+r" (in32),
1054 [out] "=r" (out16)
1055 );
1056 #else
1057 out16 = (in32 >> 10) & 0xFFFF;
1058 #endif
1059 return out16;
1060 }
1061
1062 /// Returns the current time-since-boot in
1063 /// "binary seconds", which are actually 1024/1000 of a
1064 /// second long.
1065 LIB8STATIC uint16_t bseconds16()
1066 {
1067 uint32_t ms = GET_MILLIS();
1068 uint16_t s16;
1069 s16 = div1024_32_16( ms);
1070 return s16;
1071 }
1072
1073 /// Preprocessor-based class "template" for ::CEveryNTime, used with `EVERY_N_TIME` timekeepers.
1074 /// Classes to implement ::EVERY_N_MILLIS, ::EVERY_N_SECONDS,
1075 /// ::EVERY_N_MINUTES, ::EVERY_N_HOURS, and ::EVERY_N_BSECONDS.
1076 #if 1
1077 #define INSTANTIATE_EVERY_N_TIME_PERIODS(NAME,TIMETYPE,TIMEGETTER) \
1078 class NAME { \
1079 public: \
1080 TIMETYPE mPrevTrigger; \
1081 TIMETYPE mPeriod; \
1082 \
1083 NAME() { reset(); mPeriod = 1; }; \
1084 NAME(TIMETYPE period) { reset(); setPeriod(period); }; \
1085 void setPeriod( TIMETYPE period) { mPeriod = period; }; \
1086 TIMETYPE getTime() { return (TIMETYPE)(TIMEGETTER()); }; \
1087 TIMETYPE getPeriod() { return mPeriod; }; \
1088 TIMETYPE getElapsed() { return getTime() - mPrevTrigger; } \
1089 TIMETYPE getRemaining() { return mPeriod - getElapsed(); } \
1090 TIMETYPE getLastTriggerTime() { return mPrevTrigger; } \
1091 bool ready() { \
1092 bool isReady = (getElapsed() >= mPeriod); \
1093 if( isReady ) { reset(); } \
1094 return isReady; \
1095 } \
1096 void reset() { mPrevTrigger = getTime(); }; \
1097 void trigger() { mPrevTrigger = getTime() - mPeriod; }; \
1098 \
1099 operator bool() { return ready(); } \
1100 };
1101
1102 /// @name CEveryNTime Base Classes
1103 /// These macros define the time interval checking classes
1104 /// used in the `EVERY_N_TIME` time macros.
1105 /// @{
1106
1107 #if defined(FASTLED_DOXYGEN)
1108 /// Time interval checking class.
1109 /// Keeps track of a time interval in order to limit how often code
1110 /// is executed.
1111 /// @note TIMETYPE is specific to the initialized class, and is in the
1112 /// units used by the time function. E.g. for ::EVERY_N_MILLIS it's uint32_t
1113 /// and milliseconds, for ::EVERY_N_HOURS it's uint8_t and hours, etc.
1114 /// @warning This specific class isn't actually part of the library! It's created
1115 /// using a preprocessor macro (::INSTANTIATE_EVERY_N_TIME_PERIODS) as
1116 /// a new class for every different time unit. It has been recreated
1117 /// specifically for the documentation, so that the methods can be documented
1118 /// as usual.
1119 /// @see INSTANTIATE_EVERY_N_TIME_PERIODS
1120 class CEveryNTime {
1121 public:
1122 TIMETYPE mPrevTrigger; ///< Timestamp of the last time the class was "ready"
1123 TIMETYPE mPeriod; ///< Timing interval to check
1124
1125 /// Default constructor
1126 CEveryNTime() { reset(); mPeriod = 1; };
1127 /// Constructor
1128 /// @param period the time interval between triggers
1129 CEveryNTime(TIMETYPE period) { reset(); setPeriod(period); };
1130
1131 /// Set the time interval between triggers
1132 void setPeriod( TIMETYPE period) { mPeriod = period; };
1133
1134 /// Get the current time according to the class' timekeeper
1135 TIMETYPE getTime() { return (TIMETYPE)(TIMEGETTER()); };
1136
1137 /// Get the time interval between triggers
1138 TIMETYPE getPeriod() { return mPeriod; };
1139
1140 /// Get the time elapsed since the last trigger event
1141 TIMETYPE getElapsed() { return getTime() - mPrevTrigger; }
1142
1143 /// Get the time until the next trigger event
1144 TIMETYPE getRemaining() { return mPeriod - getElapsed(); }
1145
1146 /// Get the timestamp of the most recent trigger event
1147 TIMETYPE getLastTriggerTime() { return mPrevTrigger; }
1148
1149 /// Check if the time interval has elapsed
1150 bool ready() {
1151 bool isReady = (getElapsed() >= mPeriod);
1152 if( isReady ) { reset(); }
1153 return isReady;
1154 }
1155
1156 /// Reset the timestamp to the current time
1157 void reset() { mPrevTrigger = getTime(); };
1158
1159 /// Reset the timestamp so it is ready() on next call
1160 void trigger() { mPrevTrigger = getTime() - mPeriod; };
1161
1162 /// @copydoc ready()
1163 operator bool() { return ready(); }
1164 };
1165 #endif // FASTLED_DOXYGEN
1166
1167 /// Create the CEveryNMillis class for millisecond intervals
1168 INSTANTIATE_EVERY_N_TIME_PERIODS(CEveryNMillis,uint32_t,GET_MILLIS);
1169
1170 /// Create the CEveryNSeconds class for second intervals
1171 INSTANTIATE_EVERY_N_TIME_PERIODS(CEveryNSeconds,uint16_t,seconds16);
1172
1173 /// Create the CEveryNBSeconds class for bsecond intervals
1174 INSTANTIATE_EVERY_N_TIME_PERIODS(CEveryNBSeconds,uint16_t,bseconds16);
1175
1176 /// Create the CEveryNMinutes class for minutes intervals
1177 INSTANTIATE_EVERY_N_TIME_PERIODS(CEveryNMinutes,uint16_t,minutes16);
1178
1179 /// Create the CEveryNHours class for hours intervals
1180 INSTANTIATE_EVERY_N_TIME_PERIODS(CEveryNHours,uint8_t,hours8);
1181
1182 /// Alias for CEveryNMillis
1183 #define CEveryNMilliseconds CEveryNMillis
1184
1185 /// Create the CEveryNMillisDynamic class for dynamic millisecond intervals
1186 class CEveryNMillisDynamic {
1187 public:
1188 uint32_t mPrevTrigger;
1189 uint32_t mPeriod;
1190
1191 CEveryNMillisDynamic(uint32_t period) : mPeriod(period) { reset(); };
1192 uint32_t getTime() { return GET_MILLIS(); };
1193 uint32_t getPeriod() const { return mPeriod; };
1194 uint32_t getElapsed() { return getTime() - mPrevTrigger; }
1195 uint32_t getRemaining() { return getPeriod() - getElapsed(); }
1196 uint32_t getLastTriggerTime() { return mPrevTrigger; }
1197 bool ready() {
1198 bool isReady = (getElapsed() >= getPeriod());
1199 if( isReady ) { reset(); }
1200 return isReady;
1201 }
1202 void reset() { mPrevTrigger = getTime(); };
1203 void trigger() { mPrevTrigger = getTime() - getPeriod(); };
1204 void setPeriod(uint32_t period) { mPeriod = period; }
1205
1206 operator bool() { return ready(); }
1207 };
1208 /// @} CEveryNTime Base Classes
1209
1210
1211
1212 // ————————————————————————————————————————————————
1213 // Random‐interval version of EVERY_N_MILLISECONDS:
1214 // on each trigger, pick the next period randomly in [MIN..MAX].
1215 // ————————————————————————————————————————————————
1216 class CEveryNMillisRandom {
1217 public:
1218 uint32_t mPrevTrigger;
1219 uint32_t mPeriod;
1220 uint32_t mMinPeriod;
1221 uint32_t mMaxPeriod;
1222
1223 CEveryNMillisRandom(uint32_t minPeriod, uint32_t maxPeriod)
1224 : mMinPeriod(minPeriod), mMaxPeriod(maxPeriod)
1225 {
1226 computeNext();
1227 reset();
1228 }
1229
1230 void computeNext() {
1231 // random16(x) returns [0..x-1], so this yields MIN..MAX
1232 uint32_t range = mMaxPeriod - mMinPeriod + 1;
1233 mPeriod = mMinPeriod + random16(range);
1234 }
1235
1236 uint32_t getTime() const { return GET_MILLIS(); }
1237
1238 bool ready() {
1239 uint32_t now = getTime();
1240 if (now - mPrevTrigger >= mPeriod) {
1241 mPrevTrigger = now;
1242 computeNext();
1243 return true;
1244 }
1245 return false;
1246 }
1247
1248 void reset() { mPrevTrigger = getTime(); }
1249 };
1250
1251 #else
1252
1253 // Under C++11 rules, we would be allowed to use not-external
1254 // -linkage-type symbols as template arguments,
1255 // e.g., LIB8STATIC seconds16, and we'd be able to use these
1256 // templates as shown below.
1257 // However, under C++03 rules, we cannot do that, and thus we
1258 // have to resort to the preprocessor to 'instantiate' 'templates',
1259 // as handled above.
1260 template<typename timeType,timeType (*timeGetter)()>
1261 class CEveryNTimePeriods {
1262 public:
1263 timeType mPrevTrigger;
1264 timeType mPeriod;
1265
1266 CEveryNTimePeriods() { reset(); mPeriod = 1; };
1267 CEveryNTimePeriods(timeType period) { reset(); setPeriod(period); };
1268 void setPeriod( timeType period) { mPeriod = period; };
1269 timeType getTime() { return (timeType)(timeGetter()); };
1270 timeType getPeriod() { return mPeriod; };
1271 timeType getElapsed() { return getTime() - mPrevTrigger; }
1272 timeType getRemaining() { return mPeriod - getElapsed(); }
1273 timeType getLastTriggerTime() { return mPrevTrigger; }
1274 bool ready() {
1275 bool isReady = (getElapsed() >= mPeriod);
1276 if( isReady ) { reset(); }
1277 return isReady;
1278 }
1279 void reset() { mPrevTrigger = getTime(); };
1280 void trigger() { mPrevTrigger = getTime() - mPeriod; };
1281
1282 operator bool() { return ready(); }
1283 };
1284 typedef CEveryNTimePeriods<uint16_t,seconds16> CEveryNSeconds;
1285 typedef CEveryNTimePeriods<uint16_t,bseconds16> CEveryNBSeconds;
1286 typedef CEveryNTimePeriods<uint32_t,millis> CEveryNMillis;
1287 typedef CEveryNTimePeriods<uint16_t,minutes16> CEveryNMinutes;
1288 typedef CEveryNTimePeriods<uint8_t,hours8> CEveryNHours;
1289 #endif
1290
1291
1292 /// @name "EVERY_N_TIME" Macros
1293 /// Check whether to excecute a block of code every N amount of time.
1294 /// These are useful for limiting how often code runs. For example,
1295 /// you can use ::fill_rainbow() to fill a strip of LEDs with color,
1296 /// combined with an ::EVERY_N_MILLIS block to limit how fast the colors
1297 /// change:
1298 /// @code{.cpp}
1299 /// static uint8_t hue = 0;
1300 /// fill_rainbow(leds, NUM_LEDS, hue);
1301 /// EVERY_N_MILLIS(20) { hue++; } // advances hue every 20 milliseconds
1302 /// @endcode
1303 /// Note that in order for these to be accurate, the EVERY_N block must
1304 /// be evaluated at a regular basis.
1305 /// @{
1306
1307 /// @cond
1308 #define CONCAT_HELPER( x, y ) x##y
1309 #define CONCAT_MACRO( x, y ) CONCAT_HELPER( x, y )
1310 /// @endcond
1311
1312
1313 /// Checks whether to execute a block of code every N milliseconds
1314 /// @see GET_MILLIS
1315 #define EVERY_N_MILLIS(N) EVERY_N_MILLIS_I(CONCAT_MACRO(PER, __COUNTER__ ),N)
1316
1317 /// Checks whether to execute a block of code every N milliseconds, using a custom instance name
1318 /// @copydetails EVERY_N_MILLIS
1319 #define EVERY_N_MILLIS_I(NAME,N) static CEveryNMillis NAME(N); if( NAME )
1320
1321
1322 /// Checks whether to execute a block of code every N seconds
1323 /// @see seconds16()
1324 #define EVERY_N_SECONDS(N) EVERY_N_SECONDS_I(CONCAT_MACRO(PER, __COUNTER__ ),N)
1325
1326 /// Checks whether to execute a block of code every N seconds, using a custom instance name
1327 /// @copydetails EVERY_N_SECONDS
1328 #define EVERY_N_SECONDS_I(NAME,N) static CEveryNSeconds NAME(N); if( NAME )
1329
1330
1331 /// Checks whether to execute a block of code every N bseconds
1332 /// @see bseconds16()
1333 #define EVERY_N_BSECONDS(N) EVERY_N_BSECONDS_I(CONCAT_MACRO(PER, __COUNTER__ ),N)
1334
1335 /// Checks whether to execute a block of code every N bseconds, using a custom instance name
1336 /// @copydetails EVERY_N_BSECONDS
1337 #define EVERY_N_BSECONDS_I(NAME,N) static CEveryNBSeconds NAME(N); if( NAME )
1338
1339
1340 /// Checks whether to execute a block of code every N minutes
1341 /// @see minutes16()
1342 #define EVERY_N_MINUTES(N) EVERY_N_MINUTES_I(CONCAT_MACRO(PER, __COUNTER__ ),N)
1343
1344 /// Checks whether to execute a block of code every N minutes, using a custom instance name
1345 /// @copydetails EVERY_N_MINUTES
1346 #define EVERY_N_MINUTES_I(NAME,N) static CEveryNMinutes NAME(N); if( NAME )
1347
1348
1349 /// Checks whether to execute a block of code every N hours
1350 /// @see hours8()
1351 #define EVERY_N_HOURS(N) EVERY_N_HOURS_I(CONCAT_MACRO(PER, __COUNTER__ ),N)
1352
1353 /// Checks whether to execute a block of code every N hours, using a custom instance name
1354 /// @copydetails EVERY_N_HOURS
1355 #define EVERY_N_HOURS_I(NAME,N) static CEveryNHours NAME(N); if( NAME )
1356
1357
1358 /// Alias for ::EVERY_N_MILLIS
1359 #define EVERY_N_MILLISECONDS(N) EVERY_N_MILLIS(N)
1360 /// Alias for ::EVERY_N_MILLIS_I
1361 #define EVERY_N_MILLISECONDS_I(NAME,N) EVERY_N_MILLIS_I(NAME,N)
1362
1363 /// Checks whether to execute a block of code every N milliseconds, where N is determined dynamically
1364 #define EVERY_N_MILLISECONDS_DYNAMIC(PERIOD_FUNC) EVERY_N_MILLISECONDS_DYNAMIC_I(CONCAT_MACRO(__dynamic_millis_timer, __COUNTER__ ), (PERIOD_FUNC))
1365
1366 /// Checks whether to execute a block of code every N milliseconds, where N is determined dynamically, using a custom instance name
1367 #define EVERY_N_MILLISECONDS_DYNAMIC_I(NAME, PERIOD_FUNC) \
1368 static CEveryNMillisDynamic NAME(1); \
1369 NAME.setPeriod(PERIOD_FUNC); \
1370 if( NAME )
1371
1372
1373 #define EVERY_N_MILLISECONDS_RANDOM(MIN, MAX) \
1374 EVERY_N_MILLISECONDS_RANDOM_I( \
1375 CONCAT_MACRO(_permRand, __COUNTER__), MIN, MAX)
1376
1377 #define EVERY_N_MILLISECONDS_RANDOM_I(NAME, MIN, MAX) \
1378 static CEveryNMillisRandom NAME(MIN, MAX); \
1379 if (NAME.ready())
1380
1381 /// @} Every_N
1382 /// @} Timekeeping
1383
1384
1385 // These defines are used to declare hidden or commented symbols for the
1386 // purposes of Doxygen documentation generation. They do not affect your program.
1387 #ifdef FASTLED_DOXYGEN
1388 /// Set this flag to use the get_millisecond_timer() function in place
1389 /// of the default millis() function.
1390 /// @ingroup Timekeeping
1391 #define USE_GET_MILLISECOND_TIMER
1392 #endif
1393
1394 FASTLED_NAMESPACE_END
1395
1396 #endif
1397