FastLED 3.9.15
Loading...
Searching...
No Matches
RX.ino

This example demonstrates FastLED's RX channel API on ESP32 by capturing edge transitions from manual pin toggles.

This example demonstrates FastLED's RX channel API on ESP32 by capturing edge transitions from manual pin toggles. This validates the RX channel can accurately capture timing data.

Hardware Setup:

Test Flow:

  1. Create and initialize RX channel
  2. Toggle pin in a defined pattern (HIGH/LOW with specific delays)
  3. Capture edge timing data using RX channel
  4. Analyze and display raw edge timings

Platform Support:

run with (in fastled repo)

// @filter: (platform is esp32)
// bash debug RX --expect "TX Pin: GPIO 0" --expect "RX Pin: GPIO 1" --expect "RX Backend: RMT" --fail-on ERROR
#include <FastLED.h>
#include "test.h"
#include "SketchHalt.h"
// ============================================================================
// Configuration
// ============================================================================
// ⚠️ DO NOT CHANGE THESE PIN ASSIGNMENTS - NO EXCEPTIONS! ⚠️
// These specific pins are required for hardware testing infrastructure.
// Changing PIN_TX or PIN_RX will break automated testing equipment.
// PHYSICALLY CONNECT GPIO 0 TO GPIO 19 WITH A WIRE FOR THIS TEST.
#define EDGE_BUFFER_SIZE 100
#define WAIT_TIMEOUT_MS 100
// Pin and RX type configuration (extern for test.cpp access)
const int PIN_TX = 0; // DO NOT CHANGE - REQUIRED FOR TEST INFRASTRUCTURE
const int PIN_RX = 1; // DO NOT CHANGE - REQUIRED FOR TEST INFRASTRUCTURE
// ============================================================================
// Pin Toggle Pattern
// ============================================================================
// Pattern: HIGH 1ms, LOW 1ms, HIGH 2ms, LOW 2ms, HIGH 3ms, LOW 100us
{true, 1000}, // HIGH for 1ms
{false, 1000}, // LOW for 1ms
{true, 2000}, // HIGH for 2ms
{false, 2000}, // LOW for 2ms
{true, 3000}, // HIGH for 3ms
{false, 100} // LOW for 100us (end)
}};
// ============================================================================
// Global State
// ============================================================================
}
// Sketch halt controller - handles safe halting without watchdog timer resets
// ============================================================================
// Arduino Setup & Loop
// ============================================================================
void setup() {
Serial.begin(115200);
while (!Serial && millis() < 3000);
const char* loop_back_mode = PIN_TX == PIN_RX ? "INTERNAL" : "JUMPER WIRE";
FL_WARN("\n=== FastLED RX Channel Test ===");
FL_WARN("Platform: ESP32");
FL_WARN("TX Pin: GPIO " << PIN_TX);
FL_WARN("RX Pin: GPIO " << PIN_RX);
FL_WARN("RX Backend: " << (RX_BACKEND == fl::RxBackend::RMT ? "RMT" : "ISR"));
FL_WARN("LOOP BACK MODE: " << loop_back_mode);
// Sanity check: Verify jumper wire connection when TX and RX are different pins
if (PIN_TX != PIN_RX) {
halt.error("Missing jumper wire between TX and RX pins");
return;
}
} else {
FL_WARN("TX and RX use same pin (" << PIN_TX << ") - no jumper wire needed");
}
FL_WARN("");
// Create RX channel for testing
// Use 1MHz resolution for better timing accuracy (1us per tick)
FL_WARN("Creating RX channel for testing...");
fl::RxChannelConfig test_channel_config(PIN_RX, RX_BACKEND);
auto rx_test = FastLED.addRx(test_channel_config);
if (!rx_test) {
halt.error("Failed to create RX channel for testing");
return;
}
// Initialize test RX channel with config
test_config.edge_capacity = 10;
test_config.hz = 1000000; // 1MHz resolution for better timing accuracy
test_config.signal_range_min_ns = 100;
test_config.signal_range_max_ns = 10000000;
test_config.start_low = true;
if (!rx_test->begin(test_config)) {
halt.error("Failed to initialize test RX channel");
return;
}
// Test RX channel functionality
if (!testRxChannelSanity(rx_test, PIN_TX)) {
halt.error("RX channel sanity check failed - RX not working");
return;
}
FL_WARN("");
// Create main RX channel for the loop
// Use 1MHz resolution to allow longer timeouts (40MHz = ~819us max, 1MHz = ~32ms max)
FL_WARN("Creating main RX channel...");
fl::RxChannelConfig main_channel_config(PIN_RX, RX_BACKEND);
rxChannelSingleton() = FastLED.addRx(main_channel_config);
halt.error("Failed to create main RX channel");
return;
}
FL_WARN("✓ Main RX channel created\n");
delay(1000);
}
void loop() {
// IMPORTANT: Must be first line - handles halt state and prevents watchdog resets
if (halt.check()) return;
FL_WARN("\n╔════════════════════════════════════════════════════════════════╗");
FL_WARN("║ RX DEVICE TEST");
FL_WARN("╚════════════════════════════════════════════════════════════════╝\n");
// Configure RX channel
config.edge_capacity = EDGE_BUFFER_SIZE;
config.hz = 1000000; // 1MHz resolution (allows up to ~32ms timeout)
config.signal_range_min_ns = 100; // 100ns glitch filter
config.signal_range_max_ns = 10000000; // 10ms idle timeout (1MHz RMT allows up to ~32ms)
config.start_low = true; // Pin starts LOW
// Execute toggles and capture data
FL_WARN("[TEST] Initializing RX channel and executing toggles...");
auto& rx_channel = rxChannelSingleton();
rx_channel->setConfig(config);
// Wait for capture completion
FL_WARN("[TEST] Waiting for capture (timeout: " << WAIT_TIMEOUT_MS << "ms)...");
auto wait_result = rx_channel->wait(WAIT_TIMEOUT_MS);
if (wait_result == fl::RxWaitResult::TIMEOUT) {
FL_ERROR("Timeout waiting for data");
} else if (wait_result == fl::RxWaitResult::BUFFER_OVERFLOW) {
FL_ERROR("Buffer overflow during capture");
} else {
FL_WARN("[TEST] ✓ Data captured successfully");
// Get edge timings
size_t edge_count = rx_channel->getRawEdgeTimes(edge_buffer);
// Validate edge timing against expected pattern
const uint32_t TOLERANCE_PERCENT = 15; // ±15% tolerance for timing jitter
validateEdgeTiming(edge_buffer, edge_count, TEST_PATTERN, TOLERANCE_PERCENT);
}
FL_WARN("\n╔════════════════════════════════════════════════════════════════╗");
FL_WARN("║ TEST COMPLETE - Waiting 5 seconds...");
FL_WARN("╚════════════════════════════════════════════════════════════════╝\n");
delay(5000);
}
void setup()
void loop()
#define PIN_TX
const fl::RxBackend RX_BACKEND
#define PIN_RX
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS CFastLED FastLED
Global LED strip management instance.
fl::shared_ptr< fl::RxChannel > & rxChannelSingleton()
Definition RX.ino:66
SketchHalt halt
Definition RX.ino:71
#define EDGE_BUFFER_SIZE
Definition RX.ino:40
#define WAIT_TIMEOUT_MS
Definition RX.ino:41
const fl::array< PinToggle, 6 > TEST_PATTERN
Definition RX.ino:53
Sketch halting mechanism that prevents watchdog timer resets.
Definition SketchHalt.h:25
A fixed-size array implementation similar to std::array.
Definition array.h:27
#define FL_WARN(X)
Definition log.h:276
#define FL_ERROR(X)
Definition log.h:219
fl::u32 uint32_t
Definition s16x16x4.h:219
fl::u32 millis()
Universal millisecond timer - returns milliseconds since system startup.
void delay(u32 ms, bool run_async=true) FL_NOEXCEPT
Public delay wrapper that keeps bare Arduino delay() preferred after using fl::delay; while still all...
Definition delay.h:98
RxBackend
Definition types.h:8
@ RMT
ESP32-only RMT capture backend.
Definition types.h:10
@ TIMEOUT
Operation timed out.
Definition rx.h:153
@ BUFFER_OVERFLOW
Buffer overflow.
Definition rx.h:154
#define Serial
Definition serial.h:304
void executeToggles(fl::RxChannel &rx, fl::span< const PinToggle > toggles, int pin_tx, uint32_t wait_ms)
Execute pin toggles and initialize RX channel for capture.
Definition test.cpp:36
bool testRxChannelSanity(fl::shared_ptr< fl::RxChannel > rx, int pin_tx)
Test RX channel functionality with low-frequency pattern.
Definition test.cpp:160
bool validateEdgeTiming(fl::span< const fl::EdgeTime > edges, size_t edge_count, fl::span< const PinToggle > expected_pattern, uint32_t tolerance_percent)
Validate captured edge timings against expected pattern.
Definition test.cpp:60
bool verifyJumperWire(int pin_tx, int pin_rx)
Verify jumper wire connection between TX and RX pins.
Definition test.cpp:7