ESPHome  2025.2.0
remote_base.h
Go to the documentation of this file.
1 #include <utility>
2 #include <vector>
3 
4 #pragma once
5 
9 #include "esphome/core/hal.h"
10 
11 #if defined(USE_ESP32) && ESP_IDF_VERSION_MAJOR < 5
12 #include <driver/rmt.h>
13 #endif
14 
15 namespace esphome {
16 namespace remote_base {
17 
18 enum ToleranceMode : uint8_t {
21 };
22 
23 using RawTimings = std::vector<int32_t>;
24 
26  public:
27  void mark(uint32_t length) { this->data_.push_back(length); }
28  void space(uint32_t length) { this->data_.push_back(-length); }
29  void item(uint32_t mark, uint32_t space) {
30  this->mark(mark);
31  this->space(space);
32  }
33  void reserve(uint32_t len) { this->data_.reserve(len); }
34  void set_carrier_frequency(uint32_t carrier_frequency) { this->carrier_frequency_ = carrier_frequency; }
35  uint32_t get_carrier_frequency() const { return this->carrier_frequency_; }
36  const RawTimings &get_data() const { return this->data_; }
37  void set_data(const RawTimings &data) { this->data_ = data; }
38  void reset() {
39  this->data_.clear();
40  this->carrier_frequency_ = 0;
41  }
42 
43  protected:
45  uint32_t carrier_frequency_{0};
46 };
47 
49  public:
50  explicit RemoteReceiveData(const RawTimings &data, uint32_t tolerance, ToleranceMode tolerance_mode)
51  : data_(data), index_(0), tolerance_(tolerance), tolerance_mode_(tolerance_mode) {}
52 
53  const RawTimings &get_raw_data() const { return this->data_; }
54  uint32_t get_index() const { return index_; }
55  int32_t operator[](uint32_t index) const { return this->data_[index]; }
56  int32_t size() const { return this->data_.size(); }
57  bool is_valid(uint32_t offset = 0) const { return this->index_ + offset < this->data_.size(); }
58  int32_t peek(uint32_t offset = 0) const { return this->data_[this->index_ + offset]; }
59  bool peek_mark(uint32_t length, uint32_t offset = 0) const;
60  bool peek_space(uint32_t length, uint32_t offset = 0) const;
61  bool peek_space_at_least(uint32_t length, uint32_t offset = 0) const;
62  bool peek_item(uint32_t mark, uint32_t space, uint32_t offset = 0) const {
63  return this->peek_space(space, offset + 1) && this->peek_mark(mark, offset);
64  }
65 
66  bool expect_mark(uint32_t length);
67  bool expect_space(uint32_t length);
68  bool expect_item(uint32_t mark, uint32_t space);
69  bool expect_pulse_with_gap(uint32_t mark, uint32_t space);
70  void advance(uint32_t amount = 1) { this->index_ += amount; }
71  void reset() { this->index_ = 0; }
72 
73  void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode) {
74  this->tolerance_ = tolerance;
75  this->tolerance_mode_ = tolerance_mode;
76  }
77  uint32_t get_tolerance() { return tolerance_; }
78  ToleranceMode get_tolerance_mode() { return this->tolerance_mode_; }
79 
80  protected:
81  int32_t lower_bound_(uint32_t length) const {
82  if (this->tolerance_mode_ == TOLERANCE_MODE_TIME) {
83  return int32_t(length - this->tolerance_);
84  } else if (this->tolerance_mode_ == TOLERANCE_MODE_PERCENTAGE) {
85  return int32_t(100 - this->tolerance_) * length / 100U;
86  }
87  return 0;
88  }
89  int32_t upper_bound_(uint32_t length) const {
90  if (this->tolerance_mode_ == TOLERANCE_MODE_TIME) {
91  return int32_t(length + this->tolerance_);
92  } else if (this->tolerance_mode_ == TOLERANCE_MODE_PERCENTAGE) {
93  return int32_t(100 + this->tolerance_) * length / 100U;
94  }
95  return 0;
96  }
97 
98  const RawTimings &data_;
99  uint32_t index_;
100  uint32_t tolerance_;
102 };
103 
105  public:
106  explicit RemoteComponentBase(InternalGPIOPin *pin) : pin_(pin){};
107 
108  protected:
109  InternalGPIOPin *pin_;
110 };
111 
112 #ifdef USE_ESP32
114  public:
115 #if ESP_IDF_VERSION_MAJOR >= 5
116  void set_clock_resolution(uint32_t clock_resolution) { this->clock_resolution_ = clock_resolution; }
117  void set_rmt_symbols(uint32_t rmt_symbols) { this->rmt_symbols_ = rmt_symbols; }
118 #else
119  explicit RemoteRMTChannel(uint8_t mem_block_num = 1);
120  explicit RemoteRMTChannel(rmt_channel_t channel, uint8_t mem_block_num = 1);
121 
122  void config_rmt(rmt_config_t &rmt);
123  void set_clock_divider(uint8_t clock_divider) { this->clock_divider_ = clock_divider; }
124 #endif
125 
126  protected:
127  uint32_t from_microseconds_(uint32_t us) {
128 #if ESP_IDF_VERSION_MAJOR >= 5
129  const uint32_t ticks_per_ten_us = this->clock_resolution_ / 100000u;
130 #else
131  const uint32_t ticks_per_ten_us = 80000000u / this->clock_divider_ / 100000u;
132 #endif
133  return us * ticks_per_ten_us / 10;
134  }
135  uint32_t to_microseconds_(uint32_t ticks) {
136 #if ESP_IDF_VERSION_MAJOR >= 5
137  const uint32_t ticks_per_ten_us = this->clock_resolution_ / 100000u;
138 #else
139  const uint32_t ticks_per_ten_us = 80000000u / this->clock_divider_ / 100000u;
140 #endif
141  return (ticks * 10) / ticks_per_ten_us;
142  }
144 #if ESP_IDF_VERSION_MAJOR >= 5
145  uint32_t clock_resolution_{1000000};
146  uint32_t rmt_symbols_;
147 #else
148  rmt_channel_t channel_{RMT_CHANNEL_0};
149  uint8_t mem_block_num_;
150  uint8_t clock_divider_{80};
151 #endif
152 };
153 #endif
154 
156  public:
158  class TransmitCall {
159  public:
160  explicit TransmitCall(RemoteTransmitterBase *parent) : parent_(parent) {}
161  RemoteTransmitData *get_data() { return &this->parent_->temp_; }
162  void set_send_times(uint32_t send_times) { send_times_ = send_times; }
163  void set_send_wait(uint32_t send_wait) { send_wait_ = send_wait; }
164  void perform() { this->parent_->send_(this->send_times_, this->send_wait_); }
165 
166  protected:
168  uint32_t send_times_{1};
169  uint32_t send_wait_{0};
170  };
171 
173  this->temp_.reset();
174  return TransmitCall(this);
175  }
176  template<typename Protocol>
177  void transmit(const typename Protocol::ProtocolData &data, uint32_t send_times = 1, uint32_t send_wait = 0) {
178  auto call = this->transmit();
179  Protocol().encode(call.get_data(), data);
180  call.set_send_times(send_times);
181  call.set_send_wait(send_wait);
182  call.perform();
183  }
184 
185  protected:
186  void send_(uint32_t send_times, uint32_t send_wait);
187  virtual void send_internal(uint32_t send_times, uint32_t send_wait) = 0;
188  void send_single_() { this->send_(1, 0); }
189 
192 };
193 
195  public:
196  virtual bool on_receive(RemoteReceiveData data) = 0;
197 };
198 
200  public:
201  virtual bool dump(RemoteReceiveData src) = 0;
202  virtual bool is_secondary() { return false; }
203 };
204 
206  public:
208  void register_listener(RemoteReceiverListener *listener) { this->listeners_.push_back(listener); }
209  void register_dumper(RemoteReceiverDumperBase *dumper);
210  void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode) {
211  this->tolerance_ = tolerance;
212  this->tolerance_mode_ = tolerance_mode;
213  }
214 
215  protected:
216  void call_listeners_();
217  void call_dumpers_();
219  this->call_listeners_();
220  this->call_dumpers_();
221  }
222 
223  std::vector<RemoteReceiverListener *> listeners_;
224  std::vector<RemoteReceiverDumperBase *> dumpers_;
225  std::vector<RemoteReceiverDumperBase *> secondary_dumpers_;
227  uint32_t tolerance_{25};
229 };
230 
232  public Component,
233  public RemoteReceiverListener {
234  public:
236  void dump_config() override;
237  virtual bool matches(RemoteReceiveData src) = 0;
238  bool on_receive(RemoteReceiveData src) override;
239 };
240 
241 /* TEMPLATES */
242 
243 template<typename T> class RemoteProtocol {
244  public:
245  using ProtocolData = T;
246  virtual void encode(RemoteTransmitData *dst, const ProtocolData &data) = 0;
247  virtual optional<ProtocolData> decode(RemoteReceiveData src) = 0;
248  virtual void dump(const ProtocolData &data) = 0;
249 };
250 
251 template<typename T> class RemoteReceiverBinarySensor : public RemoteReceiverBinarySensorBase {
252  public:
254 
255  protected:
256  bool matches(RemoteReceiveData src) override {
257  auto proto = T();
258  auto res = proto.decode(src);
259  return res.has_value() && *res == this->data_;
260  }
261 
262  public:
263  void set_data(typename T::ProtocolData data) { data_ = data; }
264 
265  protected:
266  typename T::ProtocolData data_;
267 };
268 
269 template<typename T>
270 class RemoteReceiverTrigger : public Trigger<typename T::ProtocolData>, public RemoteReceiverListener {
271  protected:
272  bool on_receive(RemoteReceiveData src) override {
273  auto proto = T();
274  auto res = proto.decode(src);
275  if (res.has_value()) {
276  this->trigger(*res);
277  return true;
278  }
279  return false;
280  }
281 };
282 
284  public:
286  RemoteTransmittable(RemoteTransmitterBase *transmitter) : transmitter_(transmitter) {}
287  void set_transmitter(RemoteTransmitterBase *transmitter) { this->transmitter_ = transmitter; }
288 
289  protected:
290  template<typename Protocol>
291  void transmit_(const typename Protocol::ProtocolData &data, uint32_t send_times = 1, uint32_t send_wait = 0) {
292  this->transmitter_->transmit<Protocol>(data, send_times, send_wait);
293  }
295 };
296 
297 template<typename... Ts> class RemoteTransmitterActionBase : public RemoteTransmittable, public Action<Ts...> {
298  TEMPLATABLE_VALUE(uint32_t, send_times)
299  TEMPLATABLE_VALUE(uint32_t, send_wait)
300 
301  protected:
302  void play(Ts... x) override {
303  auto call = this->transmitter_->transmit();
304  this->encode(call.get_data(), x...);
305  call.set_send_times(this->send_times_.value_or(x..., 1));
306  call.set_send_wait(this->send_wait_.value_or(x..., 0));
307  call.perform();
308  }
309  virtual void encode(RemoteTransmitData *dst, Ts... x) = 0;
310 };
311 
312 template<typename T> class RemoteReceiverDumper : public RemoteReceiverDumperBase {
313  public:
314  bool dump(RemoteReceiveData src) override {
315  auto proto = T();
316  auto decoded = proto.decode(src);
317  if (!decoded.has_value())
318  return false;
319  proto.dump(*decoded);
320  return true;
321  }
322 };
323 
324 #define DECLARE_REMOTE_PROTOCOL_(prefix) \
325  using prefix##BinarySensor = RemoteReceiverBinarySensor<prefix##Protocol>; \
326  using prefix##Trigger = RemoteReceiverTrigger<prefix##Protocol>; \
327  using prefix##Dumper = RemoteReceiverDumper<prefix##Protocol>;
328 #define DECLARE_REMOTE_PROTOCOL(prefix) DECLARE_REMOTE_PROTOCOL_(prefix)
329 
330 } // namespace remote_base
331 } // namespace esphome
void register_listener(RemoteReceiverListener *listener)
Definition: remote_base.h:208
void set_data(const RawTimings &data)
Definition: remote_base.h:37
RemoteTransmitData temp_
Use same vector for all transmits, avoids many allocations.
Definition: remote_base.h:191
int32_t operator[](uint32_t index) const
Definition: remote_base.h:55
const RawTimings & get_raw_data() const
Definition: remote_base.h:53
void set_carrier_frequency(uint32_t carrier_frequency)
Definition: remote_base.h:34
uint16_t x
Definition: tt21100.cpp:17
void item(uint32_t mark, uint32_t space)
Definition: remote_base.h:29
std::vector< RemoteReceiverDumperBase * > dumpers_
Definition: remote_base.h:224
void set_data(typename T::ProtocolData data)
Definition: remote_base.h:263
std::vector< RemoteReceiverDumperBase * > secondary_dumpers_
Definition: remote_base.h:225
bool is_valid(uint32_t offset=0) const
Definition: remote_base.h:57
void set_transmitter(RemoteTransmitterBase *transmitter)
Definition: remote_base.h:287
void set_clock_resolution(uint32_t clock_resolution)
Definition: remote_base.h:116
RemoteComponentBase(InternalGPIOPin *pin)
Definition: remote_base.h:106
RemoteComponentBase * remote_base_
Definition: remote_base.h:143
std::vector< int32_t > RawTimings
Definition: remote_base.h:23
RemoteReceiveData(const RawTimings &data, uint32_t tolerance, ToleranceMode tolerance_mode)
Definition: remote_base.h:50
void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode)
Definition: remote_base.h:73
RemoteTransmitterBase * transmitter_
Definition: remote_base.h:294
int32_t lower_bound_(uint32_t length) const
Definition: remote_base.h:81
int32_t peek(uint32_t offset=0) const
Definition: remote_base.h:58
std::vector< RemoteReceiverListener * > listeners_
Definition: remote_base.h:223
void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode)
Definition: remote_base.h:210
void transmit(const typename Protocol::ProtocolData &data, uint32_t send_times=1, uint32_t send_wait=0)
Definition: remote_base.h:177
RemoteReceiverBase(InternalGPIOPin *pin)
Definition: remote_base.h:207
bool on_receive(RemoteReceiveData src) override
Definition: remote_base.h:272
bool dump(RemoteReceiveData src) override
Definition: remote_base.h:314
void set_clock_divider(uint8_t clock_divider)
Definition: remote_base.h:123
std::string size_t len
Definition: helpers.h:301
void transmit_(const typename Protocol::ProtocolData &data, uint32_t send_times=1, uint32_t send_wait=0)
Definition: remote_base.h:291
bool peek_item(uint32_t mark, uint32_t space, uint32_t offset=0) const
Definition: remote_base.h:62
uint16_t length
Definition: tt21100.cpp:12
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
bool matches(RemoteReceiveData src) override
Definition: remote_base.h:256
void advance(uint32_t amount=1)
Definition: remote_base.h:70
const RawTimings & get_data() const
Definition: remote_base.h:36
void set_rmt_symbols(uint32_t rmt_symbols)
Definition: remote_base.h:117
uint32_t to_microseconds_(uint32_t ticks)
Definition: remote_base.h:135
RemoteTransmittable(RemoteTransmitterBase *transmitter)
Definition: remote_base.h:286
int32_t upper_bound_(uint32_t length) const
Definition: remote_base.h:89
uint32_t from_microseconds_(uint32_t us)
Definition: remote_base.h:127