ESPHome  2024.4.0
rc6_protocol.cpp
Go to the documentation of this file.
1 #include "rc6_protocol.h"
2 #include "esphome/core/log.h"
3 
4 namespace esphome {
5 namespace remote_base {
6 
7 static const char *const RC6_TAG = "remote.rc6";
8 
9 static const uint16_t RC6_FREQ = 36000;
10 static const uint16_t RC6_UNIT = 444;
11 static const uint16_t RC6_HEADER_MARK = (6 * RC6_UNIT);
12 static const uint16_t RC6_HEADER_SPACE = (2 * RC6_UNIT);
13 static const uint16_t RC6_MODE_MASK = 0x07;
14 
16  dst->reserve(44);
17  dst->set_carrier_frequency(RC6_FREQ);
18 
19  // Encode header
20  dst->item(RC6_HEADER_MARK, RC6_HEADER_SPACE);
21 
22  int32_t next{0};
23 
24  // Encode startbit+mode
25  uint8_t header{static_cast<uint8_t>((1 << 3) | data.mode)};
26 
27  for (uint8_t mask = 0x8; mask; mask >>= 1) {
28  if (header & mask) {
29  if (next < 0) {
30  dst->space(-next);
31  next = 0;
32  }
33  if (next >= 0) {
34  next = next + RC6_UNIT;
35  dst->mark(next);
36  next = -RC6_UNIT;
37  }
38  } else {
39  if (next > 0) {
40  dst->mark(next);
41  next = 0;
42  }
43  if (next <= 0) {
44  next = next - RC6_UNIT;
45  dst->space(-next);
46  next = RC6_UNIT;
47  }
48  }
49  }
50 
51  // Toggle
52  if (data.toggle) {
53  if (next < 0) {
54  dst->space(-next);
55  next = 0;
56  }
57  if (next >= 0) {
58  next = next + RC6_UNIT * 2;
59  dst->mark(next);
60  next = -RC6_UNIT * 2;
61  }
62  } else {
63  if (next > 0) {
64  dst->mark(next);
65  next = 0;
66  }
67  if (next <= 0) {
68  next = next - RC6_UNIT * 2;
69  dst->space(-next);
70  next = RC6_UNIT * 2;
71  }
72  }
73 
74  // Encode data
75  uint16_t raw{static_cast<uint16_t>((data.address << 8) | data.command)};
76 
77  for (uint16_t mask = 0x8000; mask; mask >>= 1) {
78  if (raw & mask) {
79  if (next < 0) {
80  dst->space(-next);
81  next = 0;
82  }
83  if (next >= 0) {
84  next = next + RC6_UNIT;
85  dst->mark(next);
86  next = -RC6_UNIT;
87  }
88  } else {
89  if (next > 0) {
90  dst->mark(next);
91  next = 0;
92  }
93  if (next <= 0) {
94  next = next - RC6_UNIT;
95  dst->space(-next);
96  next = RC6_UNIT;
97  }
98  }
99  }
100 
101  if (next > 0) {
102  dst->mark(next);
103  } else {
104  dst->space(-next);
105  }
106 }
107 
109  RC6Data data{
110  .mode = 0,
111  .toggle = 0,
112  .address = 0,
113  .command = 0,
114  };
115 
116  // Check if header matches
117  if (!src.expect_item(RC6_HEADER_MARK, RC6_HEADER_SPACE)) {
118  return {};
119  }
120 
121  uint8_t bit{1};
122  uint8_t offset{0};
123  uint8_t header{0};
124  uint32_t buffer{0};
125 
126  // Startbit + mode
127  while (offset < 4) {
128  bit = src.peek() > 0;
129  header = header + (bit << (3 - offset++));
130  src.advance();
131 
132  if (src.peek_mark(RC6_UNIT) || src.peek_space(RC6_UNIT)) {
133  src.advance();
134  } else if (offset == 4) {
135  break;
136  } else if (!src.peek_mark(RC6_UNIT * 2) && !src.peek_space(RC6_UNIT * 2)) {
137  return {};
138  }
139  }
140 
141  data.mode = header & RC6_MODE_MASK;
142 
143  if (data.mode != 0) {
144  return {}; // I dont have a device to test other modes
145  }
146 
147  // Toggle
148  data.toggle = src.peek() > 0;
149  src.advance();
150  if (src.peek_mark(RC6_UNIT * 2) || src.peek_space(RC6_UNIT * 2)) {
151  src.advance();
152  }
153 
154  // Data
155  offset = 0;
156  while (offset < 16) {
157  bit = src.peek() > 0;
158  buffer = buffer + (bit << (15 - offset++));
159  src.advance();
160 
161  if (offset == 16) {
162  break;
163  } else if (src.peek_mark(RC6_UNIT) || src.peek_space(RC6_UNIT)) {
164  src.advance();
165  } else if (!src.peek_mark(RC6_UNIT * 2) && !src.peek_space(RC6_UNIT * 2)) {
166  return {};
167  }
168  }
169 
170  data.address = (0xFF00 & buffer) >> 8;
171  data.command = (0x00FF & buffer);
172  return data;
173 }
174 
175 void RC6Protocol::dump(const RC6Data &data) {
176  ESP_LOGI(RC6_TAG, "Received RC6: mode=0x%X, address=0x%02X, command=0x%02X, toggle=0x%X", data.mode, data.address,
177  data.command, data.toggle);
178 }
179 
180 } // namespace remote_base
181 } // namespace esphome
void dump(const RC6Data &data) override
uint8_t raw[35]
Definition: bl0939.h:19
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
void item(uint32_t mark, uint32_t space)
Definition: remote_base.h:24
optional< RC6Data > decode(RemoteReceiveData src) override
bool peek_mark(uint32_t length, uint32_t offset=0) const
Definition: remote_base.cpp:34
void encode(RemoteTransmitData *dst, const RC6Data &data) override
int32_t peek(uint32_t offset=0) const
Definition: remote_base.h:53
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 expect_item(uint32_t mark, uint32_t space)
Definition: remote_base.cpp:74
void advance(uint32_t amount=1)
Definition: remote_base.h:65