6#include <driver/gpio.h>
9namespace remote_transmitter {
11static const char *
const TAG =
"remote_transmitter";
14static constexpr uint32_t RMT_SYMBOL_DURATION_MAX = 0x7FFF;
16#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 1)
17static size_t IRAM_ATTR HOT encoder_callback(
const void *data,
size_t size,
size_t written,
size_t free,
18 rmt_symbol_word_t *symbols,
bool *done,
void *arg) {
19 auto *store =
static_cast<RemoteTransmitterComponentStore *
>(arg);
20 const auto *encoded =
static_cast<const rmt_symbol_half_t *
>(data);
21 size_t length = size /
sizeof(rmt_symbol_half_t);
25 for (
size_t i = 0; i < free; i++) {
26 uint16_t sym_0 = encoded[store->index++].val;
27 if (store->index >=
length) {
30 if (store->times == 0) {
32 symbols[count++].val = sym_0;
36 uint16_t sym_1 = encoded[store->index++].val;
37 if (store->index >=
length) {
40 if (store->times == 0) {
42 symbols[count++].val = sym_0 | (sym_1 << 16);
46 symbols[count++].val = sym_0 | (sym_1 << 16);
59 ESP_LOGCONFIG(TAG,
"Remote Transmitter:");
61 " Clock resolution: %" PRIu32
" hz\n"
62 " RMT symbols: %" PRIu32,
64 LOG_PIN(
" Pin: ", this->
pin_);
71 ESP_LOGE(TAG,
"Configuring RMT driver failed: %s (%s)", esp_err_to_name(this->
error_code_),
77#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 1)
78 rmt_symbol_half_t symbol = {
82 rmt_transmit_config_t config;
83 memset(&config, 0,
sizeof(config));
84 config.flags.eot_level = value;
88 rmt_symbol_word_t symbol = {
94 rmt_transmit_config_t config;
95 memset(&config, 0,
sizeof(config));
96 config.flags.eot_level = value;
98 esp_err_t error = rmt_transmit(this->
channel_, this->
encoder_, &symbol,
sizeof(symbol), &config);
99 if (error != ESP_OK) {
100 ESP_LOGW(TAG,
"rmt_transmit failed: %s", esp_err_to_name(error));
103 error = rmt_tx_wait_all_done(this->
channel_, -1);
104 if (error != ESP_OK) {
105 ESP_LOGW(TAG,
"rmt_tx_wait_all_done failed: %s", esp_err_to_name(error));
115 rmt_tx_channel_config_t channel;
116 memset(&channel, 0,
sizeof(channel));
117 channel.clk_src = RMT_CLK_SRC_DEFAULT;
119 channel.gpio_num = gpio_num_t(this->
pin_->
get_pin());
121 channel.trans_queue_depth = 1;
122 channel.flags.io_loop_back = open_drain;
123 channel.flags.io_od_mode = open_drain;
124 channel.flags.invert_out = 0;
125 channel.flags.with_dma = this->
with_dma_;
126 channel.intr_priority = 0;
127 error = rmt_new_tx_channel(&channel, &this->
channel_);
128 if (error != ESP_OK) {
130 if (error == ESP_ERR_NOT_FOUND) {
141 gpio_pullup_dis(gpio_num_t(this->
pin_->
get_pin()));
144#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 1)
145 rmt_simple_encoder_config_t encoder;
146 memset(&encoder, 0,
sizeof(encoder));
147 encoder.callback = encoder_callback;
148 encoder.arg = &this->
store_;
149 encoder.min_chunk_size = 1;
150 error = rmt_new_simple_encoder(&encoder, &this->
encoder_);
151 if (error != ESP_OK) {
158 rmt_copy_encoder_config_t encoder;
159 memset(&encoder, 0,
sizeof(encoder));
160 error = rmt_new_copy_encoder(&encoder, &this->
encoder_);
161 if (error != ESP_OK) {
170 if (error != ESP_OK) {
181 error = rmt_apply_carrier(this->
channel_,
nullptr);
183 rmt_carrier_config_t carrier;
184 memset(&carrier, 0,
sizeof(carrier));
187 carrier.flags.polarity_active_low = this->
inverted_;
188 carrier.flags.always_on = 1;
189 error = rmt_apply_carrier(this->
channel_, &carrier);
191 if (error != ESP_OK) {
200 esp_err_t error = rmt_tx_wait_all_done(this->
channel_, -1);
201 if (error != ESP_OK) {
202 ESP_LOGW(TAG,
"rmt_tx_wait_all_done failed: %s", esp_err_to_name(error));
209#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 1)
211 uint64_t total_duration = 0;
232 total_duration += send_wait * (send_times - 1);
234 while (send_wait > 0) {
237 .duration =
static_cast<uint16_t
>(
duration),
238 .level =
static_cast<uint16_t
>(this->
eot_level_),
246 bool level = value >= 0;
250 total_duration += value * send_times;
253 int32_t
duration = std::min(value, int32_t(RMT_SYMBOL_DURATION_MAX));
255 .duration =
static_cast<uint16_t
>(
duration),
256 .level =
static_cast<uint16_t
>(level ^ this->
inverted_),
262 if ((this->
rmt_temp_.data() ==
nullptr) || this->rmt_temp_.size() <= offset) {
263 ESP_LOGE(TAG,
"Empty data");
269 rmt_transmit_config_t config;
270 memset(&config, 0,
sizeof(config));
275 this->rmt_temp_.size() *
sizeof(rmt_symbol_half_t), &config);
276 if (error != ESP_OK) {
277 ESP_LOGW(TAG,
"rmt_transmit failed: %s", esp_err_to_name(error));
302 rmt_symbol_word_t rmt_item;
305 bool level =
val >= 0;
311 int32_t item = std::min(
val, int32_t(RMT_SYMBOL_DURATION_MAX));
314 if (rmt_i % 2 == 0) {
316 rmt_item.duration0 =
static_cast<uint32_t>(item);
319 rmt_item.duration1 =
static_cast<uint32_t>(item);
326 if (rmt_i % 2 == 1) {
328 rmt_item.duration1 = 0;
332 if ((this->
rmt_temp_.data() ==
nullptr) || this->rmt_temp_.empty()) {
333 ESP_LOGE(TAG,
"Empty data");
337 for (uint32_t i = 0; i < send_times; i++) {
338 rmt_transmit_config_t config;
339 memset(&config, 0,
sizeof(config));
342 this->rmt_temp_.size() *
sizeof(rmt_symbol_word_t), &config);
343 if (error != ESP_OK) {
344 ESP_LOGW(TAG,
"rmt_transmit failed: %s", esp_err_to_name(error));
349 error = rmt_tx_wait_all_done(this->
channel_, -1);
350 if (error != ESP_OK) {
351 ESP_LOGW(TAG,
"rmt_tx_wait_all_done failed: %s", esp_err_to_name(error));
354 if (i + 1 < send_times)
virtual void mark_failed()
Mark this component as failed.
void status_set_warning(const char *message=nullptr)
bool cancel_timeout(const std::string &name)
Cancel a timeout function.
void status_clear_warning()
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
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(const Ts &...x)
Inform the parent automation that the event has triggered.
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
uint32_t current_carrier_frequency_
std::string error_string_
std::vector< rmt_symbol_half_t > rmt_temp_
Trigger * complete_trigger_
rmt_channel_handle_t channel_
rmt_encoder_handle_t encoder_
Trigger * transmit_trigger_
void digital_write(bool value)
uint8_t carrier_duty_percent_
void dump_config() override
RemoteTransmitterComponentStore store_
Providing packet encoding functions for exchanging data with a remote host.
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)