FastLED 3.10.8
Loading...
Searching...
No Matches
wave8.cpp.hpp
Go to the documentation of this file.
1
10
11#include "fl/channels/wave8.h"
14#include "fl/stl/isr/memcpy.h"
15#include "fl/stl/noexcept.h"
16
18
19namespace fl {
20
21// ============================================================================
22// Public Transposition Functions
23// ============================================================================
24
26void wave8Transpose_2(const u8 (&FL_RESTRICT_PARAM lanes)[2],
27 const Wave8BitExpansionLut &lut,
28 u8 (&FL_RESTRICT_PARAM output)[2 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
29 // Allocate waveform buffers on stack (16 Wave8Bit total: 8 packed bytes per lane × 2 lanes)
30 // Each Wave8Byte is 8 bytes (8 Wave8Bit × 1 byte each)
31 // Layout: [Lane0_bit7, Lane0_bit6, ..., Lane0_bit0, Lane1_bit7, Lane1_bit6, ..., Lane1_bit0]
32 Wave8Byte laneWaveformSymbols[2];
33
34 // Convert each lane byte to wave pulse symbols (8 packed bytes each)
35 detail::wave8_convert_byte_to_wave8byte(lanes[0], lut, &laneWaveformSymbols[0]);
36 detail::wave8_convert_byte_to_wave8byte(lanes[1], lut, &laneWaveformSymbols[1]);
37
38 // Transpose waveforms to DMA format (interleave 8 packed bytes to 16 bytes)
39 detail::wave8_transpose_2(laneWaveformSymbols, output);
40}
41
43void wave8Transpose_4(const u8 (&FL_RESTRICT_PARAM lanes)[4],
44 const Wave8BitExpansionLut &lut,
45 u8 (&FL_RESTRICT_PARAM output)[4 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
46 // Allocate waveform buffers on stack (32 Wave8Bit total: 8 packed bytes per lane × 4 lanes)
47 Wave8Byte laneWaveformSymbols[4];
48
49 // Convert each lane byte to wave pulse symbols (8 packed bytes each)
50 for (int lane = 0; lane < 4; lane++) {
51 detail::wave8_convert_byte_to_wave8byte(lanes[lane], lut, &laneWaveformSymbols[lane]);
52 }
53
54 // Transpose waveforms to DMA format (interleave 32 packed bytes to 32 bytes)
55 detail::wave8_transpose_4(laneWaveformSymbols, output);
56}
57
59void wave8Transpose_8(const u8 (&FL_RESTRICT_PARAM lanes)[8],
60 const Wave8BitExpansionLut &lut,
61 u8 (&FL_RESTRICT_PARAM output)[8 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
62 // Allocate waveform buffers on stack (64 Wave8Bit total: 8 packed bytes per lane × 8 lanes)
63 Wave8Byte laneWaveformSymbols[8];
64
65 // Convert each lane byte to wave pulse symbols (8 packed bytes each)
66 for (int lane = 0; lane < 8; lane++) {
67 detail::wave8_convert_byte_to_wave8byte(lanes[lane], lut, &laneWaveformSymbols[lane]);
68 }
69
70 // Transpose waveforms to DMA format (interleave 64 packed bytes to 64 bytes)
71 detail::wave8_transpose_8(laneWaveformSymbols, output);
72}
73
75void wave8Transpose_16(const u8 (&FL_RESTRICT_PARAM lanes)[16],
76 const Wave8BitExpansionLut &lut,
77 u8 (&FL_RESTRICT_PARAM output)[16 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
78 // Allocate waveform buffers on stack (128 Wave8Bit total: 8 packed bytes per lane × 16 lanes)
79 Wave8Byte laneWaveformSymbols[16];
80
81 // Convert each lane byte to wave pulse symbols (8 packed bytes each)
82 for (int lane = 0; lane < 16; lane++) {
83 detail::wave8_convert_byte_to_wave8byte(lanes[lane], lut, &laneWaveformSymbols[lane]);
84 }
85
86 // Transpose waveforms to DMA format (interleave 128 packed bytes to 128 bytes)
87 detail::wave8_transpose_16(laneWaveformSymbols, output);
88}
89
90// ============================================================================
91// Byte-LUT overloads (#2526): cheaper expansion, same DMA output.
92// ============================================================================
93
95void wave8Transpose_2(const u8 (&FL_RESTRICT_PARAM lanes)[2],
96 const Wave8ByteExpansionLut &lut,
97 u8 (&FL_RESTRICT_PARAM output)[2 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
98 Wave8Byte laneWaveformSymbols[2];
99 detail::wave8_expand_byte(lanes[0], lut, &laneWaveformSymbols[0]);
100 detail::wave8_expand_byte(lanes[1], lut, &laneWaveformSymbols[1]);
101 detail::wave8_transpose_2(laneWaveformSymbols, output);
102}
103
105void wave8Transpose_4(const u8 (&FL_RESTRICT_PARAM lanes)[4],
106 const Wave8ByteExpansionLut &lut,
107 u8 (&FL_RESTRICT_PARAM output)[4 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
108 Wave8Byte laneWaveformSymbols[4];
109 for (int lane = 0; lane < 4; lane++) {
110 detail::wave8_expand_byte(lanes[lane], lut, &laneWaveformSymbols[lane]);
111 }
112 detail::wave8_transpose_4(laneWaveformSymbols, output);
113}
114
116void wave8Transpose_8(const u8 (&FL_RESTRICT_PARAM lanes)[8],
117 const Wave8ByteExpansionLut &lut,
118 u8 (&FL_RESTRICT_PARAM output)[8 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
119 Wave8Byte laneWaveformSymbols[8];
120 for (int lane = 0; lane < 8; lane++) {
121 detail::wave8_expand_byte(lanes[lane], lut, &laneWaveformSymbols[lane]);
122 }
123 detail::wave8_transpose_8(laneWaveformSymbols, output);
124}
125
127void wave8Transpose_16(const u8 (&FL_RESTRICT_PARAM lanes)[16],
128 const Wave8ByteExpansionLut &lut,
129 u8 (&FL_RESTRICT_PARAM output)[16 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
130 Wave8Byte laneWaveformSymbols[16];
131 for (int lane = 0; lane < 16; lane++) {
132 detail::wave8_expand_byte(lanes[lane], lut, &laneWaveformSymbols[lane]);
133 }
134 detail::wave8_transpose_16(laneWaveformSymbols, output);
135}
136
139 const u8 (&FL_RESTRICT_PARAM lanes_b)[16],
140 const Wave8ByteExpansionLut &lut,
141 u8 (&FL_RESTRICT_PARAM output_a)[16 * sizeof(Wave8Byte)],
142 u8 (&FL_RESTRICT_PARAM output_b)[16 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
143 // Expand both positions independently — compiler can interleave the two
144 // loops freely because they share no data.
145 Wave8Byte laneWaveformsA[16];
146 Wave8Byte laneWaveformsB[16];
147 for (int lane = 0; lane < 16; lane++) {
148 detail::wave8_expand_byte(lanes_a[lane], lut, &laneWaveformsA[lane]);
149 }
150 for (int lane = 0; lane < 16; lane++) {
151 detail::wave8_expand_byte(lanes_b[lane], lut, &laneWaveformsB[lane]);
152 }
153 // Symbol-major loop with both transposes inlined back-to-back: the two
154 // OR-trees share no dependencies, so the compiler can interleave them and
155 // fill the in-order pipeline bubbles. See #2548.
156 detail::wave8_transpose_16x2_pipe2(laneWaveformsA, laneWaveformsB,
157 output_a, output_b);
158}
159
162 const Wave8ByteExpansionLut &lut,
163 u8 (&FL_RESTRICT_PARAM output)[16 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
164 // Extract W0/W1 chipset constants from the lut.
165 // byte_lut[0x00].symbols[0] = waveform for input bit 7 == 0 = W0
166 // byte_lut[0xFF].symbols[0] = waveform for input bit 7 == 1 = W1
167 const u8 W0 = lut.lut[0x00].symbols[0].data;
168 const u8 W1 = lut.lut[0xFF].symbols[0].data;
169 detail::wave8_transpose_16_bf1(lanes, W0, W1, output);
170}
171
174 const Wave8ByteExpansionLut &lut,
175 u8 (&FL_RESTRICT_PARAM output)[8 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
176 const u8 W0 = lut.lut[0x00].symbols[0].data;
177 const u8 W1 = lut.lut[0xFF].symbols[0].data;
178 detail::wave8_transpose_8_bf1(lanes, W0, W1, output);
179}
180
183 const Wave8ByteExpansionLut &lut,
184 u8 (&FL_RESTRICT_PARAM output)[4 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
185 const u8 W0 = lut.lut[0x00].symbols[0].data;
186 const u8 W1 = lut.lut[0xFF].symbols[0].data;
187 detail::wave8_transpose_4_bf1(lanes, W0, W1, output);
188}
189
192 const Wave8ByteExpansionLut &lut,
193 u8 (&FL_RESTRICT_PARAM output)[2 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
194 const u8 W0 = lut.lut[0x00].symbols[0].data;
195 const u8 W1 = lut.lut[0xFF].symbols[0].data;
196 detail::wave8_transpose_2_bf1(lanes, W0, W1, output);
197}
198
201 const u8 (&FL_RESTRICT_PARAM lanes_b)[16],
202 const u8 (&FL_RESTRICT_PARAM lanes_c)[16],
203 const u8 (&FL_RESTRICT_PARAM lanes_d)[16],
204 const Wave8ByteExpansionLut &lut,
205 u8 (&FL_RESTRICT_PARAM output_a)[16 * sizeof(Wave8Byte)],
206 u8 (&FL_RESTRICT_PARAM output_b)[16 * sizeof(Wave8Byte)],
207 u8 (&FL_RESTRICT_PARAM output_c)[16 * sizeof(Wave8Byte)],
208 u8 (&FL_RESTRICT_PARAM output_d)[16 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
209 const u8 W0 = lut.lut[0x00].symbols[0].data;
210 const u8 W1 = lut.lut[0xFF].symbols[0].data;
211 detail::wave8_transpose_16x4_bf1_pipe4(lanes_a, lanes_b, lanes_c, lanes_d,
212 W0, W1,
213 output_a, output_b, output_c, output_d);
214}
215
218 const u8 (&FL_RESTRICT_PARAM lanes_b)[16],
219 const u8 (&FL_RESTRICT_PARAM lanes_c)[16],
220 const u8 (&FL_RESTRICT_PARAM lanes_d)[16],
221 const Wave8ByteExpansionLut &lut,
222 u8 (&FL_RESTRICT_PARAM output_a)[16 * sizeof(Wave8Byte)],
223 u8 (&FL_RESTRICT_PARAM output_b)[16 * sizeof(Wave8Byte)],
224 u8 (&FL_RESTRICT_PARAM output_c)[16 * sizeof(Wave8Byte)],
225 u8 (&FL_RESTRICT_PARAM output_d)[16 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
226 Wave8Byte laneWaveformsA[16];
227 Wave8Byte laneWaveformsB[16];
228 Wave8Byte laneWaveformsC[16];
229 Wave8Byte laneWaveformsD[16];
230 for (int lane = 0; lane < 16; lane++) {
231 detail::wave8_expand_byte(lanes_a[lane], lut, &laneWaveformsA[lane]);
232 }
233 for (int lane = 0; lane < 16; lane++) {
234 detail::wave8_expand_byte(lanes_b[lane], lut, &laneWaveformsB[lane]);
235 }
236 for (int lane = 0; lane < 16; lane++) {
237 detail::wave8_expand_byte(lanes_c[lane], lut, &laneWaveformsC[lane]);
238 }
239 for (int lane = 0; lane < 16; lane++) {
240 detail::wave8_expand_byte(lanes_d[lane], lut, &laneWaveformsD[lane]);
241 }
242 detail::wave8_transpose_16x4_pipe4(laneWaveformsA, laneWaveformsB,
243 laneWaveformsC, laneWaveformsD,
244 output_a, output_b, output_c, output_d);
245}
246
247// ============================================================================
248// LUT Builder from Timing Data
249// Note: This is not designed to be called from ISR handlers.
250// ============================================================================
252Wave8BitExpansionLut buildWave8ExpansionLUT(const ChipsetTiming &timing) FL_NO_EXCEPT {
253 Wave8BitExpansionLut lut;
254
255 // Step 1: Calculate absolute times from ChipsetTiming format
256 // ChipsetTiming.T1 = T0H (high time for bit 0)
257 // ChipsetTiming.T2 = T1H - T0H (ADDITIONAL high time for bit 1)
258 // ChipsetTiming.T3 = T0L (low tail duration)
259 const u32 t0h = timing.T1; // T0H: bit 0 goes LOW here
260 const u32 t1h = timing.T1 + timing.T2; // T1H: bit 1 goes LOW here
261 const u32 period = timing.T1 + timing.T2 + timing.T3; // Total period
262
263 // Step 2: Normalize absolute times
264 const float t0h_norm = static_cast<float>(t0h) / period;
265 const float t1h_norm = static_cast<float>(t1h) / period;
266
267 // Step 3: Convert to pulse counts (fixed 8 pulses per bit)
268 // pulses_bit0: number of HIGH pulses for bit 0 (before it goes LOW at t0h)
269 // pulses_bit1: number of HIGH pulses for bit 1 (before it goes LOW at t1h)
270 u32 pulses_bit0 =
271 static_cast<u32>(t0h_norm * 8.0f + 0.5f); // round
272 u32 pulses_bit1 =
273 static_cast<u32>(t1h_norm * 8.0f + 0.5f); // round
274
275 // Clamp to valid range [0, 8]
276 if (pulses_bit0 > 8)
277 pulses_bit0 = 8;
278 if (pulses_bit1 > 8)
279 pulses_bit1 = 8;
280
281 // Step 4: Generate bit0 and bit1 waveforms (1 byte each, packed format)
282 // Each bit represents one pulse (MSB = first pulse)
283 u8 bit0_waveform = 0;
284 u8 bit1_waveform = 0;
285
286 // Bit 0: Set MSB bits for HIGH pulses
287 for (u32 i = 0; i < pulses_bit0; i++) {
288 bit0_waveform |= (0x80 >> i); // Set bit from MSB
289 }
290
291 // Bit 1: Set MSB bits for HIGH pulses
292 for (u32 i = 0; i < pulses_bit1; i++) {
293 bit1_waveform |= (0x80 >> i); // Set bit from MSB
294 }
295
296 // Step 5: Build LUT for all 16 nibbles
297 for (u8 nibble = 0; nibble < 16; nibble++) {
298 // For each nibble, generate 4 Wave8Bit (one per bit, MSB first)
299 for (int bit_pos = 3; bit_pos >= 0; bit_pos--) {
300 // Extract bit (MSB first: bit 3, 2, 1, 0)
301 const bool bit_set = (nibble >> bit_pos) & 1;
302 const u8 waveform = bit_set ? bit1_waveform : bit0_waveform;
303
304 // Store packed waveform to LUT entry
305 lut.lut[nibble][3 - bit_pos].data = waveform;
306 }
307 }
308
309 return lut;
310}
311
312// Byte-indexed expansion LUT (#2526). Entry b = high-nibble expansion in
313// symbols[0..3] + low-nibble expansion in symbols[4..7], matching
314// wave8_convert_byte_to_wave8byte() exactly (so the byte path is bit-identical).
315void buildWave8ByteExpansionLUT(const Wave8BitExpansionLut &nibble,
316 Wave8ByteExpansionLut &out) FL_NO_EXCEPT {
317 for (int b = 0; b < 256; ++b) {
318 const Wave8Bit *hi = nibble.lut[(b >> 4) & 0xF];
319 const Wave8Bit *lo = nibble.lut[b & 0xF];
320 for (int i = 0; i < 4; ++i) {
321 out.lut[b].symbols[i] = hi[i];
322 out.lut[b].symbols[i + 4] = lo[i];
323 }
324 }
325}
326
327Wave8ByteExpansionLut buildWave8ByteExpansionLUT(const Wave8BitExpansionLut &nibble) FL_NO_EXCEPT {
328 Wave8ByteExpansionLut out;
329 buildWave8ByteExpansionLUT(nibble, out);
330 return out;
331}
332
333// ============================================================================
334// Untranspose Functions (Testing Only - Not Optimized)
335// ============================================================================
336
338void wave8Untranspose_2(const u8 (&FL_RESTRICT_PARAM transposed)[2 * sizeof(Wave8Byte)],
339 u8 (&FL_RESTRICT_PARAM output)[2 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
340 // Reverse the 2-lane transposition
341 // Input: 16 bytes of interleaved data (2 bytes per symbol, 8 symbols)
342 // Output: 2 Wave8Byte structures (16 bytes total, de-interleaved)
343
344 Wave8Byte lane_waves[2];
345
346 // Process each of the 8 symbols
347 for (int symbol_idx = 0; symbol_idx < 8; symbol_idx++) {
348 // Read the 2 interleaved bytes for this symbol
349 u16 interleaved = ((u16)transposed[symbol_idx * 2] << 8) |
350 transposed[symbol_idx * 2 + 1];
351
352 // De-interleave bits back to lanes
353 u8 lane0_bits = 0;
354 u8 lane1_bits = 0;
355
356 // Extract bits: interleaved format has alternating bits [L0, L1, L0, L1, ...]
357 // Bits are ordered: [L1_b7, L0_b7, L1_b6, L0_b6, L1_b5, L0_b5, L1_b4, L0_b4, ...]
358 for (int bit = 0; bit < 8; bit++) {
359 // Lane 0 bits are at odd positions (shifted left by 1)
360 if (interleaved & (1 << (bit * 2 + 1))) {
361 lane0_bits |= (1 << bit);
362 }
363 // Lane 1 bits are at even positions
364 if (interleaved & (1 << (bit * 2))) {
365 lane1_bits |= (1 << bit);
366 }
367 }
368
369 lane_waves[0].symbols[symbol_idx].data = lane0_bits;
370 lane_waves[1].symbols[symbol_idx].data = lane1_bits;
371 }
372
373 // Copy de-interleaved data to output
374 fl::isr::memcopy(output, &lane_waves[0], sizeof(Wave8Byte));
375 fl::isr::memcopy(output + sizeof(Wave8Byte), &lane_waves[1], sizeof(Wave8Byte));
376}
377
379void wave8Untranspose_4(const u8 (&FL_RESTRICT_PARAM transposed)[4 * sizeof(Wave8Byte)],
380 u8 (&FL_RESTRICT_PARAM output)[4 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
381 // Reverse the 4-lane transposition
382 // Input: 32 bytes of interleaved data (4 bytes per symbol, 8 symbols)
383 // Output: 4 Wave8Byte structures (32 bytes total, de-interleaved)
384
385 Wave8Byte lane_waves[4];
386
387 // Process each of the 8 symbols
388 for (int symbol_idx = 0; symbol_idx < 8; symbol_idx++) {
389 u8 lane_bytes[4] = {0, 0, 0, 0};
390
391 // Process 4 input bytes (2 pulses per byte)
392 for (int byte_idx = 0; byte_idx < 4; byte_idx++) {
393 u8 input_byte = transposed[symbol_idx * 4 + byte_idx];
394
395 // Calculate which pulse bits these correspond to
396 int pulse_bit_hi = 7 - (byte_idx * 2);
397 int pulse_bit_lo = pulse_bit_hi - 1;
398
399 // De-interleave 4 lanes from this byte
400 // Bit layout: [L3_hi, L2_hi, L1_hi, L0_hi, L3_lo, L2_lo, L1_lo, L0_lo]
401 for (int lane = 0; lane < 4; lane++) {
402 // Extract bits for this lane
403 u8 pulse_hi = (input_byte >> (4 + lane)) & 1;
404 u8 pulse_lo = (input_byte >> lane) & 1;
405
406 // Reconstruct lane byte
407 lane_bytes[lane] |= (pulse_hi << pulse_bit_hi);
408 lane_bytes[lane] |= (pulse_lo << pulse_bit_lo);
409 }
410 }
411
412 // Store de-interleaved bytes
413 for (int lane = 0; lane < 4; lane++) {
414 lane_waves[lane].symbols[symbol_idx].data = lane_bytes[lane];
415 }
416 }
417
418 // Copy de-interleaved data to output
419 for (int lane = 0; lane < 4; lane++) {
420 fl::isr::memcopy(output + lane * sizeof(Wave8Byte), &lane_waves[lane], sizeof(Wave8Byte));
421 }
422}
423
425void wave8Untranspose_8(const u8 (&FL_RESTRICT_PARAM transposed)[8 * sizeof(Wave8Byte)],
426 u8 (&FL_RESTRICT_PARAM output)[8 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
427 // Reverse the 8-lane transposition
428 // Input: 64 bytes of interleaved data (8 bytes per symbol, 8 symbols)
429 // Output: 8 Wave8Byte structures (64 bytes total, de-interleaved)
430
431 Wave8Byte lane_waves[8];
432
433 // Process each of the 8 symbols
434 for (int symbol_idx = 0; symbol_idx < 8; symbol_idx++) {
435 u8 lane_bytes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
436
437 // Process 8 input bytes (1 pulse per byte)
438 // After transpose+reversal: byte 0 = bit 7 (first pulse, MSB),
439 // byte 7 = bit 0 (last pulse, LSB)
440 for (int byte_idx = 0; byte_idx < 8; byte_idx++) {
441 u8 input_byte = transposed[symbol_idx * 8 + byte_idx];
442
443 // Calculate which pulse bit this corresponds to
444 // byte 0 = bit 7, byte 7 = bit 0 (reversed order)
445 int pulse_bit = 7 - byte_idx;
446
447 // De-interleave 8 lanes from this byte
448 // Bit layout: [L7, L6, L5, L4, L3, L2, L1, L0]
449 for (int lane = 0; lane < 8; lane++) {
450 // Extract bit for this lane (lane 0 = LSB, lane 7 = MSB)
451 u8 pulse = (input_byte >> lane) & 1;
452
453 // Reconstruct lane byte
454 lane_bytes[lane] |= (pulse << pulse_bit);
455 }
456 }
457
458 // Store de-interleaved bytes
459 for (int lane = 0; lane < 8; lane++) {
460 lane_waves[lane].symbols[symbol_idx].data = lane_bytes[lane];
461 }
462 }
463
464 // Copy de-interleaved data to output
465 for (int lane = 0; lane < 8; lane++) {
466 fl::isr::memcopy(output + lane * sizeof(Wave8Byte), &lane_waves[lane], sizeof(Wave8Byte));
467 }
468}
469
471void wave8Untranspose_16(const u8 (&FL_RESTRICT_PARAM transposed)[16 * sizeof(Wave8Byte)],
472 u8 (&FL_RESTRICT_PARAM output)[16 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
473 // Reverse the 16-lane transposition
474 // Input: 128 bytes of interleaved data (16 bytes per symbol, 8 symbols)
475 // Output: 16 Wave8Byte structures (128 bytes total, de-interleaved)
476
477 Wave8Byte lane_waves[16];
478
479 // Process each of the 8 symbols
480 for (int symbol_idx = 0; symbol_idx < 8; symbol_idx++) {
481 u8 lane_bytes[16] = {0};
482
483 // Process 8 pulses (16 bytes total: 2 bytes per pulse)
484 for (int pulse_idx = 0; pulse_idx < 8; pulse_idx++) {
485 int pulse_bit = 7 - pulse_idx;
486
487 // Read 16-bit word for this pulse
488 int input_offset = symbol_idx * 16 + pulse_idx * 2;
489 u16 input_word = (u16)transposed[input_offset] |
490 ((u16)transposed[input_offset + 1] << 8);
491
492 // De-interleave 16 lanes from this word
493 // Bit layout: [L15, L14, L13, ..., L1, L0]
494 for (int lane = 0; lane < 16; lane++) {
495 // Extract bit for this lane (lane 0 = LSB, lane 15 = MSB)
496 u8 pulse = (input_word >> lane) & 1;
497
498 // Reconstruct lane byte
499 lane_bytes[lane] |= (pulse << pulse_bit);
500 }
501 }
502
503 // Store de-interleaved bytes
504 for (int lane = 0; lane < 16; lane++) {
505 lane_waves[lane].symbols[symbol_idx].data = lane_bytes[lane];
506 }
507 }
508
509 // Copy de-interleaved data to output
510 for (int lane = 0; lane < 16; lane++) {
511 fl::isr::memcopy(output + lane * sizeof(Wave8Byte), &lane_waves[lane], sizeof(Wave8Byte));
512 }
513}
514
515} // namespace fl
516
#define FL_OPTIMIZATION_LEVEL_O3_BEGIN
#define FL_OPTIMIZATION_LEVEL_O3_END
#define FL_OPTIMIZE_FUNCTION
#define FL_IRAM
#define FL_RESTRICT_PARAM
Out-of-line declarations for wave8 transposition internals.
Centralized LED chipset timing definitions with nanosecond precision.
ISR-safe memory operations (inline, header-only)
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_16_bf1(const u8 lanes[16], u8 W0, u8 W1, u8 output[16 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_16x2_pipe2(const Wave8Byte lane_waves_a[16], const Wave8Byte lane_waves_b[16], u8 output_a[16 *sizeof(Wave8Byte)], u8 output_b[16 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_4(const Wave8Byte lane_waves[4], u8 output[4 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
Definition wave8.cpp.hpp:62
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_16x4_pipe4(const Wave8Byte lane_waves_a[16], const Wave8Byte lane_waves_b[16], const Wave8Byte lane_waves_c[16], const Wave8Byte lane_waves_d[16], u8 output_a[16 *sizeof(Wave8Byte)], u8 output_b[16 *sizeof(Wave8Byte)], u8 output_c[16 *sizeof(Wave8Byte)], u8 output_d[16 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_8(const Wave8Byte lane_waves[8], u8 output[8 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_16(const Wave8Byte lane_waves[16], u8 output[16 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_16x4_bf1_pipe4(const u8 lanes_a[16], const u8 lanes_b[16], const u8 lanes_c[16], const u8 lanes_d[16], u8 W0, u8 W1, u8 output_a[16 *sizeof(Wave8Byte)], u8 output_b[16 *sizeof(Wave8Byte)], u8 output_c[16 *sizeof(Wave8Byte)], u8 output_d[16 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_4_bf1(const u8 lanes[4], u8 W0, u8 W1, u8 output[4 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_8_bf1(const u8 lanes[8], u8 W0, u8 W1, u8 output[8 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_2(const Wave8Byte lane_waves[2], u8 output[2 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
Definition wave8.cpp.hpp:48
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_convert_byte_to_wave8byte(u8 byte_value, const Wave8BitExpansionLut &lut, Wave8Byte *output) FL_NO_EXCEPT
Definition wave8.cpp.hpp:24
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_2_bf1(const u8 lanes[2], u8 W0, u8 W1, u8 output[2 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_expand_byte(u8 byte_value, const Wave8ByteExpansionLut &lut, Wave8Byte *output) FL_NO_EXCEPT
Definition wave8.cpp.hpp:39
FL_OPTIMIZE_FUNCTION FL_IRAM FASTLED_FORCE_INLINE void memcopy(void *FL_RESTRICT_PARAM dst, const void *FL_RESTRICT_PARAM src, size_t num_bytes)
ISR-optimized memcpy with alignment detection and switch dispatch.
Definition memcpy.h:75
unsigned char u8
Definition stdint.h:131
FL_OPTIMIZE_FUNCTION FL_IRAM void wave8Transpose_4(const u8(&FL_RESTRICT_PARAM lanes)[4], const Wave8BitExpansionLut &lut, u8(&FL_RESTRICT_PARAM output)[4 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
Definition wave8.cpp.hpp:43
FL_OPTIMIZE_FUNCTION FL_IRAM void wave8Transpose_16x4_pipe4(const u8(&FL_RESTRICT_PARAM lanes_a)[16], const u8(&FL_RESTRICT_PARAM lanes_b)[16], const u8(&FL_RESTRICT_PARAM lanes_c)[16], const u8(&FL_RESTRICT_PARAM lanes_d)[16], const Wave8ByteExpansionLut &lut, u8(&FL_RESTRICT_PARAM output_a)[16 *sizeof(Wave8Byte)], u8(&FL_RESTRICT_PARAM output_b)[16 *sizeof(Wave8Byte)], u8(&FL_RESTRICT_PARAM output_c)[16 *sizeof(Wave8Byte)], u8(&FL_RESTRICT_PARAM output_d)[16 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
Pipe4: transpose 16-lane × 4-byte-positions (#2548).
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
FL_OPTIMIZE_FUNCTION void wave8Untranspose_2(const u8(&FL_RESTRICT_PARAM transposed)[2 *sizeof(Wave8Byte)], u8(&FL_RESTRICT_PARAM output)[2 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_OPTIMIZE_FUNCTION FL_IRAM void wave8Transpose_2_bf1(const u8(&FL_RESTRICT_PARAM lanes)[2], const Wave8ByteExpansionLut &lut, u8(&FL_RESTRICT_PARAM output)[2 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
BF1 for 2-lane Wave8 (#2548 deep-dive followup).
FL_OPTIMIZE_FUNCTION FL_IRAM void wave8Transpose_8_bf1(const u8(&FL_RESTRICT_PARAM lanes)[8], const Wave8ByteExpansionLut &lut, u8(&FL_RESTRICT_PARAM output)[8 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
BF1 for 8-lane Wave8 (#2548 deep-dive followup).
FL_OPTIMIZE_FUNCTION FL_IRAM void wave8Transpose_2(const u8(&FL_RESTRICT_PARAM lanes)[2], const Wave8BitExpansionLut &lut, u8(&FL_RESTRICT_PARAM output)[2 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
Definition wave8.cpp.hpp:26
FL_OPTIMIZE_FUNCTION FL_IRAM void wave8Transpose_16_bf1(const u8(&FL_RESTRICT_PARAM lanes)[16], const Wave8ByteExpansionLut &lut, u8(&FL_RESTRICT_PARAM output)[16 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
BF1: chipset-aware direct encode for 16-lane Wave8 (#2548 deep-dive).
FL_OPTIMIZE_FUNCTION FL_IRAM void wave8Transpose_8(const u8(&FL_RESTRICT_PARAM lanes)[8], const Wave8BitExpansionLut &lut, u8(&FL_RESTRICT_PARAM output)[8 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
Definition wave8.cpp.hpp:59
FL_OPTIMIZE_FUNCTION void wave8Untranspose_4(const u8(&FL_RESTRICT_PARAM transposed)[4 *sizeof(Wave8Byte)], u8(&FL_RESTRICT_PARAM output)[4 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
void buildWave8ByteExpansionLUT(const Wave8BitExpansionLut &nibble, Wave8ByteExpansionLut &out) FL_NO_EXCEPT
Out-param overload: fill an existing 2 KB LUT in place.
FL_OPTIMIZE_FUNCTION FL_IRAM void wave8Transpose_16x4_bf1_pipe4(const u8(&FL_RESTRICT_PARAM lanes_a)[16], const u8(&FL_RESTRICT_PARAM lanes_b)[16], const u8(&FL_RESTRICT_PARAM lanes_c)[16], const u8(&FL_RESTRICT_PARAM lanes_d)[16], const Wave8ByteExpansionLut &lut, u8(&FL_RESTRICT_PARAM output_a)[16 *sizeof(Wave8Byte)], u8(&FL_RESTRICT_PARAM output_b)[16 *sizeof(Wave8Byte)], u8(&FL_RESTRICT_PARAM output_c)[16 *sizeof(Wave8Byte)], u8(&FL_RESTRICT_PARAM output_d)[16 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
BF1 + pipe4: 4-position-pipelined direct encode (#2548 deep-dive).
FL_OPTIMIZE_FUNCTION void wave8Untranspose_16(const u8(&FL_RESTRICT_PARAM transposed)[16 *sizeof(Wave8Byte)], u8(&FL_RESTRICT_PARAM output)[16 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_OPTIMIZE_FUNCTION FL_IRAM void wave8Transpose_16(const u8(&FL_RESTRICT_PARAM lanes)[16], const Wave8BitExpansionLut &lut, u8(&FL_RESTRICT_PARAM output)[16 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
Definition wave8.cpp.hpp:75
FL_OPTIMIZE_FUNCTION Wave8BitExpansionLut buildWave8ExpansionLUT(const ChipsetTiming &timing) FL_NO_EXCEPT
Build a Wave8BitExpansionLut from chipset timing data.
FL_OPTIMIZE_FUNCTION FL_IRAM void wave8Transpose_16x2_pipe2(const u8(&FL_RESTRICT_PARAM lanes_a)[16], const u8(&FL_RESTRICT_PARAM lanes_b)[16], const Wave8ByteExpansionLut &lut, u8(&FL_RESTRICT_PARAM output_a)[16 *sizeof(Wave8Byte)], u8(&FL_RESTRICT_PARAM output_b)[16 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
Pipe2: transpose 16-lane × 2-byte-positions (#2548).
FL_OPTIMIZE_FUNCTION FL_IRAM void wave8Transpose_4_bf1(const u8(&FL_RESTRICT_PARAM lanes)[4], const Wave8ByteExpansionLut &lut, u8(&FL_RESTRICT_PARAM output)[4 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
BF1 for 4-lane Wave8 (#2548 deep-dive followup).
FL_OPTIMIZE_FUNCTION void wave8Untranspose_8(const u8(&FL_RESTRICT_PARAM transposed)[8 *sizeof(Wave8Byte)], u8(&FL_RESTRICT_PARAM output)[8 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
@ W1
White is second.
Definition eorder.h:28
@ W0
White is first.
Definition eorder.h:29
Base definition for an LED controller.
Definition crgb.hpp:179
Generic chipset timing entry Provides T1, T2, T3 timing parameters in nanoseconds for any LED protoco...
Definition led_timing.h:86
Type-safe container for packed 8-bit wave pulse pattern.
Definition wave8.h:23