mirror of
https://github.com/esphome/esphome.git
synced 2025-09-04 04:12:23 +01:00
fixed ble adv
This commit is contained in:
@@ -339,6 +339,11 @@ def create_field_type_info(
|
||||
) -> TypeInfo:
|
||||
"""Create the appropriate TypeInfo instance for a field, handling repeated fields and custom options."""
|
||||
if field.label == 3: # repeated
|
||||
# Check if this repeated field has fixed_array_with_length_define option
|
||||
if (
|
||||
fixed_size := get_field_opt(field, pb.fixed_array_with_length_define)
|
||||
) is not None:
|
||||
return FixedArrayWithLengthRepeatedType(field, fixed_size)
|
||||
# Check if this repeated field has fixed_array_size option
|
||||
if (fixed_size := get_field_opt(field, pb.fixed_array_size)) is not None:
|
||||
return FixedArrayRepeatedType(field, fixed_size)
|
||||
@@ -1230,6 +1235,72 @@ class FixedArrayRepeatedType(TypeInfo):
|
||||
return underlying_size * self.array_size
|
||||
|
||||
|
||||
class FixedArrayWithLengthRepeatedType(FixedArrayRepeatedType):
|
||||
"""Special type for fixed-size repeated fields with variable length tracking.
|
||||
|
||||
Similar to FixedArrayRepeatedType but generates an additional length field
|
||||
to track how many elements are actually in use. Only encodes/sends elements
|
||||
up to the current length.
|
||||
|
||||
Fixed arrays with length are only supported for encoding (SOURCE_SERVER) since
|
||||
we cannot control how many items we receive when decoding.
|
||||
"""
|
||||
|
||||
@property
|
||||
def public_content(self) -> list[str]:
|
||||
# Return both the array and the length field
|
||||
return [
|
||||
f"{self.cpp_type} {self.field_name}{{}};",
|
||||
f"uint16_t {self.field_name}_len{{0}};",
|
||||
]
|
||||
|
||||
@property
|
||||
def encode_content(self) -> str:
|
||||
# Helper to generate encode statement for a single element
|
||||
def encode_element(element: str) -> str:
|
||||
if isinstance(self._ti, EnumType):
|
||||
return f"buffer.{self._ti.encode_func}({self.number}, static_cast<uint32_t>({element}), true);"
|
||||
return f"buffer.{self._ti.encode_func}({self.number}, {element}, true);"
|
||||
|
||||
# Always use a loop up to the current length
|
||||
o = f"for (uint16_t i = 0; i < this->{self.field_name}_len; i++) {{\n"
|
||||
o += f" {encode_element(f'this->{self.field_name}[i]')}\n"
|
||||
o += "}"
|
||||
return o
|
||||
|
||||
@property
|
||||
def dump_content(self) -> str:
|
||||
# Dump only the active elements
|
||||
o = f"for (uint16_t i = 0; i < this->{self.field_name}_len; i++) {{\n"
|
||||
# Check if underlying type can use dump_field
|
||||
if type(self._ti).can_use_dump_field():
|
||||
o += f' dump_field(out, "{self.name}", {self._ti.dump_field_value(f"this->{self.field_name}[i]")}, 4);\n'
|
||||
else:
|
||||
o += f' out.append(" {self.name}: ");\n'
|
||||
o += indent(self._ti.dump(f"this->{self.field_name}[i]")) + "\n"
|
||||
o += ' out.append("\\n");\n'
|
||||
o += "}"
|
||||
return o
|
||||
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
# Calculate size only for active elements
|
||||
o = f"for (uint16_t i = 0; i < {name}_len; i++) {{\n"
|
||||
o += f" {self._ti.get_size_calculation(f'{name}[i]', True)}\n"
|
||||
o += "}"
|
||||
return o
|
||||
|
||||
def get_estimated_size(self) -> int:
|
||||
# For fixed arrays with length, estimate based on typical usage
|
||||
# Assume on average half the array is used
|
||||
underlying_size = self._ti.get_estimated_size()
|
||||
if self.is_define:
|
||||
# When using a define, estimate 8 elements as typical
|
||||
return underlying_size * 8
|
||||
return underlying_size * (
|
||||
self.array_size // 2 if self.array_size > 2 else self.array_size
|
||||
)
|
||||
|
||||
|
||||
class RepeatedTypeInfo(TypeInfo):
|
||||
def __init__(self, field: descriptor.FieldDescriptorProto) -> None:
|
||||
super().__init__(field)
|
||||
@@ -1711,6 +1782,19 @@ def build_message_type(
|
||||
f"since we cannot trust or control the number of items received from clients."
|
||||
)
|
||||
|
||||
# Validate that fixed_array_with_length_define is only used in encode-only messages
|
||||
if (
|
||||
needs_decode
|
||||
and field.label == 3
|
||||
and get_field_opt(field, pb.fixed_array_with_length_define) is not None
|
||||
):
|
||||
raise ValueError(
|
||||
f"Message '{desc.name}' uses fixed_array_with_length_define on field '{field.name}' "
|
||||
f"but has source={SOURCE_NAMES[source]}. "
|
||||
f"Fixed arrays with length are only supported for SOURCE_SERVER (encode-only) messages "
|
||||
f"since we cannot trust or control the number of items received from clients."
|
||||
)
|
||||
|
||||
ti = create_field_type_info(field, needs_decode, needs_encode)
|
||||
|
||||
# Skip field declarations for fields that are in the base class
|
||||
|
Reference in New Issue
Block a user