FastLED 3.10.6
Loading...
Searching...
No Matches

◆ writeHD108()

template<typename CONTAINER_UIN8_T>
void fl::PixelIterator::writeHD108 ( CONTAINER_UIN8_T * out,
bool managed = false )
inline

Encode pixels in HD108 format (zero allocation)

Parameters
outOutput buffer to write encoded bytes
Note
Protocol: 16-bit RGB with gamma correction and brightness control
Parameters
managedTrue when the source is the colour-managed one, i.e. loadAndScaleRGB16 yields a device drive rather than a widened 8-bit pixel. Then the fixed 2.8 gamma is skipped: it would be a second shaping stage after the device solve (#4326).

Definition at line 624 of file pixel_iterator.h.

624 {
625 auto back_ins = fl::back_inserter(*out);
626
627 // One loop for both sources. This used to be two: the managed path
628 // written out by hand here, and the 8-bit path routed through
629 // `encodeHD108` over `makeScaledPixelRangeRGB`. Each carried its own
630 // copy of the framing -- the 8-byte start frame, the per-LED emit of
631 // header + three big-endian channels, the latch -- and together they
632 // made this the largest encoder body in a Blink build (481 B on
633 // esp32dev, ahead of `writeWS2812`, the only one Blink runs). The only
634 // thing that differed was where the 16-bit channels came from, so
635 // that is now the only branch (FastLED#4402).
636 //
637 // Byte-identical to the iterator path by construction:
638 // `ScaledPixelIteratorRGB::advance()` is exactly `has(1)`,
639 // `loadAndScaleRGB` into wire order, `stepDithering`, `advanceData`,
640 // once per pixel; the bytes it hands `encodeHD108` are captured before
641 // the step, which is what this loop does too.
642 //
643 // Inline rather than an `encodeHD108_wide` in hd108.h: that header is
644 // included *by* this one, before `PixelIterator` exists, and a
645 // concrete `PixelIterator&` parameter is not a dependent type -- so
646 // its body would be checked there and fail (#4326).
647#if FL_PLATFORM_HAS_TINY_MEMORY
648 // No wide source exists on TINY, so the flag selects nothing there.
649 FL_UNUSED(managed);
650#endif
651 for (int i = 0; i < 8; i++) {
652 *back_ins++ = 0x00; // start frame
653 }
654 // `hd108BrightnessHeader` discards its argument and pins every gain
655 // at 31, so this is 0xFF 0xFF whatever is passed (#4402).
656 u8 f0, f1;
657 hd108BrightnessHeader(0, &f0, &f1);
658 fl::size num_leds = 0;
659 while (has(1)) {
660 u16 r16, g16, b16;
661#if !FL_PLATFORM_HAS_TINY_MEMORY
662 if (managed) {
663 // The managed source has already quantized its device drive
664 // once, to 16 bits. `hd108GammaCorrect` exists to widen an
665 // 8-bit pixel to the 16 this chipset carries; a fixed 2.8
666 // curve on top of a solved drive is the second shaping stage
667 // B1 and section 6 of the spec forbid after the device
668 // solve, and unlike UCS7604's `mGamma.value_or(2.8f)` this
669 // one is hardcoded -- no caller could have chosen otherwise.
670 loadAndScaleRGB16(&r16, &g16, &b16);
671 } else
672#endif
673 {
674 u8 b0, b1, b2;
675 loadAndScaleRGB(&b0, &b1, &b2); // wire order
676 r16 = hd108GammaCorrect(b0);
677 g16 = hd108GammaCorrect(b1);
678 b16 = hd108GammaCorrect(b2);
679 }
680 *back_ins++ = f0;
681 *back_ins++ = f1;
682 *back_ins++ = static_cast<u8>(r16 >> 8);
683 *back_ins++ = static_cast<u8>(r16 & 0xFF);
684 *back_ins++ = static_cast<u8>(g16 >> 8);
685 *back_ins++ = static_cast<u8>(g16 & 0xFF);
686 *back_ins++ = static_cast<u8>(b16 >> 8);
687 *back_ins++ = static_cast<u8>(b16 & 0xFF);
689 advanceData();
690 ++num_leds;
691 }
692 const fl::size latch = num_leds / 2 + 4;
693 for (fl::size i = 0; i < latch; i++) {
694 *back_ins++ = 0xFF; // end frame
695 }
696 }
void advanceData() FL_NO_EXCEPT
int size() FL_NO_EXCEPT
void loadAndScaleRGB(u8 *r_out, u8 *g_out, u8 *b_out) FL_NO_EXCEPT
void loadAndScaleRGB16(u16 *r_out, u16 *g_out, u16 *b_out) FL_NO_EXCEPT
One pixel at the source's own precision, wire-ordered.
bool has(int n) FL_NO_EXCEPT
void stepDithering() FL_NO_EXCEPT
#define FL_UNUSED(x)
back_insert_iterator< Container > back_inserter(Container &c) FL_NO_EXCEPT
Helper function to create a back_insert_iterator.
Definition iterator.h:139
unsigned char u8
Definition stdint.h:131
void hd108BrightnessHeader(u8 brightness_8bit, u8 *f0_out, u8 *f1_out) FL_NO_EXCEPT
Generate HD108 per-channel gain header bytes.
u16 hd108GammaCorrect(u8 value) FL_NO_EXCEPT
Convert 8-bit color to HD108 16-bit gamma-corrected value (gamma 2.8)

References advanceData(), fl::back_inserter(), fl::FL_NO_EXCEPT, FL_UNUSED, has(), fl::hd108BrightnessHeader(), fl::hd108GammaCorrect(), loadAndScaleRGB(), loadAndScaleRGB16(), and stepDithering().

+ Here is the call graph for this function: