This commit is contained in:
J. Nick Koston 2025-07-10 11:54:56 -10:00
parent b3bb059e42
commit ae945c9a96
No known key found for this signature in database
4 changed files with 88 additions and 50 deletions

View File

@ -100,14 +100,22 @@ const FieldMetaV3 DeviceInfoResponse::FIELDS_V3[20] = {
{16, 40, {.offset = PROTO_FIELD_OFFSET(DeviceInfoResponse, suggested_area)}},
{18, 40, {.offset = PROTO_FIELD_OFFSET(DeviceInfoResponse, bluetooth_mac_address)}},
{19, 32, {.offset = PROTO_FIELD_OFFSET(DeviceInfoResponse, api_encryption_supported)}},
{22, 42, {.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(DeviceInfoResponse, area)), .message_type_id = 9}}};
{22,
42,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(DeviceInfoResponse, area) & 0xFF),
.message_type_id =
static_cast<uint8_t>(9 | (((PROTO_FIELD_OFFSET(DeviceInfoResponse, area) >> 8) & 0x0F) << 4))}}};
const RepeatedFieldMetaV3 DeviceInfoResponse::REPEATED_FIELDS_V3[2] = {
{20,
42,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(DeviceInfoResponse, devices)), .message_type_id = 0}},
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(DeviceInfoResponse, devices) & 0xFF),
.message_type_id =
static_cast<uint8_t>(0 | (((PROTO_FIELD_OFFSET(DeviceInfoResponse, devices) >> 8) & 0x0F) << 4))}},
{21,
42,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(DeviceInfoResponse, areas)), .message_type_id = 1}}};
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(DeviceInfoResponse, areas) & 0xFF),
.message_type_id =
static_cast<uint8_t>(1 | (((PROTO_FIELD_OFFSET(DeviceInfoResponse, areas) >> 8) & 0x0F) << 4))}}};
#ifdef USE_BINARY_SENSOR
const FieldMetaV3 ListEntitiesBinarySensorResponse::FIELDS_V3[10] = {
{1, 8, {.offset = PROTO_FIELD_OFFSET(ListEntitiesBinarySensorResponse, object_id)}},
@ -342,16 +350,19 @@ const FieldMetaV3 HomeassistantServiceResponse::FIELDS_V3[2] = {
const RepeatedFieldMetaV3 HomeassistantServiceResponse::REPEATED_FIELDS_V3[3] = {
{2,
10,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(HomeassistantServiceResponse, data)),
.message_type_id = 2}},
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(HomeassistantServiceResponse, data) & 0xFF),
.message_type_id =
static_cast<uint8_t>(2 | (((PROTO_FIELD_OFFSET(HomeassistantServiceResponse, data) >> 8) & 0x0F) << 4))}},
{3,
10,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(HomeassistantServiceResponse, data_template)),
.message_type_id = 2}},
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(HomeassistantServiceResponse, data_template) & 0xFF),
.message_type_id = static_cast<uint8_t>(
2 | (((PROTO_FIELD_OFFSET(HomeassistantServiceResponse, data_template) >> 8) & 0x0F) << 4))}},
{4,
10,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(HomeassistantServiceResponse, variables)),
.message_type_id = 2}}};
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(HomeassistantServiceResponse, variables) & 0xFF),
.message_type_id = static_cast<uint8_t>(
2 | (((PROTO_FIELD_OFFSET(HomeassistantServiceResponse, variables) >> 8) & 0x0F) << 4))}}};
const FieldMetaV3 SubscribeHomeAssistantStateResponse::FIELDS_V3[3] = {
{1, 8, {.offset = PROTO_FIELD_OFFSET(SubscribeHomeAssistantStateResponse, entity_id)}},
{2, 8, {.offset = PROTO_FIELD_OFFSET(SubscribeHomeAssistantStateResponse, attribute)}},
@ -371,8 +382,9 @@ const FieldMetaV3 ListEntitiesServicesResponse::FIELDS_V3[2] = {
const RepeatedFieldMetaV3 ListEntitiesServicesResponse::REPEATED_FIELDS_V3[1] = {
{3,
10,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(ListEntitiesServicesResponse, args)),
.message_type_id = 3}}};
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(ListEntitiesServicesResponse, args) & 0xFF),
.message_type_id =
static_cast<uint8_t>(3 | (((PROTO_FIELD_OFFSET(ListEntitiesServicesResponse, args) >> 8) & 0x0F) << 4))}}};
const FieldMetaV3 ExecuteServiceArgument::FIELDS_V3[5] = {
{1, 0, {.offset = PROTO_FIELD_OFFSET(ExecuteServiceArgument, bool_)}},
{2, 1, {.offset = PROTO_FIELD_OFFSET(ExecuteServiceArgument, legacy_int)}},
@ -389,7 +401,9 @@ const FieldMetaV3 ExecuteServiceRequest::FIELDS_V3[1] = {
const RepeatedFieldMetaV3 ExecuteServiceRequest::REPEATED_FIELDS_V3[1] = {
{2,
10,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(ExecuteServiceRequest, args)), .message_type_id = 4}}};
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(ExecuteServiceRequest, args) & 0xFF),
.message_type_id =
static_cast<uint8_t>(4 | (((PROTO_FIELD_OFFSET(ExecuteServiceRequest, args) >> 8) & 0x0F) << 4))}}};
#ifdef USE_CAMERA
const FieldMetaV3 ListEntitiesCameraResponse::FIELDS_V3[8] = {
{1, 8, {.offset = PROTO_FIELD_OFFSET(ListEntitiesCameraResponse, object_id)}},
@ -612,8 +626,9 @@ const FieldMetaV3 ListEntitiesMediaPlayerResponse::FIELDS_V3[9] = {
const RepeatedFieldMetaV3 ListEntitiesMediaPlayerResponse::REPEATED_FIELDS_V3[1] = {
{9,
10,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(ListEntitiesMediaPlayerResponse, supported_formats)),
.message_type_id = 5}}};
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(ListEntitiesMediaPlayerResponse, supported_formats) & 0xFF),
.message_type_id = static_cast<uint8_t>(
5 | (((PROTO_FIELD_OFFSET(ListEntitiesMediaPlayerResponse, supported_formats) >> 8) & 0x0F) << 4))}}};
const FieldMetaV3 MediaPlayerStateResponse::FIELDS_V3[5] = {
{1, 12, {.offset = PROTO_FIELD_OFFSET(MediaPlayerStateResponse, key)}},
{2, 7, {.offset = PROTO_FIELD_OFFSET(MediaPlayerStateResponse, state)}},
@ -648,12 +663,15 @@ const RepeatedFieldMetaV3 BluetoothLEAdvertisementResponse::REPEATED_FIELDS_V3[3
{4, 8, {.offset = PROTO_FIELD_OFFSET(BluetoothLEAdvertisementResponse, service_uuids)}},
{5,
10,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(BluetoothLEAdvertisementResponse, service_data)),
.message_type_id = 6}},
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(BluetoothLEAdvertisementResponse, service_data) & 0xFF),
.message_type_id = static_cast<uint8_t>(
6 | (((PROTO_FIELD_OFFSET(BluetoothLEAdvertisementResponse, service_data) >> 8) & 0x0F) << 4))}},
{6,
10,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(BluetoothLEAdvertisementResponse, manufacturer_data)),
.message_type_id = 6}}};
{.offset_low =
static_cast<uint8_t>(PROTO_FIELD_OFFSET(BluetoothLEAdvertisementResponse, manufacturer_data) & 0xFF),
.message_type_id = static_cast<uint8_t>(
6 | (((PROTO_FIELD_OFFSET(BluetoothLEAdvertisementResponse, manufacturer_data) >> 8) & 0x0F) << 4))}}};
const FieldMetaV3 BluetoothLERawAdvertisement::FIELDS_V3[4] = {
{1, 4, {.offset = PROTO_FIELD_OFFSET(BluetoothLERawAdvertisement, address)}},
{2, 5, {.offset = PROTO_FIELD_OFFSET(BluetoothLERawAdvertisement, rssi)}},
@ -662,8 +680,10 @@ const FieldMetaV3 BluetoothLERawAdvertisement::FIELDS_V3[4] = {
const RepeatedFieldMetaV3 BluetoothLERawAdvertisementsResponse::REPEATED_FIELDS_V3[1] = {
{1,
10,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(BluetoothLERawAdvertisementsResponse, advertisements)),
.message_type_id = 7}}};
{.offset_low =
static_cast<uint8_t>(PROTO_FIELD_OFFSET(BluetoothLERawAdvertisementsResponse, advertisements) & 0xFF),
.message_type_id = static_cast<uint8_t>(
7 | (((PROTO_FIELD_OFFSET(BluetoothLERawAdvertisementsResponse, advertisements) >> 8) & 0x0F) << 4))}}};
const FieldMetaV3 BluetoothDeviceRequest::FIELDS_V3[4] = {
{1, 4, {.offset = PROTO_FIELD_OFFSET(BluetoothDeviceRequest, address)}},
{2, 7, {.offset = PROTO_FIELD_OFFSET(BluetoothDeviceRequest, request_type)}},
@ -687,23 +707,26 @@ const RepeatedFieldMetaV3 BluetoothGATTCharacteristic::REPEATED_FIELDS_V3[2] = {
{1, 4, {.offset = PROTO_FIELD_OFFSET(BluetoothGATTCharacteristic, uuid)}},
{4,
10,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(BluetoothGATTCharacteristic, descriptors)),
.message_type_id = 8}}};
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(BluetoothGATTCharacteristic, descriptors) & 0xFF),
.message_type_id = static_cast<uint8_t>(
8 | (((PROTO_FIELD_OFFSET(BluetoothGATTCharacteristic, descriptors) >> 8) & 0x0F) << 4))}}};
const FieldMetaV3 BluetoothGATTService::FIELDS_V3[1] = {
{2, 2, {.offset = PROTO_FIELD_OFFSET(BluetoothGATTService, handle)}}};
const RepeatedFieldMetaV3 BluetoothGATTService::REPEATED_FIELDS_V3[2] = {
{1, 4, {.offset = PROTO_FIELD_OFFSET(BluetoothGATTService, uuid)}},
{3,
10,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(BluetoothGATTService, characteristics)),
.message_type_id = 9}}};
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(BluetoothGATTService, characteristics) & 0xFF),
.message_type_id =
static_cast<uint8_t>(9 | (((PROTO_FIELD_OFFSET(BluetoothGATTService, characteristics) >> 8) & 0x0F) << 4))}}};
const FieldMetaV3 BluetoothGATTGetServicesResponse::FIELDS_V3[1] = {
{1, 4, {.offset = PROTO_FIELD_OFFSET(BluetoothGATTGetServicesResponse, address)}}};
const RepeatedFieldMetaV3 BluetoothGATTGetServicesResponse::REPEATED_FIELDS_V3[1] = {
{2,
10,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(BluetoothGATTGetServicesResponse, services)),
.message_type_id = 10}}};
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(BluetoothGATTGetServicesResponse, services) & 0xFF),
.message_type_id = static_cast<uint8_t>(
10 | (((PROTO_FIELD_OFFSET(BluetoothGATTGetServicesResponse, services) >> 8) & 0x0F) << 4))}}};
const FieldMetaV3 BluetoothGATTGetServicesDoneResponse::FIELDS_V3[1] = {
{1, 4, {.offset = PROTO_FIELD_OFFSET(BluetoothGATTGetServicesDoneResponse, address)}}};
const FieldMetaV3 BluetoothGATTReadRequest::FIELDS_V3[2] = {
@ -780,8 +803,9 @@ const FieldMetaV3 VoiceAssistantRequest::FIELDS_V3[5] = {
{3, 2, {.offset = PROTO_FIELD_OFFSET(VoiceAssistantRequest, flags)}},
{4,
10,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(VoiceAssistantRequest, audio_settings)),
.message_type_id = 105}},
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(VoiceAssistantRequest, audio_settings) & 0xFF),
.message_type_id = static_cast<uint8_t>(
105 | (((PROTO_FIELD_OFFSET(VoiceAssistantRequest, audio_settings) >> 8) & 0x0F) << 4))}},
{5, 8, {.offset = PROTO_FIELD_OFFSET(VoiceAssistantRequest, wake_word_phrase)}}};
const FieldMetaV3 VoiceAssistantResponse::FIELDS_V3[2] = {
{1, 2, {.offset = PROTO_FIELD_OFFSET(VoiceAssistantResponse, port)}},
@ -794,8 +818,9 @@ const FieldMetaV3 VoiceAssistantEventResponse::FIELDS_V3[1] = {
const RepeatedFieldMetaV3 VoiceAssistantEventResponse::REPEATED_FIELDS_V3[1] = {
{2,
10,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(VoiceAssistantEventResponse, data)),
.message_type_id = 11}}};
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(VoiceAssistantEventResponse, data) & 0xFF),
.message_type_id =
static_cast<uint8_t>(11 | (((PROTO_FIELD_OFFSET(VoiceAssistantEventResponse, data) >> 8) & 0x0F) << 4))}}};
const FieldMetaV3 VoiceAssistantAudio::FIELDS_V3[2] = {
{1, 9, {.offset = PROTO_FIELD_OFFSET(VoiceAssistantAudio, data)}},
{2, 0, {.offset = PROTO_FIELD_OFFSET(VoiceAssistantAudio, end)}}};
@ -823,8 +848,10 @@ const FieldMetaV3 VoiceAssistantConfigurationResponse::FIELDS_V3[1] = {
const RepeatedFieldMetaV3 VoiceAssistantConfigurationResponse::REPEATED_FIELDS_V3[2] = {
{1,
10,
{.offset_low = static_cast<uint8_t>(PROTO_FIELD_OFFSET(VoiceAssistantConfigurationResponse, available_wake_words)),
.message_type_id = 12}},
{.offset_low =
static_cast<uint8_t>(PROTO_FIELD_OFFSET(VoiceAssistantConfigurationResponse, available_wake_words) & 0xFF),
.message_type_id = static_cast<uint8_t>(
12 | (((PROTO_FIELD_OFFSET(VoiceAssistantConfigurationResponse, available_wake_words) >> 8) & 0x0F) << 4))}},
{2, 8, {.offset = PROTO_FIELD_OFFSET(VoiceAssistantConfigurationResponse, active_wake_words)}}};
const RepeatedFieldMetaV3 VoiceAssistantSetConfiguration::REPEATED_FIELDS_V3[1] = {
{1, 8, {.offset = PROTO_FIELD_OFFSET(VoiceAssistantSetConfiguration, active_wake_words)}}};

