6#include <soc/soc_caps.h>
8#include <driver/gpio.h>
14static constexpr uint32_t COMPLETE_TIMEOUT_ID = 0;
17static constexpr uint32_t RMT_SYMBOL_DURATION_MAX = 0x7FFF;
19#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 1)
20static size_t IRAM_ATTR HOT encoder_callback(
const void *data,
size_t size,
size_t written,
size_t free,
21 rmt_symbol_word_t *symbols,
bool *done,
void *arg) {
22 auto *store =
static_cast<RemoteTransmitterComponentStore *
>(arg);
23 const auto *encoded =
static_cast<const rmt_symbol_half_t *
>(
data);
24 size_t length =
size /
sizeof(rmt_symbol_half_t);
28 for (
size_t i = 0; i < free; i++) {
29 uint16_t sym_0 = encoded[store->index++].val;
30 if (store->index >=
length) {
33 if (store->times == 0) {
35 symbols[
count++].val = sym_0;
39 uint16_t sym_1 = encoded[store->index++].val;
40 if (store->index >=
length) {
43 if (store->times == 0) {
45 symbols[
count++].val = sym_0 | (sym_1 << 16);
49 symbols[
count++].val = sym_0 | (sym_1 << 16);
57 ESP_LOGE(TAG,
"RMT driver failed: %s", esp_err_to_name(error));
67 ESP_LOGCONFIG(TAG,
"Remote Transmitter:");
69 " Clock resolution: %" PRIu32
" hz\n"
70 " RMT symbols: %" PRIu32,
72 LOG_PIN(
" Pin: ", this->
pin_);
80#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 1)
81 rmt_symbol_half_t symbol = {
85 rmt_transmit_config_t config;
86 memset(&config, 0,
sizeof(config));
87 config.flags.eot_level =
value;
91 rmt_symbol_word_t symbol = {
97 rmt_transmit_config_t config;
98 memset(&config, 0,
sizeof(config));
99 config.flags.eot_level =
value;
102 if (error != ESP_OK) {
106 error = rmt_tx_wait_all_done(this->
channel_, -1);
107 if (error != ESP_OK) {
108 ESP_LOGW(TAG,
"rmt_tx_wait_all_done failed: %s",
esp_err_to_name(error));
118 rmt_tx_channel_config_t channel;
119 memset(&channel, 0,
sizeof(channel));
120 channel.clk_src = RMT_CLK_SRC_DEFAULT;
122 channel.gpio_num = gpio_num_t(this->
pin_->
get_pin());
124 channel.trans_queue_depth = 1;
125 channel.flags.invert_out = 0;
126 channel.flags.with_dma = this->
with_dma_;
127 channel.intr_priority = 0;
128#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(6, 0, 0)
129 channel.flags.io_loop_back = open_drain;
130 channel.flags.io_od_mode = open_drain;
132 error = rmt_new_tx_channel(&channel, &this->
channel_);
133 if (error != ESP_OK) {
135 error == ESP_ERR_NOT_FOUND ? LOG_STR(
"out of RMT symbol memory") : LOG_STR(
"in rmt_new_tx_channel"));
138#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
140 gpio_num_t gpio = gpio_num_t(this->
pin_->
get_pin());
141 gpio_od_enable(gpio);
142 gpio_input_enable(gpio);
148 gpio_pullup_dis(gpio_num_t(this->
pin_->
get_pin()));
151#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 1)
152 rmt_simple_encoder_config_t encoder;
153 memset(&encoder, 0,
sizeof(encoder));
154 encoder.callback = encoder_callback;
155 encoder.arg = &this->
store_;
156 encoder.min_chunk_size = 1;
157 error = rmt_new_simple_encoder(&encoder, &this->
encoder_);
158 if (error != ESP_OK) {
159 this->
fail_(error, LOG_STR(
"in rmt_new_simple_encoder"));
163 rmt_copy_encoder_config_t encoder;
164 memset(&encoder, 0,
sizeof(encoder));
165 error = rmt_new_copy_encoder(&encoder, &this->
encoder_);
166 if (error != ESP_OK) {
167 this->
fail_(error, LOG_STR(
"in rmt_new_copy_encoder"));
173 if (error != ESP_OK) {
174 this->
fail_(error, LOG_STR(
"in rmt_enable"));
182 error = rmt_apply_carrier(this->
channel_,
nullptr);
184 rmt_carrier_config_t carrier;
185 memset(&carrier, 0,
sizeof(carrier));
188 carrier.flags.polarity_active_low = this->
inverted_;
189 carrier.flags.always_on = 1;
190 error = rmt_apply_carrier(this->
channel_, &carrier);
192 if (error != ESP_OK) {
193 this->
fail_(error, LOG_STR(
"in rmt_apply_carrier"));
199 esp_err_t error = rmt_tx_wait_all_done(this->
channel_, -1);
200 if (error != ESP_OK) {
201 ESP_LOGW(TAG,
"rmt_tx_wait_all_done failed: %s", esp_err_to_name(error));
208#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 1)
217 uint64_t total_duration = 0;
241 total_duration += send_wait * (send_times - 1);
243 while (send_wait > 0) {
246 .duration =
static_cast<uint16_t
>(
duration),
247 .level =
static_cast<uint16_t
>(this->
eot_level_),
255 bool level =
value >= 0;
259 total_duration +=
value * send_times;
262 int32_t
duration = std::min(value, int32_t(RMT_SYMBOL_DURATION_MAX));
264 .duration =
static_cast<uint16_t
>(
duration),
265 .level =
static_cast<uint16_t
>(level ^ this->
inverted_),
271 if ((this->
rmt_temp_.data() ==
nullptr) || this->rmt_temp_.size() <= offset) {
272 ESP_LOGE(TAG,
"Empty data");
280 rmt_transmit_config_t config;
281 memset(&config, 0,
sizeof(config));
286 this->rmt_temp_.size() *
sizeof(rmt_symbol_half_t), &config);
323 rmt_symbol_word_t rmt_item;
326 bool level =
val >= 0;
332 int32_t item = std::min(
val, int32_t(RMT_SYMBOL_DURATION_MAX));
335 if (rmt_i % 2 == 0) {
337 rmt_item.duration0 =
static_cast<uint32_t>(item);
340 rmt_item.duration1 =
static_cast<uint32_t>(item);
347 if (rmt_i % 2 == 1) {
349 rmt_item.duration1 = 0;
353 if ((this->
rmt_temp_.data() ==
nullptr) || this->rmt_temp_.empty()) {
354 ESP_LOGE(TAG,
"Empty data");
360 bool sent = send_times != 0;
361 for (
uint32_t i = 0; i < send_times; i++) {
362 rmt_transmit_config_t config;
363 memset(&config, 0,
sizeof(config));
366 this->rmt_temp_.size() *
sizeof(rmt_symbol_word_t), &config);
367 if (error != ESP_OK) {
372 error = rmt_tx_wait_all_done(this->
channel_, -1);
373 if (error != ESP_OK) {
374 ESP_LOGW(TAG,
"rmt_tx_wait_all_done failed: %s",
esp_err_to_name(error));
378 if (i + 1 < send_times)
void mark_failed()
Mark this component as failed.
void status_set_warning()
bool status_comm_result(bool ok)
Clears the warning when ok, else sets it with message (default "Communication failed"); returns ok.
bool cancel_timeout(const char *name)
Cancel a timeout function.
void set_timeout(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a const char* name.
void status_clear_warning()
void trigger(const Ts &...x) ESPHOME_ALWAYS_INLINE
Inform the parent automation that the event has triggered.
gpio::Flags get_flags() const override
uint32_t clock_resolution_
uint32_t from_microseconds_(uint32_t us)
uint32_t get_carrier_frequency() const
const RawTimings & get_data() const
RemoteTransmitData temp_
Use same vector for all transmits, avoids many allocations.
void send_internal(uint32_t send_times, uint32_t send_wait) override
void fail_(esp_err_t error, const LogString *reason)
void fire_complete_(bool sent=true)
void flush_pending_completion() override
uint32_t current_carrier_frequency_
std::vector< rmt_symbol_half_t > rmt_temp_
Trigger transmit_trigger_
rmt_channel_handle_t channel_
rmt_encoder_handle_t encoder_
void digital_write(bool value)
uint8_t carrier_duty_percent_
void dump_config() override
RemoteTransmitterComponentStore store_
const char * esp_err_to_name(esp_err_t err)
std::span< const uint8_t > data
ESPHOME_LOG_TAG(TAG, "remote_transmitter")
value[LAYOUT.day_index()]
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)