GCC Code Coverage Report


Directory: ./
File: overlays/wled/FX.h
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 145 152 95.4%
Functions: 50 57 87.7%
Branches: 29 48 60.4%

Line Branch Exec Source
1 #pragma once
2 /*
3 WS2812FX.h - Library for WS2812 LED effects.
4 Harm Aldick - 2016
5 www.aldick.org
6
7 Copyright (c) 2016 Harm Aldick
8 Licensed under the EUPL v. 1.2 or later
9 Adapted from code originally licensed under the MIT license
10
11 Modified for WLED
12
13 Segment class/struct (c) 2022 Blaz Kristan (@blazoncek)
14 */
15
16 #ifndef WS2812FX_h
17 #define WS2812FX_h
18
19 #include <vector>
20 #include "wled.h"
21
22 #include "const.h"
23 #include "bus_manager.h"
24
25 #define FASTLED_INTERNAL //remove annoying pragma messages
26 #define USE_GET_MILLISECOND_TIMER
27 #include "FastLED.h"
28
29 #define DEFAULT_BRIGHTNESS (uint8_t)127
30 #define DEFAULT_MODE (uint8_t)0
31 #define DEFAULT_SPEED (uint8_t)128
32 #define DEFAULT_INTENSITY (uint8_t)128
33 #define DEFAULT_COLOR (uint32_t)0xFFAA00
34 #define DEFAULT_C1 (uint8_t)128
35 #define DEFAULT_C2 (uint8_t)128
36 #define DEFAULT_C3 (uint8_t)16
37
38 #ifndef MIN
39 #define MIN(a,b) ((a)<(b)?(a):(b))
40 #endif
41 #ifndef MAX
42 #define MAX(a,b) ((a)>(b)?(a):(b))
43 #endif
44
45 //color mangling macros
46 #ifndef RGBW32
47 #define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b))))
48 #endif
49
50 extern bool realtimeRespectLedMaps; // used in getMappedPixelIndex()
51 extern byte realtimeMode; // used in getMappedPixelIndex()
52
53 /* Not used in all effects yet */
54 #define WLED_FPS 40
55 #define FRAMETIME_FIXED (1000/WLED_FPS)
56 #define FRAMETIME strip().getFrameTime()
57 #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
58 #define MIN_FRAME_DELAY 2 // minimum wait between repaints, to keep other functions like WiFi alive
59 #elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
60 #define MIN_FRAME_DELAY 3 // S2/C3 are slower than normal esp32, and only have one core
61 #else
62 #define MIN_FRAME_DELAY 8 // 8266 legacy MIN_SHOW_DELAY
63 #endif
64 #define FPS_UNLIMITED 0
65
66 // FPS calculation (can be defined as compile flag for debugging)
67 #ifndef FPS_CALC_AVG
68 #define FPS_CALC_AVG 7 // average FPS calculation over this many frames (moving average)
69 #endif
70 #ifndef FPS_MULTIPLIER
71 #define FPS_MULTIPLIER 1 // dev option: multiplier to get sub-frame FPS without floats
72 #endif
73 #define FPS_CALC_SHIFT 7 // bit shift for fixed point math
74
75 /* each segment uses 82 bytes of SRAM memory, so if you're application fails because of
76 insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
77 #ifdef ESP8266
78 #define MAX_NUM_SEGMENTS 16
79 /* How much data bytes all segments combined may allocate */
80 #define MAX_SEGMENT_DATA 5120
81 #elif defined(CONFIG_IDF_TARGET_ESP32S2)
82 #define MAX_NUM_SEGMENTS 20
83 #define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*512) // 10k by default (S2 is short on free RAM)
84 #else
85 #define MAX_NUM_SEGMENTS 32 // warning: going beyond 32 may consume too much RAM for stable operation
86 #define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*1280) // 40k by default
87 #endif
88
89 /* How much data bytes each segment should max allocate to leave enough space for other segments,
90 assuming each segment uses the same amount of data. 256 for ESP8266, 640 for ESP32. */
91 #define FAIR_DATA_PER_SEG (MAX_SEGMENT_DATA / strip().getMaxSegments())
92
93 #define NUM_COLORS 3 /* number of colors per segment */
94 #define SEGMENT strip()._segments[strip().getCurrSegmentId()]
95 #define SEGENV strip()._segments[strip().getCurrSegmentId()]
96 #define SEGCOLOR(x) Segment::getCurrentColor(x)
97 #define SEGPALETTE Segment::getCurrentPalette()
98 #define SEGLEN Segment::vLength()
99 #define SEG_W Segment::vWidth()
100 #define SEG_H Segment::vHeight()
101 #define SPEED_FORMULA_L (5U + (50U*(255U - SEGMENT.speed))/SEGLEN)
102
103 // some common colors
104 #define RED (uint32_t)0xFF0000
105 #define GREEN (uint32_t)0x00FF00
106 #define BLUE (uint32_t)0x0000FF
107 #define WHITE (uint32_t)0xFFFFFF
108 #define BLACK (uint32_t)0x000000
109 #define YELLOW (uint32_t)0xFFFF00
110 #define CYAN (uint32_t)0x00FFFF
111 #define MAGENTA (uint32_t)0xFF00FF
112 #define PURPLE (uint32_t)0x400080
113 #define ORANGE (uint32_t)0xFF3000
114 #define PINK (uint32_t)0xFF1493
115 #define GREY (uint32_t)0x808080
116 #define GRAY GREY
117 #define DARKGREY (uint32_t)0x333333
118 #define DARKGRAY DARKGREY
119 #define ULTRAWHITE (uint32_t)0xFFFFFFFF
120 #define DARKSLATEGRAY (uint32_t)0x2F4F4F
121 #define DARKSLATEGREY DARKSLATEGRAY
122
123 // segment options
124 #define NO_OPTIONS (uint16_t)0x0000
125 #define TRANSPOSED (uint16_t)0x0100 // rotated 90deg & reversed
126 #define MIRROR_Y_2D (uint16_t)0x0080
127 #define REVERSE_Y_2D (uint16_t)0x0040
128 #define RESET_REQ (uint16_t)0x0020
129 #define FROZEN (uint16_t)0x0010
130 #define MIRROR (uint16_t)0x0008
131 #define SEGMENT_ON (uint16_t)0x0004
132 #define REVERSE (uint16_t)0x0002
133 #define SELECTED (uint16_t)0x0001
134
135 #define FX_MODE_STATIC 0
136 #define FX_MODE_BLINK 1
137 #define FX_MODE_BREATH 2
138 #define FX_MODE_COLOR_WIPE 3
139 #define FX_MODE_COLOR_WIPE_RANDOM 4
140 #define FX_MODE_RANDOM_COLOR 5
141 #define FX_MODE_COLOR_SWEEP 6
142 #define FX_MODE_DYNAMIC 7
143 #define FX_MODE_RAINBOW 8
144 #define FX_MODE_RAINBOW_CYCLE 9
145 #define FX_MODE_SCAN 10
146 #define FX_MODE_DUAL_SCAN 11
147 #define FX_MODE_FADE 12
148 #define FX_MODE_THEATER_CHASE 13
149 #define FX_MODE_THEATER_CHASE_RAINBOW 14
150 #define FX_MODE_RUNNING_LIGHTS 15
151 #define FX_MODE_SAW 16
152 #define FX_MODE_TWINKLE 17
153 #define FX_MODE_DISSOLVE 18
154 #define FX_MODE_DISSOLVE_RANDOM 19 // candidate for removal (use Dissolve with with check 3)
155 #define FX_MODE_SPARKLE 20
156 #define FX_MODE_FLASH_SPARKLE 21
157 #define FX_MODE_HYPER_SPARKLE 22
158 #define FX_MODE_STROBE 23
159 #define FX_MODE_STROBE_RAINBOW 24
160 #define FX_MODE_MULTI_STROBE 25
161 #define FX_MODE_BLINK_RAINBOW 26
162 #define FX_MODE_ANDROID 27
163 #define FX_MODE_CHASE_COLOR 28
164 #define FX_MODE_CHASE_RANDOM 29
165 #define FX_MODE_CHASE_RAINBOW 30
166 #define FX_MODE_CHASE_FLASH 31
167 #define FX_MODE_CHASE_FLASH_RANDOM 32
168 #define FX_MODE_CHASE_RAINBOW_WHITE 33
169 #define FX_MODE_COLORFUL 34
170 #define FX_MODE_TRAFFIC_LIGHT 35
171 #define FX_MODE_COLOR_SWEEP_RANDOM 36
172 #define FX_MODE_RUNNING_COLOR 37
173 #define FX_MODE_AURORA 38
174 #define FX_MODE_RUNNING_RANDOM 39
175 #define FX_MODE_LARSON_SCANNER 40
176 #define FX_MODE_COMET 41
177 #define FX_MODE_FIREWORKS 42
178 #define FX_MODE_RAIN 43
179 #define FX_MODE_TETRIX 44 //was Merry Christmas prior to 0.12.0 (use "Chase 2" with Red/Green)
180 #define FX_MODE_FIRE_FLICKER 45
181 #define FX_MODE_GRADIENT 46
182 #define FX_MODE_LOADING 47
183 #define FX_MODE_ROLLINGBALLS 48 //was Police before 0.14
184 #define FX_MODE_FAIRY 49 //was Police All prior to 0.13.0-b6 (use "Two Dots" with Red/Blue and full intensity)
185 #define FX_MODE_TWO_DOTS 50
186 #define FX_MODE_FAIRYTWINKLE 51 //was Two Areas prior to 0.13.0-b6 (use "Two Dots" with full intensity)
187 #define FX_MODE_RUNNING_DUAL 52
188 #define FX_MODE_IMAGE 53
189 #define FX_MODE_TRICOLOR_CHASE 54
190 #define FX_MODE_TRICOLOR_WIPE 55
191 #define FX_MODE_TRICOLOR_FADE 56
192 #define FX_MODE_LIGHTNING 57
193 #define FX_MODE_ICU 58
194 #define FX_MODE_MULTI_COMET 59
195 #define FX_MODE_DUAL_LARSON_SCANNER 60 // candidate for removal (use Scanner with with check 1)
196 #define FX_MODE_RANDOM_CHASE 61
197 #define FX_MODE_OSCILLATE 62
198 #define FX_MODE_PRIDE_2015 63
199 #define FX_MODE_JUGGLE 64
200 #define FX_MODE_PALETTE 65
201 #define FX_MODE_FIRE_2012 66
202 #define FX_MODE_COLORWAVES 67
203 #define FX_MODE_BPM 68
204 #define FX_MODE_FILLNOISE8 69
205 #define FX_MODE_NOISE16_1 70
206 #define FX_MODE_NOISE16_2 71
207 #define FX_MODE_NOISE16_3 72
208 #define FX_MODE_NOISE16_4 73
209 #define FX_MODE_COLORTWINKLE 74
210 #define FX_MODE_LAKE 75
211 #define FX_MODE_METEOR 76
212 #define FX_MODE_COPY 77 // was METEOR_SMOOTH (merged with meteor); reused upstream for Copy Segment
213 #define FX_MODE_RAILWAY 78
214 #define FX_MODE_RIPPLE 79
215 #define FX_MODE_TWINKLEFOX 80
216 #define FX_MODE_TWINKLECAT 81
217 #define FX_MODE_HALLOWEEN_EYES 82
218 #define FX_MODE_STATIC_PATTERN 83
219 #define FX_MODE_TRI_STATIC_PATTERN 84
220 #define FX_MODE_SPOTS 85
221 #define FX_MODE_SPOTS_FADE 86
222 #define FX_MODE_GLITTER 87
223 #define FX_MODE_CANDLE 88
224 #define FX_MODE_STARBURST 89
225 #define FX_MODE_EXPLODING_FIREWORKS 90
226 #define FX_MODE_BOUNCINGBALLS 91
227 #define FX_MODE_SINELON 92
228 #define FX_MODE_SINELON_DUAL 93
229 #define FX_MODE_SINELON_RAINBOW 94
230 #define FX_MODE_POPCORN 95
231 #define FX_MODE_DRIP 96
232 #define FX_MODE_PLASMA 97
233 #define FX_MODE_PERCENT 98
234 #define FX_MODE_RIPPLE_RAINBOW 99
235 #define FX_MODE_HEARTBEAT 100
236 #define FX_MODE_PACIFICA 101
237 #define FX_MODE_CANDLE_MULTI 102
238 #define FX_MODE_SOLID_GLITTER 103 // candidate for removal (use glitter)
239 #define FX_MODE_SUNRISE 104
240 #define FX_MODE_PHASED 105
241 #define FX_MODE_TWINKLEUP 106
242 #define FX_MODE_NOISEPAL 107
243 #define FX_MODE_SINEWAVE 108
244 #define FX_MODE_PHASEDNOISE 109
245 #define FX_MODE_FLOW 110
246 #define FX_MODE_CHUNCHUN 111
247 #define FX_MODE_DANCING_SHADOWS 112
248 #define FX_MODE_WASHING_MACHINE 113
249 #define FX_MODE_2DPLASMAROTOZOOM 114 // was Candy Cane prior to 0.14 (use Chase 2)
250 #define FX_MODE_BLENDS 115
251 #define FX_MODE_TV_SIMULATOR 116
252 #define FX_MODE_DYNAMIC_SMOOTH 117 // candidate for removal (check3 in dynamic)
253
254 // new 0.14 2D effects
255 #define FX_MODE_2DSPACESHIPS 118 //gap fill
256 #define FX_MODE_2DCRAZYBEES 119 //gap fill
257 #define FX_MODE_2DGHOSTRIDER 120 //gap fill
258 #define FX_MODE_2DBLOBS 121 //gap fill
259 #define FX_MODE_2DSCROLLTEXT 122 //gap fill
260 #define FX_MODE_2DDRIFTROSE 123 //gap fill
261 #define FX_MODE_2DDISTORTIONWAVES 124 //gap fill
262 #define FX_MODE_2DSOAP 125 //gap fill
263 #define FX_MODE_2DOCTOPUS 126 //gap fill
264 #define FX_MODE_2DWAVINGCELL 127 //gap fill
265
266 // WLED-SR effects (SR compatible IDs !!!)
267 #define FX_MODE_PIXELS 128
268 #define FX_MODE_PIXELWAVE 129
269 #define FX_MODE_JUGGLES 130
270 #define FX_MODE_MATRIPIX 131
271 #define FX_MODE_GRAVIMETER 132
272 #define FX_MODE_PLASMOID 133
273 #define FX_MODE_PUDDLES 134
274 #define FX_MODE_MIDNOISE 135
275 #define FX_MODE_NOISEMETER 136
276 #define FX_MODE_FREQWAVE 137
277 #define FX_MODE_FREQMATRIX 138
278 #define FX_MODE_2DGEQ 139
279 #define FX_MODE_WATERFALL 140
280 #define FX_MODE_FREQPIXELS 141
281 #define FX_MODE_BINMAP 142
282 #define FX_MODE_NOISEFIRE 143
283 #define FX_MODE_PUDDLEPEAK 144
284 #define FX_MODE_NOISEMOVE 145
285 #define FX_MODE_2DNOISE 146
286 #define FX_MODE_PERLINMOVE 147
287 #define FX_MODE_RIPPLEPEAK 148
288 #define FX_MODE_2DFIRENOISE 149
289 #define FX_MODE_2DSQUAREDSWIRL 150
290 #define FX_MODE_PACMAN 151 // gap fill (was 2DFIRE2012). Do NOT renumber; SR-ID range must remain stable.
291 #define FX_MODE_2DDNA 152
292 #define FX_MODE_2DMATRIX 153
293 #define FX_MODE_2DMETABALLS 154
294 #define FX_MODE_FREQMAP 155
295 #define FX_MODE_GRAVCENTER 156
296 #define FX_MODE_GRAVCENTRIC 157
297 #define FX_MODE_GRAVFREQ 158
298 #define FX_MODE_DJLIGHT 159
299 #define FX_MODE_2DFUNKYPLANK 160
300 #define FX_MODE_SHIMMER 161 // gap fill, non-SR 1D effect
301 #define FX_MODE_2DPULSER 162
302 #define FX_MODE_BLURZ 163
303 #define FX_MODE_2DDRIFT 164
304 #define FX_MODE_2DWAVERLY 165
305 #define FX_MODE_2DSUNRADIATION 166
306 #define FX_MODE_2DCOLOREDBURSTS 167
307 #define FX_MODE_2DJULIA 168
308 // #define FX_MODE_2DPOOLNOISE 169 //have been removed in WLED SR in the past because of low mem but should be added back
309 // #define FX_MODE_2DTWISTER 170 //have been removed in WLED SR in the past because of low mem but should be added back
310 // #define FX_MODE_2DCAELEMENTATY 171 //have been removed in WLED SR in the past because of low mem but should be added back
311 #define FX_MODE_2DGAMEOFLIFE 172
312 #define FX_MODE_2DTARTAN 173
313 #define FX_MODE_2DPOLARLIGHTS 174
314 #define FX_MODE_2DSWIRL 175
315 #define FX_MODE_2DLISSAJOUS 176
316 #define FX_MODE_2DFRIZZLES 177
317 #define FX_MODE_2DPLASMABALL 178
318 #define FX_MODE_FLOWSTRIPE 179
319 #define FX_MODE_2DHIPHOTIC 180
320 #define FX_MODE_2DSINDOTS 181
321 #define FX_MODE_2DDNASPIRAL 182
322 #define FX_MODE_2DBLACKHOLE 183
323 #define FX_MODE_WAVESINS 184
324 #define FX_MODE_ROCKTAVES 185
325 #define FX_MODE_2DAKEMI 186
326 #define FX_MODE_PARTICLEVOLCANO 187
327 #define FX_MODE_PARTICLEFIRE 188
328 #define FX_MODE_PARTICLEFIREWORKS 189
329 #define FX_MODE_PARTICLEVORTEX 190
330 #define FX_MODE_PARTICLEPERLIN 191
331 #define FX_MODE_PARTICLEPIT 192
332 #define FX_MODE_PARTICLEBOX 193
333 #define FX_MODE_PARTICLEATTRACTOR 194
334 #define FX_MODE_PARTICLEIMPACT 195
335 #define FX_MODE_PARTICLEWATERFALL 196
336 #define FX_MODE_PARTICLESPRAY 197
337 #define FX_MODE_PARTICLESGEQ 198
338 #define FX_MODE_PARTICLECENTERGEQ 199
339 #define FX_MODE_PARTICLEGHOSTRIDER 200
340 #define FX_MODE_PARTICLEBLOBS 201
341 #define FX_MODE_PSDRIP 202
342 #define FX_MODE_PSPINBALL 203
343 #define FX_MODE_PSDANCINGSHADOWS 204
344 #define FX_MODE_PSFIREWORKS1D 205
345 #define FX_MODE_PSSPARKLER 206
346 #define FX_MODE_PSHOURGLASS 207
347 #define FX_MODE_PS1DSPRAY 208
348 #define FX_MODE_PSBALANCE 209
349 #define FX_MODE_PSCHASE 210
350 #define FX_MODE_PSSTARBURST 211
351 #define FX_MODE_PS1DGEQ 212
352 #define FX_MODE_PSFIRE1D 213
353 #define FX_MODE_PS1DSONICSTREAM 214
354 #define FX_MODE_PS1DSONICBOOM 215
355 #define FX_MODE_PS1DSPRINGY 216
356 #define FX_MODE_PARTICLEGALAXY 217
357 #define FX_MODE_COLORCLOUDS 218
358 #define FX_MODE_SLOW_TRANSITION 219
359 #define MODE_COUNT 220
360
361
362 #define BLEND_STYLE_FADE 0x00 // universal
363 #define BLEND_STYLE_FAIRY_DUST 0x01 // universal
364 #define BLEND_STYLE_SWIPE_RIGHT 0x02 // 1D or 2D
365 #define BLEND_STYLE_SWIPE_LEFT 0x03 // 1D or 2D
366 #define BLEND_STYLE_PINCH_OUT 0x04 // 1D or 2D
367 #define BLEND_STYLE_INSIDE_OUT 0x05 // 1D or 2D
368 #define BLEND_STYLE_SWIPE_UP 0x06 // 2D
369 #define BLEND_STYLE_SWIPE_DOWN 0x07 // 2D
370 #define BLEND_STYLE_OPEN_H 0x08 // 2D
371 #define BLEND_STYLE_OPEN_V 0x09 // 2D
372 // as there are many push variants to optimise if statements they are groupped together
373 #define BLEND_STYLE_PUSH_RIGHT 0x10 // 1D or 2D (& 0b00010000)
374 #define BLEND_STYLE_PUSH_LEFT 0x11 // 1D or 2D (& 0b00010000)
375 #define BLEND_STYLE_PUSH_UP 0x12 // 2D (& 0b00010000)
376 #define BLEND_STYLE_PUSH_DOWN 0x13 // 2D (& 0b00010000)
377 #define BLEND_STYLE_PUSH_TL 0x14 // 2D (& 0b00010000)
378 #define BLEND_STYLE_PUSH_TR 0x15 // 2D (& 0b00010000)
379 #define BLEND_STYLE_PUSH_BR 0x16 // 2D (& 0b00010000)
380 #define BLEND_STYLE_PUSH_BL 0x17 // 2D (& 0b00010000)
381 #define BLEND_STYLE_PUSH_MASK 0x10
382 #define BLEND_STYLE_COUNT 18
383
384
385 typedef enum mapping1D2D {
386 M12_Pixels = 0,
387 M12_pBar = 1,
388 M12_pArc = 2,
389 M12_pCorner = 3,
390 M12_sPinwheel = 4
391 } mapping1D2D_t;
392
393 // segment, 68 bytes
394 typedef struct Segment {
395 public:
396 uint16_t start; // start index / start X coordinate 2D (left)
397 uint16_t stop; // stop index / stop X coordinate 2D (right); segment is invalid if stop == 0
398 uint16_t offset;
399 uint8_t speed;
400 uint8_t intensity;
401 uint8_t palette;
402 uint8_t mode;
403 union {
404 uint16_t options; //bit pattern: msb first: [transposed mirrorY reverseY] transitional (tbd) paused needspixelstate mirrored on reverse selected
405 struct {
406 bool selected : 1; // 0 : selected
407 bool reverse : 1; // 1 : reversed
408 bool on : 1; // 2 : is On
409 bool mirror : 1; // 3 : mirrored
410 bool freeze : 1; // 4 : paused/frozen
411 bool reset : 1; // 5 : indicates that Segment runtime requires reset
412 bool reverse_y : 1; // 6 : reversed Y (2D)
413 bool mirror_y : 1; // 7 : mirrored Y (2D)
414 bool transpose : 1; // 8 : transposed (2D, swapped X & Y)
415 uint8_t map1D2D : 3; // 9-11 : mapping for 1D effect on 2D (0-use as strip, 1-expand vertically, 2-circular/arc, 3-rectangular/corner, ...)
416 uint8_t soundSim : 2; // 12-13 : 0-3 sound simulation types ("soft" & "hard" or "on"/"off")
417 uint8_t set : 2; // 14-15 : 0-3 UI segment sets/groups
418 };
419 };
420 uint8_t grouping, spacing;
421 uint8_t opacity;
422 uint32_t colors[NUM_COLORS];
423 uint8_t cct; //0==1900K, 255==10091K
424 uint8_t custom1, custom2; // custom FX parameters/sliders
425 struct {
426 uint8_t custom3 : 5; // reduced range slider (0-31)
427 bool check1 : 1; // checkmark 1
428 bool check2 : 1; // checkmark 2
429 bool check3 : 1; // checkmark 3
430 };
431 uint8_t startY; // start Y coodrinate 2D (top); there should be no more than 255 rows
432 uint8_t stopY; // stop Y coordinate 2D (bottom); there should be no more than 255 rows
433 // note: two bytes of padding are added here
434 char *name;
435
436 // runtime data
437 unsigned long next_time; // millis() of next update
438 uint32_t step; // custom "step" var
439 uint32_t call; // call counter
440 uint16_t aux0; // custom var
441 uint16_t aux1; // custom var
442 byte *data; // effect data pointer
443 static uint16_t maxWidth, maxHeight; // these define matrix width & height (max. segment dimensions)
444
445 typedef struct TemporarySegmentData {
446 uint16_t _optionsT;
447 uint32_t _colorT[NUM_COLORS];
448 uint8_t _speedT;
449 uint8_t _intensityT;
450 uint8_t _custom1T, _custom2T; // custom FX parameters/sliders
451 struct {
452 uint8_t _custom3T : 5; // reduced range slider (0-31)
453 bool _check1T : 1; // checkmark 1
454 bool _check2T : 1; // checkmark 2
455 bool _check3T : 1; // checkmark 3
456 };
457 uint16_t _aux0T;
458 uint16_t _aux1T;
459 uint32_t _stepT;
460 uint32_t _callT;
461 uint8_t *_dataT;
462 unsigned _dataLenT;
463 TemporarySegmentData()
464 : _dataT(nullptr) // just in case...
465 , _dataLenT(0)
466 {}
467 } tmpsegd_t;
468
469 private:
470 union {
471 uint8_t _capabilities;
472 struct {
473 bool _isRGB : 1;
474 bool _hasW : 1;
475 bool _isCCT : 1;
476 bool _manualW : 1;
477 uint8_t _reserved : 4;
478 };
479 };
480 uint8_t _default_palette; // palette number that gets assigned to pal0
481 unsigned _dataLen;
482 static unsigned _usedSegmentData;
483 static uint8_t _segBri; // brightness of segment for current effect
484 static unsigned _vLength; // 1D dimension used for current effect
485 static unsigned _vWidth, _vHeight; // 2D dimensions used for current effect
486 static uint32_t _currentColors[NUM_COLORS]; // colors used for current effect
487 static bool _colorScaled; // color has been scaled prior to setPixelColor() call
488 static CRGBPalette16 _currentPalette; // palette used for current effect (includes transition, used in color_from_palette())
489 static CRGBPalette16 _randomPalette; // actual random palette
490 static CRGBPalette16 _newRandomPalette; // target random palette
491 static uint16_t _lastPaletteChange; // last random palette change time in millis()/1000
492 static uint16_t _lastPaletteBlend; // blend palette according to set Transition Delay in millis()%0xFFFF
493 static uint16_t _transitionprogress; // current transition progress 0 - 0xFFFF
494 #ifndef WLED_DISABLE_MODE_BLEND
495 static bool _modeBlend; // mode/effect blending semaphore
496 // clipping
497 static uint16_t _clipStart, _clipStop;
498 static uint8_t _clipStartY, _clipStopY;
499 #endif
500
501 // transition data, valid only if transitional==true, holds values during transition (72 bytes)
502 struct Transition {
503 #ifndef WLED_DISABLE_MODE_BLEND
504 tmpsegd_t _segT; // previous segment environment
505 uint8_t _modeT; // previous mode/effect
506 #else
507 uint32_t _colorT[NUM_COLORS];
508 #endif
509 uint8_t _palTid; // previous palette
510 uint8_t _briT; // temporary brightness
511 uint8_t _cctT; // temporary CCT
512 CRGBPalette16 _palT; // temporary palette
513 uint8_t _prevPaletteBlends; // number of previous palette blends (there are max 255 blends possible)
514 unsigned long _start; // must accommodate millis()
515 uint16_t _dur;
516 // -> here is one byte of padding
517 1196 Transition(uint16_t dur=750)
518
1/2
✓ Branch 0 taken 1196 times.
✗ Branch 1 not taken.
1196 : _palT(CRGBPalette16(CRGB::Black))
519 1196 , _prevPaletteBlends(0)
520 1196 , _start(millis())
521 1196 , _dur(dur)
522 1196 {}
523 } *_t;
524
525 [[gnu::hot]] void _setPixelColorXY_raw(const int& x, const int& y, uint32_t& col) const; // set pixel without mapping (internal use only)
526
527 public:
528
529 1196 Segment(uint16_t sStart=0, uint16_t sStop=30) :
530 1196 start(sStart),
531 1196 stop(sStop),
532 1196 offset(0),
533 1196 speed(DEFAULT_SPEED),
534 1196 intensity(DEFAULT_INTENSITY),
535 1196 palette(0),
536 1196 mode(DEFAULT_MODE),
537 1196 options(SELECTED | SEGMENT_ON),
538 1196 grouping(1),
539 1196 spacing(0),
540 1196 opacity(255),
541 1196 colors{DEFAULT_COLOR,BLACK,BLACK},
542 1196 cct(127),
543 1196 custom1(DEFAULT_C1),
544 1196 custom2(DEFAULT_C2),
545 1196 custom3(DEFAULT_C3),
546 1196 check1(false),
547 1196 check2(false),
548 1196 check3(false),
549 1196 startY(0),
550 1196 stopY(1),
551 1196 name(nullptr),
552 1196 next_time(0),
553 1196 step(0),
554 1196 call(0),
555 1196 aux0(0),
556 1196 aux1(0),
557 1196 data(nullptr),
558 1196 _capabilities(0),
559 1196 _default_palette(0),
560 1196 _dataLen(0),
561 1196 _t(nullptr)
562 {
563 #ifdef WLED_DEBUG
564 //Serial.printf("-- Creating segment: %p\n", this);
565 #endif
566 1196 }
567
568 1196 Segment(uint16_t sStartX, uint16_t sStopX, uint16_t sStartY, uint16_t sStopY) : Segment(sStartX, sStopX) {
569 1196 startY = sStartY;
570 1196 stopY = sStopY;
571 1196 }
572
573 Segment(const Segment &orig); // copy constructor
574 Segment(Segment &&orig) noexcept; // move constructor
575
576 2366 ~Segment() {
577 #ifdef WLED_DEBUG
578 //Serial.printf("-- Destroying segment: %p", this);
579 //if (name) Serial.printf(" %s (%p)", name, name);
580 //if (data) Serial.printf(" %d->(%p)", (int)_dataLen, data);
581 //Serial.println();
582 #endif
583
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2364 times.
2366 if (name) { free(name); name = nullptr; }
584 2366 stopTransition();
585 2366 deallocateData();
586 2366 }
587
588 Segment& operator= (const Segment &orig); // copy assignment
589 Segment& operator= (Segment &&orig) noexcept; // move assignment
590
591 #ifdef WLED_DEBUG
592 size_t getSize() const { return sizeof(Segment) + (data?_dataLen:0) + (name?strlen(name):0) + (_t?sizeof(Transition):0); }
593 #endif
594
595 inline bool getOption(uint8_t n) const { return ((options >> n) & 0x01); }
596 ✗ inline bool isSelected() const { return selected; }
597 76465 inline bool isInTransition() const { return _t != nullptr; }
598 7326894 inline bool isActive() const { return stop > start; }
599 inline bool hasRGB() const { return _isRGB; }
600 inline bool hasWhite() const { return _hasW; }
601 inline bool isCCT() const { return _isCCT; }
602
1/2
✓ Branch 0 taken 3154236 times.
✗ Branch 1 not taken.
3154236 inline uint16_t width() const { return isActive() ? (stop - start) : 0; } // segment width in physical pixels (length if 1D)
603 3154525 inline uint16_t height() const { return stopY - startY; } // segment height (if 2D) in physical pixels (it *is* always >=1)
604 236033 inline uint16_t length() const { return width() * height(); } // segment length (count) in physical pixels
605 3957145 inline uint16_t groupLength() const { return grouping + spacing; }
606 ✗ inline uint8_t getLightCapabilities() const { return _capabilities; }
607 inline void deactivate() { setGeometry(0,0); }
608 ✗ inline Segment &clearName() { if (name) free(name); name = nullptr; return *this; }
609 inline Segment &setName(const String &name) { return setName(name.c_str()); }
610
611 1161 inline static unsigned getUsedSegmentData() { return Segment::_usedSegmentData; }
612 775 inline static void addUsedSegmentData(int len) { Segment::_usedSegmentData += len; }
613 #ifndef WLED_DISABLE_MODE_BLEND
614 inline static void modeBlend(bool blend) { _modeBlend = blend; }
615 inline static bool getmodeBlend(void) { return _modeBlend; }
616 #endif
617 // point the static draw dimensions at this segment, so the pixel accessors address it
618 ✗ inline void setDrawDimensions() const { Segment::_vWidth = virtualWidth(); Segment::_vHeight = virtualHeight(); Segment::_vLength = virtualLength(); }
619 2323231 inline static unsigned vLength() { return Segment::_vLength; }
620 4615250 inline static unsigned vWidth() { return Segment::_vWidth; }
621 3889493 inline static unsigned vHeight() { return Segment::_vHeight; }
622 940459 inline static uint32_t getCurrentColor(unsigned i) { return Segment::_currentColors[i]; } // { return i < 3 ? Segment::_currentColors[i] : 0; }
623 149394 inline static const CRGBPalette16 &getCurrentPalette() { return Segment::_currentPalette; }
624 inline static uint8_t getCurrentBrightness() { return Segment::_segBri; }
625 static void handleRandomPalette();
626
627 void beginDraw(); // set up parameters for current effect
628 void setGeometry(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1, uint8_t m12=0);
629 Segment &setColor(uint8_t slot, uint32_t c);
630 Segment &setCCT(uint16_t k);
631 Segment &setOpacity(uint8_t o);
632 Segment &setOption(uint8_t n, bool val);
633 Segment &setMode(uint8_t fx, bool loadDefaults = false);
634 Segment &setPalette(uint8_t pal);
635 Segment &setName(const char* name);
636 uint8_t differs(const Segment& b) const;
637 void refreshLightCapabilities();
638
639 // runtime data functions
640 inline uint16_t dataSize() const { return _dataLen; }
641 bool allocateData(size_t len); // allocates effect data buffer in heap and clears it
642 void deallocateData(); // deallocates (frees) effect data buffer from heap
643 void resetIfRequired(); // sets all SEGENV variables to 0 and clears data buffer
644 /**
645 * Flags that before the next effect is calculated,
646 * the internal segment state should be reset.
647 * Call resetIfRequired before calling the next effect function.
648 * Safe to call from interrupts and network requests.
649 */
650 2392 inline Segment &markForReset() { reset = true; return *this; } // setOption(SEG_OPTION_RESET, true)
651
652 // transition functions
653 void startTransition(uint16_t dur); // transition has to start before actual segment values change
654 void stopTransition(); // ends transition mode by destroying transition structure (does nothing if not in transition)
655
2/2
✓ Branch 0 taken 2649 times.
✓ Branch 1 taken 5902 times.
8551 inline void handleTransition() { updateTransitionProgress(); if (progress() == 0xFFFFU) stopTransition(); }
656 #ifndef WLED_DISABLE_MODE_BLEND
657 void swapSegenv(tmpsegd_t &tmpSegD); // copies segment data into specifed buffer, if buffer is not a transition buffer, segment data is overwritten from transition buffer
658 void restoreSegenv(const tmpsegd_t &tmpSegD); // restores segment data from buffer, if buffer is not transition buffer, changed values are copied to transition buffer
659 #endif
660 [[gnu::hot]] void updateTransitionProgress(); // set current progression of transition
661 26257 inline uint16_t progress() const { return Segment::_transitionprogress; } // transition progression between 0-65535
662 [[gnu::hot]] uint8_t currentBri(bool useCct = false) const; // current segment brightness/CCT (blended while in transition)
663 uint8_t currentMode() const; // currently active effect/mode (while in transition)
664 [[gnu::hot]] uint32_t currentColor(uint8_t slot) const; // currently active segment color (blended while in transition)
665 CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal);
666 void loadOldPalette(); // loads old FX palette into _currentPalette
667
668 // 1D strip
669 [[gnu::hot]] uint16_t virtualLength() const;
670 [[gnu::hot]] void setPixelColor(int i, uint32_t c) const; // set relative pixel within segment with color
671 632457 inline void setPixelColor(unsigned n, uint32_t c) const { setPixelColor(int(n), c); }
672 19665 inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) const { setPixelColor(n, RGBW32(r,g,b,w)); }
673 181962 inline void setPixelColor(int n, CRGB c) const { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); }
674 #ifdef WLED_USE_AA_PIXELS
675 void setPixelColor(float i, uint32_t c, bool aa = true) const;
676 inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) const { setPixelColor(i, RGBW32(r,g,b,w), aa); }
677 inline void setPixelColor(float i, CRGB c, bool aa = true) const { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); }
678 #endif
679 #ifndef WLED_DISABLE_MODE_BLEND
680 static inline void setClippingRect(int startX, int stopX, int startY = 0, int stopY = 1) { _clipStart = startX; _clipStop = stopX; _clipStartY = startY; _clipStopY = stopY; };
681 #endif
682 bool isPixelClipped(int i) const;
683 [[gnu::hot]] uint32_t getPixelColor(int i) const;
684 // 1D support functions (some implement 2D as well)
685 void blur(uint8_t, bool smear = false);
686 void clear();
687 void fill(uint32_t c);
688 void fade_out(uint8_t r);
689 void fadeToSecondaryBy(uint8_t fadeBy);
690 void fadeToBlackBy(uint8_t fadeBy);
691 31968 inline void blendPixelColor(int n, uint32_t color, uint8_t blend) { setPixelColor(n, color_blend(getPixelColor(n), color, blend)); }
692 7511 inline void blendPixelColor(int n, CRGB c, uint8_t blend) { blendPixelColor(n, RGBW32(c.r,c.g,c.b,0), blend); }
693 7594 inline void addPixelColor(int n, uint32_t color, bool preserveCR = true) { setPixelColor(n, color_add(getPixelColor(n), color, preserveCR)); }
694 inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool preserveCR = true) { addPixelColor(n, RGBW32(r,g,b,w), preserveCR); }
695 inline void addPixelColor(int n, CRGB c, bool preserveCR = true) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), preserveCR); }
696 inline void fadePixelColor(uint16_t n, uint8_t fade) { setPixelColor(n, color_fade(getPixelColor(n), fade, true)); }
697 [[gnu::hot]] uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255) const;
698 [[gnu::hot]] uint32_t color_wheel(uint8_t pos) const;
699
700 // 2D Blur: shortcuts for bluring columns or rows only (50% faster than full 2D blur)
701 4 inline void blurCols(fract8 blur_amount, bool smear = false) { // blur all columns
702 4 blur2D(0, blur_amount, smear);
703 4 }
704 inline void blurRows(fract8 blur_amount, bool smear = false) { // blur all rows
705 blur2D(blur_amount, 0, smear);
706 }
707
708 // 2D matrix
709 [[gnu::hot]] unsigned virtualWidth() const; // segment width in virtual pixels (accounts for groupping and spacing)
710 [[gnu::hot]] unsigned virtualHeight() const; // segment height in virtual pixels (accounts for groupping and spacing)
711 115 inline unsigned nrOfVStrips() const { // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D)
712 #ifndef WLED_DISABLE_2D
713
3/4
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
115 return (is2D() && map1D2D == M12_pBar) ? virtualWidth() : 1;
714 #else
715 return 1;
716 #endif
717 }
718 #ifndef WLED_DISABLE_2D
719
3/4
✓ Branch 0 taken 2144643 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1768640 times.
✓ Branch 3 taken 376003 times.
2144643 inline bool is2D() const { return (width()>1 && height()>1); }
720 [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c) const; // set relative pixel within segment with color
721 128075 inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) const { setPixelColorXY(int(x), int(y), c); }
722 18 inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) const { setPixelColorXY(x, y, RGBW32(r,g,b,w)); }
723 139585 inline void setPixelColorXY(int x, int y, CRGB c) const { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
724 inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) const { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); }
725 #ifdef WLED_USE_AA_PIXELS
726 void setPixelColorXY(float x, float y, uint32_t c, bool aa = true) const;
727 inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) const { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); }
728 inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) const { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); }
729 #endif
730 [[gnu::hot]] bool isPixelXYClipped(int x, int y) const;
731 [[gnu::hot]] uint32_t getPixelColorXY(int x, int y) const;
732 // 2D support functions
733 inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); }
734 inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); }
735 68448 inline void addPixelColorXY(int x, int y, uint32_t color, bool preserveCR = true) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color, preserveCR)); }
736 inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool preserveCR = true) { addPixelColorXY(x, y, RGBW32(r,g,b,w), preserveCR); }
737 inline void addPixelColorXY(int x, int y, CRGB c, bool preserveCR = true) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), preserveCR); }
738 2832 inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); }
739 //void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur
740 void blur2D(uint8_t blur_x, uint8_t blur_y, bool smear = false);
741 void moveX(int delta, bool wrap = false);
742 void moveY(int delta, bool wrap = false);
743 void move(unsigned dir, unsigned delta, bool wrap = false);
744 void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false);
745 inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { drawCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); }
746 void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false);
747 inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { fillCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); }
748 void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft = false);
749 inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0), soft); } // automatic inline
750 void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0, int8_t rotate = 0, bool usePalGrad = false);
751 inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0)); } // automatic inline
752 inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0, bool usePalGrad = false) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0), rotate, usePalGrad); } // automatic inline
753 void wu_pixel(uint32_t x, uint32_t y, CRGB c);
754 inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); }
755 #else
756 inline bool is2D() const { return false; }
757 inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); }
758 inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); }
759 inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); }
760 inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0)); }
761 inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColor(int(x), RGBW32(c.r,c.g,c.b,0)); }
762 #ifdef WLED_USE_AA_PIXELS
763 inline void setPixelColorXY(float x, float y, uint32_t c, bool aa = true) { setPixelColor(x, c, aa); }
764 inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColor(x, RGBW32(r,g,b,w), aa); }
765 inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0), aa); }
766 #endif
767 inline bool isPixelXYClipped(int x, int y) { return isPixelClipped(x); }
768 inline uint32_t getPixelColorXY(int x, int y) { return getPixelColor(x); }
769 inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t c, uint8_t blend) { blendPixelColor(x, c, blend); }
770 inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColor(x, RGBW32(c.r,c.g,c.b,0), blend); }
771 inline void addPixelColorXY(int x, int y, uint32_t color, bool saturate = false) { addPixelColor(x, color, saturate); }
772 inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool saturate = false) { addPixelColor(x, RGBW32(r,g,b,w), saturate); }
773 inline void addPixelColorXY(int x, int y, CRGB c, bool saturate = false) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0), saturate); }
774 inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { fadePixelColor(x, fade); }
775 //inline void box_blur(unsigned i, bool vertical, fract8 blur_amount) {}
776 inline void blur2D(uint8_t blur_x, uint8_t blur_y, bool smear = false) {}
777 inline void blurRow(int row, fract8 blur_amount, bool smear = false) {}
778 inline void blurCol(int col, fract8 blur_amount, bool smear = false) {}
779 inline void moveX(int delta, bool wrap = false) {}
780 inline void moveY(int delta, bool wrap = false) {}
781 inline void move(uint8_t dir, uint8_t delta, bool wrap = false) {}
782 inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false) {}
783 inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {}
784 inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false) {}
785 inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {}
786 inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft = false) {}
787 inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false) {}
788 inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t = 0, int8_t = 0, bool = false) {}
789 inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB color) {}
790 inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0, bool usePalGrad = false) {}
791 inline void wu_pixel(uint32_t x, uint32_t y, CRGB c) {}
792 #endif
793 } segment;
794 //static int segSize = sizeof(Segment);
795
796 // main "strip" class
797 class WS2812FX { // 96 bytes
798 typedef uint16_t (*mode_ptr)(); // pointer to mode function
799 typedef void (*show_callback)(); // pre show callback
800 typedef struct ModeData {
801 uint8_t _id; // mode (effect) id
802 mode_ptr _fcn; // mode (effect) function
803 const char *_data; // mode (effect) name and its UI control data
804 ModeData(uint8_t id, uint16_t (*fcn)(void), const char *data) : _id(id), _fcn(fcn), _data(data) {}
805 } mode_data_t;
806
807 public:
808
809 3542 WS2812FX() :
810 3542 paletteBlend(0),
811 3542 now(millis()),
812 3542 timebase(0),
813 3542 isMatrix(false),
814 #ifndef WLED_DISABLE_2D
815 3542 panels(1),
816 #endif
817 #ifdef WLED_AUTOSEGMENTS
818 autoSegments(true),
819 #else
820 3542 autoSegments(false),
821 #endif
822 3542 correctWB(false),
823 3542 cctFromRgb(false),
824 // true private variables
825 3542 _suspend(false),
826 3542 _length(DEFAULT_LED_COUNT),
827 3542 _brightness(DEFAULT_BRIGHTNESS),
828 3542 _transitionDur(750),
829 3542 _targetFps(WLED_FPS),
830 3542 _frametime(FRAMETIME_FIXED),
831 3542 _cumulativeFps(50 << FPS_CALC_SHIFT),
832 3542 _isServicing(false),
833 3542 _isOffRefreshRequired(false),
834 3542 _hasWhiteChannel(false),
835 3542 _triggered(false),
836 3542 _modeCount(MODE_COUNT),
837 3542 _callback(nullptr),
838 3542 customMappingTable(nullptr),
839 3542 customMappingSize(0),
840 3542 _lastShow(0),
841 3542 _lastServiceShow(0),
842 3542 _segment_index(0),
843 3542 _mainSegment(0)
844 {
845
1/2
✓ Branch 0 taken 3542 times.
✗ Branch 1 not taken.
3542 _mode.reserve(_modeCount); // allocate memory to prevent initial fragmentation (does not increase size())
846
1/2
✓ Branch 0 taken 3542 times.
✗ Branch 1 not taken.
3542 _modeData.reserve(_modeCount); // allocate memory to prevent initial fragmentation (does not increase size())
847
3/6
✓ Branch 0 taken 3542 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3542 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3542 times.
3542 if (_mode.capacity() <= 1 || _modeData.capacity() <= 1) _modeCount = 1; // memory allocation failed only show Solid
848
1/2
✓ Branch 0 taken 3542 times.
✗ Branch 1 not taken.
3542 else setupEffectData();
849 3542 }
850
851 1628 ~WS2812FX() {
852
2/2
✓ Branch 0 taken 941 times.
✓ Branch 1 taken 687 times.
1628 if (customMappingTable) free(customMappingTable);
853 1628 _mode.clear();
854 1628 _modeData.clear();
855 1628 _segments.clear();
856 #ifndef WLED_DISABLE_2D
857 1628 panel.clear();
858 #endif
859 1628 customPalettes.clear();
860 1628 }
861
862
863 void
864 #ifdef WLED_DEBUG
865 printSize(), // prints memory usage for strip components
866 #endif
867 finalizeInit(), // initialises strip components
868 service(), // executes effect functions when due and calls strip.show()
869 setCCT(uint16_t k), // sets global CCT (either in relative 0-255 value or in K)
870 setBrightness(uint8_t b, bool direct = false), // sets strip brightness
871 setRange(uint16_t i, uint16_t i2, uint32_t col), // used for clock overlay
872 purgeSegments(), // removes inactive segments from RAM (may incure penalty and memory fragmentation but reduces vector footprint)
873 setMainSegmentId(unsigned n = 0),
874 resetSegments(), // marks all segments for reset
875 makeAutoSegments(bool forceReset = false), // will create segments based on configured outputs
876 fixInvalidSegments(), // fixes incorrect segment configuration
877 setPixelColor(unsigned i, uint32_t c) const, // paints absolute strip pixel with index n and color c
878 show(), // initiates LED output
879 setTargetFps(unsigned fps),
880 setupEffectData(); // add default effects to the list; defined in FX.cpp
881
882 inline void resetTimebase() { timebase = 0UL - millis(); }
883
3/4
✓ Branch 0 taken 1196 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1196 times.
✓ Branch 3 taken 3542 times.
4738 inline void restartRuntime() { for (Segment &seg : _segments) { seg.markForReset().resetIfRequired(); } }
884 inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); }
885 inline void setPixelColor(unsigned n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) const { setPixelColor(n, RGBW32(r,g,b,w)); }
886 inline void setPixelColor(unsigned n, CRGB c) const { setPixelColor(n, c.red, c.green, c.blue); }
887 inline void fill(uint32_t c) const { for (unsigned i = 0; i < getLengthTotal(); i++) setPixelColor(i, c); } // fill whole strip with color (inline)
888 ✗ inline void trigger() { _triggered = true; } // Forces the next frame to be computed on all active segments.
889 inline void setShowCallback(show_callback cb) { _callback = cb; }
890 inline void setTransition(uint16_t t) { _transitionDur = t; } // sets transition time (in ms)
891 inline void appendSegment(const Segment &seg = Segment()) { if (_segments.size() < getMaxSegments()) _segments.push_back(seg); }
892 inline void suspend() { _suspend = true; } // will suspend (and canacel) strip.service() execution
893 3542 inline void resume() { _suspend = false; } // will resume strip.service() execution
894
895 bool
896 checkSegmentAlignment() const,
897 hasRGBWBus() const,
898 hasCCTBus() const,
899 deserializeMap(unsigned n = 0);
900
901 inline bool isUpdating() const { return !BusManager::canAllShow(); } // return true if the strip is being sent pixel updates
902 inline bool isServicing() const { return _isServicing; } // returns true if strip.service() is executing
903 inline bool hasWhiteChannel() const { return _hasWhiteChannel; } // returns true if strip contains separate white chanel
904 282 inline bool isOffRefreshRequired() const { return _isOffRefreshRequired; } // returns true if strip requires regular updates (i.e. TM1814 chipset)
905 inline bool isSuspended() const { return _suspend; } // returns true if strip.service() execution is suspended
906 inline bool needsUpdate() const { return _triggered; } // returns true if strip received a trigger() request
907
908 uint8_t
909 paletteBlend,
910 getActiveSegmentsNum() const,
911 getFirstSelectedSegId() const,
912 getLastActiveSegmentId() const,
913 getActiveSegsLightCapabilities(bool selectedOnly = false) const,
914 addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name); // add effect to the list; defined in FX.cpp;
915
916 46 inline uint8_t getBrightness() const { return _brightness; } // returns current strip brightness
917 179 inline static constexpr unsigned getMaxSegments() { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value)
918 ✗ inline uint8_t getSegmentsNum() const { return _segments.size(); } // returns currently present segments
919 3419346 inline uint8_t getCurrSegmentId() const { return _segment_index; } // returns current segment index (only valid while strip.isServicing())
920 ✗ inline uint8_t getMainSegmentId() const { return _mainSegment; } // returns main segment index
921 inline uint8_t getPaletteCount() const { return 13 + GRADIENT_PALETTE_COUNT + customPalettes.size(); }
922 inline uint8_t getTargetFps() const { return _targetFps; } // returns rough FPS value for las 2s interval
923 2116506 inline uint8_t getModeCount() const { return _modeCount; } // returns number of registered modes/effects
924
925 uint16_t
926 getLengthPhysical() const,
927 getLengthTotal() const; // will include virtual/nonexistent pixels in matrix
928
929 inline uint16_t getFps() const { return (millis() - _lastShow > 2000) ? 0 : (FPS_MULTIPLIER * _cumulativeFps) >> FPS_CALC_SHIFT; } // Returns the refresh rate of the LED strip (_cumulativeFps is stored in fixed point)
930 23509 inline uint16_t getFrameTime() const { return _frametime; } // returns amount of time a frame should take (in ms)
931 inline uint16_t getMinShowDelay() const { return MIN_FRAME_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant)
932 inline uint16_t getLength() const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H)
933 11719 inline uint16_t getTransition() const { return _transitionDur; } // returns currently set transition time (in ms)
934 3570471 inline uint16_t getMappedPixelIndex(uint16_t index) const { // convert logical address to physical
935
3/6
✓ Branch 0 taken 2900507 times.
✓ Branch 1 taken 669964 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2900507 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3570471 if (index < customMappingSize && (realtimeMode == REALTIME_MODE_INACTIVE || realtimeRespectLedMaps)) index = customMappingTable[index];
936 3570471 return index;
937 };
938
939 unsigned long now, timebase;
940 uint32_t getPixelColor(unsigned i) const;
941
942 inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call
943
944
2/4
✓ Branch 0 taken 2622046 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2622046 times.
✗ Branch 3 not taken.
2622046 const char *getModeData(unsigned id = 0) const { return (id && id < _modeCount) ? _modeData[id] : PSTR("Solid"); }
945 inline const char **getModeDataSrc() { return &(_modeData[0]); } // vectors use arrays for underlying data
946
947 Segment& getSegment(unsigned id);
948 inline Segment& getFirstSelectedSeg() { return _segments[getFirstSelectedSegId()]; } // returns reference to first segment that is "selected"
949 inline Segment& getMainSegment() { return _segments[getMainSegmentId()]; } // returns reference to main segment
950 inline Segment* getSegments() { return &(_segments[0]); } // returns pointer to segment vector structure (warning: use carefully)
951
952 // 2D support (panels)
953 bool
954 isMatrix;
955
956 #ifndef WLED_DISABLE_2D
957 #define WLED_MAX_PANELS 18
958 uint8_t
959 panels;
960
961 typedef struct panel_t {
962 uint16_t xOffset; // x offset relative to the top left of matrix in LEDs
963 uint16_t yOffset; // y offset relative to the top left of matrix in LEDs
964 uint8_t width; // width of the panel
965 uint8_t height; // height of the panel
966 union {
967 uint8_t options;
968 struct {
969 bool bottomStart : 1; // starts at bottom?
970 bool rightStart : 1; // starts on right?
971 bool vertical : 1; // is vertical?
972 bool serpentine : 1; // is serpentine?
973 };
974 };
975 1196 panel_t()
976 1196 : xOffset(0)
977 1196 , yOffset(0)
978 1196 , width(8)
979 1196 , height(8)
980 1196 , options(0)
981 1196 {}
982 } Panel;
983 std::vector<Panel> panel;
984 #endif
985
986 void setUpMatrix(); // sets up automatic matrix ledmap from panel configuration
987
988 // outsmart the compiler :) by correctly overloading
989 2141600 inline void setPixelColorXY(int x, int y, uint32_t c) const { setPixelColor((unsigned)(y * Segment::maxWidth + x), c); }
990 inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) const { setPixelColorXY(x, y, RGBW32(r,g,b,w)); }
991 inline void setPixelColorXY(int x, int y, CRGB c) const { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
992
993
1/2
✓ Branch 0 taken 758907 times.
✗ Branch 1 not taken.
758907 inline uint32_t getPixelColorXY(int x, int y) const { return getPixelColor(isMatrix ? y * Segment::maxWidth + x : x); }
994
995 // end 2D support
996
997 void loadCustomPalettes(); // loads custom palettes from JSON
998 std::vector<CRGBPalette16> customPalettes; // TODO: move custom palettes out of WS2812FX class
999
1000 struct {
1001 bool autoSegments : 1;
1002 bool correctWB : 1;
1003 bool cctFromRgb : 1;
1004 };
1005
1006 std::vector<segment> _segments;
1007 friend struct Segment;
1008
1009 private:
1010 volatile bool _suspend;
1011
1012 uint16_t _length;
1013 uint8_t _brightness;
1014 uint16_t _transitionDur;
1015
1016 uint8_t _targetFps;
1017 uint16_t _frametime;
1018 uint16_t _cumulativeFps;
1019
1020 // will require only 1 byte
1021 struct {
1022 bool _isServicing : 1;
1023 bool _isOffRefreshRequired : 1; //periodic refresh is required for the strip to remain off.
1024 bool _hasWhiteChannel : 1;
1025 bool _triggered : 1;
1026 };
1027
1028 uint8_t _modeCount;
1029 std::vector<mode_ptr> _mode; // SRAM footprint: 4 bytes per element
1030 std::vector<const char*> _modeData; // mode (effect) name and its slider control data array
1031
1032 show_callback _callback;
1033
1034 uint16_t* customMappingTable;
1035 uint16_t customMappingSize;
1036
1037 unsigned long _lastShow;
1038 unsigned long _lastServiceShow;
1039
1040 uint8_t _segment_index;
1041 uint8_t _mainSegment;
1042 };
1043
1044 extern const char JSON_mode_names[];
1045 extern const char JSON_palette_names[];
1046
1047 #endif
1048