ESPHome  2024.4.1
rc_switch_protocol.cpp
Go to the documentation of this file.
1 #include "rc_switch_protocol.h"
2 #include "esphome/core/log.h"
3 
4 namespace esphome {
5 namespace remote_base {
6 
7 static const char *const TAG = "remote.rc_switch";
8 
9 const RCSwitchBase RC_SWITCH_PROTOCOLS[9] = {RCSwitchBase(0, 0, 0, 0, 0, 0, false),
10  RCSwitchBase(350, 10850, 350, 1050, 1050, 350, false),
11  RCSwitchBase(650, 6500, 650, 1300, 1300, 650, false),
12  RCSwitchBase(3000, 7100, 400, 1100, 900, 600, false),
13  RCSwitchBase(380, 2280, 380, 1140, 1140, 380, false),
14  RCSwitchBase(3000, 7000, 500, 1000, 1000, 500, false),
15  RCSwitchBase(10350, 450, 450, 900, 900, 450, true),
16  RCSwitchBase(300, 9300, 150, 900, 900, 150, false),
17  RCSwitchBase(250, 2500, 250, 1250, 250, 250, false)};
18 
19 RCSwitchBase::RCSwitchBase(uint32_t sync_high, uint32_t sync_low, uint32_t zero_high, uint32_t zero_low,
20  uint32_t one_high, uint32_t one_low, bool inverted)
21  : sync_high_(sync_high),
22  sync_low_(sync_low),
23  zero_high_(zero_high),
24  zero_low_(zero_low),
25  one_high_(one_high),
26  one_low_(one_low),
27  inverted_(inverted) {}
28 
30  if (!this->inverted_) {
31  dst->mark(this->one_high_);
32  dst->space(this->one_low_);
33  } else {
34  dst->space(this->one_high_);
35  dst->mark(this->one_low_);
36  }
37 }
39  if (!this->inverted_) {
40  dst->mark(this->zero_high_);
41  dst->space(this->zero_low_);
42  } else {
43  dst->space(this->zero_high_);
44  dst->mark(this->zero_low_);
45  }
46 }
48  if (!this->inverted_) {
49  dst->mark(this->sync_high_);
50  dst->space(this->sync_low_);
51  } else {
52  dst->space(this->sync_high_);
53  dst->mark(this->sync_low_);
54  }
55 }
56 void RCSwitchBase::transmit(RemoteTransmitData *dst, uint64_t code, uint8_t len) const {
57  dst->set_carrier_frequency(0);
58  this->sync(dst);
59  for (int16_t i = len - 1; i >= 0; i--) {
60  if (code & ((uint64_t) 1 << i)) {
61  this->one(dst);
62  } else {
63  this->zero(dst);
64  }
65  }
66 }
67 
69  if (!this->inverted_) {
70  if (!src.peek_mark(this->one_high_))
71  return false;
72  if (!src.peek_space(this->one_low_, 1))
73  return false;
74  } else {
75  if (!src.peek_space(this->one_high_))
76  return false;
77  if (!src.peek_mark(this->one_low_, 1))
78  return false;
79  }
80  src.advance(2);
81  return true;
82 }
84  if (!this->inverted_) {
85  if (!src.peek_mark(this->zero_high_))
86  return false;
87  if (!src.peek_space(this->zero_low_, 1))
88  return false;
89  } else {
90  if (!src.peek_space(this->zero_high_))
91  return false;
92  if (!src.peek_mark(this->zero_low_, 1))
93  return false;
94  }
95  src.advance(2);
96  return true;
97 }
99  if (!this->inverted_) {
100  if (!src.peek_mark(this->sync_high_))
101  return false;
102  if (!src.peek_space(this->sync_low_, 1))
103  return false;
104  } else {
105  // We can't peek a space at the beginning because signals starts with a low to high transition.
106  // this long space at the beginning is the separation between the transmissions itself, so it is actually
107  // added at the end kind of artificially (by the value given to "idle:" option by the user in the yaml)
108  if (!src.peek_mark(this->sync_low_))
109  return false;
110  src.advance(1);
111  return true;
112  }
113  src.advance(2);
114  return true;
115 }
116 bool RCSwitchBase::decode(RemoteReceiveData &src, uint64_t *out_data, uint8_t *out_nbits) const {
117  // ignore if sync doesn't exist
118  this->expect_sync(src);
119 
120  *out_data = 0;
121  for (*out_nbits = 0; *out_nbits < 64; *out_nbits += 1) {
122  if (this->expect_zero(src)) {
123  *out_data <<= 1;
124  *out_data |= 0;
125  } else if (this->expect_one(src)) {
126  *out_data <<= 1;
127  *out_data |= 1;
128  } else {
129  return *out_nbits >= 8;
130  }
131  }
132  return true;
133 }
135  RCSwitchData out;
136  uint8_t out_nbits;
137  for (uint8_t i = 1; i <= 8; i++) {
138  src.reset();
139  const RCSwitchBase *protocol = &RC_SWITCH_PROTOCOLS[i];
140  if (protocol->decode(src, &out.code, &out_nbits) && out_nbits >= 3) {
141  out.protocol = i;
142  return out;
143  }
144  }
145  return {};
146 }
147 
148 void RCSwitchBase::simple_code_to_tristate(uint16_t code, uint8_t nbits, uint64_t *out_code) {
149  *out_code = 0;
150  for (int8_t i = nbits - 1; i >= 0; i--) {
151  *out_code <<= 2;
152  if (code & (1 << i)) {
153  *out_code |= 0b01;
154  } else {
155  *out_code |= 0b00;
156  }
157  }
158 }
159 void RCSwitchBase::type_a_code(uint8_t switch_group, uint8_t switch_device, bool state, uint64_t *out_code,
160  uint8_t *out_nbits) {
161  uint16_t code = 0;
162  code = switch_group ^ 0b11111;
163  code <<= 5;
164  code |= switch_device ^ 0b11111;
165  code <<= 2;
166  code |= state ? 0b01 : 0b10;
167  simple_code_to_tristate(code, 12, out_code);
168  *out_nbits = 24;
169 }
170 void RCSwitchBase::type_b_code(uint8_t address_code, uint8_t channel_code, bool state, uint64_t *out_code,
171  uint8_t *out_nbits) {
172  uint16_t code = 0;
173  code |= (address_code == 1) ? 0 : 0b1000;
174  code |= (address_code == 2) ? 0 : 0b0100;
175  code |= (address_code == 3) ? 0 : 0b0010;
176  code |= (address_code == 4) ? 0 : 0b0001;
177  code <<= 4;
178  code |= (channel_code == 1) ? 0 : 0b1000;
179  code |= (channel_code == 2) ? 0 : 0b0100;
180  code |= (channel_code == 3) ? 0 : 0b0010;
181  code |= (channel_code == 4) ? 0 : 0b0001;
182  code <<= 4;
183  code |= 0b1110;
184  code |= state ? 0b1 : 0b0;
185  simple_code_to_tristate(code, 12, out_code);
186  *out_nbits = 24;
187 }
188 void RCSwitchBase::type_c_code(uint8_t family, uint8_t group, uint8_t device, bool state, uint64_t *out_code,
189  uint8_t *out_nbits) {
190  uint16_t code = 0;
191  code |= (family & 0b0001) ? 0b1000 : 0;
192  code |= (family & 0b0010) ? 0b0100 : 0;
193  code |= (family & 0b0100) ? 0b0010 : 0;
194  code |= (family & 0b1000) ? 0b0001 : 0;
195  code <<= 4;
196  code |= ((device - 1) & 0b01) ? 0b1000 : 0;
197  code |= ((device - 1) & 0b10) ? 0b0100 : 0;
198  code |= ((group - 1) & 0b01) ? 0b0010 : 0;
199  code |= ((group - 1) & 0b10) ? 0b0001 : 0;
200  code <<= 4;
201  code |= 0b0110;
202  code |= state ? 0b1 : 0b0;
203  simple_code_to_tristate(code, 12, out_code);
204  *out_nbits = 24;
205 }
206 void RCSwitchBase::type_d_code(uint8_t group, uint8_t device, bool state, uint64_t *out_code, uint8_t *out_nbits) {
207  *out_code = 0;
208  *out_code |= (group == 0) ? 0b11000000 : 0b01000000;
209  *out_code |= (group == 1) ? 0b00110000 : 0b00010000;
210  *out_code |= (group == 2) ? 0b00001100 : 0b00000100;
211  *out_code |= (group == 3) ? 0b00000011 : 0b00000001;
212  *out_code <<= 6;
213  *out_code |= (device == 1) ? 0b110000 : 0b010000;
214  *out_code |= (device == 2) ? 0b001100 : 0b000100;
215  *out_code |= (device == 3) ? 0b000011 : 0b000001;
216  *out_code <<= 6;
217  *out_code |= 0b000000;
218  *out_code <<= 4;
219  *out_code |= state ? 0b1100 : 0b0011;
220  *out_nbits = 24;
221 }
222 
223 uint64_t decode_binary_string(const std::string &data) {
224  uint64_t ret = 0;
225  for (char c : data) {
226  ret <<= 1UL;
227  ret |= (c != '0');
228  }
229  return ret;
230 }
231 
232 uint64_t decode_binary_string_mask(const std::string &data) {
233  uint64_t ret = 0;
234  for (char c : data) {
235  ret <<= 1UL;
236  ret |= (c != 'x');
237  }
238  return ret;
239 }
240 
242  uint64_t decoded_code;
243  uint8_t decoded_nbits;
244  if (!this->protocol_.decode(src, &decoded_code, &decoded_nbits))
245  return false;
246 
247  return decoded_nbits == this->nbits_ && (decoded_code & this->mask_) == (this->code_ & this->mask_);
248 }
250  for (uint8_t i = 1; i <= 8; i++) {
251  src.reset();
252  uint64_t out_data;
253  uint8_t out_nbits;
254  const RCSwitchBase *protocol = &RC_SWITCH_PROTOCOLS[i];
255  if (protocol->decode(src, &out_data, &out_nbits) && out_nbits >= 3) {
256  char buffer[65];
257  for (uint8_t j = 0; j < out_nbits; j++)
258  buffer[j] = (out_data & ((uint64_t) 1 << (out_nbits - j - 1))) ? '1' : '0';
259 
260  buffer[out_nbits] = '\0';
261  ESP_LOGI(TAG, "Received RCSwitch Raw: protocol=%u data='%s'", i, buffer);
262 
263  // only send first decoded protocol
264  return true;
265  }
266  }
267  return false;
268 }
269 
270 } // namespace remote_base
271 } // namespace esphome
bool decode(RemoteReceiveData &src, uint64_t *out_data, uint8_t *out_nbits) const
void zero(RemoteTransmitData *dst) const
void set_carrier_frequency(uint32_t carrier_frequency)
Definition: remote_base.h:29
bool peek_space(uint32_t length, uint32_t offset=0) const
Definition: remote_base.cpp:43
bool expect_one(RemoteReceiveData &src) const
void transmit(RemoteTransmitData *dst, uint64_t code, uint8_t len) const
void sync(RemoteTransmitData *dst) const
static void type_d_code(uint8_t group, uint8_t device, bool state, uint64_t *out_code, uint8_t *out_nbits)
static void type_c_code(uint8_t family, uint8_t group, uint8_t device, bool state, uint64_t *out_code, uint8_t *out_nbits)
bool peek_mark(uint32_t length, uint32_t offset=0) const
Definition: remote_base.cpp:34
bool expect_zero(RemoteReceiveData &src) const
static void type_a_code(uint8_t switch_group, uint8_t switch_device, bool state, uint64_t *out_code, uint8_t *out_nbits)
static void simple_code_to_tristate(uint16_t code, uint8_t nbits, uint64_t *out_code)
uint64_t decode_binary_string_mask(const std::string &data)
bool expect_sync(RemoteReceiveData &src) const
const RCSwitchBase RC_SWITCH_PROTOCOLS[9]
bool dump(RemoteReceiveData src) override
std::string size_t len
Definition: helpers.h:292
void one(RemoteTransmitData *dst) const
uint64_t decode_binary_string(const std::string &data)
static void type_b_code(uint8_t address_code, uint8_t channel_code, bool state, uint64_t *out_code, uint8_t *out_nbits)
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
bool matches(RemoteReceiveData src) override
void advance(uint32_t amount=1)
Definition: remote_base.h:65
bool state
Definition: fan.h:34