3#include <driver/rmt_rx.h>
4#include <driver/rmt_tx.h>
5#include <freertos/FreeRTOS.h>
6#include <freertos/queue.h>
7#include <freertos/task.h>
11#include "TransceiverConfig.h"
12#include "pulse/RxDriver.h"
13#include "pulse/TxDriver.h"
14#include "pulse/TxDriverCommon.h"
15#include "pulse/TxProtocol.h"
16#include "pulse/codecs/Codec.h"
17#include "pulse/tools/RingBuffer.h"
18#include "pulse/tools/Vector.h"
39 Logger::info(
"begin TxProtocolESP32 with bitFrequencyHz=%d, pin=%d",
46 if (!createTxChannel(
tx_channel))
return false;
47 if (!applyCarrierConfig(
tx_channel))
return false;
48 if (!createCopyEncoder())
return false;
49 if (!enableTxChannel(
tx_channel))
return false;
52 _txTransmitConfig = {.loop_count = 0, .flags = {}};
56 void sendPreamble()
override {
57 if (is_frame_closed) {
62 is_frame_closed =
false;
63 for (
const auto&
edge : output) {
82 if (output.
size() % 2 != 0) {
84 if (output.
size() > 0) {
91 for (
size_t i = 0,
j = 0;
i + 1 < output.
size();
i += 2, ++
j) {
92 _itemsBuffer[
j].duration0 = output[
i].pulseUs;
93 _itemsBuffer[
j].level0 = output[
i].level ? 1 : 0;
94 _itemsBuffer[
j].duration1 = output[
i + 1].pulseUs;
95 _itemsBuffer[
j].level1 = output[
i + 1].level ? 1 : 0;
97 "TX edge %zu: level0=%d, duration0=%d us, level1=%d, duration1=%d "
99 j, output[
i].level, output[
i].pulseUs, output[
i + 1].level,
100 output[
i + 1].pulseUs);
113 _itemsBuffer.
clear();
118 if (is_frame_closed)
return;
120 _codec->
encode(sum, output);
133 if (output.
size() % 2 != 0) {
134 Logger::error(
"Odd edge count %zu in sendEnd, padding with 1us edge",
136 if (output.
size() > 0) {
142 for (
size_t i = 0,
j = 0;
i + 1 < output.
size();
i += 2, ++
j) {
143 _itemsBuffer[
j].duration0 = output[
i].pulseUs;
144 _itemsBuffer[
j].level0 = output[
i].level ? 1 : 0;
145 _itemsBuffer[
j].duration1 = output[
i + 1].pulseUs;
146 _itemsBuffer[
j].level1 = output[
i + 1].level ? 1 : 0;
149 "TX End frame edge %zu: level0=%d, duration0=%d us, level1=%d, "
151 j, output[
i].level, output[
i].pulseUs, output[
i + 1].level,
152 output[
i + 1].pulseUs);
164 is_frame_closed =
true;
167 bool isFrameClosed()
const override {
return is_frame_closed; }
170 Codec* _codec =
nullptr;
179 bool is_frame_closed =
true;
183 static constexpr uint32_t kRmtResolutionHz = 1000000;
210 Logger::error(
"RMT TX DMA unsupported, retrying without DMA");
222 if (_carrierHz == 0)
return true;
229 "Carrier frequency too high for RMT resolution, clamped to %u Hz",
245 bool createCopyEncoder() {
289 TxDriverCommon::init(protocol, codec, pin,
useChecksum);
290 protocol.setCarrierHz(_carrierHz);
294 TxProtocolESP32 protocol;
295 uint32_t _carrierHz = CARRIER_HZ;
297 void sendPreamble() { protocol.sendPreamble(); }
299 void sendData(
const uint8_t* data, uint8_t len) {
300 protocol.sendData(data, len);
303 void sendEnd() { protocol.sendEnd(_useChecksum); }
Abstract base class for IR protocol encoding and decoding.
virtual size_t encode(uint8_t byte, Vector< OutputEdge > &output)=0
Fill output vector with protocol-specific OutputSpec(s) for a byte.
virtual int getEndOfFrameDelayUs()=0
virtual bool getIdleLevel() const
Provides the initial ldle state (low or hith)
Preamble & getPreamble()
Get the preamble detector associated with this codec.
virtual bool begin(uint32_t bitFrequencyHz)
initialization method for codecs that require setup before use (e.g., loading PIO programs,...
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 info(const char *format,...)
Log an informational message with formatting.
virtual int getEdges(pulsewire::Vector< pulsewire::OutputEdge > &output) const =0
Returns the expected preamble edges for this protocol.
Provides common logic for transmitting signals using various framing modes.
ESP32-specific TxDriver implementation that uses TxProtocolESP32 for transmission.
TxDriverESP32(Codec &codec, uint8_t pin, uint32_t freq=CARRIER_HZ, bool useChecksum=false)
ESP32-specific TxProtocol implementation using RMT for precise timing and DMA support.
Abstract base class for defining transmission protocols.
Small, header-only vector replacement for non-STL environments.
void resize(size_t n)
Resize vector to n elements.
void clear()
Remove all elements.
void push_back(const T &value)
Add element to end of vector.
T * data()
Pointer to underlying data.
T & back()
Access last element.
size_t size() const
Number of elements in vector.
Specifies a single IR signal segment for protocol-agnostic transmission.