23 return (a > b) ? (a - b) : (b - a);
37 if (pulse_width_ns == 0)
return 0;
38 u8 lo =
static_cast<u8>(timing_ns / pulse_width_ns);
40 u32 err_lo =
absDiff(
static_cast<u32
>(lo) * pulse_width_ns, timing_ns);
41 u32 err_hi =
absDiff(
static_cast<u32
>(hi) * pulse_width_ns, timing_ns);
43 return (err_hi < err_lo) ? hi : lo;
74 const int P =
static_cast<int>(pulses_per_bit);
78 for (
int i = 0; i <
P; i++) {
79 wire[i] = (i < static_cast<int>(pulses_a)) ? 1 : 0;
83 for (
int i = 0; i <
P; i++) {
84 wire[
P + i] = (i < static_cast<int>(pulses_b)) ? 1 : 0;
94 const int data_bits = 2 *
P - 2;
95 for (
int i = 0; i < data_bits; i++) {
96 int data_bit = wire[1 + i] ? 0 : 1;
97 byte_val |=
static_cast<u8>(data_bit << i);
130 const u32 period_ns = timing.total_period_ns();
131 if (period_ns == 0)
return fit;
136 static_cast<u64>(pulses_per_bit) * 1000000000ULL / period_ns;
137 if (baud == 0 || baud > max_baud_rate)
return fit;
139 const u32 pulse_width_ns = period_ns / pulses_per_bit;
140 if (pulse_width_ns == 0)
return fit;
142 const u32 t0h_ns = timing.t1_ns;
143 const u32 t1h_ns = timing.t1_ns + timing.t2_ns;
144 const u8 max_pulses =
static_cast<u8>(pulses_per_bit - 1);
148 if (pulses_0 < 1 || pulses_0 > max_pulses)
return fit;
149 if (pulses_1 < 1 || pulses_1 > max_pulses)
return fit;
150 if (pulses_0 == pulses_1)
return fit;
160 constexpr u32 kMinSymbolSeparationNs = 400;
161 const u8 pulses_1_raw = pulses_1;
162 while (pulses_1 < max_pulses &&
163 static_cast<u32
>(pulses_1 - pulses_0) * pulse_width_ns <
164 kMinSymbolSeparationNs) {
172 const u32 tolerance_ns = pulse_width_ns / 2;
173 const u32 actual_t0h =
static_cast<u32
>(pulses_0) * pulse_width_ns;
174 const u32 actual_t1h =
static_cast<u32
>(pulses_1) * pulse_width_ns;
175 const u32 t1h_tolerance_ns =
177 static_cast<u32
>(pulses_1 - pulses_1_raw) * pulse_width_ns;
178 const u32 err_t0h =
absDiff(actual_t0h, t0h_ns);
179 const u32 err_t1h =
absDiff(actual_t1h, t1h_ns);
180 if (err_t0h > tolerance_ns)
return fit;
181 if (err_t1h > t1h_tolerance_ns)
return fit;
183 const u32 raw_t1h =
static_cast<u32
>(pulses_1_raw) * pulse_width_ns;
184 const u32 err_t1h_raw =
absDiff(raw_t1h, t1h_ns);
190 fit.
max_err_ns = err_t0h > err_t1h_raw ? err_t0h : err_t1h_raw;
200 return ChipsetTiming{0, 0, 0, timing.reset_us,
"uart_infeasible"};
205 const UartWaveFit fit = fitUartWave(timing, lut.
pulses_per_bit, max_baud_rate);
207 return ChipsetTiming{0, 0, 0, timing.reset_us,
"uart_infeasible"};
209 const u32 period_ns = timing.total_period_ns();
211 const u32 t0h = fit.pulses_0 * pulse_width_ns;
212 const u32 t1h = fit.pulses_1 * pulse_width_ns;
213 return ChipsetTiming{t0h, t1h - t0h, period_ns - t1h, timing.reset_us,
233 const UartWaveFit fit5 = fitUartWave(timing, 5, max_baud_rate);
234 const UartWaveFit fit4 = fitUartWave(timing, 4, max_baud_rate);
237 UartWaveFit fit = {};
238 constexpr u32 kHysteresisNs = 50;
244 constexpr u32 kMaxSymbolErrorNs = 150;
245 if (fit5.ok && fit4.ok) {
246 const bool fit5_classifiable = fit5.max_err_ns <= kMaxSymbolErrorNs;
247 const bool fit4_classifiable = fit4.max_err_ns <= kMaxSymbolErrorNs;
248 if (fit5_classifiable != fit4_classifiable) {
254 P = fit5_classifiable ? 5 : 4;
255 fit = fit5_classifiable ? fit5 : fit4;
256 }
else if (fit4.total_err_ns + kHysteresisNs < fit5.total_err_ns) {
263 }
else if (fit5.ok) {
266 }
else if (fit4.ok) {
274 result.lut[0] = buildUartByte(fit.pulses_0, fit.pulses_0,
P);
275 result.lut[1] = buildUartByte(fit.pulses_0, fit.pulses_1,
P);
276 result.lut[2] = buildUartByte(fit.pulses_1, fit.pulses_0,
P);
277 result.lut[3] = buildUartByte(fit.pulses_1, fit.pulses_1,
P);
290 return fitUartWave(timing, 5, max_baud_rate).
ok ||
291 fitUartWave(timing, 4, max_baud_rate).
ok;
298 size_t output_capacity,
300 size_t required_size = input_size * 4;
302 if (required_size > output_capacity) {
306 for (
size_t i = 0; i < input_size; ++i) {
310 return required_size;
318 size_t required_size = input_size * 4;
320 if (required_size > output_capacity) {
324 for (
size_t i = 0; i < input_size; ++i) {
328 return required_size;
#define FL_OPTIMIZATION_LEVEL_O3_BEGIN
#define FL_OPTIMIZATION_LEVEL_O3_END
#define FL_OPTIMIZE_FUNCTION
u8 computePulseCount(u32 timing_ns, u32 pulse_width_ns) FL_NO_EXCEPT
Compute HIGH pulse count for a given timing value.
u8 buildUartByte(u8 pulses_a, u8 pulses_b, u8 pulses_per_bit=5) FL_NO_EXCEPT
Build a UART data byte from two LED bit pulse counts.
u32 absDiff(u32 a, u32 b) FL_NO_EXCEPT
Absolute value of difference (unsigned-safe)
UartWaveFit fitUartWave(const ChipsetTimingConfig &timing, u8 pulses_per_bit, u32 max_baud_rate) FL_NO_EXCEPT
Evaluate whether P pulses/LED-bit can represent the timing.
u32 total_err_ns
|T0H err| + |T1H err| vs nominal, post-bump
u32 max_err_ns
Worst single-symbol error, measured pre-bump.
Fit result for one UART wave geometry (P pulses per LED bit)
FASTLED_FORCE_INLINE FL_IRAM FL_OPTIMIZE_FUNCTION void encodeUartByte(u8 led_byte, u8 *output, const Wave10Lut &lut) FL_NO_EXCEPT
Encode 1 LED byte to 4 UART bytes using a Wave10 LUT.
bool canRepresentTiming(const ChipsetTimingConfig &timing) FL_NO_EXCEPT
Check if a chipset timing can be accurately represented by UART.
FL_IRAM FL_OPTIMIZE_FUNCTION size_t encodeLedsToUart(const u8 *input, size_t input_size, u8 *output, size_t output_capacity, const Wave10Lut &lut) FL_NO_EXCEPT
Encode LED pixel data to UART bytes using a Wave10 LUT.
constexpr u32 kMaxUartBaudRate
Maximum UART baud rate supported by ESP32 variants.
FASTLED_FORCE_INLINE fl::u8 P(fl::u8 x)
Wave10Lut buildWave10LutForMaxBaud(const ChipsetTimingConfig &timing, u32 max_baud_rate) FL_NO_EXCEPT
Build a UART waveform LUT with a backend-specific baud ceiling.
Wave10Lut buildWave10Lut(const ChipsetTimingConfig &timing) FL_NO_EXCEPT
Build a Wave10 LUT from chipset timing parameters.
expected< T, E > result
Alias for expected (Rust-style naming)
InputGamut g FL_NO_EXCEPT
ChipsetTiming uartWireTiming(const ChipsetTimingConfig &timing, u32 max_baud_rate) FL_NO_EXCEPT
The wire timing the UART encoder actually produces for a chipset.
bool canRepresentTimingForMaxBaud(const ChipsetTimingConfig &timing, u32 max_baud_rate) FL_NO_EXCEPT
Timing feasibility with a backend-specific baud ceiling.
Base definition for an LED controller.
Generic chipset timing entry Provides T1, T2, T3 timing parameters in nanoseconds for any LED protoco...
Runtime bit-period timing for a clockless chipset.
u8 pulses_per_bit
Frame geometry: 5 (wave10) or 4 (wave8-frame); 0 = infeasible.
Wave lookup table for UART LED encoding (waveN family)
Platform-neutral UART wave4/wave5 encoder API.