Decode SPI bit stream from raw RMT edges into LED RGB bytes The SPI data pin carries APA102 encoded data clocked by PCLK. RMT RX captures edges on the data pin. Each edge duration / bit_period_ns gives the number of consecutive same-value bits. Returns number of LED RGB bytes written to rx_buffer, or 0 on error.
| 172 | // gives the number of consecutive same-value bits. |
| 173 | // Returns number of LED RGB bytes written to rx_buffer, or 0 on error. |
| 174 | static size_t decodeSpiEdges(fl::shared_ptr<fl::RxChannel> rx_channel, |
| 175 | fl::span<uint8_t> rx_buffer, |
| 176 | uint32_t clock_hz) { |
| 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 | // Read raw edges (up to 4096 to handle large strips) |
| 187 | constexpr size_t MAX_EDGES = 4096; |
| 188 | fl::vector<fl::EdgeTime> edges(MAX_EDGES); |
| 189 | fl::span<fl::EdgeTime> edge_span(edges.data(), edges.size()); |
| 190 | size_t edge_count = rx_channel->getRawEdgeTimes(edge_span, 0); |
| 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 | // Reconstruct bit stream from edges |
| 199 | // Each edge has a level (high/low) and duration in ns. |
| 200 | // Number of bits = round(duration_ns / bit_period_ns) |
| 201 | fl::vector<uint8_t> bits; |
| 202 | bits.reserve(edge_count * 4); // Rough estimate |
| 203 | |
| 204 | for (size_t i = 0; i < edge_count; i++) { |
| 205 | uint32_t duration = edges[i].ns; |
| 206 | uint32_t num_bits = (duration + half_bit_ns) / bit_period_ns; |
| 207 | if (num_bits == 0) num_bits = 1; // At least 1 bit per edge |
| 208 | uint8_t bit_val = edges[i].high ? 1 : 0; |
| 209 | for (uint32_t b = 0; b < num_bits; b++) { |
| 210 | bits.push_back(bit_val); |
| 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 | // Convert bits to bytes (MSB first) |
| 222 | size_t total_bytes = bits.size() / 8; |
| 223 | fl::vector<uint8_t> raw_bytes(total_bytes); |
| 224 | for (size_t i = 0; i < total_bytes; i++) { |
| 225 | uint8_t byte_val = 0; |
| 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 | } |