43#if defined(FL_IS_ARM_LPC_845) && defined(FASTLED_LPC_PWM_DMA)
59#include "platforms/arm/lpc/drivers/sct_dma/channel_engine_lpc_sct_dma.h"
63#include "platforms/arm/lpc/drivers/sct_dma/bus_traits.h"
68struct PwmDmaClocklessState {
72inline PwmDmaClocklessState& pwmDmaClocklessState()
FL_NO_EXCEPT {
80inline fl::ChipsetTimingConfig ws2812b_timing()
FL_NO_EXCEPT {
81 return fl::ChipsetTimingConfig(350, 450, 450,
87inline fl::ChipsetTiming4Phase ws2812b_decoder_timing()
FL_NO_EXCEPT {
88 fl::ChipsetTiming4Phase
t{};
89 t.t0h_min_ns = 250;
t.t0h_max_ns = 550;
90 t.t0l_min_ns = 700;
t.t0l_max_ns = 1000;
91 t.t1h_min_ns = 650;
t.t1h_max_ns = 950;
92 t.t1l_min_ns = 300;
t.t1l_max_ns = 600;
94 t.gap_tolerance_ns = 0;
101inline fl::ChannelDataPtr makeSolidChannelData(
103 fl::ChipsetTimingConfig
t = ws2812b_timing();
104 fl::vector_psram<fl::u8> encoded(
static_cast<fl::size
>(num_leds * 3));
105 const fl::u8 r =
static_cast<fl::u8>((rgb >> 16) & 0xFF);
107 const fl::u8 b =
static_cast<fl::u8>((rgb >> 0) & 0xFF);
108 for (
int i = 0; i < num_leds; ++i) {
109 encoded[i * 3 + 0] =
g;
110 encoded[i * 3 + 1] = r;
111 encoded[i * 3 + 2] = b;
118inline fl::string frameOnceHandler(
int led_count, fl::u32 rgb,
int data_pin)
FL_NO_EXCEPT {
119 if (led_count <= 0 || led_count > 300 || data_pin < 0 || data_pin > 31) {
120 return fl::string(
"0,0,0,0");
122 auto& engine = fl::BusTraits<fl::Bus::BIT_BANG>::instance();
123 auto ch = makeSolidChannelData(data_pin, led_count, rgb);
124 if (!engine.canHandle(ch)) {
125 return fl::string(
"0,0,0,0");
128 const fl::u32 t_start =
micros();
138 const fl::u32 t_end =
micros();
139 const fl::u32 dur_us = t_end - t_start;
142 s << 1 <<
',' << t_start <<
',' << t_end <<
',' << dur_us;
147inline fl::string frameBurstHandler(
int led_count, fl::u32 rgb,
149 if (led_count <= 0 || led_count > 300 || n_frames <= 0 ||
150 n_frames > 1000 || data_pin < 0 || data_pin > 31) {
151 return fl::string(
"0,0,0");
153 auto& engine = fl::BusTraits<fl::Bus::BIT_BANG>::instance();
154 auto ch = makeSolidChannelData(data_pin, led_count, rgb);
155 if (!engine.canHandle(ch)) {
156 return fl::string(
"0,0,0");
159 const fl::u32 t_start =
micros();
160 for (
int i = 0; i < n_frames; ++i) {
167 if ((i & 0x3F) == 0) {
171 const fl::u32 t_end =
micros();
172 const fl::u32 total_us = t_end - t_start;
174 const fl::u32 fps_x100 = total_us > 0
175 ? (
static_cast<fl::u32
>(n_frames) * 100u * 1000000u / total_us)
179 s << 1 <<
',' << total_us <<
',' << fps_x100;
191inline fl::string captureSelfHandler(
int led_count, fl::u32 rgb,
192 int data_pin,
int rx_pin,
194 if (led_count <= 0 || led_count > 32 || data_pin < 0 || data_pin > 31 ||
195 rx_pin < 0 || rx_pin > 31 || capture_ms <= 0 || capture_ms > 200) {
196 return fl::string(
"0");
202 auto rx = fl::LpcSctRxChannel::create(rx_pin);
203 if (!rx)
return fl::string(
"0");
205 cfg.
buffer_size =
static_cast<fl::u32
>(led_count * 3 * 16 + 32);
207 if (!rx->begin(cfg))
return fl::string(
"0");
210 auto& engine = fl::BusTraits<fl::Bus::BIT_BANG>::instance();
211 auto ch = makeSolidChannelData(data_pin, led_count, rgb);
212 if (!engine.canHandle(ch))
return fl::string(
"0");
221 (void)rx->wait(
static_cast<fl::u32
>(capture_ms));
224 const fl::size decoded_cap =
static_cast<fl::size
>(led_count * 3);
225 fl::u8* decoded = pwmDmaClocklessState().decoded;
226 if (decoded_cap >
sizeof(decoded))
return fl::string(
"0");
227 auto result = rx->decode(ws2812b_decoder_timing(),
228 fl::span<fl::u8>(decoded, decoded_cap));
229 if (!
result.ok())
return fl::string(
"0");
230 const fl::u32 n_decoded =
result.value();
235 s << 1 <<
',' << n_decoded;
236 for (fl::u32 i = 0; i < n_decoded; ++i) {
237 s << ',' << static_cast<fl::u32>(decoded[i]);
245 remote.bind(
"pwmDmaClFrameOnce",
246 [](
int led_count, fl::u32 rgb,
int data_pin) -> fl::string {
247 return frameOnceHandler(led_count, rgb, data_pin);
249 remote.bind(
"pwmDmaClFrameBurst",
250 [](
int led_count, fl::u32 rgb,
int n_frames,
int data_pin) -> fl::string {
251 return frameBurstHandler(led_count, rgb, n_frames, data_pin);
253 remote.bind(
"pwmDmaClCaptureSelf",
254 [](
int led_count, fl::u32 rgb,
int data_pin,
int rx_pin,
255 int capture_ms) -> fl::string {
256 return captureSelfHandler(led_count, rgb, data_pin, rx_pin,
fl::unique_ptr< fl::Remote > remote
Portable compile-time identifiers for LED channel buses.
Per-driver traits keyed on fl::Bus.
Runtime chipset timing configuration for clockless LED drivers.
static ChannelDataPtr create(const ChipsetVariant &chipset, fl::vector_psram< u8 > &&encodedData=fl::vector_psram< u8 >(), ChannelPixelFormat pixelFormat=ChannelPixelFormat::RGB) FL_NO_EXCEPT
Create channel transmission data (modern variant-based API)
static T & instance() FL_NO_EXCEPT
static Watchdog & instance() FL_NO_EXCEPT
string str() const FL_NO_EXCEPT
Channel transmission data - lightweight DTO for driver transmission.
constexpr remove_reference< T >::type && move(T &&t) FL_NO_EXCEPT
fl::u32 micros()
Universal microsecond timer - returns microseconds since system startup.
expected< T, E > result
Alias for expected (Rust-style naming)
Common RX interfaces and shared types.
@ READY
Hardware idle; ready to accept new transmissions.
size_t buffer_size
Buffer size in symbols/edges (default: 512)
bool start_low
Pin idle state: true=LOW (WS2812B), false=HIGH (inverted)
Compile-time timing extraction from ChipsetTiming structs.