View File

@ -284,9 +284,10 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) {
case ProtoFieldType::TYPE_MESSAGE: {
// Use repeated message handler registry
uint8_t handler_id = repeated_fields[j].get_message_type_id();
ESP_LOGD(TAG, "Repeated TYPE_MESSAGE field %d, handler_id=%d, REPEATED_MESSAGE_HANDLER_COUNT=%zu",
ESP_LOGD(TAG, "Repeated TYPE_MESSAGE field %d, handler_id=%d, REPEATED_MESSAGE_HANDLER_COUNT=%zu",
field_id, handler_id, REPEATED_MESSAGE_HANDLER_COUNT);
if (handler_id < REPEATED_MESSAGE_HANDLER_COUNT && REPEATED_MESSAGE_HANDLERS[handler_id].decode != nullptr) {
if (handler_id < REPEATED_MESSAGE_HANDLER_COUNT &&
REPEATED_MESSAGE_HANDLERS[handler_id].decode != nullptr) {
decoded = REPEATED_MESSAGE_HANDLERS[handler_id].decode(field_addr, value);
ESP_LOGD(TAG, "Decoded repeated message field %d: %s", field_id, decoded ? "success" : "failed");
} else {
@ -583,8 +584,9 @@ void ProtoMessage::encode(ProtoWriteBuffer buffer) const {
}
case ProtoFieldType::TYPE_MESSAGE: {
// Use message handler registry
if (fields[i].get_message_type_id() < MESSAGE_HANDLER_COUNT) {
MESSAGE_HANDLERS[fields[i].get_message_type_id()].encode(buffer, field_addr, fields[i].field_num);
uint8_t handler_id = fields[i].get_message_type_id();
if (handler_id < MESSAGE_HANDLER_COUNT && MESSAGE_HANDLERS[handler_id].encode != nullptr) {
MESSAGE_HANDLERS[handler_id].encode(buffer, field_addr, fields[i].field_num);
}
break;
}
@ -821,9 +823,9 @@ void ProtoMessage::calculate_size(uint32_t &total_size) const {
}
case ProtoFieldType::TYPE_MESSAGE: {
// Use message handler registry
if (fields[i].get_message_type_id() < MESSAGE_HANDLER_COUNT) {
MESSAGE_HANDLERS[fields[i].get_message_type_id()].size(total_size, field_addr,
fields[i].get_precalced_size(), false);
uint8_t handler_id = fields[i].get_message_type_id();
if (handler_id < MESSAGE_HANDLER_COUNT && MESSAGE_HANDLERS[handler_id].size != nullptr) {
MESSAGE_HANDLERS[handler_id].size(total_size, field_addr, fields[i].get_precalced_size(), false);
}
break;
}
@ -834,8 +836,8 @@ void ProtoMessage::calculate_size(uint32_t &total_size) const {
const RepeatedFieldMetaV3 *repeated_fields = get_repeated_field_metadata_v3();
size_t repeated_count = get_repeated_field_count_v3();
for (size_t i = 0; i < repeated_count; i++) {
if (repeated_fields != nullptr) {
if (repeated_fields != nullptr) {
for (size_t i = 0; i < repeated_count; i++) {
const void *field_addr = base + repeated_fields[i].get_offset();
switch (repeated_fields[i].get_type()) {

View File

@ -298,11 +298,13 @@ struct FieldMetaV3 {
uint8_t get_precalced_size() const { return ((type_and_size >> 5) & 0x03) + 1; }
uint16_t get_offset() const {
if (get_type() == ProtoFieldType::TYPE_MESSAGE) {
return offset_low; // Limited to 255 for messages
// Reconstruct full offset from packed fields
// Bits 0-7 from offset_low, bits 8-11 from upper nibble of message_type_id
return static_cast<uint16_t>(offset_low) | (static_cast<uint16_t>(message_type_id & 0xF0) << 4);
}
return offset;
}
uint8_t get_message_type_id() const { return message_type_id; }
uint8_t get_message_type_id() const { return message_type_id & 0x0F; }
};
// V2 structures removed - we only use V3 now
@ -484,11 +486,13 @@ struct RepeatedFieldMetaV3 {
uint8_t get_precalced_size() const { return ((type_and_size >> 5) & 0x03) + 1; }
uint16_t get_offset() const {
if (get_type() == ProtoFieldType::TYPE_MESSAGE) {
return offset_low; // Limited to 255 for messages
// Reconstruct full offset from packed fields
// Bits 0-7 from offset_low, bits 8-11 from upper nibble of message_type_id
return static_cast<uint16_t>(offset_low) | (static_cast<uint16_t>(message_type_id & 0xF0) << 4);
}
return offset;
}
uint8_t get_message_type_id() const { return message_type_id; }
uint8_t get_message_type_id() const { return message_type_id & 0x0F; }
};
// V2 structures removed - we only use V3 now

View File

@ -1344,11 +1344,11 @@ def build_message_type(
type_and_size = (type_num & 0x1F) | ((field_tag_size - 1) << 5)
if field.type == descriptor.FieldDescriptorProto.TYPE_MESSAGE:
# For messages, use offset_low and message_type_id
# For messages, use offset_low and message_type_id with offset extension
message_type_id = get_repeated_message_type_id(ti._ti.type_name)
offset = f"PROTO_FIELD_OFFSET({desc.name}, {ti.field_name})"
repeated_fields_v3.append(
f"{{{field.number}, {type_and_size}, {{.offset_low = static_cast<uint8_t>({offset}), .message_type_id = {message_type_id}}}}}"
f"{{{field.number}, {type_and_size}, {{.offset_low = static_cast<uint8_t>({offset} & 0xFF), .message_type_id = static_cast<uint8_t>({message_type_id} | ((({offset} >> 8) & 0x0F) << 4))}}}}"
)
else:
# Non-message types use full offset
@ -1369,9 +1369,13 @@ def build_message_type(
# For messages, use offset_low and message_type_id
message_type_id = get_message_type_id(ti.type_name)
offset = f"PROTO_FIELD_OFFSET({desc.name}, {ti.field_name})"
# Check if offset fits in 8 bits
# Since we have so few message types, we can use the upper bits of
# message_type_id to extend the offset range
# Bits 0-3: actual message type ID (supports 16 types)
# Bits 4-7: bits 8-11 of offset (extends offset to 12 bits = 4096)
regular_fields_v3.append(
f"{{{field.number}, {type_and_size}, {{.offset_low = static_cast<uint8_t>({offset}), .message_type_id = {message_type_id}}}}}"
f"{{{field.number}, {type_and_size}, {{.offset_low = static_cast<uint8_t>({offset} & 0xFF), .message_type_id = static_cast<uint8_t>({message_type_id} | ((({offset} >> 8) & 0x0F) << 4))}}}}"
)
else:
# Non-message types use full offset
@ -1391,8 +1395,9 @@ def build_message_type(
type_and_size = (10 & 0x1F) | ((field_tag_size - 1) << 5)
message_type_id = get_message_type_id(ti.type_name)
offset = f"PROTO_FIELD_OFFSET({desc.name}, {ti.field_name})"
# Same encoding as above for large offsets
regular_fields_v3.append(
f"{{{field.number}, {type_and_size}, {{.offset_low = static_cast<uint8_t>({offset}), .message_type_id = {message_type_id}}}}}"
f"{{{field.number}, {type_and_size}, {{.offset_low = static_cast<uint8_t>({offset} & 0xFF), .message_type_id = static_cast<uint8_t>({message_type_id} | ((({offset} >> 8) & 0x0F) << 4))}}}}"
)
# Store metadata info for later generation outside the class