ESPHome  2023.3.1
remote_base.h
Go to the documentation of this file.
1 #include <utility>
2 #include <vector>
3 
4 #pragma once
5 
7 #include "esphome/core/hal.h"
10 
11 #ifdef USE_ESP32
12 #include <driver/rmt.h>
13 #endif
14 
15 namespace esphome {
16 namespace remote_base {
17 
19  public:
20  void mark(uint32_t length) { this->data_.push_back(length); }
21 
22  void space(uint32_t length) { this->data_.push_back(-length); }
23 
24  void item(uint32_t mark, uint32_t space) {
25  this->mark(mark);
26  this->space(space);
27  }
28 
29  void reserve(uint32_t len) { this->data_.reserve(len); }
30 
31  void set_carrier_frequency(uint32_t carrier_frequency) { this->carrier_frequency_ = carrier_frequency; }
32 
33  uint32_t get_carrier_frequency() const { return this->carrier_frequency_; }
34 
35  const std::vector<int32_t> &get_data() const { return this->data_; }
36 
37  void set_data(const std::vector<int32_t> &data) {
38  this->data_.clear();
39  this->data_.reserve(data.size());
40  for (auto dat : data)
41  this->data_.push_back(dat);
42  }
43 
44  void reset() {
45  this->data_.clear();
46  this->carrier_frequency_ = 0;
47  }
48 
49  std::vector<int32_t>::iterator begin() { return this->data_.begin(); }
50 
51  std::vector<int32_t>::iterator end() { return this->data_.end(); }
52 
53  protected:
54  std::vector<int32_t> data_{};
55  uint32_t carrier_frequency_{0};
56 };
57 
59  public:
60  RemoteReceiveData(std::vector<int32_t> *data, uint8_t tolerance) : data_(data), tolerance_(tolerance) {}
61 
62  bool peek_mark(uint32_t length, uint32_t offset = 0) {
63  if (int32_t(this->index_ + offset) >= this->size())
64  return false;
65  int32_t value = this->peek(offset);
66  const int32_t lo = this->lower_bound_(length);
67  const int32_t hi = this->upper_bound_(length);
68  return value >= 0 && lo <= value && value <= hi;
69  }
70 
71  bool peek_space(uint32_t length, uint32_t offset = 0) {
72  if (int32_t(this->index_ + offset) >= this->size())
73  return false;
74  int32_t value = this->peek(offset);
75  const int32_t lo = this->lower_bound_(length);
76  const int32_t hi = this->upper_bound_(length);
77  return value <= 0 && lo <= -value && -value <= hi;
78  }
79 
80  bool peek_space_at_least(uint32_t length, uint32_t offset = 0) {
81  if (int32_t(this->index_ + offset) >= this->size())
82  return false;
83  int32_t value = this->pos(this->index_ + offset);
84  const int32_t lo = this->lower_bound_(length);
85  return value <= 0 && lo <= -value;
86  }
87 
88  bool peek_item(uint32_t mark, uint32_t space, uint32_t offset = 0) {
89  return this->peek_mark(mark, offset) && this->peek_space(space, offset + 1);
90  }
91 
92  int32_t peek(uint32_t offset = 0) { return (*this)[this->index_ + offset]; }
93 
94  void advance(uint32_t amount = 1) { this->index_ += amount; }
95 
96  bool expect_mark(uint32_t length) {
97  if (this->peek_mark(length)) {
98  this->advance();
99  return true;
100  }
101  return false;
102  }
103 
104  bool expect_space(uint32_t length) {
105  if (this->peek_space(length)) {
106  this->advance();
107  return true;
108  }
109  return false;
110  }
111 
112  bool expect_item(uint32_t mark, uint32_t space) {
113  if (this->peek_item(mark, space)) {
114  this->advance(2);
115  return true;
116  }
117  return false;
118  }
119 
120  bool expect_pulse_with_gap(uint32_t mark, uint32_t space) {
121  if (this->peek_mark(mark, 0) && this->peek_space_at_least(space, 1)) {
122  this->advance(2);
123  return true;
124  }
125  return false;
126  }
127 
128  uint32_t get_index() { return index_; }
129 
130  void reset() { this->index_ = 0; }
131 
132  int32_t pos(uint32_t index) const { return (*this->data_)[index]; }
133 
134  int32_t operator[](uint32_t index) const { return this->pos(index); }
135 
136  int32_t size() const { return this->data_->size(); }
137 
138  std::vector<int32_t> *get_raw_data() { return this->data_; }
139 
140  protected:
141  int32_t lower_bound_(uint32_t length) { return int32_t(100 - this->tolerance_) * length / 100U; }
142  int32_t upper_bound_(uint32_t length) { return int32_t(100 + this->tolerance_) * length / 100U; }
143 
144  uint32_t index_{0};
145  std::vector<int32_t> *data_;
146  uint8_t tolerance_;
147 };
148 
149 template<typename T> class RemoteProtocol {
150  public:
151  virtual void encode(RemoteTransmitData *dst, const T &data) = 0;
152 
153  virtual optional<T> decode(RemoteReceiveData src) = 0;
154 
155  virtual void dump(const T &data) = 0;
156 };
157 
159  public:
160  explicit RemoteComponentBase(InternalGPIOPin *pin) : pin_(pin){};
161 
162  protected:
163  InternalGPIOPin *pin_;
164 };
165 
166 #ifdef USE_ESP32
168  public:
169  explicit RemoteRMTChannel(uint8_t mem_block_num = 1);
170 
171  void config_rmt(rmt_config_t &rmt);
172  void set_clock_divider(uint8_t clock_divider) { this->clock_divider_ = clock_divider; }
173 
174  protected:
175  uint32_t from_microseconds_(uint32_t us) {
176  const uint32_t ticks_per_ten_us = 80000000u / this->clock_divider_ / 100000u;
177  return us * ticks_per_ten_us / 10;
178  }
179  uint32_t to_microseconds_(uint32_t ticks) {
180  const uint32_t ticks_per_ten_us = 80000000u / this->clock_divider_ / 100000u;
181  return (ticks * 10) / ticks_per_ten_us;
182  }
184  rmt_channel_t channel_{RMT_CHANNEL_0};
185  uint8_t mem_block_num_;
186  uint8_t clock_divider_{80};
187 };
188 #endif
189 
191  public:
193  class TransmitCall {
194  public:
195  explicit TransmitCall(RemoteTransmitterBase *parent) : parent_(parent) {}
196  RemoteTransmitData *get_data() { return &this->parent_->temp_; }
197  void set_send_times(uint32_t send_times) { send_times_ = send_times; }
198  void set_send_wait(uint32_t send_wait) { send_wait_ = send_wait; }
199 
200  void perform() { this->parent_->send_(this->send_times_, this->send_wait_); }
201 
202  protected:
204  uint32_t send_times_{1};
205  uint32_t send_wait_{0};
206  };
207 
209  this->temp_.reset();
210  return TransmitCall(this);
211  }
212 
213  protected:
214  void send_(uint32_t send_times, uint32_t send_wait);
215  virtual void send_internal(uint32_t send_times, uint32_t send_wait) = 0;
216  void send_single_() { this->send_(1, 0); }
217 
220 };
221 
223  public:
224  virtual bool on_receive(RemoteReceiveData data) = 0;
225 };
226 
228  public:
229  virtual bool dump(RemoteReceiveData src) = 0;
230  virtual bool is_secondary() { return false; }
231 };
232 
234  public:
236  void register_listener(RemoteReceiverListener *listener) { this->listeners_.push_back(listener); }
238  if (dumper->is_secondary()) {
239  this->secondary_dumpers_.push_back(dumper);
240  } else {
241  this->dumpers_.push_back(dumper);
242  }
243  }
244  void set_tolerance(uint8_t tolerance) { tolerance_ = tolerance; }
245 
246  protected:
248  bool success = false;
249  for (auto *listener : this->listeners_) {
250  auto data = RemoteReceiveData(&this->temp_, this->tolerance_);
251  if (listener->on_receive(data))
252  success = true;
253  }
254  return success;
255  }
256  void call_dumpers_() {
257  bool success = false;
258  for (auto *dumper : this->dumpers_) {
259  auto data = RemoteReceiveData(&this->temp_, this->tolerance_);
260  if (dumper->dump(data))
261  success = true;
262  }
263  if (!success) {
264  for (auto *dumper : this->secondary_dumpers_) {
265  auto data = RemoteReceiveData(&this->temp_, this->tolerance_);
266  dumper->dump(data);
267  }
268  }
269  }
271  if (this->call_listeners_())
272  return;
273  // If a listener handled, then do not dump
274  this->call_dumpers_();
275  }
276 
277  std::vector<RemoteReceiverListener *> listeners_;
278  std::vector<RemoteReceiverDumperBase *> dumpers_;
279  std::vector<RemoteReceiverDumperBase *> secondary_dumpers_;
280  std::vector<int32_t> temp_;
281  uint8_t tolerance_{25};
282 };
283 
285  public Component,
286  public RemoteReceiverListener {
287  public:
289  void dump_config() override;
290  virtual bool matches(RemoteReceiveData src) = 0;
291  bool on_receive(RemoteReceiveData src) override {
292  if (this->matches(src)) {
293  this->publish_state(true);
294  yield();
295  this->publish_state(false);
296  return true;
297  }
298  return false;
299  }
300 };
301 
302 template<typename T, typename D> class RemoteReceiverBinarySensor : public RemoteReceiverBinarySensorBase {
303  public:
305 
306  protected:
307  bool matches(RemoteReceiveData src) override {
308  auto proto = T();
309  auto res = proto.decode(src);
310  return res.has_value() && *res == this->data_;
311  }
312 
313  public:
314  void set_data(D data) { data_ = data; }
315 
316  protected:
317  D data_;
318 };
319 
320 template<typename T, typename D> class RemoteReceiverTrigger : public Trigger<D>, public RemoteReceiverListener {
321  protected:
322  bool on_receive(RemoteReceiveData src) override {
323  auto proto = T();
324  auto res = proto.decode(src);
325  if (res.has_value()) {
326  this->trigger(*res);
327  return true;
328  }
329  return false;
330  }
331 };
332 
333 template<typename... Ts> class RemoteTransmitterActionBase : public Action<Ts...> {
334  public:
335  void set_parent(RemoteTransmitterBase *parent) { this->parent_ = parent; }
336 
337  TEMPLATABLE_VALUE(uint32_t, send_times);
338  TEMPLATABLE_VALUE(uint32_t, send_wait);
339 
340  void play(Ts... x) override {
341  auto call = this->parent_->transmit();
342  this->encode(call.get_data(), x...);
343  call.set_send_times(this->send_times_.value_or(x..., 1));
344  call.set_send_wait(this->send_wait_.value_or(x..., 0));
345  call.perform();
346  }
347 
348  protected:
349  virtual void encode(RemoteTransmitData *dst, Ts... x) = 0;
350 
352 };
353 
354 template<typename T, typename D> class RemoteReceiverDumper : public RemoteReceiverDumperBase {
355  public:
356  bool dump(RemoteReceiveData src) override {
357  auto proto = T();
358  auto decoded = proto.decode(src);
359  if (!decoded.has_value())
360  return false;
361  proto.dump(*decoded);
362  return true;
363  }
364 };
365 
366 #define DECLARE_REMOTE_PROTOCOL_(prefix) \
367  using prefix##BinarySensor = RemoteReceiverBinarySensor<prefix##Protocol, prefix##Data>; \
368  using prefix##Trigger = RemoteReceiverTrigger<prefix##Protocol, prefix##Data>; \
369  using prefix##Dumper = RemoteReceiverDumper<prefix##Protocol, prefix##Data>;
370 #define DECLARE_REMOTE_PROTOCOL(prefix) DECLARE_REMOTE_PROTOCOL_(prefix)
371 
372 } // namespace remote_base
373 } // namespace esphome
void register_listener(RemoteReceiverListener *listener)
Definition: remote_base.h:236
bool expect_pulse_with_gap(uint32_t mark, uint32_t space)
Definition: remote_base.h:120
RemoteTransmitData temp_
Use same vector for all transmits, avoids many allocations.
Definition: remote_base.h:219
int32_t operator[](uint32_t index) const
Definition: remote_base.h:134
RemoteReceiveData(std::vector< int32_t > *data, uint8_t tolerance)
Definition: remote_base.h:60
void set_carrier_frequency(uint32_t carrier_frequency)
Definition: remote_base.h:31
bool on_receive(RemoteReceiveData src) override
Definition: remote_base.h:322
void item(uint32_t mark, uint32_t space)
Definition: remote_base.h:24
int32_t peek(uint32_t offset=0)
Definition: remote_base.h:92
std::vector< int32_t > * get_raw_data()
Definition: remote_base.h:138
std::vector< int32_t > * data_
Definition: remote_base.h:145
std::vector< int32_t >::iterator begin()
Definition: remote_base.h:49
bool peek_space(uint32_t length, uint32_t offset=0)
Definition: remote_base.h:71
std::vector< RemoteReceiverDumperBase * > dumpers_
Definition: remote_base.h:278
std::vector< RemoteReceiverDumperBase * > secondary_dumpers_
Definition: remote_base.h:279
const std::vector< int32_t > & get_data() const
Definition: remote_base.h:35
RemoteComponentBase(InternalGPIOPin *pin)
Definition: remote_base.h:160
RemoteComponentBase * remote_base_
Definition: remote_base.h:183
int32_t upper_bound_(uint32_t length)
Definition: remote_base.h:142
bool dump(RemoteReceiveData src) override
Definition: remote_base.h:356
std::vector< int32_t >::iterator end()
Definition: remote_base.h:51
bool peek_mark(uint32_t length, uint32_t offset=0)
Definition: remote_base.h:62
int32_t lower_bound_(uint32_t length)
Definition: remote_base.h:141
std::vector< RemoteReceiverListener * > listeners_
Definition: remote_base.h:277
bool on_receive(RemoteReceiveData src) override
Definition: remote_base.h:291
int32_t pos(uint32_t index) const
Definition: remote_base.h:132
void set_data(const std::vector< int32_t > &data)
Definition: remote_base.h:37
RemoteReceiverBase(InternalGPIOPin *pin)
Definition: remote_base.h:235
void set_clock_divider(uint8_t clock_divider)
Definition: remote_base.h:172
void set_parent(RemoteTransmitterBase *parent)
Definition: remote_base.h:335
bool matches(RemoteReceiveData src) override
Definition: remote_base.h:307
std::string size_t len
Definition: helpers.h:286
void IRAM_ATTR HOT yield()
Definition: core.cpp:25
bool peek_item(uint32_t mark, uint32_t space, uint32_t offset=0)
Definition: remote_base.h:88
Definition: a4988.cpp:4
void register_dumper(RemoteReceiverDumperBase *dumper)
Definition: remote_base.h:237
bool expect_item(uint32_t mark, uint32_t space)
Definition: remote_base.h:112
void advance(uint32_t amount=1)
Definition: remote_base.h:94
void set_tolerance(uint8_t tolerance)
Definition: remote_base.h:244
uint32_t to_microseconds_(uint32_t ticks)
Definition: remote_base.h:179
bool peek_space_at_least(uint32_t length, uint32_t offset=0)
Definition: remote_base.h:80
uint32_t from_microseconds_(uint32_t us)
Definition: remote_base.h:175