ESPHome 2025.9.0-dev
Loading...
Searching...
No Matches
remote_transmitter_esp32.cpp
Go to the documentation of this file.
2#include "esphome/core/log.h"
4
5#ifdef USE_ESP32
6#include <driver/gpio.h>
7
8namespace esphome {
9namespace remote_transmitter {
10
11static const char *const TAG = "remote_transmitter";
12
14 this->inverted_ = this->pin_->is_inverted();
15 this->configure_rmt_();
16}
17
19 ESP_LOGCONFIG(TAG, "Remote Transmitter:");
20 ESP_LOGCONFIG(TAG,
21 " Clock resolution: %" PRIu32 " hz\n"
22 " RMT symbols: %" PRIu32,
23 this->clock_resolution_, this->rmt_symbols_);
24 LOG_PIN(" Pin: ", this->pin_);
25
26 if (this->current_carrier_frequency_ != 0 && this->carrier_duty_percent_ != 100) {
27 ESP_LOGCONFIG(TAG, " Carrier Duty: %u%%", this->carrier_duty_percent_);
28 }
29
30 if (this->is_failed()) {
31 ESP_LOGE(TAG, "Configuring RMT driver failed: %s (%s)", esp_err_to_name(this->error_code_),
32 this->error_string_.c_str());
33 }
34}
35
37 rmt_symbol_word_t symbol = {
38 .duration0 = 1,
39 .level0 = value,
40 .duration1 = 0,
41 .level1 = value,
42 };
43 rmt_transmit_config_t config;
44 memset(&config, 0, sizeof(config));
45 config.loop_count = 0;
46 config.flags.eot_level = value;
47 esp_err_t error = rmt_transmit(this->channel_, this->encoder_, &symbol, sizeof(symbol), &config);
48 if (error != ESP_OK) {
49 ESP_LOGW(TAG, "rmt_transmit failed: %s", esp_err_to_name(error));
50 this->status_set_warning();
51 }
52 error = rmt_tx_wait_all_done(this->channel_, -1);
53 if (error != ESP_OK) {
54 ESP_LOGW(TAG, "rmt_tx_wait_all_done failed: %s", esp_err_to_name(error));
55 this->status_set_warning();
56 }
57}
58
60 esp_err_t error;
61
62 if (!this->initialized_) {
63 bool open_drain = (this->pin_->get_flags() & gpio::FLAG_OPEN_DRAIN) != 0;
64 rmt_tx_channel_config_t channel;
65 memset(&channel, 0, sizeof(channel));
66 channel.clk_src = RMT_CLK_SRC_DEFAULT;
67 channel.resolution_hz = this->clock_resolution_;
68 channel.gpio_num = gpio_num_t(this->pin_->get_pin());
69 channel.mem_block_symbols = this->rmt_symbols_;
70 channel.trans_queue_depth = 1;
71 channel.flags.io_loop_back = open_drain;
72 channel.flags.io_od_mode = open_drain;
73 channel.flags.invert_out = 0;
74 channel.flags.with_dma = this->with_dma_;
75 channel.intr_priority = 0;
76 error = rmt_new_tx_channel(&channel, &this->channel_);
77 if (error != ESP_OK) {
78 this->error_code_ = error;
79 if (error == ESP_ERR_NOT_FOUND) {
80 this->error_string_ = "out of RMT symbol memory";
81 } else {
82 this->error_string_ = "in rmt_new_tx_channel";
83 }
84 this->mark_failed();
85 return;
86 }
87 if (this->pin_->get_flags() & gpio::FLAG_PULLUP) {
88 gpio_pullup_en(gpio_num_t(this->pin_->get_pin()));
89 } else {
90 gpio_pullup_dis(gpio_num_t(this->pin_->get_pin()));
91 }
92
93 rmt_copy_encoder_config_t encoder;
94 memset(&encoder, 0, sizeof(encoder));
95 error = rmt_new_copy_encoder(&encoder, &this->encoder_);
96 if (error != ESP_OK) {
97 this->error_code_ = error;
98 this->error_string_ = "in rmt_new_copy_encoder";
99 this->mark_failed();
100 return;
101 }
102
103 error = rmt_enable(this->channel_);
104 if (error != ESP_OK) {
105 this->error_code_ = error;
106 this->error_string_ = "in rmt_enable";
107 this->mark_failed();
108 return;
109 }
110 this->digital_write(open_drain || this->inverted_);
111 this->initialized_ = true;
112 }
113
114 if (this->current_carrier_frequency_ == 0 || this->carrier_duty_percent_ == 100) {
115 error = rmt_apply_carrier(this->channel_, nullptr);
116 } else {
117 rmt_carrier_config_t carrier;
118 memset(&carrier, 0, sizeof(carrier));
119 carrier.frequency_hz = this->current_carrier_frequency_;
120 carrier.duty_cycle = (float) this->carrier_duty_percent_ / 100.0f;
121 carrier.flags.polarity_active_low = this->inverted_;
122 carrier.flags.always_on = 1;
123 error = rmt_apply_carrier(this->channel_, &carrier);
124 }
125 if (error != ESP_OK) {
126 this->error_code_ = error;
127 this->error_string_ = "in rmt_apply_carrier";
128 this->mark_failed();
129 return;
130 }
131}
132
133void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t send_wait) {
134 if (this->is_failed())
135 return;
136
139 this->configure_rmt_();
140 }
141
142 this->rmt_temp_.clear();
143 this->rmt_temp_.reserve((this->temp_.get_data().size() + 1) / 2);
144 uint32_t rmt_i = 0;
145 rmt_symbol_word_t rmt_item;
146
147 for (int32_t val : this->temp_.get_data()) {
148 bool level = val >= 0;
149 if (!level)
150 val = -val;
151 val = this->from_microseconds_(static_cast<uint32_t>(val));
152
153 do {
154 int32_t item = std::min(val, int32_t(32767));
155 val -= item;
156
157 if (rmt_i % 2 == 0) {
158 rmt_item.level0 = static_cast<uint32_t>(level ^ this->inverted_);
159 rmt_item.duration0 = static_cast<uint32_t>(item);
160 } else {
161 rmt_item.level1 = static_cast<uint32_t>(level ^ this->inverted_);
162 rmt_item.duration1 = static_cast<uint32_t>(item);
163 this->rmt_temp_.push_back(rmt_item);
164 }
165 rmt_i++;
166 } while (val != 0);
167 }
168
169 if (rmt_i % 2 == 1) {
170 rmt_item.level1 = 0;
171 rmt_item.duration1 = 0;
172 this->rmt_temp_.push_back(rmt_item);
173 }
174
175 if ((this->rmt_temp_.data() == nullptr) || this->rmt_temp_.empty()) {
176 ESP_LOGE(TAG, "Empty data");
177 return;
178 }
179 this->transmit_trigger_->trigger();
180 for (uint32_t i = 0; i < send_times; i++) {
181 rmt_transmit_config_t config;
182 memset(&config, 0, sizeof(config));
183 config.loop_count = 0;
184 config.flags.eot_level = this->eot_level_;
185 esp_err_t error = rmt_transmit(this->channel_, this->encoder_, this->rmt_temp_.data(),
186 this->rmt_temp_.size() * sizeof(rmt_symbol_word_t), &config);
187 if (error != ESP_OK) {
188 ESP_LOGW(TAG, "rmt_transmit failed: %s", esp_err_to_name(error));
189 this->status_set_warning();
190 } else {
191 this->status_clear_warning();
192 }
193 error = rmt_tx_wait_all_done(this->channel_, -1);
194 if (error != ESP_OK) {
195 ESP_LOGW(TAG, "rmt_tx_wait_all_done failed: %s", esp_err_to_name(error));
196 this->status_set_warning();
197 }
198 if (i + 1 < send_times)
199 delayMicroseconds(send_wait);
200 }
201 this->complete_trigger_->trigger();
202}
203
204} // namespace remote_transmitter
205} // namespace esphome
206
207#endif
virtual void mark_failed()
Mark this component as failed.
bool is_failed() const
void status_set_warning(const char *message=nullptr)
void status_clear_warning()
virtual gpio::Flags get_flags() const =0
Retrieve GPIO pin flags.
virtual uint8_t get_pin() const =0
virtual bool is_inverted() const =0
void trigger(Ts... x)
Inform the parent automation that the event has triggered.
Definition automation.h:145
uint32_t from_microseconds_(uint32_t us)
const RawTimings & get_data() const
Definition remote_base.h:32
RemoteTransmitData temp_
Use same vector for all transmits, avoids many allocations.
void send_internal(uint32_t send_times, uint32_t send_wait) override
mopeka_std_values val[4]
@ FLAG_OPEN_DRAIN
Definition gpio.h:20
@ FLAG_PULLUP
Definition gpio.h:21
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition core.cpp:31