From ad2b74d9b49ec18c90bfc9f6404161faf29c1f78 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 7 May 2025 23:01:10 -0500 Subject: [PATCH] Correct Protobuf Wire Type for `encode_fixed64` (#8713) --- esphome/components/api/proto.h | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index 81e20d47be..bfa1a5c280 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -149,6 +149,18 @@ class ProtoWriteBuffer { void write(uint8_t value) { this->buffer_->push_back(value); } void encode_varint_raw(ProtoVarInt value) { value.encode(*this->buffer_); } void encode_varint_raw(uint32_t value) { this->encode_varint_raw(ProtoVarInt(value)); } + /** + * Encode a field key (tag/wire type combination). + * + * @param field_id Field number (tag) in the protobuf message + * @param type Wire type value: + * - 0: Varint (int32, int64, uint32, uint64, sint32, sint64, bool, enum) + * - 1: 64-bit (fixed64, sfixed64, double) + * - 2: Length-delimited (string, bytes, embedded messages, packed repeated fields) + * - 5: 32-bit (fixed32, sfixed32, float) + * + * Following https://protobuf.dev/programming-guides/encoding/#structure + */ void encode_field_raw(uint32_t field_id, uint32_t type) { uint32_t val = (field_id << 3) | (type & 0b111); this->encode_varint_raw(val); @@ -157,7 +169,7 @@ class ProtoWriteBuffer { if (len == 0 && !force) return; - this->encode_field_raw(field_id, 2); + this->encode_field_raw(field_id, 2); // type 2: Length-delimited string this->encode_varint_raw(len); auto *data = reinterpret_cast(string); this->buffer_->insert(this->buffer_->end(), data, data + len); @@ -171,26 +183,26 @@ class ProtoWriteBuffer { void encode_uint32(uint32_t field_id, uint32_t value, bool force = false) { if (value == 0 && !force) return; - this->encode_field_raw(field_id, 0); + this->encode_field_raw(field_id, 0); // type 0: Varint - uint32 this->encode_varint_raw(value); } void encode_uint64(uint32_t field_id, uint64_t value, bool force = false) { if (value == 0 && !force) return; - this->encode_field_raw(field_id, 0); + this->encode_field_raw(field_id, 0); // type 0: Varint - uint64 this->encode_varint_raw(ProtoVarInt(value)); } void encode_bool(uint32_t field_id, bool value, bool force = false) { if (!value && !force) return; - this->encode_field_raw(field_id, 0); + this->encode_field_raw(field_id, 0); // type 0: Varint - bool this->write(0x01); } void encode_fixed32(uint32_t field_id, uint32_t value, bool force = false) { if (value == 0 && !force) return; - this->encode_field_raw(field_id, 5); + this->encode_field_raw(field_id, 5); // type 5: 32-bit fixed32 this->write((value >> 0) & 0xFF); this->write((value >> 8) & 0xFF); this->write((value >> 16) & 0xFF); @@ -200,7 +212,7 @@ class ProtoWriteBuffer { if (value == 0 && !force) return; - this->encode_field_raw(field_id, 5); + this->encode_field_raw(field_id, 1); // type 1: 64-bit fixed64 this->write((value >> 0) & 0xFF); this->write((value >> 8) & 0xFF); this->write((value >> 16) & 0xFF); @@ -254,7 +266,7 @@ class ProtoWriteBuffer { this->encode_uint64(field_id, uvalue, force); } template void encode_message(uint32_t field_id, const C &value, bool force = false) { - this->encode_field_raw(field_id, 2); + this->encode_field_raw(field_id, 2); // type 2: Length-delimited message size_t begin = this->buffer_->size(); value.encode(*this);