27 const Wave8BitExpansionLut &lut,
32 Wave8Byte laneWaveformSymbols[2];
44 const Wave8BitExpansionLut &lut,
47 Wave8Byte laneWaveformSymbols[4];
50 for (
int lane = 0; lane < 4; lane++) {
60 const Wave8BitExpansionLut &lut,
63 Wave8Byte laneWaveformSymbols[8];
66 for (
int lane = 0; lane < 8; lane++) {
76 const Wave8BitExpansionLut &lut,
79 Wave8Byte laneWaveformSymbols[16];
82 for (
int lane = 0; lane < 16; lane++) {
96 const Wave8ByteExpansionLut &lut,
98 Wave8Byte laneWaveformSymbols[2];
106 const Wave8ByteExpansionLut &lut,
108 Wave8Byte laneWaveformSymbols[4];
109 for (
int lane = 0; lane < 4; lane++) {
117 const Wave8ByteExpansionLut &lut,
119 Wave8Byte laneWaveformSymbols[8];
120 for (
int lane = 0; lane < 8; lane++) {
128 const Wave8ByteExpansionLut &lut,
130 Wave8Byte laneWaveformSymbols[16];
131 for (
int lane = 0; lane < 16; lane++) {
140 const Wave8ByteExpansionLut &lut,
145 Wave8Byte laneWaveformsA[16];
146 Wave8Byte laneWaveformsB[16];
147 for (
int lane = 0; lane < 16; lane++) {
150 for (
int lane = 0; lane < 16; lane++) {
162 const Wave8ByteExpansionLut &lut,
167 const u8 W0 = lut.lut[0x00].symbols[0].data;
168 const u8 W1 = lut.lut[0xFF].symbols[0].data;
174 const Wave8ByteExpansionLut &lut,
176 const u8 W0 = lut.lut[0x00].symbols[0].data;
177 const u8 W1 = lut.lut[0xFF].symbols[0].data;
183 const Wave8ByteExpansionLut &lut,
185 const u8 W0 = lut.lut[0x00].symbols[0].data;
186 const u8 W1 = lut.lut[0xFF].symbols[0].data;
192 const Wave8ByteExpansionLut &lut,
194 const u8 W0 = lut.lut[0x00].symbols[0].data;
195 const u8 W1 = lut.lut[0xFF].symbols[0].data;
204 const Wave8ByteExpansionLut &lut,
209 const u8 W0 = lut.lut[0x00].symbols[0].data;
210 const u8 W1 = lut.lut[0xFF].symbols[0].data;
213 output_a, output_b, output_c, output_d);
221 const Wave8ByteExpansionLut &lut,
226 Wave8Byte laneWaveformsA[16];
227 Wave8Byte laneWaveformsB[16];
228 Wave8Byte laneWaveformsC[16];
229 Wave8Byte laneWaveformsD[16];
230 for (
int lane = 0; lane < 16; lane++) {
233 for (
int lane = 0; lane < 16; lane++) {
236 for (
int lane = 0; lane < 16; lane++) {
239 for (
int lane = 0; lane < 16; lane++) {
243 laneWaveformsC, laneWaveformsD,
244 output_a, output_b, output_c, output_d);
253 Wave8BitExpansionLut lut;
259 const u32 t0h = timing.T1;
260 const u32 t1h = timing.T1 + timing.T2;
261 const u32 period = timing.T1 + timing.T2 + timing.T3;
264 const float t0h_norm =
static_cast<float>(t0h) / period;
265 const float t1h_norm =
static_cast<float>(t1h) / period;
271 static_cast<u32
>(t0h_norm * 8.0f + 0.5f);
273 static_cast<u32
>(t1h_norm * 8.0f + 0.5f);
283 u8 bit0_waveform = 0;
284 u8 bit1_waveform = 0;
287 for (u32 i = 0; i < pulses_bit0; i++) {
288 bit0_waveform |= (0x80 >> i);
292 for (u32 i = 0; i < pulses_bit1; i++) {
293 bit1_waveform |= (0x80 >> i);
297 for (
u8 nibble = 0; nibble < 16; nibble++) {
299 for (
int bit_pos = 3; bit_pos >= 0; bit_pos--) {
301 const bool bit_set = (nibble >> bit_pos) & 1;
302 const u8 waveform = bit_set ? bit1_waveform : bit0_waveform;
305 lut.lut[nibble][3 - bit_pos].data = waveform;
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];
328 Wave8ByteExpansionLut out;
344 Wave8Byte lane_waves[2];
347 for (
int symbol_idx = 0; symbol_idx < 8; symbol_idx++) {
349 u16 interleaved = ((u16)transposed[symbol_idx * 2] << 8) |
350 transposed[symbol_idx * 2 + 1];
358 for (
int bit = 0; bit < 8; bit++) {
360 if (interleaved & (1 << (bit * 2 + 1))) {
361 lane0_bits |= (1 << bit);
364 if (interleaved & (1 << (bit * 2))) {
365 lane1_bits |= (1 << bit);
369 lane_waves[0].symbols[symbol_idx].data = lane0_bits;
370 lane_waves[1].symbols[symbol_idx].data = lane1_bits;
375 fl::isr::memcopy(output +
sizeof(Wave8Byte), &lane_waves[1],
sizeof(Wave8Byte));
385 Wave8Byte lane_waves[4];
388 for (
int symbol_idx = 0; symbol_idx < 8; symbol_idx++) {
389 u8 lane_bytes[4] = {0, 0, 0, 0};
392 for (
int byte_idx = 0; byte_idx < 4; byte_idx++) {
393 u8 input_byte = transposed[symbol_idx * 4 + byte_idx];
396 int pulse_bit_hi = 7 - (byte_idx * 2);
397 int pulse_bit_lo = pulse_bit_hi - 1;
401 for (
int lane = 0; lane < 4; lane++) {
403 u8 pulse_hi = (input_byte >> (4 + lane)) & 1;
404 u8 pulse_lo = (input_byte >> lane) & 1;
407 lane_bytes[lane] |= (pulse_hi << pulse_bit_hi);
408 lane_bytes[lane] |= (pulse_lo << pulse_bit_lo);
413 for (
int lane = 0; lane < 4; lane++) {
414 lane_waves[lane].symbols[symbol_idx].data = lane_bytes[lane];
419 for (
int lane = 0; lane < 4; lane++) {
420 fl::isr::memcopy(output + lane *
sizeof(Wave8Byte), &lane_waves[lane],
sizeof(Wave8Byte));
431 Wave8Byte lane_waves[8];
434 for (
int symbol_idx = 0; symbol_idx < 8; symbol_idx++) {
435 u8 lane_bytes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
440 for (
int byte_idx = 0; byte_idx < 8; byte_idx++) {
441 u8 input_byte = transposed[symbol_idx * 8 + byte_idx];
445 int pulse_bit = 7 - byte_idx;
449 for (
int lane = 0; lane < 8; lane++) {
451 u8 pulse = (input_byte >> lane) & 1;
454 lane_bytes[lane] |= (pulse << pulse_bit);
459 for (
int lane = 0; lane < 8; lane++) {
460 lane_waves[lane].symbols[symbol_idx].data = lane_bytes[lane];
465 for (
int lane = 0; lane < 8; lane++) {
466 fl::isr::memcopy(output + lane *
sizeof(Wave8Byte), &lane_waves[lane],
sizeof(Wave8Byte));
477 Wave8Byte lane_waves[16];
480 for (
int symbol_idx = 0; symbol_idx < 8; symbol_idx++) {
481 u8 lane_bytes[16] = {0};
484 for (
int pulse_idx = 0; pulse_idx < 8; pulse_idx++) {
485 int pulse_bit = 7 - pulse_idx;
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);
494 for (
int lane = 0; lane < 16; lane++) {
496 u8 pulse = (input_word >> lane) & 1;
499 lane_bytes[lane] |= (pulse << pulse_bit);
504 for (
int lane = 0; lane < 16; lane++) {
505 lane_waves[lane].symbols[symbol_idx].data = lane_bytes[lane];
510 for (
int lane = 0; lane < 16; lane++) {
511 fl::isr::memcopy(output + lane *
sizeof(Wave8Byte), &lane_waves[lane],
sizeof(Wave8Byte));
#define FL_OPTIMIZATION_LEVEL_O3_BEGIN
#define FL_OPTIMIZATION_LEVEL_O3_END
#define FL_OPTIMIZE_FUNCTION
#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
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
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_convert_byte_to_wave8byte(u8 byte_value, const Wave8BitExpansionLut &lut, Wave8Byte *output) FL_NO_EXCEPT
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
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.
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
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
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
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
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
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
Base definition for an LED controller.
Generic chipset timing entry Provides T1, T2, T3 timing parameters in nanoseconds for any LED protoco...
Type-safe container for packed 8-bit wave pulse pattern.