FastLED 3.10.6
Loading...
Searching...
No Matches
AutoResearchUartDma.h
Go to the documentation of this file.
1// AutoResearchUartDma.h — LPC845 async UART TX driver AutoResearch
2// validation harness (#3453 follow-up: ISR-refillable async drivers).
3//
4// Device-side RPC handlers exercising `ARMHardwareUARTOutputDMA<>`
5// (`platforms/arm/lpc/uart_arm_lpc_dma.h`) on real silicon: USART1 TX
6// driven by DMA0 channel 3, chunks chained from the DMA completion ISR
7// (lpc_dma_isr.h hub), while USART0 keeps serving the RPC console —
8// the "drive data and keep printing" proof.
9//
10// Gated on `FL_IS_ARM_LPC_845 && FASTLED_LPC_UART_DMA`. Mutually
11// exclusive with the SPI/PWM DMA harnesses at the flash-budget level
12// (enforced host-side by `bash autoresearch`).
13//
14// Handlers (bind via `autoresearch::uart_dma::bind(remote)`):
15//
16// `uartDmaStreamOnce(byte_count, byte_pattern)`
17// Kick an async stream and CPU-wait for completion. CSV
18// `"success,total_us,byte_count"` — host sanity-checks the wall
19// time against the configured baud.
20//
21// `uartDmaStreamOverlap(byte_count, byte_pattern)`
22// Kick the stream and beacon-toggle a volatile counter until
23// `streamDone()`. CSV `"success,total_us,toggle_count"`. Non-zero
24// toggles while a multi-chunk stream drains is the async proof —
25// and with byte_count > 1024 it also proves the ISR chunk-chaining
26// (a stalled chain would time out).
27
28#pragma once
29
30#include <FastLED.h>
31
32#if defined(FL_IS_ARM_LPC_845) && FASTLED_LPC_UART_DMA
33
34#if defined(FL_LPC_UART_DMA_CLOCKLESS_TEST)
35#include "fl/channels/bus.h"
39#endif
40#include "fl/remote/remote.h"
41#include "fl/stl/noexcept.h"
42#include "fl/stl/singleton.h"
43#include "fl/stl/sstream.h"
44#include "platforms/arm/lpc/uart_arm_lpc_dma.h" // ok platform headers — AutoResearch driver-specific test needs the concrete UART DMA driver
45
46namespace autoresearch {
47namespace uart_dma {
48
49#if !defined(FL_LPC_UART_DMA_CLOCKLESS_TEST)
50
51// Default TXD routing + baud. PIO0_9 is unclaimed on the LPC845-BRK
52// header; the bench never reads the wire (wall-clock timing only), the
53// pin just has to exist for SWM. 1 Mbaud keeps a 2048-byte stream at
54// ~20 ms — inside the RPC window with margin.
55#if !defined(FASTLED_LPC_UART_DMA_HARNESS_TX_PIN)
56#define FASTLED_LPC_UART_DMA_HARNESS_TX_PIN 9
57#endif
58#if !defined(FASTLED_LPC_UART_DMA_HARNESS_BAUD)
59#define FASTLED_LPC_UART_DMA_HARNESS_BAUD 1000000
60#endif
61
62using HarnessDriver = fl::ARMHardwareUARTOutputDMA<
63 static_cast<fl::u8>(FASTLED_LPC_UART_DMA_HARNESS_TX_PIN),
64 static_cast<fl::u32>(FASTLED_LPC_UART_DMA_HARNESS_BAUD)>;
65
66// Stream source. 2048 bytes = two full 1024-transfer descriptors →
67// at least one ISR chunk-chain per stream, which is the property under
68// test. Must outlive the stream (DMA reads it in place).
69#if !defined(FASTLED_LPC_UART_DMA_HARNESS_BYTES)
70#define FASTLED_LPC_UART_DMA_HARNESS_BYTES 2048
71#endif
72
73struct UartDmaHarnessState {
74 fl::u8 buffer[FASTLED_LPC_UART_DMA_HARNESS_BYTES];
75 HarnessDriver driver;
76};
77
78inline UartDmaHarnessState& uartDmaHarnessState() FL_NO_EXCEPT {
80}
81
82inline fl::u8* harnessBuffer() FL_NO_EXCEPT {
83 return uartDmaHarnessState().buffer;
84}
85
86inline HarnessDriver& harnessDriver() FL_NO_EXCEPT {
87 UartDmaHarnessState& state = uartDmaHarnessState();
88 state.driver.init();
89 return state.driver;
90}
91
92inline int clampByteCount(int n) FL_NO_EXCEPT {
93 if (n <= 0) return 0;
94 const int cap = static_cast<int>(FASTLED_LPC_UART_DMA_HARNESS_BYTES);
95 return (n > cap) ? cap : n;
96}
97
98// Bounded-spin guard (same pattern the SPI harness validated in #3580):
99// a healthy 2048-byte stream at 1 Mbaud drains in ~20 ms; 4M iterations
100// ≈ 2 s at 24 MHz. On timeout return a register snapshot instead of
101// wedging into the watchdog.
102inline bool spinUntilStreamDone(fl::sstream& diag) FL_NO_EXCEPT {
103 fl::u32 spins = 0;
104 while (!HarnessDriver::streamDone()) {
105 if (++spins > 4000000u) {
106 diag << 0 << ','
107 << DMA0->COMMON[0].ACTIVE << ','
108 << DMA0->CHANNEL[3].XFERCFG << ','
109 << DMA0->CHANNEL[3].CTLSTAT << ','
110 << USART1->STAT << ','
111 << DMA0->COMMON[0].ERRINT;
112 return false;
113 }
114 }
115 return true;
116}
117
118// CSV: "success,total_us,byte_count" (diag CSV on timeout).
119inline fl::string streamOnceHandler(int byte_count, int byte_pattern) FL_NO_EXCEPT {
120 const int len = clampByteCount(byte_count);
121 if (len == 0) return fl::string("0,0,0");
122 fl::u8* buf = harnessBuffer();
123 const fl::u8 pat = static_cast<fl::u8>(byte_pattern & 0xFF);
124 for (int i = 0; i < len; ++i) buf[i] = pat;
125
126 HarnessDriver& drv = harnessDriver();
127 (void)drv;
128
129 const fl::u32 t_start = micros();
130 if (!HarnessDriver::kickDmaStreamAsync(buf, static_cast<fl::u32>(len))) {
131 return fl::string("0,kick_refused,0");
132 }
133 fl::sstream diag;
134 if (!spinUntilStreamDone(diag)) return diag.str();
135 const fl::u32 total_us = micros() - t_start;
136
137 fl::sstream s;
138 s << 1 << ',' << total_us << ',' << len;
139 return s.str();
140}
141
142// CSV: "success,total_us,toggle_count" — the async proof.
143inline fl::string streamOverlapHandler(int byte_count, int byte_pattern) FL_NO_EXCEPT {
144 const int len = clampByteCount(byte_count);
145 if (len == 0) return fl::string("0,0,0");
146 fl::u8* buf = harnessBuffer();
147 const fl::u8 pat = static_cast<fl::u8>(byte_pattern & 0xFF);
148 for (int i = 0; i < len; ++i) buf[i] = pat;
149
150 HarnessDriver& drv = harnessDriver();
151 (void)drv;
152
153 const fl::u32 t_start = micros();
154 if (!HarnessDriver::kickDmaStreamAsync(buf, static_cast<fl::u32>(len))) {
155 return fl::string("0,kick_refused,0");
156 }
157
158 // Volatile beacon: real memory traffic per iteration, so a non-zero
159 // count is affirmative evidence the CPU ran application code while
160 // the DMA/ISR machinery drove the UART.
161 volatile fl::u32 toggle_count = 0;
162 fl::u32 spins = 0;
163 while (!HarnessDriver::streamDone()) {
164 ++toggle_count;
165 if (++spins > 4000000u) {
166 fl::sstream d;
167 d << 0 << ',' << DMA0->COMMON[0].ACTIVE << ','
168 << DMA0->CHANNEL[3].CTLSTAT << ',' << USART1->STAT;
169 return d.str();
170 }
171 }
172 const fl::u32 total_us = micros() - t_start;
173
174 fl::sstream s;
175 s << 1 << ',' << total_us << ',' << toggle_count;
176 return s.str();
177}
178
179// Args as a JSON array (house RpcClient convention — single `const
180// fl::json&` that is the positional-arg array). Lets the bench run over
181// fbuild's Rust serial monitor instead of raw pyserial.
182#endif // !FL_LPC_UART_DMA_CLOCKLESS_TEST
183
184inline int argInt(const fl::json& args, fl::size i, int fallback) FL_NO_EXCEPT {
185 return static_cast<int>(args[i].as_int().value_or(fallback));
186}
187
188#if defined(FL_LPC_UART_DMA_CLOCKLESS_TEST)
189
190#if !defined(FL_LPC_UART_DMA_CLOCKLESS_TX_PIN)
191#define FL_LPC_UART_DMA_CLOCKLESS_TX_PIN 10
192#endif
193#if !defined(FL_LPC_UART_DMA_CLOCKLESS_LEDS)
194#define FL_LPC_UART_DMA_CLOCKLESS_LEDS 8
195#endif
196
197constexpr fl::size kClocklessEncodedBytes =
198 FL_LPC_UART_DMA_CLOCKLESS_LEDS * 3u * 4u;
199
200struct UartDmaClocklessState {
201 fl::CRGB leds[FL_LPC_UART_DMA_CLOCKLESS_LEDS];
202 fl::u8 expected[kClocklessEncodedBytes];
203 fl::u8 received[kClocklessEncodedBytes];
204 bool registered;
205
206 UartDmaClocklessState() : registered(false) {}
207};
208
209inline UartDmaClocklessState& uartDmaClocklessState() FL_NO_EXCEPT {
211}
212
213inline fl::CRGB* clocklessLeds() FL_NO_EXCEPT {
214 return uartDmaClocklessState().leds;
215}
216
217inline bool ensureClocklessFastLedRegistered() FL_NO_EXCEPT {
218 UartDmaClocklessState& state = uartDmaClocklessState();
219 if (!state.registered) {
220 FastLED.addLeds<WS2812,
221 static_cast<fl::u8>(FL_LPC_UART_DMA_CLOCKLESS_TX_PIN),
222 GRB>(clocklessLeds(), FL_LPC_UART_DMA_CLOCKLESS_LEDS);
223 state.registered = true;
224 }
225 return state.registered;
226}
227
228inline USART_Type* clocklessUartBlock() FL_NO_EXCEPT {
229#if FASTLED_LPC_UART_DMA_INSTANCE == 2
230 return USART2;
231#else
232 return USART1;
233#endif
234}
235
236inline volatile fl::u32& clocklessDmaReg(fl::u32 offset) FL_NO_EXCEPT {
237 return *reinterpret_cast<volatile fl::u32*>(0x50008000u + offset); // ok reinterpret cast - DMA0 MMIO
238}
239
240inline fl::u32 clocklessUartActualBaud() FL_NO_EXCEPT {
241 USART_Type* u = clocklessUartBlock();
242 const fl::u32 osr = (u->OSR & 0xFu) + 1u;
243 const fl::u32 brg = (u->BRG & 0xFFFFu) + 1u;
244 return F_CPU / (osr * brg);
245}
246
247inline void clocklessUartDrainRx(fl::u32& errors) FL_NO_EXCEPT {
248 USART_Type* u = clocklessUartBlock();
249 constexpr fl::u32 kRxRdy = (1u << 0);
250 constexpr fl::u32 kOverrun = (1u << 8);
251 constexpr fl::u32 kFrame = (1u << 13);
252 constexpr fl::u32 kParity = (1u << 14);
253 while ((u->STAT & kRxRdy) != 0u) {
254 errors |= (u->RXDATSTAT & (kOverrun | kFrame | kParity));
255 }
256 u->STAT = kOverrun | kFrame | kParity;
257}
258
259inline fl::u32 clocklessAbsDiff(fl::u32 a, fl::u32 b) FL_NO_EXCEPT {
260 return a > b ? a - b : b - a;
261}
262
263inline fl::u8 clocklessPulseCount(fl::u32 timing_ns, fl::u32 pulse_ns) FL_NO_EXCEPT {
264 if (pulse_ns == 0u) {
265 return 0;
266 }
267 const fl::u8 lo = static_cast<fl::u8>(timing_ns / pulse_ns);
268 const fl::u8 hi = static_cast<fl::u8>(lo + 1u);
269 const fl::u32 err_lo = clocklessAbsDiff(static_cast<fl::u32>(lo) * pulse_ns, timing_ns);
270 const fl::u32 err_hi = clocklessAbsDiff(static_cast<fl::u32>(hi) * pulse_ns, timing_ns);
271 return err_hi < err_lo ? hi : lo;
272}
273
274inline fl::u8 clocklessBuildUartByte(fl::u8 pulses_a, fl::u8 pulses_b) FL_NO_EXCEPT {
275 fl::u8 value = 0;
276 for (int i = 0; i < 8; ++i) {
277 const int pulse = i + 1;
278 const bool wire_high =
279 (pulse < 5 && pulse < static_cast<int>(pulses_a)) ||
280 (pulse >= 5 && (pulse - 5) < static_cast<int>(pulses_b));
281 if (!wire_high) {
282 value |= static_cast<fl::u8>(1u << i);
283 }
284 }
285 return value;
286}
287
288inline bool clocklessBuildUartLut(fl::u8 lut[4], fl::u32& baud_out) FL_NO_EXCEPT {
289 const fl::ChipsetTimingConfig timing =
291 constexpr fl::u8 kPulsesPerBit = 5;
292 const fl::u32 period_ns = timing.total_period_ns();
293 if (period_ns == 0u) {
294 return false;
295 }
296
297 const fl::u32 pulse_ns = period_ns / kPulsesPerBit;
298 const fl::u8 pulses0 = clocklessPulseCount(timing.t1_ns, pulse_ns);
299 const fl::u8 pulses1 = clocklessPulseCount(timing.t1_ns + timing.t2_ns, pulse_ns);
300 if (pulses0 < 1u || pulses0 > 4u || pulses1 < 1u || pulses1 > 4u ||
301 pulses0 == pulses1) {
302 return false;
303 }
304
305 lut[0] = clocklessBuildUartByte(pulses0, pulses0);
306 lut[1] = clocklessBuildUartByte(pulses0, pulses1);
307 lut[2] = clocklessBuildUartByte(pulses1, pulses0);
308 lut[3] = clocklessBuildUartByte(pulses1, pulses1);
309 baud_out = static_cast<fl::u32>(
310 static_cast<fl::u64>(kPulsesPerBit) * 1000000000ULL / period_ns);
311 return true;
312}
313
314inline fl::size clocklessEncodeExpectedUartBytes(
315 int led_count, fl::u32 rgb, fl::u8* out, fl::size out_cap,
316 fl::u32& expected_baud) FL_NO_EXCEPT {
317 fl::u8 lut[4] = {0, 0, 0, 0};
318 if (!clocklessBuildUartLut(lut, expected_baud)) {
319 return 0;
320 }
321
322 const fl::size byte_count = static_cast<fl::size>(led_count) * 3u;
323 const fl::size encoded_count = byte_count * 4u;
324 if (encoded_count > out_cap) {
325 return 0;
326 }
327
328 const fl::u8 r = static_cast<fl::u8>((rgb >> 16) & 0xFF);
329 const fl::u8 g = static_cast<fl::u8>((rgb >> 8) & 0xFF);
330 const fl::u8 b = static_cast<fl::u8>(rgb & 0xFF);
331 fl::size o = 0;
332 for (int i = 0; i < led_count; ++i) {
333 const fl::u8 grb[3] = {g, r, b};
334 for (fl::u8 byte : grb) {
335 out[o++] = lut[(byte >> 6) & 0x03u];
336 out[o++] = lut[(byte >> 4) & 0x03u];
337 out[o++] = lut[(byte >> 2) & 0x03u];
338 out[o++] = lut[byte & 0x03u];
339 }
340 }
341 return encoded_count;
342}
343
344// CSV success: "1,n_decoded,<grb byte0>,<grb byte1>,...".
345// CSV failure: "0,loopback,<rx_count>,<expected_count>,<stream_done>,<stat>,<cfg>,<errors>,<expected_baud>,<actual_baud>,<mismatch_index>,<expected>,<actual>".
346inline fl::string clocklessLoopbackSelfHandler(
347 int led_count, fl::u32 rgb, int data_pin, int rx_pin,
348 int capture_ms) FL_NO_EXCEPT {
349 if (led_count != FL_LPC_UART_DMA_CLOCKLESS_LEDS ||
350 data_pin != FL_LPC_UART_DMA_CLOCKLESS_TX_PIN ||
351 rx_pin < 0 || rx_pin > 0x35 ||
352 !fl::lpc::LpcUartDmaRuntime::isMovableUartPin(
353 static_cast<fl::u8>(rx_pin)) ||
354 capture_ms <= 0 || capture_ms > 200) {
355 return fl::string("0,args");
356 }
357
358 ensureClocklessFastLedRegistered();
360 fl::CRGB* leds = clocklessLeds();
361 const fl::u8 r = static_cast<fl::u8>((rgb >> 16) & 0xFF);
362 const fl::u8 g = static_cast<fl::u8>((rgb >> 8) & 0xFF);
363 const fl::u8 b = static_cast<fl::u8>(rgb & 0xFF);
364 for (int i = 0; i < led_count; ++i) {
365 leds[i] = fl::CRGB(r, g, b);
366 }
367
368 UartDmaClocklessState& state = uartDmaClocklessState();
369 fl::u8* expected = state.expected;
370 fl::u8* received = state.received;
371 fl::u32 expected_baud = 0;
372 const fl::size expected_count = clocklessEncodeExpectedUartBytes(
373 led_count, rgb, expected, kClocklessEncodedBytes, expected_baud);
374 if (expected_count == 0u) {
375 return fl::string("0,encode");
376 }
377
378 fl::u32 errors = 0;
379 clocklessUartDrainRx(errors);
380 for (fl::size i = 0; i < expected_count; ++i) {
381 received[i] = 0xA5u;
382 }
383 fl::lpc::LpcUartDmaRuntime::prepareLoopbackRxBuffer(
384 received, static_cast<fl::u32>(expected_count),
385 static_cast<fl::u8>(rx_pin));
386
387 FastLED.show();
388
389 USART_Type* u = clocklessUartBlock();
390 auto& driver = fl::BusTraits<fl::Bus::UART>::instance();
391 bool stream_done = false;
392 const fl::u32 start = millis();
393 while ((millis() - start) < static_cast<fl::u32>(capture_ms)) {
394 const auto state = driver.poll();
395 stream_done = (state.state == fl::IChannelDriver::DriverState::READY);
396 if (stream_done &&
397 fl::lpc::LpcUartDmaRuntime::loopbackRxReceivedCount() >= expected_count) {
398 break;
399 }
400 }
401
402 stream_done = driver.waitForReady(1000);
403 const fl::size rx_count =
404 static_cast<fl::size>(fl::lpc::LpcUartDmaRuntime::loopbackRxReceivedCount());
405 errors |= (u->STAT & ((1u << 8) | (1u << 13) | (1u << 14)));
406 constexpr fl::u32 kLoopbackRxDmaChannel =
407 (FASTLED_LPC_UART_DMA_INSTANCE == 2) ? 4u : 2u;
408 const fl::u32 rx_dma_base = 0x400u + 16u * kLoopbackRxDmaChannel;
409 const fl::u32 rx_dma_cfg = clocklessDmaReg(rx_dma_base + 0x0u);
410 const fl::u32 rx_dma_ctlstat = clocklessDmaReg(rx_dma_base + 0x4u);
411 const fl::u32 rx_dma_xfercfg = clocklessDmaReg(rx_dma_base + 0x8u);
412 const fl::u32 rx_dma_active = clocklessDmaReg(0x030u);
413 const fl::u32 rx_dma_busy = clocklessDmaReg(0x038u);
414 const fl::u32 rx_dma_err = clocklessDmaReg(0x040u);
415 const fl::u32 rx_requested_len = g_fastled_lpc_uart_loopback_rx_len;
416 fl::lpc::LpcUartDmaRuntime::clearLoopbackRxBuffer();
417
418 fl::size mismatch = expected_count;
419 const fl::size compare_count =
420 rx_count < expected_count ? rx_count : expected_count;
421 for (fl::size i = 0; i < compare_count; ++i) {
422 if (received[i] != expected[i]) {
423 mismatch = i;
424 break;
425 }
426 }
427
428 if (rx_count != expected_count || mismatch != expected_count || errors != 0u) {
429 fl::sstream d;
430 d << 0 << ",loopback," << static_cast<fl::u32>(rx_count) << ','
431 << static_cast<fl::u32>(expected_count) << ','
432 << (stream_done ? 1 : 0) << ',' << u->STAT << ',' << u->CFG << ','
433 << errors << ',' << expected_baud << ',' << clocklessUartActualBaud()
434 << ',' << rx_dma_cfg << ',' << rx_dma_ctlstat << ','
435 << rx_dma_xfercfg << ',' << rx_dma_active << ','
436 << rx_dma_busy << ',' << rx_dma_err << ','
437 << rx_requested_len << ','
438 << g_fastled_lpc_uart_loopback_rx_arm_status << ','
439 << g_fastled_lpc_uart_loopback_rx_arm_tx_len << ','
440 << g_fastled_lpc_uart_loopback_rx_arm_xfer_readback << ','
441 << g_fastled_lpc_uart_loopback_rx_arm_desc0_readback << ',';
442 if (mismatch != expected_count) {
443 d << static_cast<fl::u32>(mismatch) << ','
444 << static_cast<fl::u32>(expected[mismatch]) << ','
445 << static_cast<fl::u32>(received[mismatch]);
446 } else {
447 d << static_cast<fl::u32>(expected_count) << ",0,0";
448 }
449 return d.str();
450 }
451
452 const fl::u32 n_decoded = static_cast<fl::u32>(led_count * 3);
453 fl::sstream s;
454 s << 1 << ',' << n_decoded;
455 for (int i = 0; i < led_count; ++i) {
456 s << ',' << static_cast<fl::u32>(g)
457 << ',' << static_cast<fl::u32>(r)
458 << ',' << static_cast<fl::u32>(b);
459 }
460 return s.str();
461}
462
463inline fl::string clocklessProbeHandler(
464 int step, int data_pin, int rx_pin) FL_NO_EXCEPT {
465 if (data_pin != FL_LPC_UART_DMA_CLOCKLESS_TX_PIN ||
466 rx_pin < 0 || rx_pin > 0x35 ||
467 !fl::lpc::LpcUartDmaRuntime::isMovableUartPin(
468 static_cast<fl::u8>(rx_pin))) {
469 return fl::string("0,args");
470 }
471 if (step <= 0) {
472 return fl::string("1,entry");
473 }
474 fl::sstream s;
475 s << 1 << ",uart_rx_dma," << clocklessUartBlock()->CFG;
476 return s.str();
477}
478
479#endif // FL_LPC_UART_DMA_CLOCKLESS_TEST
480
481inline void bind(fl::Remote& remote) FL_NO_EXCEPT {
482#if !defined(FL_LPC_UART_DMA_CLOCKLESS_TEST)
483 remote.bind("uartDmaStreamOnce",
484 [](const fl::json& args) -> fl::string {
485 return streamOnceHandler(argInt(args, 0, 0), argInt(args, 1, 0));
486 });
487 remote.bind("uartDmaStreamOverlap",
488 [](const fl::json& args) -> fl::string {
489 return streamOverlapHandler(argInt(args, 0, 0), argInt(args, 1, 0));
490 });
491#endif
492#if defined(FL_LPC_UART_DMA_CLOCKLESS_TEST)
493 remote.bind("uartDmaClocklessProbe",
494 [](const fl::json& args) -> fl::string {
495 return clocklessProbeHandler(
496 argInt(args, 0, 0),
497 argInt(args, 1, FL_LPC_UART_DMA_CLOCKLESS_TX_PIN),
498 argInt(args, 2, 11));
499 });
500 remote.bind("uartDmaClocklessLoopbackSelf",
501 [](const fl::json& args) -> fl::string {
502 return clocklessLoopbackSelfHandler(
503 argInt(args, 0, FL_LPC_UART_DMA_CLOCKLESS_LEDS),
504 static_cast<fl::u32>(argInt(args, 1, 0)),
505 argInt(args, 2, FL_LPC_UART_DMA_CLOCKLESS_TX_PIN),
506 argInt(args, 3, 11),
507 argInt(args, 4, 30));
508 });
509#endif
510}
511
512} // namespace uart_dma
513} // namespace autoresearch
514
515#endif // FL_IS_ARM_LPC_845 && FASTLED_LPC_UART_DMA
CRGB leds[1]
TestState state
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS CFastLED FastLED
Global LED strip management instance.
fl::unique_ptr< fl::Remote > remote
Definition RpcClient.ino:43
Portable compile-time identifiers for LED channel buses.
Per-driver traits keyed on fl::Bus.
Runtime chipset timing configuration for clockless LED drivers.
void show(fl::u8 scale)
Update all our controllers with the current led colors, using the passed in brightness.
void setBrightness(fl::u8 scale)
Set the global brightness scaling.
Definition FastLED.h:1601
::CLEDController & addLeds(::CLEDController *pLed, CRGB *data, int nLedsOrOffset, int nLedsIfOffset=0)
Add a CLEDController instance to the world.
static T & instance() FL_NO_EXCEPT
Definition singleton.h:81
string str() const FL_NO_EXCEPT
Definition strstream.h:43
fl::UISlider offset("Offset", 0.0f, 0.0f, 1.0f, 0.01f)
constexpr EOrder GRB
Definition eorder.h:19
unsigned char u8
Definition stdint.h:131
fl::CRGB CRGB
Definition video.h:18
constexpr ChipsetTimingConfig makeTimingConfig() FL_NO_EXCEPT
Convert compile-time CHIPSET type to runtime timing config.
fl::u32 millis()
Universal millisecond timer - returns milliseconds since system startup.
fl::u32 micros()
Universal microsecond timer - returns microseconds since system startup.
InputGamut g
Definition rgbw.h:124
corkscrew_args args
Definition old.h:149
#define FL_NO_EXCEPT
u32 t1_ns
T0H: High time for bit 0 (nanoseconds)
u32 t2_ns
T1H-T0H: Additional high time for bit 1 (nanoseconds)
constexpr u32 total_period_ns() const FL_NO_EXCEPT
Get total bit period (T1 + T2 + T3)
@ READY
Hardware idle; ready to accept new transmissions.
Definition driver.h:170
Compile-time timing extraction from ChipsetTiming structs.