FastLED 3.10.8
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 740 of file pixel_iterator.h.

740 {
741 auto back_ins = fl::back_inserter(*out);
742
743 // One loop for both sources. This used to be two: the managed path
744 // written out by hand here, and the 8-bit path routed through
745 // `encodeHD108` over `makeScaledPixelRangeRGB`. Each carried its own
746 // copy of the framing -- the 8-byte start frame, the per-LED emit of
747 // header + three big-endian channels, the latch -- and together they
748 // made this the largest encoder body in a Blink build (481 B on
749 // esp32dev, ahead of `writeWS2812`, the only one Blink runs). The only
750 // thing that differed was where the 16-bit channels came from, so
751 // that is now the only branch (FastLED#4402).
752 //
753 // Byte-identical to the iterator path by construction:
754 // `ScaledPixelIteratorRGB::advance()` is exactly `has(1)`,
755 // `loadAndScaleRGB` into wire order, `stepDithering`, `advanceData`,
756 // once per pixel; the bytes it hands `encodeHD108` are captured before
757 // the step, which is what this loop does too.
758 //
759 // Inline rather than an `encodeHD108_wide` in hd108.h: that header is
760 // included *by* this one, before `PixelIterator` exists, and a
761 // concrete `PixelIterator&` parameter is not a dependent type -- so
762 // its body would be checked there and fail (#4326).
763#if FL_PLATFORM_HAS_TINY_MEMORY
764 // No wide source exists on TINY, so the flag selects nothing there.
765 FL_UNUSED(managed);
766#endif
767 for (int i = 0; i < 8; i++) {
768 *back_ins++ = 0x00; // start frame
769 }
770 // `hd108BrightnessHeader` discards its argument and pins every gain
771 // at 31, so this is 0xFF 0xFF whatever is passed (#4402).
772 u8 f0, f1;
773 hd108BrightnessHeader(0, &f0, &f1);
774 fl::size num_leds = 0;
775 while (has(1)) {
776 u16 r16, g16, b16;
777#if !FL_PLATFORM_HAS_TINY_MEMORY
778 if (managed) {
779 // The managed source has already quantized its device drive
780 // once, to 16 bits. `hd108GammaCorrect` exists to widen an
781 // 8-bit pixel to the 16 this chipset carries; a fixed 2.8
782 // curve on top of a solved drive is the second shaping stage
783 // B1 and section 6 of the spec forbid after the device
784 // solve, and unlike UCS7604's `mGamma.value_or(2.8f)` this
785 // one is hardcoded -- no caller could have chosen otherwise.
786 loadAndScaleRGB16(&r16, &g16, &b16);
787 } else
788#endif
789 {
790 u8 b0, b1, b2;
791 loadAndScaleRGB(&b0, &b1, &b2); // wire order
792 r16 = hd108GammaCorrect(b0);
793 g16 = hd108GammaCorrect(b1);
794 b16 = hd108GammaCorrect(b2);
795 }
796 *back_ins++ = f0;
797 *back_ins++ = f1;
798 *back_ins++ = static_cast<u8>(r16 >> 8);
799 *back_ins++ = static_cast<u8>(r16 & 0xFF);
800 *back_ins++ = static_cast<u8>(g16 >> 8);
801 *back_ins++ = static_cast<u8>(g16 & 0xFF);
802 *back_ins++ = static_cast<u8>(b16 >> 8);
803 *back_ins++ = static_cast<u8>(b16 & 0xFF);
805 advanceData();
806 ++num_leds;
807 }
808 const fl::size latch = num_leds / 2 + 4;
809 for (fl::size i = 0; i < latch; i++) {
810 *back_ins++ = 0xFF; // end frame
811 }
812 }
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
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)
#define FL_UNUSED(x)

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: