Merge remote-tracking branch 'upstream-ssh/ble-mac-varint-48bit' into integration

This commit is contained in:
J. Nick Koston
2026-04-25 04:47:46 -05:00
10 changed files with 221 additions and 7 deletions
+26 -1
View File
@@ -184,6 +184,11 @@ class TypeInfo(ABC):
"""Check if this field should always be encoded (skip zero/empty check)."""
return get_field_opt(self._field, pb.force, False)
@property
def mac_address(self) -> bool:
"""Check if this uint64 field is a 48-bit MAC address (use 7-byte fast path)."""
return get_field_opt(self._field, pb.mac_address, False)
@property
def max_value(self) -> int | None:
"""Get the max_value option for this field, or None if not set."""
@@ -665,8 +670,22 @@ class UInt64Type(VarintTypeMixin, TypeInfo):
return o
def get_size_calculation(self, name: str, force: bool = False) -> str:
if self.mac_address and force:
field_id_size = self.calculate_field_id_size()
return (
f"size += ProtoSize::calc_uint64_48bit_force({field_id_size}, {name});"
)
return self._get_simple_size_calculation(name, force, "uint64")
@property
def RAW_ENCODE_MAP(self) -> dict[str, str]: # noqa: N802
if self.mac_address:
return {
**TypeInfo.RAW_ENCODE_MAP,
"encode_uint64": "ProtoEncode::encode_varint_raw_48bit(pos, {value});",
}
return TypeInfo.RAW_ENCODE_MAP
def get_estimated_size(self) -> int:
return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint
@@ -3558,8 +3577,13 @@ static const char *const TAG = "api.service";
# Generate read_message_ as APIConnection method (not base class) so the compiler
# can devirtualize and inline the on_* handler calls within the same class.
# APIConnection declares this method in api_connection.h.
# Guard with #ifdef USE_API since APIConnection itself is only defined when
# USE_API is set; without this, builds that compile this .cpp without
# USE_API (e.g. C++ unit tests for api dependencies) fail to find the
# class declaration.
out = "void APIConnection::read_message_(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) {\n"
out = "#ifdef USE_API\n"
out += "void APIConnection::read_message_(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) {\n"
# Auth check block before dispatch switch
out += " // Check authentication/connection requirements\n"
@@ -3604,6 +3628,7 @@ static const char *const TAG = "api.service";
out += " break;\n"
out += " }\n"
out += "}\n"
out += "#endif // USE_API\n"
cpp += out
hpp += "};\n"
+17 -2
View File
@@ -324,8 +324,23 @@ def compile_and_get_binary(
domain_list.append({CONF_PLATFORM: component})
# Skip "core" — it's a pseudo-component handled by the build
# system, not a real loadable component (get_component returns None)
elif get_component(component_name) is not None:
config.setdefault(component_name, [])
elif (component := get_component(component_name)) is not None:
# MULTI_CONF components store their config as a list of dicts,
# everything else stores a single dict. Run the component's
# schema with {} so defaults get populated -- code paths like
# socket.FILTER_SOURCE_FILES expect a fully-populated mapping.
if component.multi_conf:
config.setdefault(component_name, [])
elif component_name not in config:
schema = component.config_schema
try:
config[component_name] = schema({}) if schema is not None else {}
except Exception: # noqa: BLE001
# Schema requires explicit input we can't synthesize; fall
# back to an empty mapping so subscripting at least returns
# KeyError on missing keys rather than crashing on the
# wrong type.
config[component_name] = {}
# Register platforms from the extra config (benchmark.yaml) so
# USE_SENSOR, USE_LIGHT, etc. defines are emitted without needing