* @brief Decode single symbol to bit value * @param symbol RMT symbol to decode * @param timing Timing thresholds * @param ns_per_tick Cached nanoseconds per tick * @return 0 for bit 0, 1 for bit 1, -1 for invalid symbol * * Checks high time and low time against timing thresholds. * Returns -1 if timing doesn't match either bit pattern. */
| 190 | * Returns -1 if timing doesn't match either bit pattern. |
| 191 | */ |
| 192 | inline int decodeBit(RmtSymbol symbol, const ChipsetTiming4Phase &timing, |
| 193 | u32 ns_per_tick) { |
| 194 | // Cast RmtSymbol to rmt_symbol_word_t to access bitfields |
| 195 | const auto rmt_sym = fl::bit_cast<rmt_symbol_word_t>(symbol); |
| 196 | |
| 197 | // Convert tick durations to nanoseconds |
| 198 | u32 high_ns = ticksToNs(rmt_sym.duration0, ns_per_tick); |
| 199 | u32 low_ns = ticksToNs(rmt_sym.duration1, ns_per_tick); |
| 200 | |
| 201 | // WS2812B protocol: first duration is high, second is low |
| 202 | // Check if levels match expected pattern (high=1, low=0) |
| 203 | if (rmt_sym.level0 != 1 || rmt_sym.level1 != 0) { |
| 204 | // Unexpected level pattern - possibly inverted signal or noise |
| 205 | FL_WARN("decodeBit REJECTED: Invalid level pattern (level0=" << static_cast<int>(rmt_sym.level0) |
| 206 | << ", level1=" << static_cast<int>(rmt_sym.level1) << ") - expected level0=1, level1=0"); |
| 207 | return -1; |
| 208 | } |
| 209 | |
| 210 | // Decision logic: check if timing matches bit 0 pattern |
| 211 | bool t0h_match = |
| 212 | (high_ns >= timing.t0h_min_ns) && (high_ns <= timing.t0h_max_ns); |
| 213 | bool t0l_match = |
| 214 | (low_ns >= timing.t0l_min_ns) && (low_ns <= timing.t0l_max_ns); |
| 215 | |
| 216 | if (t0h_match && t0l_match) { |
| 217 | return 0; // Bit 0 |
| 218 | } |
| 219 | |
| 220 | // Check if timing matches bit 1 pattern |
| 221 | bool t1h_match = |
| 222 | (high_ns >= timing.t1h_min_ns) && (high_ns <= timing.t1h_max_ns); |
| 223 | bool t1l_match = |
| 224 | (low_ns >= timing.t1l_min_ns) && (low_ns <= timing.t1l_max_ns); |
| 225 | |
| 226 | if (t1h_match && t1l_match) { |
| 227 | return 1; // Bit 1 |
| 228 | } |
| 229 | |
| 230 | // Timing doesn't match either pattern - log detailed rejection reason |
| 231 | FL_WARN("decodeBit REJECTED: Timing mismatch (high=" << high_ns << "ns, low=" << low_ns << "ns)"); |
| 232 | FL_WARN(" Bit0 thresholds: t0h=[" << timing.t0h_min_ns << "-" << timing.t0h_max_ns |
| 233 | << "]ns (match=" << t0h_match << "), t0l=[" << timing.t0l_min_ns << "-" << timing.t0l_max_ns |
| 234 | << "]ns (match=" << t0l_match << ")"); |
| 235 | FL_WARN(" Bit1 thresholds: t1h=[" << timing.t1h_min_ns << "-" << timing.t1h_max_ns |
| 236 | << "]ns (match=" << t1h_match << "), t1l=[" << timing.t1l_min_ns << "-" << timing.t1l_max_ns |
| 237 | << "]ns (match=" << t1l_match << ")"); |
| 238 | |
| 239 | return -1; // Invalid |
| 240 | } |
| 241 | |
| 242 | /** |
| 243 | * @brief Decode RMT symbols to bytes (span-based implementation) |
no test coverage detected