ESPHome  2022.12.8
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  for (size_t i = 0; i < len; i++)
164  this->write(data[i]);
165  }
166  void encode_string(uint32_t field_id, const std::string &value, bool force = false) {
167  this->encode_string(field_id, value.data(), value.size());
168  }
169  void encode_bytes(uint32_t field_id, const uint8_t *data, size_t len, bool force = false) {
170  this->encode_string(field_id, reinterpret_cast<const char *>(data), len, force);
171  }
172  void encode_uint32(uint32_t field_id, uint32_t value, bool force = false) {
173  if (value == 0 && !force)
174  return;
175  this->encode_field_raw(field_id, 0);
176  this->encode_varint_raw(value);
177  }
178  void encode_uint64(uint32_t field_id, uint64_t value, bool force = false) {
179  if (value == 0 && !force)
180  return;
181  this->encode_field_raw(field_id, 0);
182  this->encode_varint_raw(ProtoVarInt(value));
183  }
184  void encode_bool(uint32_t field_id, bool value, bool force = false) {
185  if (!value && !force)
186  return;
187  this->encode_field_raw(field_id, 0);
188  this->write(0x01);
189  }
190  void encode_fixed32(uint32_t field_id, uint32_t value, bool force = false) {
191  if (value == 0 && !force)
192  return;
193 
194  this->encode_field_raw(field_id, 5);
195  this->write((value >> 0) & 0xFF);
196  this->write((value >> 8) & 0xFF);
197  this->write((value >> 16) & 0xFF);
198  this->write((value >> 24) & 0xFF);
199  }
200  void encode_fixed64(uint32_t field_id, uint64_t value, bool force = false) {
201  if (value == 0 && !force)
202  return;
203 
204  this->encode_field_raw(field_id, 5);
205  this->write((value >> 0) & 0xFF);
206  this->write((value >> 8) & 0xFF);
207  this->write((value >> 16) & 0xFF);
208  this->write((value >> 24) & 0xFF);
209  this->write((value >> 32) & 0xFF);
210  this->write((value >> 40) & 0xFF);
211  this->write((value >> 48) & 0xFF);
212  this->write((value >> 56) & 0xFF);
213  }
214  template<typename T> void encode_enum(uint32_t field_id, T value, bool force = false) {
215  this->encode_uint32(field_id, static_cast<uint32_t>(value), force);
216  }
217  void encode_float(uint32_t field_id, float value, bool force = false) {
218  if (value == 0.0f && !force)
219  return;
220 
221  union {
222  float value;
223  uint32_t raw;
224  } val{};
225  val.value = value;
226  this->encode_fixed32(field_id, val.raw);
227  }
228  void encode_int32(uint32_t field_id, int32_t value, bool force = false) {
229  if (value < 0) {
230  // negative int32 is always 10 byte long
231  this->encode_int64(field_id, value, force);
232  return;
233  }
234  this->encode_uint32(field_id, static_cast<uint32_t>(value), force);
235  }
236  void encode_int64(uint32_t field_id, int64_t value, bool force = false) {
237  this->encode_uint64(field_id, static_cast<uint64_t>(value), force);
238  }
239  void encode_sint32(uint32_t field_id, int32_t value, bool force = false) {
240  uint32_t uvalue;
241  if (value < 0) {
242  uvalue = ~(value << 1);
243  } else {
244  uvalue = value << 1;
245  }
246  this->encode_uint32(field_id, uvalue, force);
247  }
248  void encode_sint64(uint32_t field_id, int64_t value, bool force = false) {
249  uint64_t uvalue;
250  if (value < 0) {
251  uvalue = ~(value << 1);
252  } else {
253  uvalue = value << 1;
254  }
255  this->encode_uint64(field_id, uvalue, force);
256  }
257  template<class C> void encode_message(uint32_t field_id, const C &value, bool force = false) {
258  this->encode_field_raw(field_id, 2);
259  size_t begin = this->buffer_->size();
260 
261  value.encode(*this);
262 
263  const uint32_t nested_length = this->buffer_->size() - begin;
264  // add size varint
265  std::vector<uint8_t> var;
266  ProtoVarInt(nested_length).encode(var);
267  this->buffer_->insert(this->buffer_->begin() + begin, var.begin(), var.end());
268  }
269  std::vector<uint8_t> *get_buffer() const { return buffer_; }
270 
271  protected:
272  std::vector<uint8_t> *buffer_;
273 };
274 
276  public:
277  virtual ~ProtoMessage() = default;
278  virtual void encode(ProtoWriteBuffer buffer) const = 0;
279  void decode(const uint8_t *buffer, size_t length);
280 #ifdef HAS_PROTO_MESSAGE_DUMP
281  std::string dump() const;
282  virtual void dump_to(std::string &out) const = 0;
283 #endif
284 
285  protected:
286  virtual bool decode_varint(uint32_t field_id, ProtoVarInt value) { return false; }
287  virtual bool decode_length(uint32_t field_id, ProtoLengthDelimited value) { return false; }
288  virtual bool decode_32bit(uint32_t field_id, Proto32Bit value) { return false; }
289  virtual bool decode_64bit(uint32_t field_id, Proto64Bit value) { return false; }
290 };
291 
292 template<typename T> const char *proto_enum_to_string(T value);
293 
295  public:
296  protected:
297  virtual bool is_authenticated() = 0;
298  virtual bool is_connection_setup() = 0;
299  virtual void on_fatal_error() = 0;
300  virtual void on_unauthenticated_access() = 0;
301  virtual void on_no_setup_connection() = 0;
302  virtual ProtoWriteBuffer create_buffer() = 0;
303  virtual bool send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) = 0;
304  virtual bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) = 0;
305 
306  template<class C> bool send_message_(const C &msg, uint32_t message_type) {
307  auto buffer = this->create_buffer();
308  msg.encode(buffer);
309  return this->send_buffer(buffer, message_type);
310  }
311 };
312 
313 } // namespace api
314 } // namespace esphome
void encode_fixed32(uint32_t field_id, uint32_t value, bool force=false)
Definition: proto.h:190
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:269
virtual bool decode_32bit(uint32_t field_id, Proto32Bit value)
Definition: proto.h:288
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:166
virtual bool decode_varint(uint32_t field_id, ProtoVarInt value)
Definition: proto.h:286
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:272
virtual bool decode_64bit(uint32_t field_id, Proto64Bit value)
Definition: proto.h:289
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:217
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:175
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:178
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:306
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:239
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:184
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:172
virtual bool decode_length(uint32_t field_id, ProtoLengthDelimited value)
Definition: proto.h:287
void encode_int32(uint32_t field_id, int32_t value, bool force=false)
Definition: proto.h:228
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:200
std::string size_t len
Definition: helpers.h:281
Definition: a4988.cpp:4
void write(uint8_t value)
Definition: proto.h:149
uint32_t val
Definition: datatypes.h:85
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:248
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:214
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:257
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:169
ProtoVarInt(uint64_t value)
Definition: proto.h:20
void encode_int64(uint32_t field_id, int64_t value, bool force=false)
Definition: proto.h:236