176 {
177 if (!rx_channel || clock_hz == 0) {
178 FL_WARN(
"[SPI DECODE] Invalid parameters");
179 return 0;
180 }
181
182 const uint32_t bit_period_ns =
static_cast<uint32_t>(1000000000ULL / clock_hz);
183 const uint32_t half_bit_ns = bit_period_ns / 2;
184 FL_WARN(
"[SPI DECODE] clock=" << clock_hz <<
" Hz, bit_period=" << bit_period_ns <<
" ns");
185
186
187 constexpr size_t MAX_EDGES = 4096;
191
192 if (edge_count == 0) {
193 FL_WARN(
"[SPI DECODE] No edges captured");
194 return 0;
195 }
196 FL_WARN(
"[SPI DECODE] Captured " << edge_count <<
" edges");
197
198
199
200
203
204 for (size_t i = 0; i < edge_count; i++) {
206 uint32_t num_bits = (duration + half_bit_ns) / bit_period_ns;
207 if (num_bits == 0) num_bits = 1;
208 uint8_t bit_val = edges[i].high ? 1 : 0;
209 for (uint32_t b = 0; b < num_bits; b++) {
211 }
212 }
213
214 FL_WARN(
"[SPI DECODE] Reconstructed " << bits.
size() <<
" bits");
215
216 if (bits.
size() < 32) {
217 FL_WARN(
"[SPI DECODE] Too few bits for APA102 frame");
218 return 0;
219 }
220
221
222 size_t total_bytes = bits.
size() / 8;
224 for (size_t i = 0; i < total_bytes; i++) {
226 for (int bit = 7; bit >= 0; bit--) {
227 size_t bit_idx = i * 8 + (7 - bit);
228 if (bit_idx < bits.
size() && bits[bit_idx]) {
229 byte_val |= (1 << bit);
230 }
231 }
232 raw_bytes[i] = byte_val;
233 }
234
235 FL_WARN(
"[SPI DECODE] Decoded " << total_bytes <<
" raw bytes");
236
237
238 {
240 dbg << "[SPI DECODE] First bytes:";
241 size_t show = total_bytes < 20 ? total_bytes : 20;
242 for (
size_t i = 0; i <
show; i++) {
243 dbg << " 0x";
244 uint8_t hi = raw_bytes[i] >> 4;
245 uint8_t lo = raw_bytes[i] & 0xF;
246 dbg << (char)(hi < 10 ? '0' + hi : 'A' + hi - 10);
247 dbg << (char)(lo < 10 ? '0' + lo : 'A' + lo - 10);
248 }
250 }
251
252
253
254
255
256 size_t data_start = 0;
257
258
259 if (total_bytes >= 4 && raw_bytes[0] == 0x00 && raw_bytes[1] == 0x00 &&
260 raw_bytes[2] == 0x00 && raw_bytes[3] == 0x00) {
261 data_start = 4;
262 FL_WARN(
"[SPI DECODE] Found start frame at offset 0");
263 } else {
264
265
266 FL_WARN(
"[SPI DECODE] No start frame (first edge = first LED data)");
267 }
268
269
270
271
272
273
274
275
276 size_t led_bytes_written = 0;
277 size_t pos = data_start;
278
279 while (
pos + 4 <= total_bytes) {
281
282
283 if ((header & 0xE0) != 0xE0) {
284 FL_WARN(
"[SPI DECODE] End of LED data at byte " <<
pos
285 << " (header=0x" << ((header >> 4) < 10 ? '0' + (header >> 4) : 'A' + (header >> 4) - 10)
286 << ((header & 0xF) < 10 ? '0' + (header & 0xF) : 'A' + (header & 0xF) - 10) << ")");
287 break;
288 }
289
293
294 if (led_bytes_written + 3 <= rx_buffer.
size()) {
295 rx_buffer[led_bytes_written + 0] = c0;
296 rx_buffer[led_bytes_written + 1] = c1;
297 rx_buffer[led_bytes_written + 2] = c2;
298 led_bytes_written += 3;
299 } else {
300 FL_WARN(
"[SPI DECODE] rx_buffer full at LED " << (led_bytes_written / 3));
301 break;
302 }
304 }
305
306 size_t num_leds = led_bytes_written / 3;
307 FL_WARN(
"[SPI DECODE] Extracted " << num_leds <<
" LEDs (" << led_bytes_written <<
" RGB bytes)");
308 return led_bytes_written;
309}
size_t getRawEdgeTimes(fl::span< EdgeTime > out, size_t offset=0) FL_NOEXCEPT
constexpr fl::size size() const FL_NOEXCEPT
string str() const FL_NOEXCEPT
fl::size size() const FL_NOEXCEPT
void reserve(fl::size n) FL_NOEXCEPT
void push_back(const T &value) FL_NOEXCEPT