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