FastLED 3.9.15
Loading...
Searching...
No Matches
apa102.h
Go to the documentation of this file.
1#pragma once
2
19
20#include "fl/stl/stdint.h"
21#include "fl/stl/array.h"
25#include "fl/stl/noexcept.h"
26
27namespace fl {
28
29// NOTE: The old loadAndScale_APA102_HD<RGB_ORDER>() function has been removed.
30// RGB reordering now happens upstream via ScaledPixelIteratorRGB adapter.
31// The encoder receives wire-ordered RGB data (fl::array<u8, 3>) and brightness separately.
32// For APA102HD usage, the chipset controller uses ScaledPixelIteratorRGB + ScaledPixelIteratorBrightness
33// with the existing encodeAPA102_HD() function that accepts separate RGB and brightness iterators.
34
44template <typename InputIterator, typename OutputIterator>
45void encodeAPA102(InputIterator first, InputIterator last, OutputIterator out,
46 u8 global_brightness = 31) FL_NOEXCEPT {
47 // Clamp brightness to 5-bit range
48 global_brightness = global_brightness & 0x1F;
49
50 // Start frame: 4 bytes of 0x00
51 *out++ = 0x00;
52 *out++ = 0x00;
53 *out++ = 0x00;
54 *out++ = 0x00;
55
56 // LED data: brightness header + BGR (count pixels as we go)
57 size_t num_leds = 0;
58 while (first != last) {
59 const fl::array<u8, BYTES_PER_PIXEL_RGB>& pixel = *first;
60 *out++ = 0xE0 | global_brightness;
61 *out++ = pixel[0]; // Index 0 (BGR order: Blue)
62 *out++ = pixel[1]; // Index 1 (BGR order: Green)
63 *out++ = pixel[2]; // Index 2 (BGR order: Red)
64 ++first;
65 ++num_leds;
66 }
67
68 // End frame: ⌈num_leds/32⌉ DWords of 0xFF
69 size_t end_dwords = (num_leds / 32) + 1;
70 for (size_t i = 0; i < end_dwords * 4; i++) {
71 *out++ = 0xFF;
72 }
73}
74
85template <typename InputIterator, typename BrightnessIterator, typename OutputIterator>
86void encodeAPA102_HD(InputIterator first, InputIterator last,
87 BrightnessIterator brightness_first, OutputIterator out) FL_NOEXCEPT {
88 // Start frame: 4 bytes of 0x00
89 *out++ = 0x00;
90 *out++ = 0x00;
91 *out++ = 0x00;
92 *out++ = 0x00;
93
94 // LED data: brightness header + BGR (per-LED brightness, count as we go)
95 size_t num_leds = 0;
96 while (first != last) {
97 const fl::array<u8, BYTES_PER_PIXEL_RGB>& pixel = *first;
98 u8 brightness_8bit = *brightness_first;
99 u8 brightness_5bit = mapBrightness8to5(brightness_8bit);
100
101 *out++ = 0xE0 | brightness_5bit;
102 *out++ = pixel[0]; // Index 0 (BGR order: Blue)
103 *out++ = pixel[1]; // Index 1 (BGR order: Green)
104 *out++ = pixel[2]; // Index 2 (BGR order: Red)
105
106 ++first;
107 ++brightness_first;
108 ++num_leds;
109 }
110
111 // End frame: ⌈num_leds/32⌉ DWords of 0xFF
112 size_t end_dwords = (num_leds / 32) + 1;
113 for (size_t i = 0; i < end_dwords * 4; i++) {
114 *out++ = 0xFF;
115 }
116}
117
128template <typename InputIterator, typename OutputIterator>
131void encodeAPA102_AutoBrightness(InputIterator first, InputIterator last,
132 OutputIterator out) FL_NOEXCEPT {
133 if (first == last) {
134 // Empty range - just write start frame (no end frame needed for 0 LEDs)
135 *out++ = 0x00; *out++ = 0x00; *out++ = 0x00; *out++ = 0x00;
136 return;
137 }
138
139 // Start frame
140 *out++ = 0x00;
141 *out++ = 0x00;
142 *out++ = 0x00;
143 *out++ = 0x00;
144
145 // Extract global brightness from first pixel
146 const fl::array<u8, BYTES_PER_PIXEL_RGB>& first_pixel = *first;
147 const u16 maxBrightness = 0x1F;
148 // Use sequential comparisons to avoid nested fl::max (helps AVR register allocation)
149 u8 max_rg = (first_pixel[2] > first_pixel[1]) ? first_pixel[2] : first_pixel[1];
150 u8 max_component = (max_rg > first_pixel[0]) ? max_rg : first_pixel[0];
151 u16 brightness = ((((u16)max_component + 1) * maxBrightness - 1) >> 8) + 1;
152 u8 global_brightness = static_cast<u8>(brightness);
153
154 // Write first LED with extracted brightness (BGR order: 0=B, 1=G, 2=R)
155 u8 s0 = (maxBrightness * first_pixel[2] + (brightness >> 1)) / brightness; // Red
156 u8 s1 = (maxBrightness * first_pixel[1] + (brightness >> 1)) / brightness; // Green
157 u8 s2 = (maxBrightness * first_pixel[0] + (brightness >> 1)) / brightness; // Blue
158
159 *out++ = 0xE0 | (global_brightness & 0x1F);
160 *out++ = s2; // Blue
161 *out++ = s1; // Green
162 *out++ = s0; // Red
163 ++first;
164
165 // Write remaining LEDs (count as we go)
166 size_t num_leds = 1; // Already wrote first pixel
167 while (first != last) {
168 const fl::array<u8, BYTES_PER_PIXEL_RGB>& pixel = *first;
169 *out++ = 0xE0 | (global_brightness & 0x1F);
170 *out++ = pixel[0]; // Index 0 (BGR order: Blue)
171 *out++ = pixel[1]; // Index 1 (BGR order: Green)
172 *out++ = pixel[2]; // Index 2 (BGR order: Red)
173 ++first;
174 ++num_leds;
175 }
176
177 // End frame
178 size_t end_dwords = (num_leds / 32) + 1;
179 for (size_t i = 0; i < end_dwords * 4; i++) {
180 *out++ = 0xFF;
181 }
182}
183
184} // namespace fl
fl::UISlider brightness("Brightness", BRIGHTNESS, 0, 255)
A fixed-size array implementation similar to std::array.
Definition array.h:27
Constants for SPI chipset encoders.
Shared utilities for SPI chipset encoders.
unsigned char u8
Definition stdint.h:131
void encodeAPA102(InputIterator first, InputIterator last, OutputIterator out, u8 global_brightness=31) FL_NOEXCEPT
Encode pixel data in APA102 format with global brightness.
Definition apa102.h:45
FL_NO_INLINE_IF_AVR FL_OPTIMIZE_O2 void encodeAPA102_AutoBrightness(InputIterator first, InputIterator last, OutputIterator out) FL_NOEXCEPT
Encode pixel data in APA102 format (auto-detected brightness from first pixel)
Definition apa102.h:131
u8 mapBrightness8to5(u8 brightness_8bit) FL_NOEXCEPT
Map 8-bit brightness to 5-bit (0-31)
void encodeAPA102_HD(InputIterator first, InputIterator last, BrightnessIterator brightness_first, OutputIterator out) FL_NOEXCEPT
Encode pixel data in APA102 format with per-LED brightness.
Definition apa102.h:86
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_NO_INLINE_IF_AVR
#define FL_OPTIMIZE_O2
#define FL_NOEXCEPT