FastLED 3.10.8
Loading...
Searching...
No Matches
ucs7604.h
Go to the documentation of this file.
1#pragma once
2
19
20#include "fl/stl/stdint.h"
21#include "fl/math/ease.h"
23#include "fl/stl/compiler_control.h" // IWYU pragma: keep (FL_UNUSED)
24#include "fl/stl/noexcept.h"
25#include "fl/system/sketch_macros.h" // IWYU pragma: keep (FL_PLATFORM_HAS_TINY_MEMORY)
26
27namespace fl {
28
30enum class UCS7604Mode {
33 UCS7604_MODE_16BIT_1600KHZ = 0x9B // not implemented because of timing difference.
34};
35
38 u8 r;
39 u8 g;
40 u8 b;
41 u8 w;
42
44 UCS7604CurrentControl() FL_NO_EXCEPT : r(0xF), g(0xF), b(0xF), w(0xF) {}
45
48 FL_NO_EXCEPT : r(brightness & 0xF), g(brightness & 0xF), b(brightness & 0xF), w(brightness & 0xF) {}
49
52 FL_NO_EXCEPT : r(r_ & 0xF), g(g_ & 0xF), b(b_ & 0xF), w(w_ & 0xF) {}
53};
54
70template <typename OutputIterator>
71void buildUCS7604Preamble(OutputIterator out, UCS7604Mode mode,
72 u8 r_current, u8 g_current,
73 u8 b_current, u8 w_current) FL_NO_EXCEPT {
74 // Sync pattern (6 bytes)
75 *out++ = 0xFF;
76 *out++ = 0xFF;
77 *out++ = 0xFF;
78 *out++ = 0xFF;
79 *out++ = 0xFF;
80 *out++ = 0xFF;
81
82 // Header (2 bytes)
83 *out++ = 0x00;
84 *out++ = 0x03;
85
86 // Mode byte
87 *out++ = static_cast<u8>(mode);
88
89 // Current control (4 bytes, 4-bit each, wire order RGBW)
90 *out++ = r_current & 0x0F;
91 *out++ = g_current & 0x0F;
92 *out++ = b_current & 0x0F;
93 *out++ = w_current & 0x0F;
94
95 // Reserved (2 bytes)
96 *out++ = 0x00;
97 *out++ = 0x00;
98}
99
107template <typename InputIterator, typename OutputIterator>
108void encodeUCS7604_8bit_RGB(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT {
109 while (first != last) {
110 const auto& pixel = *first;
111 *out++ = pixel[0]; // R
112 *out++ = pixel[1]; // G
113 *out++ = pixel[2]; // B
114 ++first;
115 }
116}
117
125template <typename InputIterator, typename OutputIterator>
126void encodeUCS7604_8bit_RGBW(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT {
127 while (first != last) {
128 const auto& pixel = *first;
129 *out++ = pixel[0]; // R
130 *out++ = pixel[1]; // G
131 *out++ = pixel[2]; // B
132 *out++ = pixel[3]; // W
133 ++first;
134 }
135}
136
145template <typename InputIterator, typename OutputIterator>
146void encodeUCS7604_16bit_RGB(InputIterator first, InputIterator last, OutputIterator out,
147 const Gamma8& gamma) FL_NO_EXCEPT {
148 while (first != last) {
149 const auto& pixel = *first;
150
151 // Apply gamma correction for 16-bit output
152 u8 rgb_in[3] = { pixel[0], pixel[1], pixel[2] };
153 u16 rgb_out[3];
154 gamma.convert(fl::span<const u8>(rgb_in, 3), fl::span<u16>(rgb_out, 3));
155
156 // Write big-endian 16-bit values
157 *out++ = rgb_out[0] >> 8;
158 *out++ = rgb_out[0] & 0xFF;
159 *out++ = rgb_out[1] >> 8;
160 *out++ = rgb_out[1] & 0xFF;
161 *out++ = rgb_out[2] >> 8;
162 *out++ = rgb_out[2] & 0xFF;
163 ++first;
164 }
165}
166
189#if !FL_PLATFORM_HAS_TINY_MEMORY
190template <typename OutputIterator>
191void encodeUCS7604_16bit_RGB_wide(PixelIterator& pixels, OutputIterator out) FL_NO_EXCEPT {
192 while (pixels.has(1)) {
193 u16 r16, g16, b16;
194 pixels.loadAndScaleRGB16(&r16, &g16, &b16);
195 *out++ = r16 >> 8;
196 *out++ = r16 & 0xFF;
197 *out++ = g16 >> 8;
198 *out++ = g16 & 0xFF;
199 *out++ = b16 >> 8;
200 *out++ = b16 & 0xFF;
201 pixels.stepDithering();
202 pixels.advanceData();
203 }
204}
205#endif // !FL_PLATFORM_HAS_TINY_MEMORY
206
215template <typename InputIterator, typename OutputIterator>
216void encodeUCS7604_16bit_RGBW(InputIterator first, InputIterator last, OutputIterator out,
217 const Gamma8& gamma) FL_NO_EXCEPT {
218 while (first != last) {
219 const auto& pixel = *first;
220
221 // Apply gamma correction for 16-bit output
222 u8 rgbw_in[4] = { pixel[0], pixel[1], pixel[2], pixel[3] };
223 u16 rgbw_out[4];
224 gamma.convert(fl::span<const u8>(rgbw_in, 4), fl::span<u16>(rgbw_out, 4));
225
226 // Write big-endian 16-bit values
227 *out++ = rgbw_out[0] >> 8;
228 *out++ = rgbw_out[0] & 0xFF;
229 *out++ = rgbw_out[1] >> 8;
230 *out++ = rgbw_out[1] & 0xFF;
231 *out++ = rgbw_out[2] >> 8;
232 *out++ = rgbw_out[2] & 0xFF;
233 *out++ = rgbw_out[3] >> 8;
234 *out++ = rgbw_out[3] & 0xFF;
235 ++first;
236 }
237}
238
240inline size_t ucs7604BytesPerLed(UCS7604Mode mode, bool is_rgbw) FL_NO_EXCEPT {
242 return is_rgbw ? 4u : 3u;
243 }
244 return is_rgbw ? 8u : 6u;
245}
246
253inline size_t ucs7604FrameBytes(size_t num_leds, UCS7604Mode mode,
254 bool is_rgbw) FL_NO_EXCEPT {
255 constexpr size_t kPreambleLen = 15;
256 const size_t total = kPreambleLen + num_leds * ucs7604BytesPerLed(mode, is_rgbw);
257 // The protocol requires the total to be divisible by 3.
258 return total + (3u - (total % 3u)) % 3u;
259}
260
272template <typename OutputIterator>
273void encodeUCS7604(PixelIterator& pixel_iter, size_t num_leds, OutputIterator out,
274 UCS7604Mode mode, const UCS7604CurrentControl& current, bool is_rgbw,
275 const Gamma8* gamma = nullptr,
276 bool wide_source = false) FL_NO_EXCEPT {
277 constexpr size_t PREAMBLE_LEN = 15;
278
279#if FL_PLATFORM_HAS_TINY_MEMORY
280 // No wide encoder exists on TINY, so the flag selects nothing there.
281 FL_UNUSED(wide_source);
282#endif
283
284 // Padding comes from ucs7604FrameBytes() so the length callers predict and
285 // the length written here are the same number by construction.
286 const size_t led_data_size = num_leds * ucs7604BytesPerLed(mode, is_rgbw);
287 const size_t padding =
288 ucs7604FrameBytes(num_leds, mode, is_rgbw) - PREAMBLE_LEN - led_data_size;
289
290 // Build preamble (15 bytes) with current control
291 buildUCS7604Preamble(out, mode, current.r, current.g, current.b, current.w);
292
293 // Add padding (0-2 zero bytes)
294 for (size_t i = 0; i < padding; ++i) {
295 *out++ = 0;
296 }
297
298 // Encode LED data based on mode and RGB/RGBW
300 if (is_rgbw) {
301 auto range = makeScaledPixelRangeRGBW(&pixel_iter);
302 encodeUCS7604_8bit_RGBW(range.first, range.second, out);
303 } else {
304 auto range = makeScaledPixelRangeRGB(&pixel_iter);
305 encodeUCS7604_8bit_RGB(range.first, range.second, out);
306 }
307 } else {
308 // 16-bit modes -- fall back to gamma 2.8 if no gamma provided
309 static fl::shared_ptr<const Gamma8> default_gamma;
310 const Gamma8& g = gamma ? *gamma : *(default_gamma ? default_gamma : (default_gamma = Gamma8::getOrCreate(2.8f)));
311 if (is_rgbw) {
312 // RGBW stays on the gamma path: `ColorManagedPixelSource`
313 // delegates its RGBW entry point to the legacy controller, so
314 // there is no wide drive to consume here yet.
315 auto range = makeScaledPixelRangeRGBW(&pixel_iter);
316 encodeUCS7604_16bit_RGBW(range.first, range.second, out, g);
317#if !FL_PLATFORM_HAS_TINY_MEMORY
318 } else if (wide_source) {
319 encodeUCS7604_16bit_RGB_wide(pixel_iter, out);
320#endif
321 } else {
322 auto range = makeScaledPixelRangeRGB(&pixel_iter);
323 encodeUCS7604_16bit_RGB(range.first, range.second, out, g);
324 }
325 }
326}
327
328} // namespace fl
fl::UISlider brightness("Brightness", BRIGHTNESS, 0, 255)
static fl::shared_ptr< const Gamma8 > getOrCreate(float gamma) FL_NO_EXCEPT
Definition ease.cpp.hpp:460
#define FL_UNUSED(x)
void encodeUCS7604_8bit_RGBW(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT
Encode RGBW pixels in UCS7604 8-bit format.
Definition ucs7604.h:126
unsigned char u8
Definition stdint.h:131
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
void encodeUCS7604_16bit_RGBW(InputIterator first, InputIterator last, OutputIterator out, const Gamma8 &gamma) FL_NO_EXCEPT
Encode RGBW pixels in UCS7604 16-bit format with gamma correction.
Definition ucs7604.h:216
constexpr u32 gamma(float g) FL_NO_EXCEPT
Definition gamma_lut.h:36
size_t ucs7604FrameBytes(size_t num_leds, UCS7604Mode mode, bool is_rgbw) FL_NO_EXCEPT
Total wire bytes of a complete UCS7604 frame.
Definition ucs7604.h:253
pair< detail::ScaledPixelIteratorRGBW, detail::ScaledPixelIteratorRGBW > makeScaledPixelRangeRGBW(PixelIterator *pixels) FL_NO_EXCEPT
Create RGBW input iterator range from PixelIterator.
void buildUCS7604Preamble(OutputIterator out, UCS7604Mode mode, u8 r_current, u8 g_current, u8 b_current, u8 w_current) FL_NO_EXCEPT
Build UCS7604 preamble (15 bytes)
Definition ucs7604.h:71
void encodeUCS7604_16bit_RGB_wide(PixelIterator &pixels, OutputIterator out) FL_NO_EXCEPT
Wide RGB straight off the iterator, with no adapter (P8, #4042 / #4326).
Definition ucs7604.h:191
UCS7604Mode
UCS7604 protocol configuration modes.
Definition ucs7604.h:30
@ UCS7604_MODE_8BIT_800KHZ
Definition ucs7604.h:31
@ UCS7604_MODE_16BIT_1600KHZ
Definition ucs7604.h:33
@ UCS7604_MODE_16BIT_800KHZ
Definition ucs7604.h:32
void encodeUCS7604_16bit_RGB(InputIterator first, InputIterator last, OutputIterator out, const Gamma8 &gamma) FL_NO_EXCEPT
Encode RGB pixels in UCS7604 16-bit format with gamma correction.
Definition ucs7604.h:146
void encodeUCS7604(PixelIterator &pixel_iter, size_t num_leds, OutputIterator out, UCS7604Mode mode, const UCS7604CurrentControl &current, bool is_rgbw, const Gamma8 *gamma=nullptr, bool wide_source=false) FL_NO_EXCEPT
Encode complete UCS7604 frame (preamble + padding + pixel data)
Definition ucs7604.h:273
InputGamut g
Definition rgbw.h:125
void encodeUCS7604_8bit_RGB(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT
Encode RGB pixels in UCS7604 8-bit format.
Definition ucs7604.h:108
size_t ucs7604BytesPerLed(UCS7604Mode mode, bool is_rgbw) FL_NO_EXCEPT
Wire bytes each LED contributes to a UCS7604 frame.
Definition ucs7604.h:240
pair< detail::ScaledPixelIteratorRGB, detail::ScaledPixelIteratorRGB > makeScaledPixelRangeRGB(PixelIterator *pixels) FL_NO_EXCEPT
Create RGB input iterator range from PixelIterator.
Base definition for an LED controller.
Definition crgb.hpp:179
Adapter layer bridging PixelIterator to encoder input iterators.
u8 g
Green channel current (0x0-0xF)
Definition ucs7604.h:39
u8 b
Blue channel current (0x0-0xF)
Definition ucs7604.h:40
u8 w
White channel current (0x0-0xF)
Definition ucs7604.h:41
UCS7604CurrentControl(u8 r_, u8 g_, u8 b_, u8 w_) FL_NO_EXCEPT
Construct from individual channel values.
Definition ucs7604.h:51
UCS7604CurrentControl(u8 brightness) FL_NO_EXCEPT
Construct from single brightness value (all channels)
Definition ucs7604.h:47
UCS7604CurrentControl() FL_NO_EXCEPT
Default constructor - maximum brightness.
Definition ucs7604.h:44
u8 r
Red channel current (0x0-0xF)
Definition ucs7604.h:38
UCS7604 current control structure with 4-bit fields for each channel.
Definition ucs7604.h:37