FastLED 3.10.6
Loading...
Searching...
No Matches
capabilities.h
Go to the documentation of this file.
1
16
17#pragma once
18
19#include "fl/stl/bitset.h"
20#include "fl/stl/noexcept.h"
21#include "fl/stl/optional.h"
22#include "fl/stl/span.h"
23#include "fl/stl/stdint.h"
24#include "fl/stl/string_view.h"
25
26namespace fl {
27
28// =====================================================================
29// Protocol — what bus shape the channel uses.
30// =====================================================================
31
32enum class Protocol : fl::u8 {
34 Spi = 1,
35};
36
37
38// =====================================================================
39// FreqRange / NanosRange — inclusive [min, max] ranges with explicit
40// "unspecified" sentinels.
41//
42// All-zero is intentionally NOT the unspecified state — that would
43// silently match every legitimate value. Use any() / exactly() /
44// atLeast() / atMost() to construct.
45// =====================================================================
46
47struct FreqRange {
48 fl::u32 min_hz;
49 fl::u32 max_hz;
50
51 static constexpr FreqRange any() FL_NO_EXCEPT {
52 return {0u, 0xFFFFFFFFu};
53 }
54 static constexpr FreqRange exactly(fl::u32 hz) FL_NO_EXCEPT {
55 return {hz, hz};
56 }
57 static constexpr FreqRange atLeast(fl::u32 hz) FL_NO_EXCEPT {
58 return {hz, 0xFFFFFFFFu};
59 }
60 static constexpr FreqRange atMost(fl::u32 hz) FL_NO_EXCEPT {
61 return {0u, hz};
62 }
63
64 constexpr bool isUnspecified() const FL_NO_EXCEPT {
65 return min_hz == 0u && max_hz == 0xFFFFFFFFu;
66 }
67 constexpr bool contains(fl::u32 hz) const FL_NO_EXCEPT {
68 return hz >= min_hz && hz <= max_hz;
69 }
70};
71
72struct NanosRange {
73 fl::u32 min_ns;
74 fl::u32 max_ns;
75
76 static constexpr NanosRange any() FL_NO_EXCEPT {
77 return {0u, 0xFFFFFFFFu};
78 }
79 static constexpr NanosRange exactly(fl::u32 ns) FL_NO_EXCEPT {
80 return {ns, ns};
81 }
82 static constexpr NanosRange atLeast(fl::u32 ns) FL_NO_EXCEPT {
83 return {ns, 0xFFFFFFFFu};
84 }
85 static constexpr NanosRange atMost(fl::u32 ns) FL_NO_EXCEPT {
86 return {0u, ns};
87 }
88
89 constexpr bool isUnspecified() const FL_NO_EXCEPT {
90 return min_ns == 0u && max_ns == 0xFFFFFFFFu;
91 }
92 constexpr bool contains(fl::u32 ns) const FL_NO_EXCEPT {
93 return ns >= min_ns && ns <= max_ns;
94 }
95};
96
97
98// =====================================================================
99// PinSet — discriminated pin allowlist (bitset-backed).
100//
101// Four conceptual shapes, three encodings:
102// None — slot not applicable (e.g. clock on a Clockless group)
103// AnyOutputPin — any GPIO output (RMT5-style flexibility)
104// Allowlist size = 1 — fixed pin (LPUART per-instance TX, SPI IO_MUX)
105// Allowlist size N>1 — flex within an allowlist (FlexIO shifters)
106// =====================================================================
107
111static constexpr fl::u32 kPinSetCapacity = 128u;
112
114
115enum class PinSetKind : fl::u8 {
116 None = 0,
119};
120
121struct PinSet {
124
126 constexpr PinSet(PinSetKind k) FL_NO_EXCEPT : kind(k), pins() {}
127 constexpr PinSet(PinSetKind k, const PinBitset& b) FL_NO_EXCEPT : kind(k), pins(b) {}
128
130 static constexpr PinSet none() FL_NO_EXCEPT { return PinSet(PinSetKind::None); }
131
134
137 template <fl::size N>
138 static PinSet allowlist(const fl::i16 (&arr)[N]) FL_NO_EXCEPT {
140 for (fl::size i = 0; i < N; ++i) {
141 if (arr[i] >= 0 && static_cast<fl::u32>(arr[i]) < kPinSetCapacity) {
142 ps.pins.set(static_cast<fl::u32>(arr[i]));
143 }
144 }
145 return ps;
146 }
147
150 static PinSet fixed(fl::i16 pin) FL_NO_EXCEPT;
151
154 bool accepts(fl::i16 pin) const FL_NO_EXCEPT;
155
160 bool acceptsAll(const PinBitset& request) const FL_NO_EXCEPT;
161};
162
163
164// =====================================================================
165// ClocklessTimingCapability — driver's clock-tree model.
166//
167// Captures the physics: tick width = base_clock_hz / divider, phases
168// are held for an integer number of ticks. Compatibility with a
169// chipset's tolerance windows is determined by whether an integer N
170// exists such that N * tick_ns falls inside each window.
171//
172// DMA-fed drivers (PARLIO, I2S) also fit: their "tick" is the divided
173// peripheral clock, their "phase" is consecutive same-state bits in a
174// shaped data pattern.
175// =====================================================================
176
179 fl::u16 min_divider;
180 fl::u16 max_divider;
182
184 return {0u, 0u, 0u, 0u};
185 }
186 constexpr bool isUnspecified() const FL_NO_EXCEPT {
187 return base_clock_hz == 0u;
188 }
189};
190
191
192// =====================================================================
193// PinGroup — one independent hardware resource.
194//
195// Multiple groups per driver describe distinct slots (RMT channels,
196// FlexIO instances, LPUART instances). Each can independently match
197// some subset of requests.
198// =====================================================================
199
251
252
253// =====================================================================
254// DriverCapabilities — tiny constant-header descriptor.
255//
256// Note: there is intentionally NO supported_chipsets field. Chipset
257// support is a derived consequence of timing — if a chipset's tolerance
258// windows can be hit by the driver's clock tree, the chipset is
259// supported. New chipsets work automatically without driver updates.
260// =====================================================================
261
290
291
292// =====================================================================
293// ChipsetClocklessTiming — chipset's per-phase tolerance windows.
294//
295// Each window is the inclusive [min, max] in nanoseconds that the
296// driver's quantized output must land inside for the chipset to be
297// driven correctly. e.g. WS2812 T0H is nominally 350 ns ± 150 ns,
298// so t0h_window = {200, 500}.
299// =====================================================================
300
312
313
314// =====================================================================
315// ChannelRequest — passive input to canMatch.
316//
317// One type for both single-pin and ganged-multi-pin requests: data_pins
318// is a bitset, so a single-pin request just has one bit set. Drivers
319// that fan out to N independent groups vs gang into one group is the
320// resolver's concern (not the request's).
321//
322// Requests are NOT a first-class API surface — sketches don't construct
323// them. The Channel Manager builds them from addLeds<>() calls and
324// hands them to fl::canMatch against each driver's published capability
325// data.
326// =====================================================================
327
349
350
351// =====================================================================
352// HandleResult — outcome of canMatch / canMatchBulk.
353// =====================================================================
354
364
366constexpr bool isYes(HandleResult r) FL_NO_EXCEPT {
367 return r == HandleResult::Yes;
368}
369
370} // namespace fl
SPI Device - RAII wrapper for multi-lane SPI.
Definition spi.h:53
P ps[MAXP]
Definition Luminova.h:57
unsigned char u8
Definition stdint.h:131
constexpr bool isYes(HandleResult r) FL_NO_EXCEPT
Convenience: most call sites really want a bool.
fl::bitset_fixed< kPinSetCapacity > PinBitset
Optional< T > optional
Definition optional.h:16
HandleResult
@ NoPinPair
clock pin not in the matching group's allowlist
@ NoProtocol
driver doesn't support the requested Protocol
@ NoPin
data pin not in any matching group's allowlist
@ NoCapacity
group full / driver-total cap reached
@ NoTiming
chipset tolerance windows can't be hit
@ NoFrequency
requested freq outside driver/group range
InputGamut g FL_NO_EXCEPT
Definition rgbw.h:121
@ Clockless
Single data line + async timing (WS2812, SK6812, ...)
static constexpr fl::u32 kPinSetCapacity
Maximum pin number representable in a PinSet's bitset.
Base definition for an LED controller.
Definition crgb.hpp:179
ChipsetClocklessTiming timing
unspecified/any for Spi requests
ChannelRequest() FL_NO_EXCEPT
PinBitset data_pins
bit N set = pin N included
fl::i16 clock_pin
-1 for Clockless; single shared clock for Spi
fl::optional< fl::u32 > frequency_hz
mostly SPI override
static constexpr ChipsetClocklessTiming unspecified() FL_NO_EXCEPT
fl::u32 base_clock_hz
e.g. 80'000'000 for RMT5 (APB_CLK)
fl::u16 max_divider
largest divider -> coarsest tick width
constexpr bool isUnspecified() const FL_NO_EXCEPT
fl::u16 max_phase_ticks
counter-width cap per phase
static constexpr ClocklessTimingCapability unspecified() FL_NO_EXCEPT
fl::u16 min_divider
smallest divider -> finest tick width
fl::u8 priority
higher = preferred
fl::u8 max_total_channels
aggregate cap; 0 = unbounded
FreqRange clockless_frequency
Aggregate frequency ranges.
fl::string_view name
diagnostics, e.g. "RMT5"
DriverCapabilities() FL_NO_EXCEPT
Definition in capabilities.cpp.hpp.
struct fl::DriverCapabilities::Flags flags
ClocklessTimingCapability clockless_timing
Clock-tree model — the ONLY chipset-support gate.
fl::u8 requires_dma_memory
DMA can't reach PSRAM.
fl::u8 mixed_protocols_ok
CL+SPI on same instance OK.
fl::u8 synchronized_start
all groups latch on same clock edge
Peripheral-flavor flags. Default zero = neutral / no claim.
static constexpr FreqRange atMost(fl::u32 hz) FL_NO_EXCEPT
static constexpr FreqRange exactly(fl::u32 hz) FL_NO_EXCEPT
static constexpr FreqRange any() FL_NO_EXCEPT
static constexpr FreqRange atLeast(fl::u32 hz) FL_NO_EXCEPT
constexpr bool isUnspecified() const FL_NO_EXCEPT
constexpr bool contains(fl::u32 hz) const FL_NO_EXCEPT
constexpr bool isUnspecified() const FL_NO_EXCEPT
static constexpr NanosRange exactly(fl::u32 ns) FL_NO_EXCEPT
static constexpr NanosRange any() FL_NO_EXCEPT
static constexpr NanosRange atLeast(fl::u32 ns) FL_NO_EXCEPT
constexpr bool contains(fl::u32 ns) const FL_NO_EXCEPT
static constexpr NanosRange atMost(fl::u32 ns) FL_NO_EXCEPT
bool pins_must_be_contiguous
True iff a bulk request's data_pins bitset must be contiguous (set bits form an unbroken run).
fl::u16 instance_id
opaque ID; used in diagnostics
fl::u8 max_concurrent
how many data_pins can be active concurrently
fl::u8 shared_clock_domain_id
Groups sharing a non-zero shared_clock_domain_id must all run at the same frequency (PARLIO timer,...
Protocol protocol
group is Clockless OR Spi
constexpr PinGroup() FL_NO_EXCEPT
FreqRange frequency
Frequency range for this group's clock.
fl::u8 shared_budget_id
Groups sharing a non-zero shared_budget_id draw concurrent slots from one pool.
PinSet data_pins
data-line allowlist (or AnyOutput)
PinSet clock_pins
clock-line allowlist; None for Clockless
static constexpr PinSet none() FL_NO_EXCEPT
Factory: slot is not applicable.
constexpr PinSet(PinSetKind k, const PinBitset &b) FL_NO_EXCEPT
constexpr PinSet() FL_NO_EXCEPT
bool accepts(fl::i16 pin) const FL_NO_EXCEPT
True iff this set accepts the given single pin.
bool acceptsAll(const PinBitset &request) const FL_NO_EXCEPT
True iff every set bit in request is also accepted here.
static PinSet allowlist(const fl::i16(&arr)[N]) FL_NO_EXCEPT
Factory: allowlist of pins, constructed from a static array.
static PinSet fixed(fl::i16 pin) FL_NO_EXCEPT
Factory: allowlist with a single pin (the "fixed pin" idiom).
PinSetKind kind
constexpr PinSet(PinSetKind k) FL_NO_EXCEPT
PinBitset pins
only meaningful when kind == Allowlist
static constexpr PinSet anyOutput() FL_NO_EXCEPT
Factory: any GPIO output pin in [0, kPinSetCapacity).