ESPHome  2024.12.2
proto.h
Go to the documentation of this file.
1 #pragma once
2 
4 #include "esphome/core/log.h"
5 #include "esphome/core/helpers.h"
6 
7 #include <vector>
8 
9 #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
10 #define HAS_PROTO_MESSAGE_DUMP
11 #endif
12 
13 namespace esphome {
14 namespace api {
15 
17 class ProtoVarInt {
18  public:
19  ProtoVarInt() : value_(0) {}
20  explicit ProtoVarInt(uint64_t value) : value_(value) {}
21 
22  static optional<ProtoVarInt> parse(const uint8_t *buffer, uint32_t len, uint32_t *consumed) {
23  if (consumed != nullptr)
24  *consumed = 0;
25 
26  if (len == 0)
27  return {};
28 
29  uint64_t result = 0;
30  uint8_t bitpos = 0;
31 
32  for (uint32_t i = 0; i < len; i++) {
33  uint8_t val = buffer[i];
34  result |= uint64_t(val & 0x7F) << uint64_t(bitpos);
35  bitpos += 7;
36  if ((val & 0x80) == 0) {
37  if (consumed != nullptr)
38  *consumed = i + 1;
39  return ProtoVarInt(result);
40  }
41  }
42 
43  return {};
44  }
45 
46  uint32_t as_uint32() const { return this->value_; }
47  uint64_t as_uint64() const { return this->value_; }
48  bool as_bool() const { return this->value_; }
49  template<typename T> T as_enum() const { return static_cast<T>(this->as_uint32()); }
50  int32_t as_int32() const {
51  // Not ZigZag encoded
52  return static_cast<int32_t>(this->as_int64());
53  }
54  int64_t as_int64() const {
55  // Not ZigZag encoded
56  return static_cast<int64_t>(this->value_);
57  }
58  int32_t as_sint32() const {
59  // with ZigZag encoding
60  if (this->value_ & 1) {
61  return static_cast<int32_t>(~(this->value_ >> 1));
62  } else {
63  return static_cast<int32_t>(this->value_ >> 1);
64  }
65  }
66  int64_t as_sint64() const {
67  // with ZigZag encoding
68  if (this->value_ & 1) {
69  return static_cast<int64_t>(~(this->value_ >> 1));
70  } else {
71  return static_cast<int64_t>(this->value_ >> 1);
72  }
73  }
74  void encode(std::vector<uint8_t> &out) {
75  uint64_t val = this->value_;
76  if (val <= 0x7F) {
77  out.push_back(val);
78  return;
79  }
80  while (val) {
81  uint8_t temp = val & 0x7F;
82  val >>= 7;
83  if (val) {
84  out.push_back(temp | 0x80);
85  } else {
86  out.push_back(temp);
87  }
88  }
89  }
90 
91  protected:
92  uint64_t value_;
93 };
94 
96  public:
97  explicit ProtoLengthDelimited(const uint8_t *value, size_t length) : value_(value), length_(length) {}
98  std::string as_string() const { return std::string(reinterpret_cast<const char *>(this->value_), this->length_); }
99  template<class C> C as_message() const {
100  auto msg = C();
101  msg.decode(this->value_, this->length_);
102  return msg;
103  }
104 
105  protected:
106  const uint8_t *const value_;
107  const size_t length_;
108 };
109 
110 class Proto32Bit {
111  public:
112  explicit Proto32Bit(uint32_t value) : value_(value) {}
113  uint32_t as_fixed32() const { return this->value_; }
114  int32_t as_sfixed32() const { return static_cast<int32_t>(this->value_); }
115  float as_float() const {
116  union {
117  uint32_t raw;
118  float value;
119  } s{};
120  s.raw = this->value_;
121  return s.value;
122  }
123 
124  protected:
125  const uint32_t value_;
126 };
127 
128 class Proto64Bit {
129  public:
130  explicit Proto64Bit(uint64_t value) : value_(value) {}
131  uint64_t as_fixed64() const { return this->value_; }
132  int64_t as_sfixed64() const { return static_cast<int64_t>(this->value_); }
133  double as_double() const {
134  union {
135  uint64_t raw;
136  double value;
137  } s{};
138  s.raw = this->value_;
139  return s.value;
140  }
141 
142  protected:
143  const uint64_t value_;
144 };
145 
147  public:
148  ProtoWriteBuffer(std::vector<uint8_t> *buffer) : buffer_(buffer) {}
149  void write(uint8_t value) { this->buffer_->push_back(value); }
150  void encode_varint_raw(ProtoVarInt value) { value.encode(*this->buffer_); }
151  void encode_varint_raw(uint32_t value) { this->encode_varint_raw(ProtoVarInt(value)); }
152  void encode_field_raw(uint32_t field_id, uint32_t type) {
153  uint32_t val = (field_id << 3) | (type & 0b111);
154  this->encode_varint_raw(val);
155  }
156  void encode_string(uint32_t field_id, const char *string, size_t len, bool force = false) {
157  if (len == 0 && !force)
158  return;
159 
160  this->encode_field_raw(field_id, 2);
161  this->encode_varint_raw(len);
162  auto *data = reinterpret_cast<const uint8_t *>(string);
163  this->buffer_->insert(this->buffer_->end(), data, data + len);
164  }
165  void encode_string(uint32_t field_id, const std::string &value, bool force = false) {
166  this->encode_string(field_id, value.data(), value.size());
167  }
168  void encode_bytes(uint32_t field_id, const uint8_t *data, size_t len, bool force = false) {
169  this->encode_string(field_id, reinterpret_cast<const char *>(data), len, force);
170  }
171  void encode_uint32(uint32_t field_id, uint32_t value, bool force = false) {
172  if (value == 0 && !force)
173  return;
174  this->encode_field_raw(field_id, 0);
175  this->encode_varint_raw(value);
176  }
177  void encode_uint64(uint32_t field_id, uint64_t value, bool force = false) {
178  if (value == 0 && !force)
179  return;
180  this->encode_field_raw(field_id, 0);
181  this->encode_varint_raw(ProtoVarInt(value));
182  }
183  void encode_bool(uint32_t field_id, bool value, bool force = false) {
184  if (!value && !force)
185  return;
186  this->encode_field_raw(field_id, 0);
187  this->write(0x01);
188  }
189  void encode_fixed32(uint32_t field_id, uint32_t value, bool force = false) {
190  if (value == 0 && !force)
191  return;
192 
193  this->encode_field_raw(field_id, 5);
194  this->write((value >> 0) & 0xFF);
195  this->write((value >> 8) & 0xFF);
196  this->write((value >> 16) & 0xFF);
197  this->write((value >> 24) & 0xFF);
198  }
199  void encode_fixed64(uint32_t field_id, uint64_t value, bool force = false) {
200  if (value == 0 && !force)
201  return;
202 
203  this->encode_field_raw(field_id, 5);
204  this->write((value >> 0) & 0xFF);
205  this->write((value >> 8) & 0xFF);
206  this->write((value >> 16) & 0xFF);
207  this->write((value >> 24) & 0xFF);
208  this->write((value >> 32) & 0xFF);
209  this->write((value >> 40) & 0xFF);
210  this->write((value >> 48) & 0xFF);
211  this->write((value >> 56) & 0xFF);
212  }
213  template<typename T> void encode_enum(uint32_t field_id, T value, bool force = false) {
214  this->encode_uint32(field_id, static_cast<uint32_t>(value), force);
215  }
216  void encode_float(uint32_t field_id, float value, bool force = false) {
217  if (value == 0.0f && !force)
218  return;
219 
220  union {
221  float value;
222  uint32_t raw;
223  } val{};
224  val.value = value;
225  this->encode_fixed32(field_id, val.raw);
226  }
227  void encode_int32(uint32_t field_id, int32_t value, bool force = false) {
228  if (value < 0) {
229  // negative int32 is always 10 byte long
230  this->encode_int64(field_id, value, force);
231  return;
232  }
233  this->encode_uint32(field_id, static_cast<uint32_t>(value), force);
234  }
235  void encode_int64(uint32_t field_id, int64_t value, bool force = false) {
236  this->encode_uint64(field_id, static_cast<uint64_t>(value), force);
237  }
238  void encode_sint32(uint32_t field_id, int32_t value, bool force = false) {
239  uint32_t uvalue;
240  if (value < 0) {
241  uvalue = ~(value << 1);
242  } else {
243  uvalue = value << 1;
244  }
245  this->encode_uint32(field_id, uvalue, force);
246  }
247  void encode_sint64(uint32_t field_id, int64_t value, bool force = false) {
248  uint64_t uvalue;
249  if (value < 0) {
250  uvalue = ~(value << 1);
251  } else {
252  uvalue = value << 1;
253  }
254  this->encode_uint64(field_id, uvalue, force);
255  }
256  template<class C> void encode_message(uint32_t field_id, const C &value, bool force = false) {
257  this->encode_field_raw(field_id, 2);
258  size_t begin = this->buffer_->size();
259 
260  value.encode(*this);
261 
262  const uint32_t nested_length = this->buffer_->size() - begin;
263  // add size varint
264  std::vector<uint8_t> var;
265  ProtoVarInt(nested_length).encode(var);
266  this->buffer_->insert(this->buffer_->begin() + begin, var.begin(), var.end());
267  }
268  std::vector<uint8_t> *get_buffer() const { return buffer_; }
269 
270  protected:
271  std::vector<uint8_t> *buffer_;
272 };
273 
275  public:
276  virtual ~ProtoMessage() = default;
277  virtual void encode(ProtoWriteBuffer buffer) const = 0;
278  void decode(const uint8_t *buffer, size_t length);
279 #ifdef HAS_PROTO_MESSAGE_DUMP
280  std::string dump() const;
281  virtual void dump_to(std::string &out) const = 0;
282 #endif
283 
284  protected:
285  virtual bool decode_varint(uint32_t field_id, ProtoVarInt value) { return false; }
286  virtual bool decode_length(uint32_t field_id, ProtoLengthDelimited value) { return false; }
287  virtual bool decode_32bit(uint32_t field_id, Proto32Bit value) { return false; }
288  virtual bool decode_64bit(uint32_t field_id, Proto64Bit value) { return false; }
289 };
290 
291 template<typename T> const char *proto_enum_to_string(T value);
292 
294  public:
295  protected:
296  virtual bool is_authenticated() = 0;
297  virtual bool is_connection_setup() = 0;
298  virtual void on_fatal_error() = 0;
299  virtual void on_unauthenticated_access() = 0;
300  virtual void on_no_setup_connection() = 0;
301  virtual ProtoWriteBuffer create_buffer() = 0;
302  virtual bool send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) = 0;
303  virtual bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) = 0;
304 
305  template<class C> bool send_message_(const C &msg, uint32_t message_type) {
306  auto buffer = this->create_buffer();
307  msg.encode(buffer);
308  return this->send_buffer(buffer, message_type);
309  }
310 };
311 
312 } // namespace api
313 } // namespace esphome
void encode_fixed32(uint32_t field_id, uint32_t value, bool force=false)
Definition: proto.h:189
int32_t as_sint32() const
Definition: proto.h:58
uint8_t raw[35]
Definition: bl0939.h:19
std::vector< uint8_t > * get_buffer() const
Definition: proto.h:268
virtual bool decode_32bit(uint32_t field_id, Proto32Bit value)
Definition: proto.h:287
ProtoWriteBuffer(std::vector< uint8_t > *buffer)
Definition: proto.h:148
void encode_string(uint32_t field_id, const std::string &value, bool force=false)
Definition: proto.h:165
virtual bool decode_varint(uint32_t field_id, ProtoVarInt value)
Definition: proto.h:285
int64_t as_sfixed64() const
Definition: proto.h:132
Representation of a VarInt - in ProtoBuf should be 64bit but we only use 32bit.
Definition: proto.h:17
std::vector< uint8_t > * buffer_
Definition: proto.h:271
virtual bool decode_64bit(uint32_t field_id, Proto64Bit value)
Definition: proto.h:288
static optional< ProtoVarInt > parse(const uint8_t *buffer, uint32_t len, uint32_t *consumed)
Definition: proto.h:22
void encode_float(uint32_t field_id, float value, bool force=false)
Definition: proto.h:216
constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
Encode a 32-bit value given four bytes in most to least significant byte order.
Definition: helpers.h:187
std::string as_string() const
Definition: proto.h:98
void encode_uint64(uint32_t field_id, uint64_t value, bool force=false)
Definition: proto.h:177
mopeka_std_values val[4]
uint64_t as_fixed64() const
Definition: proto.h:131
const uint8_t *const value_
Definition: proto.h:106
const uint32_t value_
Definition: proto.h:125
float as_float() const
Definition: proto.h:115
Proto32Bit(uint32_t value)
Definition: proto.h:112
bool send_message_(const C &msg, uint32_t message_type)
Definition: proto.h:305
void encode_field_raw(uint32_t field_id, uint32_t type)
Definition: proto.h:152
void encode_sint32(uint32_t field_id, int32_t value, bool force=false)
Definition: proto.h:238
int32_t as_int32() const
Definition: proto.h:50
uint32_t as_fixed32() const
Definition: proto.h:113
uint64_t as_uint64() const
Definition: proto.h:47
const char * proto_enum_to_string(T value)
double as_double() const
Definition: proto.h:133
void encode_bool(uint32_t field_id, bool value, bool force=false)
Definition: proto.h:183
void encode(std::vector< uint8_t > &out)
Definition: proto.h:74
uint8_t type
void encode_uint32(uint32_t field_id, uint32_t value, bool force=false)
Definition: proto.h:171
virtual bool decode_length(uint32_t field_id, ProtoLengthDelimited value)
Definition: proto.h:286
void encode_int32(uint32_t field_id, int32_t value, bool force=false)
Definition: proto.h:227
int64_t as_sint64() const
Definition: proto.h:66
int32_t as_sfixed32() const
Definition: proto.h:114
bool as_bool() const
Definition: proto.h:48
void encode_fixed64(uint32_t field_id, uint64_t value, bool force=false)
Definition: proto.h:199
std::string size_t len
Definition: helpers.h:293
uint16_t length
Definition: tt21100.cpp:12
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
void write(uint8_t value)
Definition: proto.h:149
void encode_varint_raw(ProtoVarInt value)
Definition: proto.h:150
const uint64_t value_
Definition: proto.h:143
void encode_string(uint32_t field_id, const char *string, size_t len, bool force=false)
Definition: proto.h:156
void encode_varint_raw(uint32_t value)
Definition: proto.h:151
uint32_t as_uint32() const
Definition: proto.h:46
void encode_sint64(uint32_t field_id, int64_t value, bool force=false)
Definition: proto.h:247
ProtoLengthDelimited(const uint8_t *value, size_t length)
Definition: proto.h:97
void encode_enum(uint32_t field_id, T value, bool force=false)
Definition: proto.h:213
int64_t as_int64() const
Definition: proto.h:54
void encode_message(uint32_t field_id, const C &value, bool force=false)
Definition: proto.h:256
Proto64Bit(uint64_t value)
Definition: proto.h:130
void encode_bytes(uint32_t field_id, const uint8_t *data, size_t len, bool force=false)
Definition: proto.h:168
ProtoVarInt(uint64_t value)
Definition: proto.h:20
void encode_int64(uint32_t field_id, int64_t value, bool force=false)
Definition: proto.h:235