FastLED 3.10.8
Loading...
Searching...
No Matches
ws2812_stream_decoder.h
Go to the documentation of this file.
1
30
31#pragma once
32
33#include "fl/channels/rx.h"
34#include "fl/stl/noexcept.h"
35#include "fl/stl/result.h"
36#include "fl/stl/span.h"
37#include "fl/stl/stdint.h"
38
39namespace fl {
40namespace channels {
41namespace rx {
42
44constexpr u32 kFlexPwmGapNs = 5000;
45
48 return (timing.t0h_max_ns + timing.t1h_min_ns) / 2u;
49}
50
53inline bool flexPwmIsMidpointSample(u32 high_ns) FL_NO_EXCEPT {
54 return high_ns >= 100u && high_ns <= 1500u;
55}
56
60 u32 high_min, u32 high_max,
61 u32 samples) FL_NO_EXCEPT {
62 if (samples >= 16 && high_max > high_min + 200u) {
63 return (high_min + high_max) / 2u;
64 }
65 return flexPwmStaticMidpointNs(timing);
66}
67
70inline int flexPwmBitFromMidpoint(u32 high_ns, u32 midpoint_ns) FL_NO_EXCEPT {
71 return (high_ns >= midpoint_ns) ? 1 : 0;
72}
73
76inline int flexPwmBitFromHigh(u32 high_ns, const ChipsetTiming4Phase& timing) FL_NO_EXCEPT {
77 if (high_ns >= timing.t0h_min_ns && high_ns <= timing.t0h_max_ns) {
78 return 0;
79 }
80 if (high_ns >= timing.t1h_min_ns && high_ns <= timing.t1h_max_ns) {
81 return 1;
82 }
83 return -1;
84}
85
89inline u32 flexPwmTickDeltaNs(u16 t0, u16 t1, u32 ns_per_tick_q16) FL_NO_EXCEPT {
90 const u16 delta = static_cast<u16>(t1 - t0);
91 return static_cast<u32>((static_cast<u64>(delta) * ns_per_tick_q16) >> 16);
92}
93
95inline u32 flexPwmNsPerTickQ16(u32 counter_hz) FL_NO_EXCEPT {
96 return static_cast<u32>((static_cast<u64>(1000000000ULL) << 16) / counter_hz);
97}
98
105 fl::span<u8> bytes_out) FL_NO_EXCEPT;
106
111 public:
113 static constexpr u32 kCalibrationBits = 64;
116 static constexpr u32 kExceptionBandNs = 150;
117 static constexpr u32 kMaxExceptions = 32;
118
119 struct Stats {
120 u32 pairs = 0;
121 u32 bits = 0;
122 u32 errors = 0;
123 u32 fullBytes = 0;
126 u32 exceptions = 0;
128 bool inexact = false;
129 bool gapBitShift = false;
130 bool overrun = false;
131 };
132
137 void reset(const ChipsetTiming4Phase& stream_timing, u32 ns_per_tick_q16,
139
142
145 void markOverrun() FL_NO_EXCEPT { mStats.overrun = true; }
146
150 void flush() FL_NO_EXCEPT;
151
154 void finish(const ChipsetTiming4Phase& timing) FL_NO_EXCEPT;
155
159 fl::result<u32, DecodeError> copyTo(fl::span<u8> out) const FL_NO_EXCEPT;
160
161 const Stats& stats() const FL_NO_EXCEPT { return mStats; }
162 size_t diagEdgeCount() const FL_NO_EXCEPT { return mDiagCount; }
163
164 private:
165 enum class Mode : u8 { Midpoint, FromHigh };
166 struct Pending {
169 };
170 struct Exception {
171 u32 bit_pos; // position of the bit (or where it was dropped)
174 bool stream_valid; // FromHigh: classified (not dropped) while streaming
175 };
176
177 void emitPair(u16 rise, u16 fall, bool has_low, u32 low_ns) FL_NO_EXCEPT;
178 void emitEdge(bool high, u32 ns) FL_NO_EXCEPT;
179 void pushBit(u32 high_ns, Mode mode) FL_NO_EXCEPT;
180 void classify(u32 high_ns, Mode mode) FL_NO_EXCEPT;
181 void calibrate() FL_NO_EXCEPT;
182 void appendBit(int bit) FL_NO_EXCEPT;
183
184 void record(u32 high_ns, Mode mode, bool stream_valid) FL_NO_EXCEPT;
185
190 size_t mDiagCount = 0;
191
192 bool mHavePrev = false;
193 bool mStarted = false;
194 u16 mPrevRise = 0;
195 u16 mPrevFall = 0;
196
197 u32 mEdgeIndex = 0; // index in the equivalent batch edge list
198 u32 mHighMin = 0xFFFFFFFFu;
199 u32 mHighMax = 0;
201
202 bool mCalibrated = false;
203 u32 mMidpoint = 0;
206
209
211 u32 mBitCount = 0;
212 u32 mBitPos = 0; // bits appended so far
213 bool mFlushed = false;
214 bool mPartialWritten = false;
215
217};
218
219} // namespace rx
220} // namespace channels
221} // namespace fl
void finish(const ChipsetTiming4Phase &timing) FL_NO_EXCEPT
Re-classify the recorded bits with the decode-time timing and write the partial final byte.
void classify(u32 high_ns, Mode mode) FL_NO_EXCEPT
void flush() FL_NO_EXCEPT
End of capture: decode the final pair (HIGH only; its LOW is the reset) and fix the calibration.
void markOverrun() FL_NO_EXCEPT
Captures were lost (ring overwritten before decode).
void pushBit(u32 high_ns, Mode mode) FL_NO_EXCEPT
void emitEdge(bool high, u32 ns) FL_NO_EXCEPT
void push(fl::span< const u16 > captures) FL_NO_EXCEPT
Consume capture pairs laid out as [rise0, fall0, rise1, fall1...].
void emitPair(u16 rise, u16 fall, bool has_low, u32 low_ns) FL_NO_EXCEPT
void record(u32 high_ns, Mode mode, bool stream_valid) FL_NO_EXCEPT
const Stats & stats() const FL_NO_EXCEPT
static constexpr u32 kExceptionBandNs
Bits within this distance of the calibrated threshold are recorded for re-classification against the ...
static constexpr u32 kCalibrationBits
Bits classified before the threshold is fixed. 64 bits = 8 bytes.
void reset(const ChipsetTiming4Phase &stream_timing, u32 ns_per_tick_q16, fl::span< u8 > out, fl::span< EdgeTime > diag_edges) FL_NO_EXCEPT
Start a frame.
fl::result< u32, DecodeError > copyTo(fl::span< u8 > out) const FL_NO_EXCEPT
Copy the decoded frame into out with the batch decoder's result rules (overflow, >10% error rate,...
Streaming decoder over (rise, fall) capture pairs.
bool overrun
the owner reported lost captures
bool gapBitShift
a gap bit kept/dropped differs from decode timing
u32 exceptionsDropped
near-threshold bits that did not fit
u32 frameMidpointNs
whole-frame midpoint, set by finish()
u32 fullBytes
complete bytes decoded (may exceed capacity)
bool inexact
finish() could not guarantee batch equality
u32 errors
out-of-window bits (batch error_count)
u32 bits
bits classified (batch total_bits)
fl::result< u32, DecodeError > decodeFlexPwmEdges(const ChipsetTiming4Phase &timing, fl::span< const EdgeTime > edges, fl::span< u8 > bytes_out) FL_NO_EXCEPT
Batch decoder over an edge list (HIGH, LOW, HIGH, ... with a LOW left out after a gap).
constexpr u32 kFlexPwmGapNs
A LOW longer than this ends the bit without a LOW edge (gap or reset).
bool flexPwmIsMidpointSample(u32 high_ns) FL_NO_EXCEPT
Whether a HIGH width contributes to the adaptive-midpoint pre-pass (idle and glitch widths are exclud...
u32 flexPwmNsPerTickQ16(u32 counter_hz) FL_NO_EXCEPT
Q16.16 ns-per-tick for a counter clock.
int flexPwmBitFromHigh(u32 high_ns, const ChipsetTiming4Phase &timing) FL_NO_EXCEPT
Bit from a HIGH whose LOW was a gap/reset or was not captured: range check against the T0H / T1H wind...
u32 flexPwmStaticMidpointNs(const ChipsetTiming4Phase &timing) FL_NO_EXCEPT
Static threshold between a 0 and a 1 HIGH: midpoint of T0H max / T1H min.
u32 flexPwmTickDeltaNs(u16 t0, u16 t1, u32 ns_per_tick_q16) FL_NO_EXCEPT
Convert a 16-bit capture-counter delta to ns.
int flexPwmBitFromMidpoint(u32 high_ns, u32 midpoint_ns) FL_NO_EXCEPT
Bit from a HIGH followed by a normal LOW: HIGH-only midpoint split.
u32 flexPwmAdaptiveMidpointNs(const ChipsetTiming4Phase &timing, u32 high_min, u32 high_max, u32 samples) FL_NO_EXCEPT
#3416 adaptive midpoint: (min + max) / 2 of the observed HIGH widths once there are enough samples sp...
unsigned char u8
Definition stdint.h:131
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
DecodeError
Error codes for RX decoder operations.
Definition rx.h:68
Base definition for an LED controller.
Definition crgb.hpp:179
4-phase RX timing thresholds for chipset detection
Definition rx.h:88
result<T, E> type alias for fl::expected (Rust-style naming)
Common RX interfaces and shared types.
fl::u64 u64
Definition stdint.h:220