FastLED 3.10.8
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
49namespace fl {
50
51template <>
53#ifdef FL_IS_RP
54 return RpPioRxDevice::create(pin);
55#elif defined(FL_IS_STUB)
56 return NativeRxDevice::create(pin);
57#else
58 (void)pin;
59 return createDummy();
60#endif
61}
62
63// Private static helper - creates dummy device (singleton pattern)
65 static fl::shared_ptr<RxDevice> dummy = fl::make_shared<DummyRxDevice>( // okay static in header
66 "RX devices not supported on this platform"
67 );
68 return dummy;
69}
70
71// Implementation of make4PhaseTiming function
73 u32 tolerance_ns) FL_NO_EXCEPT {
74 // Calculate derived values from 3-phase timing
75 // The encoder uses:
76 // Bit 0: T1 high + (T2+T3) low
77 // Bit 1: (T1+T2) high + T3 low
78 u32 t0h = timing_3phase.T1; // Bit 0 high time
79 u32 t0l = timing_3phase.T2 + timing_3phase.T3; // Bit 0 low time
80 u32 t1h = timing_3phase.T1 + timing_3phase.T2; // Bit 1 high time
81 u32 t1l = timing_3phase.T3; // Bit 1 low time
82
84
85 // Bit 0 timing thresholds
86 result.t0h_min_ns = (t0h > tolerance_ns) ? (t0h - tolerance_ns) : 0;
87 result.t0h_max_ns = t0h + tolerance_ns;
88 result.t0l_min_ns = (t0l > tolerance_ns) ? (t0l - tolerance_ns) : 0;
89 result.t0l_max_ns = t0l + tolerance_ns;
90
91 // Bit 1 timing thresholds
92 result.t1h_min_ns = (t1h > tolerance_ns) ? (t1h - tolerance_ns) : 0;
93 result.t1h_max_ns = t1h + tolerance_ns;
94 result.t1l_min_ns = (t1l > tolerance_ns) ? (t1l - tolerance_ns) : 0;
95 result.t1l_max_ns = t1l + tolerance_ns;
96
97 // Reset pulse threshold
98 result.reset_min_us = timing_3phase.RESET;
99
100 // gap_tolerance_ns retains its default value of 0
101
102 return result;
103}
104
105} // namespace fl
106
107
108
109// ESP32-specific explicit template specializations
110namespace fl {
111
112#ifdef FL_IS_ESP32
113
114// RMT device specialization for ESP32.
115//
116// The `RmtRxChannel::create` impl only exists on chips that actually have RMT
117// silicon: the IDF 4.x impl in `rmt_rx_4/` gates on
118// `FASTLED_ESP32_HAS_RMT && !FASTLED_ESP32_RMT5_ONLY_PLATFORM && !FASTLED_RMT5`
119// and the IDF 5.x impl in `rmt_rx_5/` gates on `FASTLED_RMT5`. On ESP32-C2
120// the SoC has no RMT peripheral (`SOC_RMT_SUPPORTED == 0`, so
121// `FASTLED_ESP32_HAS_RMT == 0`), and the workflow forces
122// `FASTLED_RMT5 = 0` for that chip — so both impls skip and the specialisation
123// link-fails with `undefined reference to fl::RmtRxChannel::create(int)`.
124// Mirror the exact gates the impls use here so the specialisation collapses
125// to a DummyRxDevice on RMT-less chips.
126template <>
127fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::RMT>(int pin) FL_NO_EXCEPT {
128#if (FASTLED_ESP32_HAS_RMT && !FASTLED_ESP32_RMT5_ONLY_PLATFORM && !FASTLED_RMT5) || FASTLED_RMT5
129 auto device = RmtRxChannel::create(pin);
130 if (!device) {
131 return fl::make_shared<DummyRxDevice>("RMT RX channel creation failed");
132 }
133 return device;
134#else
135 (void)pin;
136 return fl::make_shared<DummyRxDevice>("RMT RX not supported on this ESP32 SoC");
137#endif
138}
139
140// ISR device specialization for ESP32
141template <>
142fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::ISR>(int pin) FL_NO_EXCEPT {
143 auto device = GpioIsrRx::create(pin);
144 if (!device) {
145 return fl::make_shared<DummyRxDevice>("GPIO ISR RX creation failed");
146 }
147 return device;
148}
149
150// FLEXPWM not available on ESP32
151template <>
152fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXPWM>(int pin) FL_NO_EXCEPT {
153 (void)pin;
154 return fl::make_shared<DummyRxDevice>("FLEXPWM RX not supported on ESP32");
155}
156
157// FLEXIO not available on ESP32 (Teensy 4.x peripheral). See FastLED#2764.
158template <>
159fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXIO>(int pin) FL_NO_EXCEPT {
160 (void)pin;
161 return fl::make_shared<DummyRxDevice>("FLEXIO RX not supported on ESP32");
162}
163
164// LPC_SCT_CAPTURE not available on ESP32 (LPC8xx peripheral). See FastLED#3015.
165// FastLED#3576 Phase 3 — I2S-RX oversampling backend (classic ESP32).
166template <>
167fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::I2S_RX>(int pin) FL_NO_EXCEPT {
168#if FASTLED_ESP32_HAS_I2S
169 auto device = createI2sRxSampler(pin);
170 if (device) {
171 return device;
172 }
173#endif
174 (void)pin;
175 return fl::make_shared<DummyRxDevice>("I2S_RX not supported on this chip");
176}
177
178// FastLED#3586 — PARLIO-RX oversampling backend (ESP32-C6 et al).
179template <>
180fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PARLIO_RX>(int pin) FL_NO_EXCEPT {
181 auto device = createParlioRxSampler(pin);
182 if (device) {
183 return device;
184 }
185 return fl::make_shared<DummyRxDevice>("PARLIO_RX not supported on this chip");
186}
187
188template <>
189fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::LPC_SCT_CAPTURE>(int pin) FL_NO_EXCEPT {
190 (void)pin;
191 return fl::make_shared<DummyRxDevice>("LPC_SCT_CAPTURE RX not supported on ESP32");
192}
193
194// DEFAULT maps to RMT on ESP32
195template <>
196fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PLATFORM_DEFAULT>(int pin) FL_NO_EXCEPT {
198}
199
200#elif defined(FL_IS_TEENSY_4X)
201
202// FLEXPWM device specialization for Teensy 4.x
203template <>
204fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXPWM>(int pin) FL_NO_EXCEPT {
205 auto device = FlexPwmRxChannel::create(pin);
206 if (!device) {
207 return fl::make_shared<DummyRxDevice>("FlexPWM RX channel creation failed");
208 }
209 return device;
210}
211
212// FLEXIO device specialization for Teensy 4.x — Phase 1A skeleton (FastLED#2764).
213// Returns a real FlexIoRxChannel object whose methods report inactive until
214// Phase 1B lands the FLEXIO1 register programming.
215template <>
216fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXIO>(int pin) FL_NO_EXCEPT {
217 auto device = FlexIoRxChannel::create(pin);
218 if (!device) {
219 return fl::make_shared<DummyRxDevice>("FlexIO RX channel creation failed");
220 }
221 return device;
222}
223
224// RMT not available on Teensy
225template <>
226fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::RMT>(int pin) FL_NO_EXCEPT {
227 (void)pin;
228 return fl::make_shared<DummyRxDevice>("RMT RX not supported on Teensy");
229}
230
231// ISR not available on Teensy
232template <>
233fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::ISR>(int pin) FL_NO_EXCEPT {
234 (void)pin;
235 return fl::make_shared<DummyRxDevice>("ISR RX not supported on Teensy");
236}
237
238// LPC_SCT_CAPTURE not available on Teensy (LPC8xx peripheral). See FastLED#3015.
239template <>
240fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::I2S_RX>(int pin) FL_NO_EXCEPT {
241 (void)pin;
242 return fl::make_shared<DummyRxDevice>("I2S_RX not supported on this platform");
243}
244
245template <>
246fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PARLIO_RX>(int pin) FL_NO_EXCEPT {
247 (void)pin;
248 return fl::make_shared<DummyRxDevice>("PARLIO_RX not supported on this platform");
249}
250
251template <>
252fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::LPC_SCT_CAPTURE>(int pin) FL_NO_EXCEPT {
253 (void)pin;
254 return fl::make_shared<DummyRxDevice>("LPC_SCT_CAPTURE RX not supported on Teensy");
255}
256
257// DEFAULT maps to FLEXPWM on Teensy 4.x (intentionally NOT switched to FLEXIO yet
258// — that ships in a separate PR after Phase 3 verification per FastLED#2764).
259template <>
260fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PLATFORM_DEFAULT>(int pin) FL_NO_EXCEPT {
262}
263
264#elif defined(FL_IS_ARM_LPC)
265
266// LPC8xx SCT input-capture + DMA receiver. See FastLED#3015.
267template <>
268fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::I2S_RX>(int pin) FL_NO_EXCEPT {
269 (void)pin;
270 return fl::make_shared<DummyRxDevice>("I2S_RX not supported on this platform");
271}
272
273template <>
274fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PARLIO_RX>(int pin) FL_NO_EXCEPT {
275 (void)pin;
276 return fl::make_shared<DummyRxDevice>("PARLIO_RX not supported on this platform");
277}
278
279template <>
280fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::LPC_SCT_CAPTURE>(int pin) FL_NO_EXCEPT {
281 auto device = LpcSctRxChannel::create(pin);
282 if (!device) {
283 return fl::make_shared<DummyRxDevice>("LPC SCT-capture RX channel creation failed");
284 }
285 return device;
286}
287
288// RMT not available on LPC
289template <>
290fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::RMT>(int pin) FL_NO_EXCEPT {
291 (void)pin;
292 return fl::make_shared<DummyRxDevice>("RMT RX not supported on LPC");
293}
294
295// ISR not available on LPC (Cortex-M0+ ISR latency cannot decode 800 kHz). See #3015.
296template <>
297fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::ISR>(int pin) FL_NO_EXCEPT {
298 (void)pin;
299 return fl::make_shared<DummyRxDevice>("ISR RX not feasible on LPC Cortex-M0+ (use LPC_SCT_CAPTURE)");
300}
301
302// FLEXPWM not available on LPC
303template <>
304fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXPWM>(int pin) FL_NO_EXCEPT {
305 (void)pin;
306 return fl::make_shared<DummyRxDevice>("FLEXPWM RX not supported on LPC");
307}
308
309// FLEXIO not available on LPC
310template <>
311fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXIO>(int pin) FL_NO_EXCEPT {
312 (void)pin;
313 return fl::make_shared<DummyRxDevice>("FLEXIO RX not supported on LPC");
314}
315
316// DEFAULT maps to LPC_SCT_CAPTURE on LPC.
317template <>
318fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PLATFORM_DEFAULT>(int pin) FL_NO_EXCEPT {
320}
321
322#elif defined(FL_IS_STUB)
323
324// RMT device specialization (native stub for host/desktop testing)
325template <>
326fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::RMT>(int pin) FL_NO_EXCEPT {
327 return NativeRxDevice::create(pin);
328}
329
330// ISR device specialization (native stub for host/desktop testing)
331template <>
332fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::ISR>(int pin) FL_NO_EXCEPT {
333 return NativeRxDevice::create(pin);
334}
335
336// FLEXPWM device specialization (native stub for host/desktop testing)
337template <>
338fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXPWM>(int pin) FL_NO_EXCEPT {
339 return NativeRxDevice::create(pin);
340}
341
342// FLEXIO device specialization (native stub for host/desktop testing). Same
343// NativeRxDevice fallback as the other backends so host-stub tests can exercise
344// `RxBackend::FLEXIO` against the synthetic capture buffer.
345template <>
346fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXIO>(int pin) FL_NO_EXCEPT {
347 return NativeRxDevice::create(pin);
348}
349
350// LPC_SCT_CAPTURE device specialization (native stub). Same NativeRxDevice
351// fallback so host-stub tests can exercise `RxBackend::LPC_SCT_CAPTURE`
352// against the synthetic capture buffer.
353template <>
354fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::I2S_RX>(int pin) FL_NO_EXCEPT {
355 (void)pin;
356 return fl::make_shared<DummyRxDevice>("I2S_RX not supported on this platform");
357}
358
359template <>
360fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PARLIO_RX>(int pin) FL_NO_EXCEPT {
361 (void)pin;
362 return fl::make_shared<DummyRxDevice>("PARLIO_RX not supported on this platform");
363}
364
365template <>
366fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::LPC_SCT_CAPTURE>(int pin) FL_NO_EXCEPT {
367 return NativeRxDevice::create(pin);
368}
369
370// DEFAULT maps to RMT on stub (same as ESP32 default)
371template <>
372fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PLATFORM_DEFAULT>(int pin) FL_NO_EXCEPT {
374}
375
376#else
377
378// RMT device specialization (dummy for non-ESP32, non-stub)
379template <>
380fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::RMT>(int pin) FL_NO_EXCEPT {
381 (void)pin; // Suppress unused parameter warning
382 return RxDevice::createDummy();
383}
384
385// ISR device specialization (dummy for non-ESP32, non-stub)
386template <>
387fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::ISR>(int pin) FL_NO_EXCEPT {
388 (void)pin; // Suppress unused parameter warning
389 return RxDevice::createDummy();
390}
391
392// FLEXPWM device specialization (dummy for unsupported platforms)
393template <>
394fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXPWM>(int pin) FL_NO_EXCEPT {
395 (void)pin; // Suppress unused parameter warning
396 return RxDevice::createDummy();
397}
398
399// FLEXIO device specialization (dummy for unsupported platforms)
400template <>
401fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::FLEXIO>(int pin) FL_NO_EXCEPT {
402 (void)pin; // Suppress unused parameter warning
403 return RxDevice::createDummy();
404}
405
406// LPC_SCT_CAPTURE device specialization (dummy for unsupported platforms)
407template <>
408fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::I2S_RX>(int pin) FL_NO_EXCEPT {
409 (void)pin;
410 return fl::make_shared<DummyRxDevice>("I2S_RX not supported on this platform");
411}
412
413template <>
414fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PARLIO_RX>(int pin) FL_NO_EXCEPT {
415 (void)pin;
416 return fl::make_shared<DummyRxDevice>("PARLIO_RX not supported on this platform");
417}
418
419template <>
420fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::LPC_SCT_CAPTURE>(int pin) FL_NO_EXCEPT {
421 (void)pin; // Suppress unused parameter warning
422 return RxDevice::createDummy();
423}
424
425// DEFAULT maps to PIO on RP and RMT elsewhere (returns dummy if unsupported).
426template <>
427fl::shared_ptr<RxDevice> RxDevice::create<RxDeviceType::PLATFORM_DEFAULT>(int pin) FL_NO_EXCEPT {
428#ifdef FL_IS_RP
430#else
432#endif
433}
434
435#endif // FL_IS_ESP32 / FL_IS_TEENSY_4X / FL_IS_ARM_LPC / FL_IS_STUB
436
437} // 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:64
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:72
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
Base definition for an LED controller.
Definition crgb.hpp:179
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.