ESPHome  2024.12.2
remote_receiver_esp32.cpp
Go to the documentation of this file.
1 #include "remote_receiver.h"
2 #include "esphome/core/log.h"
3 
4 #ifdef USE_ESP32
5 #include <driver/rmt.h>
6 
7 namespace esphome {
8 namespace remote_receiver {
9 
10 static const char *const TAG = "remote_receiver.esp32";
11 
13  ESP_LOGCONFIG(TAG, "Setting up Remote Receiver...");
14  this->pin_->setup();
15  rmt_config_t rmt{};
16  this->config_rmt(rmt);
17  rmt.gpio_num = gpio_num_t(this->pin_->get_pin());
18  rmt.rmt_mode = RMT_MODE_RX;
19  if (this->filter_us_ == 0) {
20  rmt.rx_config.filter_en = false;
21  } else {
22  rmt.rx_config.filter_en = true;
23  rmt.rx_config.filter_ticks_thresh = static_cast<uint8_t>(
24  std::min(this->from_microseconds_(this->filter_us_) * this->clock_divider_, (uint32_t) 255));
25  }
26  rmt.rx_config.idle_threshold =
27  static_cast<uint16_t>(std::min(this->from_microseconds_(this->idle_us_), (uint32_t) 65535));
28 
29  esp_err_t error = rmt_config(&rmt);
30  if (error != ESP_OK) {
31  this->error_code_ = error;
32  this->error_string_ = "in rmt_config";
33  this->mark_failed();
34  return;
35  }
36 
37  error = rmt_driver_install(this->channel_, this->buffer_size_, 0);
38  if (error != ESP_OK) {
39  this->error_code_ = error;
40  if (error == ESP_ERR_INVALID_STATE) {
41  this->error_string_ = str_sprintf("RMT channel %i is already in use by another component", this->channel_);
42  } else {
43  this->error_string_ = "in rmt_driver_install";
44  }
45  this->mark_failed();
46  return;
47  }
48  error = rmt_get_ringbuf_handle(this->channel_, &this->ringbuf_);
49  if (error != ESP_OK) {
50  this->error_code_ = error;
51  this->error_string_ = "in rmt_get_ringbuf_handle";
52  this->mark_failed();
53  return;
54  }
55  error = rmt_rx_start(this->channel_, true);
56  if (error != ESP_OK) {
57  this->error_code_ = error;
58  this->error_string_ = "in rmt_rx_start";
59  this->mark_failed();
60  return;
61  }
62 }
64  ESP_LOGCONFIG(TAG, "Remote Receiver:");
65  LOG_PIN(" Pin: ", this->pin_);
66  if (this->pin_->digital_read()) {
67  ESP_LOGW(TAG, "Remote Receiver Signal starts with a HIGH value. Usually this means you have to "
68  "invert the signal using 'inverted: True' in the pin schema!");
69  }
70  ESP_LOGCONFIG(TAG, " Channel: %d", this->channel_);
71  ESP_LOGCONFIG(TAG, " RMT memory blocks: %d", this->mem_block_num_);
72  ESP_LOGCONFIG(TAG, " Clock divider: %u", this->clock_divider_);
73  ESP_LOGCONFIG(TAG, " Tolerance: %" PRIu32 "%s", this->tolerance_,
74  (this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%");
75  ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %" PRIu32 " us", this->filter_us_);
76  ESP_LOGCONFIG(TAG, " Signal is done after %" PRIu32 " us of no changes", this->idle_us_);
77  if (this->is_failed()) {
78  ESP_LOGE(TAG, "Configuring RMT driver failed: %s (%s)", esp_err_to_name(this->error_code_),
79  this->error_string_.c_str());
80  }
81 }
82 
84  size_t len = 0;
85  auto *item = (rmt_item32_t *) xRingbufferReceive(this->ringbuf_, &len, 0);
86  if (item != nullptr) {
87  this->decode_rmt_(item, len);
88  vRingbufferReturnItem(this->ringbuf_, item);
89 
90  if (this->temp_.empty())
91  return;
92 
93  this->temp_.push_back(-this->idle_us_);
95  }
96 }
97 void RemoteReceiverComponent::decode_rmt_(rmt_item32_t *item, size_t len) {
98  bool prev_level = false;
99  uint32_t prev_length = 0;
100  this->temp_.clear();
101  int32_t multiplier = this->pin_->is_inverted() ? -1 : 1;
102  size_t item_count = len / sizeof(rmt_item32_t);
103  uint32_t filter_ticks = this->from_microseconds_(this->filter_us_);
104 
105  ESP_LOGVV(TAG, "START:");
106  for (size_t i = 0; i < item_count; i++) {
107  if (item[i].level0) {
108  ESP_LOGVV(TAG, "%zu A: ON %" PRIu32 "us (%u ticks)", i, this->to_microseconds_(item[i].duration0),
109  item[i].duration0);
110  } else {
111  ESP_LOGVV(TAG, "%zu A: OFF %" PRIu32 "us (%u ticks)", i, this->to_microseconds_(item[i].duration0),
112  item[i].duration0);
113  }
114  if (item[i].level1) {
115  ESP_LOGVV(TAG, "%zu B: ON %" PRIu32 "us (%u ticks)", i, this->to_microseconds_(item[i].duration1),
116  item[i].duration1);
117  } else {
118  ESP_LOGVV(TAG, "%zu B: OFF %" PRIu32 "us (%u ticks)", i, this->to_microseconds_(item[i].duration1),
119  item[i].duration1);
120  }
121  }
122  ESP_LOGVV(TAG, "\n");
123 
124  this->temp_.reserve(item_count * 2); // each RMT item has 2 pulses
125  for (size_t i = 0; i < item_count; i++) {
126  if (item[i].duration0 == 0u) {
127  // Do nothing
128  } else if ((bool(item[i].level0) == prev_level) || (item[i].duration0 < filter_ticks)) {
129  prev_length += item[i].duration0;
130  } else {
131  if (prev_length > 0) {
132  if (prev_level) {
133  this->temp_.push_back(this->to_microseconds_(prev_length) * multiplier);
134  } else {
135  this->temp_.push_back(-int32_t(this->to_microseconds_(prev_length)) * multiplier);
136  }
137  }
138  prev_level = bool(item[i].level0);
139  prev_length = item[i].duration0;
140  }
141 
142  if (item[i].duration1 == 0u) {
143  // Do nothing
144  } else if ((bool(item[i].level1) == prev_level) || (item[i].duration1 < filter_ticks)) {
145  prev_length += item[i].duration1;
146  } else {
147  if (prev_length > 0) {
148  if (prev_level) {
149  this->temp_.push_back(this->to_microseconds_(prev_length) * multiplier);
150  } else {
151  this->temp_.push_back(-int32_t(this->to_microseconds_(prev_length)) * multiplier);
152  }
153  }
154  prev_level = bool(item[i].level1);
155  prev_length = item[i].duration1;
156  }
157  }
158  if (prev_length > 0) {
159  if (prev_level) {
160  this->temp_.push_back(this->to_microseconds_(prev_length) * multiplier);
161  } else {
162  this->temp_.push_back(-int32_t(this->to_microseconds_(prev_length)) * multiplier);
163  }
164  }
165 }
166 
167 } // namespace remote_receiver
168 } // namespace esphome
169 
170 #endif
virtual void setup()=0
virtual uint8_t get_pin() const =0
std::string str_sprintf(const char *fmt,...)
Definition: helpers.cpp:320
virtual bool digital_read()=0
std::string size_t len
Definition: helpers.h:293
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
void decode_rmt_(rmt_item32_t *item, size_t len)
virtual bool is_inverted() const =0