8#if FL_PLATFORM_HAS_LARGE_MEMORY
11#define DEBUG_PRINT(x) do {} while(0)
12#define DEBUG_PRINTLN(x) do {} while(0)
25#include "platforms/cpu_frequency.h"
69struct PerfProbeMemcpyState {
70 fl::vector<uint8_t> source;
71 fl::vector<uint8_t> destination;
74PerfProbeMemcpyState& perfProbeMemcpyState() {
78#if FL_COLOR_PIPELINE_SHARED
81 fl::ChannelDataPtr frames[3];
85 if (count < 3) frames[count++] = data;
91 return Capabilities(
true,
true);
121 remote.bind(
"perfProbeMemcpy", [](
const fl::json&
args) -> fl::json {
123 int iterations = 1000;
124 if (
args.is_array() &&
args.size() >= 1 &&
args[0].is_object()) {
125 const fl::json &cfg =
args[0];
126 if (cfg.
contains(
"bytes") && cfg[
"bytes"].is_int()) {
127 bytes =
static_cast<int>(cfg[
"bytes"].
as_int().value());
129 if (cfg.
contains(
"iterations") && cfg[
"iterations"].is_int()) {
130 iterations =
static_cast<int>(cfg[
"iterations"].
as_int().value());
134 response.set(
"bytes",
static_cast<int64_t
>(bytes));
135 response.set(
"iterations",
static_cast<int64_t
>(iterations));
136 if (bytes < 64 || bytes > 8192 || iterations < 1 || iterations > 100000) {
138 response.set(
"error",
"out_of_range");
144 PerfProbeMemcpyState&
state = perfProbeMemcpyState();
145 fl::vector<uint8_t>& src_vec =
state.source;
146 fl::vector<uint8_t>& dst_vec =
state.destination;
147 if (src_vec.
size() < 8192) {
153 for (
int i = 0; i < bytes; ++i) {
154 src_buf[i] =
static_cast<uint8_t>(i & 0xFF);
157 for (
int i = 0; i < iterations; ++i) {
161 const fl::u32 total_us = t1 - t0;
162 const double total_bytes =
static_cast<double>(bytes) * iterations;
163 const double mb_per_s = (total_us > 0)
164 ? (total_bytes / total_us) * (1e6 / (1024.0 * 1024.0))
167 response.set(
"total_us",
static_cast<int64_t
>(total_us));
176 remote.bind(
"perfProbeNop", [](
const fl::json&
args) -> fl::json {
177 int iterations = 100000;
178 if (
args.is_array() &&
args.size() >= 1 &&
args[0].is_object()) {
179 const fl::json &cfg =
args[0];
180 if (cfg.
contains(
"iterations") && cfg[
"iterations"].is_int()) {
181 iterations =
static_cast<int>(cfg[
"iterations"].
as_int().value());
185 response.set(
"iterations",
static_cast<int64_t
>(iterations));
186 if (iterations < 1000 || iterations > 10000000) {
188 response.set(
"error",
"out_of_range");
193 for (
int i = 0; i < iterations; ++i) {
194#if defined(__GNUC__) || defined(__clang__)
195 __asm__
volatile(
"nop");
202 const fl::u32 total_us = t1 - t0;
203 const double us_per_iter = (iterations > 0)
204 ? (
static_cast<double>(total_us) / iterations) : 0.0;
206 response.set(
"total_us",
static_cast<int64_t
>(total_us));
207 response.set(
"us_per_iter", us_per_iter);
225 remote.bind(
"perfProbeBitBangCost", [](
const fl::json&
args) -> fl::json {
226 int iterations = 20000;
229 if (
args.is_array() &&
args.size() >= 1 &&
args[0].is_object()) {
230 const fl::json &cfg =
args[0];
231 if (cfg.
contains(
"iterations") && cfg[
"iterations"].is_int()) {
232 iterations =
static_cast<int>(cfg[
"iterations"].
as_int().value());
234 if (cfg.
contains(
"ns") && cfg[
"ns"].is_int()) {
235 ns =
static_cast<int>(cfg[
"ns"].
as_int().value());
237 if (cfg.
contains(
"pin") && cfg[
"pin"].is_int()) {
238 pin =
static_cast<int>(cfg[
"pin"].
as_int().value());
242 response.set(
"iterations",
static_cast<int64_t
>(iterations));
243 response.set(
"ns",
static_cast<int64_t
>(ns));
244 response.set(
"pin",
static_cast<int64_t
>(pin));
245 if (iterations < 1000 || iterations > 1000000 || ns < 0) {
247 response.set(
"error",
"out_of_range");
254 constexpr fl::u64 kMaxProbeNs = 2000000000ULL;
255 const fl::u64 estimated_ns =
256 static_cast<fl::u64
>(iterations) *
static_cast<fl::u64
>(ns) * 6ULL;
257 if (estimated_ns > kMaxProbeNs) {
259 response.set(
"error",
"duration_budget_exceeded");
260 response.set(
"estimated_ns",
static_cast<int64_t
>(estimated_ns));
261 response.set(
"budget_ns",
static_cast<int64_t
>(kMaxProbeNs));
265 const fl::u32 requested_ns =
static_cast<fl::u32
>(ns);
266 const fl::u32 hz =
static_cast<fl::u32
>(FL_CPU_FREQUENCY());
274 for (
int i = 0; i < iterations; ++i) {
275 __asm__ __volatile__(
"" :::
"memory");
280 for (
int i = 0; i < iterations; ++i) {
283 const fl::u32 delay_us =
fl::micros() - delay_t0;
286 for (
int i = 0; i < iterations; ++i) {
289 const fl::u32 delay_hz_us =
fl::micros() - delay_hz_t0;
303 for (
int i = 0; i < iterations; ++i) {
306 const fl::u32 delay_hz400_us =
fl::micros() - delay_hz400_t0;
309 for (
int i = 0; i < iterations; ++i) {
312 const fl::u32 delay_ct_us =
fl::micros() - delay_ct_t0;
322 for (
int i = 0; i < iterations; ++i) {
326 const fl::u32 delay_cyc_us =
fl::micros() - delay_cyc_t0;
332 for (
int i = 0; i < 8; ++i) {
339 fl::DigitalMultiWrite8 writer;
342 for (
int i = 0; i < iterations; ++i) {
350 const double denom =
static_cast<double>(iterations);
351 const double nop_per =
static_cast<double>(nop_us) / denom;
352 const double delay_per =
static_cast<double>(delay_us) / denom;
353 const double delay_hz_per =
static_cast<double>(delay_hz_us) / denom;
354 const double wb_per =
static_cast<double>(wb_us) / denom;
357 response.set(
"cpu_hz",
static_cast<int64_t
>(hz));
358 response.set(
"nop_us_per_iter", nop_per);
359 response.set(
"delay_us_per_iter", delay_per);
360 response.set(
"delay_hz_us_per_iter", delay_hz_per);
361 response.set(
"write_byte_us_per_iter", wb_per);
363 response.set(
"delay_overhead_us", delay_per - nop_per);
364 response.set(
"delay_hz_overhead_us", delay_hz_per - nop_per);
365 response.set(
"write_byte_overhead_us", wb_per - nop_per);
366 const double delay_ct_per =
static_cast<double>(delay_ct_us) / denom;
367 const double delay_cyc_per =
static_cast<double>(delay_cyc_us) / denom;
368 response.set(
"delay_ct_us_per_iter", delay_ct_per);
369 response.set(
"delay_cycles_us_per_iter", delay_cyc_per);
370 response.set(
"delay_ct_overhead_us", delay_ct_per - nop_per);
371 response.set(
"delay_cycles_overhead_us", delay_cyc_per - nop_per);
374 const double delay_hz400_per =
375 static_cast<double>(delay_hz400_us) / iterations;
376 response.set(
"delay_hz400_us_per_iter", delay_hz400_per);
377 response.set(
"ns_conversion_us", delay_hz400_per - delay_ct_per);
378 response.set(
"clock_query_us", delay_per - delay_hz_per);
380 response.set(
"predicted_bit_overhead_us",
381 3.0 * ((delay_per - nop_per) + (wb_per - nop_per)));
389 remote.bind(
"perfProbeRepeat", [](
const fl::json&
args) -> fl::json {
394 fl::string stencil_name =
"FivePoint";
395 if (
args.is_array() &&
args.size() >= 1 &&
args[0].is_object()) {
396 const fl::json &cfg =
args[0];
397 if (cfg.
contains(
"W") && cfg[
"W"].is_int()) {
398 W =
static_cast<int>(cfg[
"W"].
as_int().value());
400 if (cfg.
contains(
"H") && cfg[
"H"].is_int()) {
401 H =
static_cast<int>(cfg[
"H"].
as_int().value());
403 if (cfg.
contains(
"iterations") && cfg[
"iterations"].is_int()) {
404 iterations =
static_cast<int>(cfg[
"iterations"].
as_int().value());
406 if (cfg.
contains(
"repeats") && cfg[
"repeats"].is_int()) {
407 repeats =
static_cast<int>(cfg[
"repeats"].
as_int().value());
409 if (cfg.
contains(
"stencil") && cfg[
"stencil"].is_string()) {
410 stencil_name = cfg[
"stencil"].
as_string().value();
414 response.set(
"W",
static_cast<int64_t
>(
W));
415 response.set(
"H",
static_cast<int64_t
>(
H));
416 response.set(
"iterations",
static_cast<int64_t
>(iterations));
417 response.set(
"repeats",
static_cast<int64_t
>(repeats));
419 iterations < 1 || iterations > 1000 ||
420 repeats < 2 || repeats > 64) {
422 response.set(
"error",
"out_of_range");
426 (stencil_name ==
"NinePointIsotropic")
433 const fl::wave_perf::WavePerfRepeatResult
bench =
435 static_cast<fl::u32
>(
W),
436 static_cast<fl::u32
>(
H),
437 static_cast<fl::u32
>(iterations),
438 static_cast<fl::u32
>(repeats),
442 response.set(
"mean_us_per_update",
bench.mean_us_per_update);
443 response.set(
"std_dev_us_per_update",
bench.std_dev_us_per_update);
462 remote.bind(
"wave2dPerf", [](
const fl::json&
args) -> fl::json {
467 int iterations = 100;
468 fl::string stencil_name =
"NinePointIsotropic";
469 bool loads_only =
false;
470 if (
args.is_array() &&
args.size() >= 1 &&
args[0].is_object()) {
471 const fl::json &cfg =
args[0];
472 if (cfg.
contains(
"W") && cfg[
"W"].is_int()) {
473 W =
static_cast<int>(cfg[
"W"].
as_int().value());
475 if (cfg.
contains(
"H") && cfg[
"H"].is_int()) {
476 H =
static_cast<int>(cfg[
"H"].
as_int().value());
478 if (cfg.
contains(
"iterations") && cfg[
"iterations"].is_int()) {
479 iterations =
static_cast<int>(cfg[
"iterations"].
as_int().value());
481 if (cfg.
contains(
"stencil") && cfg[
"stencil"].is_string()) {
482 stencil_name = cfg[
"stencil"].
as_string().value();
484 if (cfg.
contains(
"loads_only") && cfg[
"loads_only"].is_bool()) {
485 loads_only = cfg[
"loads_only"].
as_bool().value();
490 response.set(
"W",
static_cast<int64_t
>(
W));
491 response.set(
"H",
static_cast<int64_t
>(
H));
492 response.set(
"iterations",
static_cast<int64_t
>(iterations));
494 response.set(
"loads_only", loads_only);
498 if (
W < 4 ||
H < 4 || W > 1024 ||
H > 1024 || iterations < 1 || iterations > 100000) {
500 response.set(
"error",
"out_of_range");
505 (stencil_name ==
"FivePoint")
513 const fl::wave_perf::WavePerfResult
bench = loads_only
515 static_cast<fl::u32
>(
W),
static_cast<fl::u32
>(
H),
516 static_cast<fl::u32
>(iterations), stencil)
518 static_cast<fl::u32>(
W), static_cast<fl::u32>(
H),
519 static_cast<fl::u32>(iterations), stencil);
522 response.set(
"total_us",
static_cast<int64_t
>(
bench.total_us));
524 response.set(
"us_per_cell_per_update",
bench.us_per_cell_per_update);
525 response.set(
"fps_at_one_update_per_frame",
526 bench.fps_at_one_update_per_frame);
530#if FL_COLOR_PIPELINE_SHARED
535 remote.bind(
"mixedPowerShowPerf", [](
const fl::json&
args) -> fl::json {
538 int budget_mw = 2500;
539 if (
args.is_array() &&
args.size() &&
args[0].is_object()) {
540 const fl::json& cfg =
args[0];
541 if (cfg.
contains(
"pixels") && cfg[
"pixels"].is_int())
542 pixels =
static_cast<int>(cfg[
"pixels"].
as_int().value());
543 if (cfg.
contains(
"frames") && cfg[
"frames"].is_int())
544 frames =
static_cast<int>(cfg[
"frames"].
as_int().value());
545 if (cfg.
contains(
"budget_mw") && cfg[
"budget_mw"].is_int())
546 budget_mw =
static_cast<int>(cfg[
"budget_mw"].
as_int().value());
549 response.set(
"pixels_per_channel", pixels);
550 response.set(
"frames_per_sample", frames);
551 response.set(
"budget_mw", budget_mw);
552 if (pixels < 1 || pixels > 128 || frames < 1 || frames > 8 ||
553 budget_mw < 625 || budget_mw > 50000) {
555 response.set(
"error",
"out_of_range");
560 response.set(
"error",
"existing_channels");
564 fl::vector<CRGB>
leds(
static_cast<fl::size
>(pixels * 3));
565 if (
leds.size() !=
static_cast<fl::size
>(pixels * 3)) {
567 response.set(
"error",
"allocation_failed");
570 for (
int i = 0; i < pixels * 3; ++i)
571 leds[
static_cast<fl::size
>(i)] =
CRGB(170 + i * 7, 220 + i * 3, 190 + i * 11);
572 fl::ChannelOptions legacy_options;
573 fl::ChannelOptions rgbw_options;
574 fl::ChannelOptions rgbww_options;
580 rgbww_options.
mWhiteCfg = fl::Rgbww(2700, 6500,
589 response.set(
"error",
"profile_build_failed");
594 fl::span<CRGB>(
leds.data(), pixels),
RGB, legacy_options));
596 fl::span<CRGB>(
leds.data() + pixels, pixels),
RGB, rgbw_options));
598 fl::span<CRGB>(
leds.data() + pixels * 2, pixels),
RGB, rgbww_options));
599 if (!legacy || !
rgbw || !rgbww || !
rgbw->isColorManaged() ||
600 !rgbww->isColorManaged()) {
602 response.set(
"error",
"channel_create_failed");
623 const fl::FramePowerPlan on_plan =
624 fl::calculateFramePowerPlan(255,
static_cast<fl::u32
>(budget_mw));
625 const fl::FramePowerPlan off_plan =
626 fl::calculateFramePowerPlan(255, 0xffffffffu);
628 bool captured_all =
true;
629 auto show_sample = [&](
bool limited, fl::u32&
hash) -> fl::u32 {
635 for (
int f = 0; f < frames; ++f) {
640 captured_all = captured_all &&
capture->count == 3;
642 for (
int c = 0; c < 3; ++c) {
643 const auto& bytes =
capture->frames[c]->getData();
644 for (fl::size i = 0; i < bytes.size(); ++i)
645 hash = (hash ^ bytes[i]) * 16777619u;
651 fl::u32 on_hash = 2166136261u, off_hash = 2166136261u;
652 fl::u32 on_us[4], off_us[4];
654 const bool order[8] = {
true,
false,
false,
true,
655 false,
true,
true,
false};
656 int on_count = 0, off_count = 0;
657 for (
int i = 0; i < 8; ++i) {
658 if (order[i]) on_us[on_count++] = show_sample(
true, on_hash);
659 else off_us[off_count++] = show_sample(
false, off_hash);
663 response.set(
"error",
"capture_failed");
666 auto median4 = [](fl::u32* values) -> fl::u32 {
667 for (
int i = 1; i < 4; ++i)
668 for (
int j = i; j > 0 && values[j] < values[j - 1]; --j) {
669 const fl::u32 tmp = values[j]; values[j] = values[j - 1]; values[j - 1] = tmp;
671 return (values[1] + values[2]) / 2;
674 response.set(
"on_median_us",
static_cast<int64_t
>(median4(on_us)));
675 response.set(
"off_median_us",
static_cast<int64_t
>(median4(off_us)));
680 response.set(
"on_fnv1a",
static_cast<int64_t
>(on_hash));
681 response.set(
"off_fnv1a",
static_cast<int64_t
>(off_hash));
686#if FL_COLOR_PROFILE_RUNTIME
695 remote.bind(
"colorPipelinePerf", [](
const fl::json&
args) -> fl::json {
699 bool response_curve =
false;
700 if (
args.is_array() &&
args.size() >= 1 &&
args[0].is_object()) {
701 const fl::json& cfg =
args[0];
702 if (cfg.
contains(
"pixels") && cfg[
"pixels"].is_int()) {
703 pixels =
static_cast<int>(cfg[
"pixels"].
as_int().value());
705 if (cfg.
contains(
"frames") && cfg[
"frames"].is_int()) {
706 frames =
static_cast<int>(cfg[
"frames"].
as_int().value());
708 if (cfg.
contains(
"dither") && cfg[
"dither"].is_bool()) {
709 dither = cfg[
"dither"].
as_bool().value();
711 if (cfg.
contains(
"response_curve") && cfg[
"response_curve"].is_bool()) {
712 response_curve = cfg[
"response_curve"].
as_bool().value();
716 response.set(
"pixels",
static_cast<int64_t
>(pixels));
717 response.set(
"frames",
static_cast<int64_t
>(frames));
719 response.set(
"response_curve", response_curve);
722 if (pixels < 1 || pixels > 4096 || frames < 1 || frames > 10000 ||
723 static_cast<long>(pixels) * frames > 50000L) {
725 response.set(
"error",
"out_of_range");
728 fl::StreamingPipelineQ16 pipeline;
730 const fl::u16 linear_response[] = {0, 32768, 65535};
731 const fl::u16 nonlinear_response[] = {0, 16384, 65535};
732 if (response_curve) {
743 response.set(
"error",
"pipeline_build_failed");
746 fl::vector<CRGB> buffer(
static_cast<fl::size
>(pixels));
747 for (
int i = 0; i < pixels; ++i) {
748 buffer[
static_cast<fl::size
>(i)] =
CRGB(
750 static_cast<uint8_t>(255 - i * 3));
756 uint32_t managed_hash = 2166136261u;
758 uint32_t managed_second_hash = 2166136261u;
759 uint32_t legacy_second_hash = 2166136261u;
760 uint32_t baab_managed_hash = 2166136261u;
761 uint32_t baab_legacy_hash = 2166136261u;
765 for (
int f = 0; f < frames; ++f) {
766 PixelController<RGB>
controller(buffer.data(), pixels, adjustment, mode);
767 fl::ColorManagedPixelSource source(
controller,
GRB, pipeline);
768 while (source.has(1)) {
770 source.loadAndScaleRGB(&b0, &b1, &b2);
774 source.advanceData();
782 for (
int f = 0; f < frames; ++f) {
783 PixelController<GRB>
controller(buffer.data(), pixels, adjustment, mode);
797 const uint32_t abba_m1_us = measure_managed(managed_hash);
798 const uint32_t abba_l2_us = measure_legacy(legacy_hash);
799 const uint32_t abba_l3_us = measure_legacy(legacy_second_hash);
800 const uint32_t abba_m4_us = measure_managed(managed_second_hash);
801 const uint32_t baab_l1_us = measure_legacy(baab_legacy_hash);
802 const uint32_t baab_m2_us = measure_managed(baab_managed_hash);
803 const uint32_t baab_m3_us = measure_managed(baab_managed_hash);
804 const uint32_t baab_l4_us = measure_legacy(baab_legacy_hash);
805 const uint32_t managed_us = abba_m1_us + abba_m4_us + baab_m2_us + baab_m3_us;
806 const uint32_t legacy_us = abba_l2_us + abba_l3_us + baab_l1_us + baab_l4_us;
808 const double n = 4.0 *
static_cast<double>(pixels) *
809 static_cast<double>(frames);
810 const double managed_per =
static_cast<double>(managed_us) / n;
811 const double legacy_per =
static_cast<double>(legacy_us) / n;
813 response.set(
"managed_us",
static_cast<int64_t
>(managed_us));
814 response.set(
"legacy_us",
static_cast<int64_t
>(legacy_us));
815 response.set(
"abba_m1_us",
static_cast<int64_t
>(abba_m1_us));
816 response.set(
"abba_l2_us",
static_cast<int64_t
>(abba_l2_us));
817 response.set(
"abba_l3_us",
static_cast<int64_t
>(abba_l3_us));
818 response.set(
"abba_m4_us",
static_cast<int64_t
>(abba_m4_us));
819 response.set(
"baab_l1_us",
static_cast<int64_t
>(baab_l1_us));
820 response.set(
"baab_m2_us",
static_cast<int64_t
>(baab_m2_us));
821 response.set(
"baab_m3_us",
static_cast<int64_t
>(baab_m3_us));
822 response.set(
"baab_l4_us",
static_cast<int64_t
>(baab_l4_us));
823 response.set(
"managed_us_per_pixel", managed_per);
824 response.set(
"legacy_us_per_pixel", legacy_per);
825 response.set(
"managed_pixels_per_second",
826 managed_per > 0.0 ? 1.0e6 / managed_per : 0.0);
827 response.set(
"managed_fnv1a",
static_cast<int64_t
>(managed_hash));
828 response.set(
"legacy_fnv1a",
static_cast<int64_t
>(legacy_hash));
829 response.set(
"managed_second_fnv1a",
static_cast<int64_t
>(managed_second_hash));
830 response.set(
"legacy_second_fnv1a",
static_cast<int64_t
>(legacy_second_hash));
831 response.set(
"baab_managed_fnv1a",
static_cast<int64_t
>(baab_managed_hash));
832 response.set(
"baab_legacy_fnv1a",
static_cast<int64_t
>(baab_legacy_hash));
Full PARLIO encode bench for ESP32-P4 (post-byte-LUT, #2526 landed).
PARLIO ISR-streaming functional validation (#2548 deep-dive follow-up).
size_t capture(fl::shared_ptr< fl::RxChannel > rx_channel, fl::span< uint8_t > rx_buffer, size_t expected_data_bytes, int tx_pin, const fl::ChipsetTimingConfig &timing, const char *driver_name, fl::RunResult *diagnostics=nullptr)
Issue #2994 repro: compounded per-sequence timing drift vs 3.10.3.
Wave8 expansion micro-benchmark for #2526.
static void bench(const char *label)
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS CFastLED FastLED
Global LED strip management instance.
CLEDController * controller
fl::unique_ptr< fl::Remote > remote
fl::net::ble — BLE GATT transport layer for JSON-RPC
ESP32-P4 Parallel IO (PARLIO) LED channel.
Runtime chipset timing configuration for clockless LED drivers.
SPI encoder configuration for clocked LED chipsets.
void bindBenchmarkMethods(fl::Remote &remote)
fl::u8 getBrightness()
Get the current global brightness setting.
static void remove(fl::ChannelPtr channel)
Remove a channel from the LED controller list.
void setMaxPowerInMilliWatts(fl::u32 milliwatts)
Set the maximum power to be used, given in milliwatts.
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.
static void add(fl::ChannelPtr channel)
Add a Channel-based LED controller (from ChannelPtr)
int count()
Get how many controllers have been registered.
void clear(bool writeData=false)
Clear the leds, wiping the local array of data.
static ChannelPtr create(const ChannelConfig &config)
Create a new channel with optional mBus driver pinning.
static ChannelManager & instance() FL_NO_EXCEPT
Get the global singleton instance.
void addDriver(int priority, fl::shared_ptr< IChannelDriver > driver) FL_NO_EXCEPT
Add a driver with priority (higher priority = preferred)
bool removeDriver(fl::shared_ptr< IChannelDriver > driver) FL_NO_EXCEPT
Remove a driver from the manager.
void init(const Pins8 &pins)
Initialize from 8 pin numbers. -1 means "skip this bit position".
void writeByte(u8 byte) const
Write a single bitmask byte to the 8 pins.
virtual fl::string getName() const FL_NO_EXCEPT
Get the driver name for affinity binding.
virtual Capabilities getCapabilities() const FL_NO_EXCEPT=0
Get driver capabilities (clockless, SPI, or both)
virtual bool canHandle(const ChannelDataPtr &data) const FL_NO_EXCEPT=0
Check if this driver can handle the given channel data.
virtual void enqueue(ChannelDataPtr channelData) FL_NO_EXCEPT=0
Enqueue channel data for transmission.
virtual void show() FL_NO_EXCEPT=0
Trigger transmission of enqueued data.
virtual DriverState poll() FL_NO_EXCEPT=0
Query driver state and perform maintenance.
Minimal interface for LED channel transmission drivers.
JSON-RPC server with scheduling support.
static T & instance() FL_NO_EXCEPT
const char * c_str() const FL_NO_EXCEPT
fl::optional< fl::string > as_string() const FL_NO_EXCEPT
fl::optional< i64 > as_int() const FL_NO_EXCEPT
fl::optional< bool > as_bool() const FL_NO_EXCEPT
bool contains(size_t idx) const FL_NO_EXCEPT
static json object() FL_NO_EXCEPT
fl::size size() const FL_NO_EXCEPT
void resize(fl::size n) FL_NO_EXCEPT
Shared colorimetric primitives reusable by the RGBW and (future) RGB colorimetric paths (issue #3255)...
#define FL_BUILTIN_MEMCPY(dest, src, n)
Channel transmission data - lightweight DTO for driver transmission.
Delay utilities for FastLED Includes nanosecond-precision delays, cycle counting, and microsecond del...
#define BINARY_DITHER
Enable dithering using binary dithering (only option)
#define DISABLE_DITHER
Disable dithering.
fl::u8 EDitherMode
The dither setting, either DISABLE_DITHER or BINARY_DITHER.
Task executor — runs registered task runners and manages the run loop.
@ POWER_SETTINGS
Reset power management (setMaxPowerInMilliWatts)
Platform-abstracted heap memory query functions.
FastLED's Elegant JSON Library: fl::json
Unified manager for channel drivers with priority-based fallback.
static constexpr EmitterProfile WS2812B
WavePerfRepeatResult runWavePerfRepeat(u32 W, u32 H, u32 iterations, u32 repeats, LaplacianStencil stencil) FL_NO_EXCEPT
WavePerfResult runWavePerf(u32 W, u32 H, u32 iterations, LaplacianStencil stencil) FL_NO_EXCEPT
WavePerfResult runWavePerfLoadsOnly(u32 W, u32 H, u32 iterations, LaplacianStencil stencil) FL_NO_EXCEPT
constexpr ChipsetTimingConfig makeTimingConfig() FL_NO_EXCEPT
Convert compile-time CHIPSET type to runtime timing config.
void delaycycles< 50 >() FL_NO_EXCEPT
fl::u32 micros()
Universal microsecond timer - returns microseconds since system startup.
@ Low
Logic low (0V / GND)
@ WwWcStart
warm-W, cool-W, then RGB
shared_ptr< T > make_shared(Args &&... args) FL_NO_EXCEPT
scope_exit< decay_t< EF > > make_scope_exit(EF &&f)
Factory for C++11/14 (no CTAD).
void pinMode(int pin, PinMode mode)
Set pin mode (input, output, pull-up, pull-down)
void delaycycles< 10 >() FL_NO_EXCEPT
void digitalWrite(int pin, PinValue val)
Write digital value to pin.
bool buildStreamingPipelineQ16(const SourceProfile &source, const colorimetric_response::EmitterProfile &device, GamutPolicy policy, StreamingPipelineQ16 *out, const Chromaticity *target_white) FL_NO_EXCEPT
Bind a source declaration and a device profile into a pipeline.
@ Output
Digital output (push-pull)
FASTLED_FORCE_INLINE void delayNanoseconds() FL_NO_EXCEPT
Delay for a compile-time constant number of nanoseconds.
Promise-based fluent API for FastLED - standalone async primitives.
RAII scope guard — executes a callable on scope exit.
Umbrella header for SIMD subsystem.
static ColorAdjustment noAdjustment()
the per-channel scale values premixed with brightness.
bool setColorProfile(const EmitterProfile &profile) FL_NO_EXCEPT
fl::variant< fl::Empty, Rgbw, Rgbww > mWhiteCfg
White-channel selection (variant): Empty = plain RGB, Rgbw = 4-channel, Rgbww = 5-channel.
static constexpr SourceProfile linearSrgb() FL_NO_EXCEPT
const u16 * response_lut_r
const u16 * response_lut_g
const u16 * response_lut_b