FastLED 3.10.9
Loading...
Searching...
No Matches
rx.cpp.hpp
Go to the documentation of this file.
3// ok no header (RxDevice class is declared in fl/channels/rx.h)
4
5#include "platforms/is_platform.h"
6#include "fl/channels/rx.h"
7// IWYU pragma: begin_keep
8#include "platforms/shared/rx_device_dummy.h" // ok platform headers
9// IWYU pragma: end_keep // ok platform headers
11#include "fl/stl/string.h"
12
13#ifdef FL_IS_ESP32
14// IWYU pragma: begin_keep
15#include "platforms/esp/32/drivers/i2s_rx/i2s_rx_sampler.h" // ok platform headers
16#include "platforms/esp/32/drivers/parlio_rx/parlio_rx_sampler.h" // ok platform headers
17#include "platforms/esp/32/drivers/rmt_rx/rmt_rx_channel.h" // ok platform headers
18#include "platforms/esp/32/drivers/gpio_isr_rx/gpio_isr_rx.h" // ok platform headers
19#include "platforms/esp/32/feature_flags/enabled.h" // ok platform headers
20#endif
21// IWYU pragma: end_keep
22
23#ifdef FL_IS_TEENSY_4X
24// IWYU pragma: begin_keep
25#include "platforms/arm/teensy/teensy4_common/rx_flexio_channel.h" // ok platform headers
26#include "platforms/arm/teensy/teensy4_common/rx_flexpwm_channel.h" // ok platform headers
27// IWYU pragma: end_keep
28#endif
29
30#ifdef FL_IS_STUB
31// IWYU pragma: begin_keep
32#include "platforms/shared/rx_device_native.h" // ok platform headers
33#include "fl/stl/noexcept.h"
34// IWYU pragma: end_keep
35#endif
36
37#ifdef FL_IS_ARM_LPC
38// IWYU pragma: begin_keep
39#include "platforms/arm/lpc/rx_sct_capture.h" // ok platform headers
40// IWYU pragma: end_keep
41#endif
42
43#ifdef FL_IS_RP
44// IWYU pragma: begin_keep
45#include "platforms/arm/rp/rpcommon/rx_pio_channel.h" // ok platform headers
46// IWYU pragma: end_keep
47#endif
48
49#ifdef FL_IS_ESP8266
50// IWYU pragma: begin_keep
51#include "platforms/esp/8266/rx_device_i2s_rx.h" // ok platform headers
52// IWYU pragma: end_keep
53#endif
54
55namespace fl {
56
57template <>
59#ifdef FL_IS_RP
60 return RpPioRxDevice::create(pin);
61#elif defined(FL_IS_STUB)
62 return NativeRxDevice::create(pin);
63#else
64 (void)pin;
65 return createDummy();
66#endif
67}
68
69// Private static helper - creates dummy device (singleton pattern)
71 static fl::shared_ptr<RxDevice> dummy = fl::make_shared<DummyRxDevice>( // okay static in header
72 "RX devices not supported on this platform"
73 );
74 return dummy;
75}
76
77// Implementation of make4PhaseTiming function
79 u32 tolerance_ns) FL_NO_EXCEPT {
80 // Calculate derived values from 3-phase timing
81 // The encoder uses:
82 // Bit 0: T1 high + (T2+T3) low
83 // Bit 1: (T1+T2) high + T3 low
84 u32 t0h = timing_3phase.T1; // Bit 0 high time
85 u32 t0l = timing_3phase.T2 + timing_3phase.T3; // Bit 0 low time
86 u32 t1h = timing_3phase.T1 + timing_3phase.T2; // Bit 1 high time
87 u32 t1l = timing_3phase.T3; // Bit 1 low time
88
90
91 // Bit 0 timing thresholds
92 result.t0h_min_ns = (t0h > tolerance_ns) ? (t0h - tolerance_ns) : 0;
93 result.t0h_max_ns = t0h + tolerance_ns;
94 result.t0l_min_ns = (t0l > tolerance_ns) ? (t0l - tolerance_ns) : 0;
95 result.t0l_max_ns = t0l + tolerance_ns;
96
97 // Bit 1 timing thresholds
98 result.t1h_min_ns = (t1h > tolerance_ns) ? (t1h - tolerance_ns) : 0;
99 result.t1h_max_ns = t1h + tolerance_ns;
100 result.t1l_min_ns = (t1l > tolerance_ns) ? (t1l - tolerance_ns) : 0;
101 result.t1l_max_ns = t1l + tolerance_ns;
102
103 // Reset pulse threshold
104 result.reset_min_us = timing_3phase.RESET;
105
106 // gap_tolerance_ns retains its default value of 0
107
108 return result;
109}
110
111} // namespace fl
112
113
114
115// ESP32-specific explicit template specializations
116namespace fl {
117
118#ifdef FL_IS_ESP32
119
120// RMT device specialization for ESP32.
121//
122// The `RmtRxChannel::create` impl only exists on chips that actually have RMT
123// silicon: the IDF 4.x impl in `rmt_rx_4/` gates on
124// `FASTLED_ESP32_HAS_RMT && !FASTLED_ESP32_RMT5_ONLY_PLATFORM && !FASTLED_RMT5`
125// and the IDF 5.x impl in `rmt_rx_5/` gates on `FASTLED_RMT5`. On ESP32-C2
126// the SoC has no RMT peripheral (`SOC_RMT_SUPPORTED == 0`, so
127// `FASTLED_ESP32_HAS_RMT == 0`), and the workflow forces
128// `FASTLED_RMT5 = 0` for that chip — so both impls skip and the specialisation
129// link-fails with `undefined reference to fl::RmtRxChannel::create(int)`.
130// Mirror the exact gates the impls use here so the specialisation collapses
131// to a DummyRxDevice on RMT-less chips.
132template <>
133fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::RMT>(int pin) FL_NO_EXCEPT {
134#if (FASTLED_ESP32_HAS_RMT && !FASTLED_ESP32_RMT5_ONLY_PLATFORM && !FASTLED_RMT5) || FASTLED_RMT5
135 auto device = RmtRxChannel::create(pin);
136 if (!device) {
137 return fl::make_shared<DummyRxDevice>("RMT RX channel creation failed");
138 }
139 return device;
140#else
141 (void)pin;
142 return fl::make_shared<DummyRxDevice>("RMT RX not supported on this ESP32 SoC");
143#endif
144}
145
146// ISR device specialization for ESP32
147template <>
148fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::ISR>(int pin) FL_NO_EXCEPT {
149 auto device = GpioIsrRx::create(pin);
150 if (!device) {
151 return fl::make_shared<DummyRxDevice>("GPIO ISR RX creation failed");
152 }
153 return device;
154}
155
156// FLEXPWM not available on ESP32
157template <>
158fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXPWM>(int pin) FL_NO_EXCEPT {
159 (void)pin;
160 return fl::make_shared<DummyRxDevice>("FLEXPWM RX not supported on ESP32");
161}
162
163// FLEXIO not available on ESP32 (Teensy 4.x peripheral). See FastLED#2764.
164template <>
165fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXIO>(int pin) FL_NO_EXCEPT {
166 (void)pin;
167 return fl::make_shared<DummyRxDevice>("FLEXIO RX not supported on ESP32");
168}
169
170// LPC_SCT_CAPTURE not available on ESP32 (LPC8xx peripheral). See FastLED#3015.
171// FastLED#3576 Phase 3 — I2S-RX oversampling backend (classic ESP32).
172template <>
173fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::I2S_RX>(int pin) FL_NO_EXCEPT {
174#if FASTLED_ESP32_HAS_I2S
175 auto device = createI2sRxSampler(pin);
176 if (device) {
177 return device;
178 }
179#endif
180 (void)pin;
181 return fl::make_shared<DummyRxDevice>("I2S_RX not supported on this chip");
182}
183
184// FastLED#3586 — PARLIO-RX oversampling backend (ESP32-C6 et al).
185template <>
186fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PARLIO_RX>(int pin) FL_NO_EXCEPT {
187 auto device = createParlioRxSampler(pin);
188 if (device) {
189 return device;
190 }
191 return fl::make_shared<DummyRxDevice>("PARLIO_RX not supported on this chip");
192}
193
194template <>
195fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::LPC_SCT_CAPTURE>(int pin) FL_NO_EXCEPT {
196 (void)pin;
197 return fl::make_shared<DummyRxDevice>("LPC_SCT_CAPTURE RX not supported on ESP32");
198}
199
200// DEFAULT maps to RMT on ESP32
201template <>
202fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PLATFORM_DEFAULT>(int pin) FL_NO_EXCEPT {
204}
205
206#elif defined(FL_IS_TEENSY_4X)
207
208// FLEXPWM device specialization for Teensy 4.x
209template <>
210fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXPWM>(int pin) FL_NO_EXCEPT {
211 auto device = FlexPwmRxChannel::create(pin);
212 if (!device) {
213 return fl::make_shared<DummyRxDevice>("FlexPWM RX channel creation failed");
214 }
215 return device;
216}
217
218// FLEXIO device specialization for Teensy 4.x — Phase 1A skeleton (FastLED#2764).
219// Returns a real FlexIoRxChannel object whose methods report inactive until
220// Phase 1B lands the FLEXIO1 register programming.
221template <>
222fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXIO>(int pin) FL_NO_EXCEPT {
223 auto device = FlexIoRxChannel::create(pin);
224 if (!device) {
225 return fl::make_shared<DummyRxDevice>("FlexIO RX channel creation failed");
226 }
227 return device;
228}
229
230// RMT not available on Teensy
231template <>
232fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::RMT>(int pin) FL_NO_EXCEPT {
233 (void)pin;
234 return fl::make_shared<DummyRxDevice>("RMT RX not supported on Teensy");
235}
236
237// ISR not available on Teensy
238template <>
239fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::ISR>(int pin) FL_NO_EXCEPT {
240 (void)pin;
241 return fl::make_shared<DummyRxDevice>("ISR RX not supported on Teensy");
242}
243
244// LPC_SCT_CAPTURE not available on Teensy (LPC8xx peripheral). See FastLED#3015.
245template <>
246fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::I2S_RX>(int pin) FL_NO_EXCEPT {
247 (void)pin;
248 return fl::make_shared<DummyRxDevice>("I2S_RX not supported on this platform");
249}
250
251template <>
252fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PARLIO_RX>(int pin) FL_NO_EXCEPT {
253 (void)pin;
254 return fl::make_shared<DummyRxDevice>("PARLIO_RX not supported on this platform");
255}
256
257template <>
258fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::LPC_SCT_CAPTURE>(int pin) FL_NO_EXCEPT {
259 (void)pin;
260 return fl::make_shared<DummyRxDevice>("LPC_SCT_CAPTURE RX not supported on Teensy");
261}
262
263// DEFAULT maps to FLEXPWM on Teensy 4.x (intentionally NOT switched to FLEXIO yet
264// — that ships in a separate PR after Phase 3 verification per FastLED#2764).
265template <>
266fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PLATFORM_DEFAULT>(int pin) FL_NO_EXCEPT {
268}
269
270#elif defined(FL_IS_ARM_LPC)
271
272// LPC8xx SCT input-capture + DMA receiver. See FastLED#3015.
273template <>
274fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::I2S_RX>(int pin) FL_NO_EXCEPT {
275 (void)pin;
276 return fl::make_shared<DummyRxDevice>("I2S_RX not supported on this platform");
277}
278
279template <>
280fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PARLIO_RX>(int pin) FL_NO_EXCEPT {
281 (void)pin;
282 return fl::make_shared<DummyRxDevice>("PARLIO_RX not supported on this platform");
283}
284
285template <>
286fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::LPC_SCT_CAPTURE>(int pin) FL_NO_EXCEPT {
287 auto device = LpcSctRxChannel::create(pin);
288 if (!device) {
289 return fl::make_shared<DummyRxDevice>("LPC SCT-capture RX channel creation failed");
290 }
291 return device;
292}
293
294// RMT not available on LPC
295template <>
296fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::RMT>(int pin) FL_NO_EXCEPT {
297 (void)pin;
298 return fl::make_shared<DummyRxDevice>("RMT RX not supported on LPC");
299}
300
301// ISR not available on LPC (Cortex-M0+ ISR latency cannot decode 800 kHz). See #3015.
302template <>
303fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::ISR>(int pin) FL_NO_EXCEPT {
304 (void)pin;
305 return fl::make_shared<DummyRxDevice>("ISR RX not feasible on LPC Cortex-M0+ (use LPC_SCT_CAPTURE)");
306}
307
308// FLEXPWM not available on LPC
309template <>
310fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXPWM>(int pin) FL_NO_EXCEPT {
311 (void)pin;
312 return fl::make_shared<DummyRxDevice>("FLEXPWM RX not supported on LPC");
313}
314
315// FLEXIO not available on LPC
316template <>
317fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXIO>(int pin) FL_NO_EXCEPT {
318 (void)pin;
319 return fl::make_shared<DummyRxDevice>("FLEXIO RX not supported on LPC");
320}
321
322// DEFAULT maps to LPC_SCT_CAPTURE on LPC.
323template <>
324fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PLATFORM_DEFAULT>(int pin) FL_NO_EXCEPT {
326}
327
328#elif defined(FL_IS_STUB)
329
330// RMT device specialization (native stub for host/desktop testing)
331template <>
332fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::RMT>(int pin) FL_NO_EXCEPT {
333 return NativeRxDevice::create(pin);
334}
335
336// ISR device specialization (native stub for host/desktop testing)
337template <>
338fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::ISR>(int pin) FL_NO_EXCEPT {
339 return NativeRxDevice::create(pin);
340}
341
342// FLEXPWM device specialization (native stub for host/desktop testing)
343template <>
344fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXPWM>(int pin) FL_NO_EXCEPT {
345 return NativeRxDevice::create(pin);
346}
347
348// FLEXIO device specialization (native stub for host/desktop testing). Same
349// NativeRxDevice fallback as the other backends so host-stub tests can exercise
350// `RxBackend::FLEXIO` against the synthetic capture buffer.
351template <>
352fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXIO>(int pin) FL_NO_EXCEPT {
353 return NativeRxDevice::create(pin);
354}
355
356// LPC_SCT_CAPTURE device specialization (native stub). Same NativeRxDevice
357// fallback so host-stub tests can exercise `RxBackend::LPC_SCT_CAPTURE`
358// against the synthetic capture buffer.
359template <>
360fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::I2S_RX>(int pin) FL_NO_EXCEPT {
361 (void)pin;
362 return fl::make_shared<DummyRxDevice>("I2S_RX not supported on this platform");
363}
364
365template <>
366fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PARLIO_RX>(int pin) FL_NO_EXCEPT {
367 (void)pin;
368 return fl::make_shared<DummyRxDevice>("PARLIO_RX not supported on this platform");
369}
370
371template <>
372fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::LPC_SCT_CAPTURE>(int pin) FL_NO_EXCEPT {
373 return NativeRxDevice::create(pin);
374}
375
376// DEFAULT maps to RMT on stub (same as ESP32 default)
377template <>
378fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PLATFORM_DEFAULT>(int pin) FL_NO_EXCEPT {
380}
381
382#elif defined(FL_IS_ESP8266)
383
384// ESP8266 has exactly one hardware receiver: the I2S peripheral's RX path
385// (#4945). PLATFORM_DEFAULT and I2S_RX both map to it. A per-edge GPIO ISR is
386// not feasible here (interrupt latency ~1 us >> the ~350 ns T0H), which is why
387// the AutoResearch benches hand-rolled a synchronous IRAM poll instead.
388template <>
389fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::I2S_RX>(int pin) FL_NO_EXCEPT {
390 return Esp8266I2sRxDevice::create(pin);
391}
392
393template <>
394fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::ISR>(int pin) FL_NO_EXCEPT {
395 (void)pin;
397 "ESP8266 has no fast GPIO-ISR RX (see #4945); use RxBackend::I2S_RX");
398}
399
400template <>
401fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::RMT>(int pin) FL_NO_EXCEPT {
402 (void)pin;
403 return fl::make_shared<DummyRxDevice>("RMT RX not supported on ESP8266");
404}
405
406template <>
407fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXPWM>(int pin) FL_NO_EXCEPT {
408 (void)pin;
409 return fl::make_shared<DummyRxDevice>("FLEXPWM RX not supported on ESP8266");
410}
411
412template <>
413fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXIO>(int pin) FL_NO_EXCEPT {
414 (void)pin;
415 return fl::make_shared<DummyRxDevice>("FLEXIO RX not supported on ESP8266");
416}
417
418template <>
419fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::LPC_SCT_CAPTURE>(int pin) FL_NO_EXCEPT {
420 (void)pin;
421 return fl::make_shared<DummyRxDevice>("LPC_SCT_CAPTURE RX not supported on ESP8266");
422}
423
424template <>
425fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PARLIO_RX>(int pin) FL_NO_EXCEPT {
426 (void)pin;
427 return fl::make_shared<DummyRxDevice>("PARLIO_RX not supported on ESP8266");
428}
429
430// DEFAULT maps to the I2S RX engine on ESP8266.
431template <>
432fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PLATFORM_DEFAULT>(int pin) FL_NO_EXCEPT {
434}
435
436#else
437template <>
438fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::RMT>(int pin) FL_NO_EXCEPT {
439 (void)pin; // Suppress unused parameter warning
440 return RxDevice::createDummy();
441}
442
443// ISR device specialization (dummy for non-ESP32, non-stub)
444template <>
445fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::ISR>(int pin) FL_NO_EXCEPT {
446 (void)pin; // Suppress unused parameter warning
447 return RxDevice::createDummy();
448}
449
450// FLEXPWM device specialization (dummy for unsupported platforms)
451template <>
452fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXPWM>(int pin) FL_NO_EXCEPT {
453 (void)pin; // Suppress unused parameter warning
454 return RxDevice::createDummy();
455}
456
457// FLEXIO device specialization (dummy for unsupported platforms)
458template <>
459fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXIO>(int pin) FL_NO_EXCEPT {
460 (void)pin; // Suppress unused parameter warning
461 return RxDevice::createDummy();
462}
463
464// LPC_SCT_CAPTURE device specialization (dummy for unsupported platforms)
465template <>
466fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::I2S_RX>(int pin) FL_NO_EXCEPT {
467 (void)pin;
468 return fl::make_shared<DummyRxDevice>("I2S_RX not supported on this platform");
469}
470
471template <>
472fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PARLIO_RX>(int pin) FL_NO_EXCEPT {
473 (void)pin;
474 return fl::make_shared<DummyRxDevice>("PARLIO_RX not supported on this platform");
475}
476
477template <>
478fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::LPC_SCT_CAPTURE>(int pin) FL_NO_EXCEPT {
479 (void)pin; // Suppress unused parameter warning
480 return RxDevice::createDummy();
481}
482
483// DEFAULT maps to PIO on RP and RMT elsewhere (returns dummy if unsupported).
484template <>
485fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PLATFORM_DEFAULT>(int pin) FL_NO_EXCEPT {
486#ifdef FL_IS_RP
488#else
490#endif
491}
492
493#endif // FL_IS_ESP32 / FL_IS_TEENSY_4X / FL_IS_ARM_LPC / FL_IS_STUB
494
495} // namespace fl
static fl::shared_ptr< RxDevice > create(int pin) FL_NO_EXCEPT
Template factory method to create RX device by type.
static fl::shared_ptr< RxDevice > createDummy() FL_NO_EXCEPT
Create dummy RxDevice instance (default fallback)
Definition rx.cpp.hpp:70
Centralized LED chipset timing definitions with nanosecond precision.
shared_ptr< T > make_shared(Args &&... args) FL_NO_EXCEPT
Definition shared_ptr.h:423
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
ChipsetTiming4Phase make4PhaseTiming(const ChipsetTiming &timing_3phase, u32 tolerance_ns) FL_NO_EXCEPT
Create 4-phase RX timing from 3-phase chipset timing with tolerance.
Definition rx.cpp.hpp:78
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
Base definition for an LED controller.
4-phase RX timing thresholds for chipset detection
Definition rx.h:88
Generic chipset timing entry Provides T1, T2, T3 timing parameters in nanoseconds for any LED protoco...
Definition led_timing.h:86
Common RX interfaces and shared types.