2#include <driver/rmt_rx.h>
3#include <driver/rmt_tx.h>
4#include <freertos/FreeRTOS.h>
5#include <freertos/queue.h>
6#include <freertos/task.h>
10#include "TransceiverConfig.h"
11#include "pulse/RxDriver.h"
12#include "pulse/TxDriver.h"
13#include "pulse/codecs/Codec.h"
14#include "pulse/tools/Logger.h"
15#include "pulse/tools/RingBuffer.h"
16#include "pulse/tools/Vector.h"
20bool rmt_rx_done_callback(rmt_channel_handle_t channel,
21 const rmt_rx_done_event_data_t* edata,
23 BaseType_t high_task_wakeup = pdFALSE;
24 QueueHandle_t receive_queue = (QueueHandle_t)user_data;
26 xQueueSendFromISR(receive_queue, edata, &high_task_wakeup);
28 return high_task_wakeup == pdTRUE;
63 : _codec(codec), _rxPin(pin), _useChecksum(
useChecksum) {}
70 Logger::info(
"begin: RxDriverESP32 with bitFrequencyHz=%d, pin=%d",
76 Logger::info(
"Reinitializing RxDriverESP32 with new frequency: %d Hz",
84 size_t symbols = _frameSize * 8;
89 Logger::error(
"Frame size too large for RMT buffer: %d symbols (max 448)",
109 "RMT RX channel with DMA failed (%d), retrying without DMA",
128 .on_recv_done = rmt_rx_done_callback,
137 _rxBuffer.resize(_rxBufferSize);
154 _rxChannel =
nullptr;
160 if (_rxBuffer.available() == 0) {
168 if (_rxBuffer.available() == 0) {
172 return _rxBuffer.available();
176 size_t _rxBufferSize = 1024;
177 size_t _frameSize = 0;
185 bool _useChecksum =
false;
186 bool isActive =
false;
191 if (_rxChannel ==
nullptr) {
192 Logger::error(
"readFrame() called but RX channel is not initialized");
196 rmt_receive_config_t rx_cfg = {
197 .signal_range_min_ns = 10,
198 .signal_range_max_ns =
202 rmt_symbol_word_t* symbols_data = _symbols.
data();
203 size_t symbols_size = (_symbols.
size()) *
sizeof(rmt_symbol_word_t);
205 Logger::debug(
"cm_receive: waiting for frame (max %d symbols)",
208 rmt_receive(_rxChannel, symbols_data, symbols_size, &rx_cfg);
215 rmt_rx_done_event_data_t rx_data{};
216 esp_err_t esp_err = xQueueReceive(receive_queue, &rx_data,
218 if (esp_err != pdTRUE) {
219 Logger::error(
"Failed to receive RMT data from queue: %d", esp_err);
224 toEdges(rx_data.received_symbols, rx_data.num_symbols, _edgeBuffer);
227 rx_data.num_symbols, _edgeBuffer.available());
230 while (!_edgeBuffer.isEmpty()) {
232 _edgeBuffer.read(edge);
233 Logger::debug(
"RX edge: level=%d duration=%d us", edge.level,
236 if (_codec.
decodeEdge(edge.pulseUs, edge.level, data)) {
237 if (_rxBuffer.write(data) == 0) {
239 _rxBuffer.
size(), _rxBuffer.available());
243 return _rxBuffer.available();
Abstract base class for IR protocol encoding and decoding.
virtual int getEndOfFrameDelayUs()=0
virtual bool decodeEdge(uint32_t durationUs, bool level, uint8_t &result)=0
Edge-based decoding for protocol-agnostic RX drivers.
virtual size_t getEdgeCount() const =0
Get the number of protocol symbols (bits, pulses, etc.) per encoded byte.
virtual bool begin(uint32_t bitFrequencyHz)
initialization method for codecs that require setup before use (e.g., loading PIO programs,...
virtual void reset()
Reset the internal state of the codec.
static void debug(const char *format,...)
Log a debug message with formatting.
static void error(const char *format,...)
Log an error message with formatting.
static void warning(const char *format,...)
Log a warning message with formatting.
static void info(const char *format,...)
Log an informational message with formatting.
Manchester encoding/decoding utility class for IR communication.
int readArray(T *dest, size_t len)
Read up to len elements into dest, returns number of elements read.
High-performance ESP32 IR RX driver using the RMT peripheral and Manchester decoding.
void end() override
Stop the receiver.
void toEdges(rmt_symbol_word_t *symbols, size_t num_symbols, RingBuffer< OutputEdge > &edges)
Convert RMT symbols to edges and feed into codec.
void setFrameSize(uint16_t size) override
Set the expected frame size for dynamic data reception.
int available() override
Get the number of bytes available in the internal buffer.
bool begin(uint32_t bitFrequencyHz) override
Start the receiver.
size_t readBytes(uint8_t *buffer, size_t length) override
RxDriverESP32(ManchesterCodec &codec, uint8_t pin, bool useChecksum=false)
void setRxBufferSize(size_t size) override
Set the size of the internal RX buffer.
Abstract base class for IR receivers.
Small, header-only vector replacement for non-STL environments.
void resize(size_t n)
Resize vector to n elements.
T * data()
Pointer to underlying data.
size_t size() const
Number of elements in vector.
Specifies a single IR signal segment for protocol-agnostic transmission.