components/esp-matter: Split attribute val's usage in data model core

We have attribute base which only contains the id and flags.
But having the data type would be benefitial when fetching value for
internally managed attributes. So, rather than guessing the type we
can fetch it.
This commit is contained in:
Shubham Patil
2025-11-21 18:17:35 +05:30
parent 8462ff05f0
commit 1ca78a590f
@@ -55,12 +55,13 @@ namespace esp_matter {
struct _attribute_base_t {
uint16_t flags; // This struct is for attributes managed internally.
esp_matter_val_type_t attribute_val_type;
uint32_t attribute_id;
struct _attribute_base_t *next;
};
struct _attribute_t : public _attribute_base_t {
esp_matter_attr_val_t val;
esp_matter_val_t attribute_val;
esp_matter_attr_bounds_t *bounds;
uint16_t endpoint_id;
uint32_t cluster_id;
@@ -219,7 +220,7 @@ static esp_err_t init_identification(endpoint_t *endpoint)
_attribute_t *identify_type_attr = (_attribute_t *)attribute::get(
identify_cluster, chip::app::Clusters::Identify::Attributes::IdentifyType::Id);
if (identify_type_attr) {
return identification::init(current_endpoint->endpoint_id, identify_type_attr->val.val.u8);
return identification::init(current_endpoint->endpoint_id, identify_type_attr->attribute_val.u8);
} else {
ESP_LOGE(TAG, "Can't get IdentifyType attribute in Identify cluster");
return ESP_ERR_INVALID_STATE;
@@ -464,11 +465,14 @@ static int compare_attr_val_with_bounds(esp_matter_attr_val_t val, esp_matter_at
static esp_err_t bound_attribute_val(attribute_t *attribute)
{
_attribute_t *current_attribute = (_attribute_t *)attribute;
int compare_result = compare_attr_val_with_bounds(current_attribute->val, *current_attribute->bounds);
esp_matter_attr_val_t temp_val;
temp_val.type = current_attribute->attribute_val_type;
temp_val.val = current_attribute->attribute_val;
int compare_result = compare_attr_val_with_bounds(temp_val, *current_attribute->bounds);
if (compare_result == 1) {
current_attribute->val = current_attribute->bounds->max;
current_attribute->attribute_val = current_attribute->bounds->max.val;
} else if (compare_result == -1) {
current_attribute->val = current_attribute->bounds->min;
current_attribute->attribute_val = current_attribute->bounds->min.val;
} else if (compare_result != 0) {
return ESP_ERR_INVALID_ARG;
}
@@ -498,6 +502,7 @@ attribute_t *create(cluster_t *cluster, uint32_t attribute_id, uint16_t flags, e
/* Set */
attribute->flags = flags;
attribute->attribute_val_type = val.type;
attribute->attribute_id = attribute_id;
} else {
attribute = (_attribute_t *)esp_matter_mem_calloc(1, sizeof(_attribute_t));
@@ -511,18 +516,21 @@ attribute_t *create(cluster_t *cluster, uint32_t attribute_id, uint16_t flags, e
attribute->override_callback = nullptr;
attribute->cluster_id = current_cluster->cluster_id;
attribute->endpoint_id = current_cluster->endpoint_id;
attribute->val.type = val.type;
attribute->attribute_val_type = val.type;
if (val.type == ESP_MATTER_VAL_TYPE_CHAR_STRING || val.type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING ||
val.type == ESP_MATTER_VAL_TYPE_OCTET_STRING || val.type == ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING) {
attribute->val.val.a.max = max_val_size;
attribute->attribute_val.a.max = max_val_size;
val.val.a.max = max_val_size;
}
bool attribute_updated = false;
if (flags & ATTRIBUTE_FLAG_NONVOLATILE) {
// Lets directly read into attribute->val so that we don't have to set the attribute value again.
// read from the NVS and store in the attribute's storage
esp_matter_attr_val_t temp_val;
temp_val.type = attribute->attribute_val_type;
esp_err_t err =
get_val_from_nvs(attribute->endpoint_id, attribute->cluster_id, attribute_id, attribute->val);
get_val_from_nvs(attribute->endpoint_id, attribute->cluster_id, attribute_id, temp_val);
if (err == ESP_OK) {
attribute->attribute_val = temp_val.val;
attribute_updated = true;
}
}
@@ -548,13 +556,13 @@ static esp_err_t destroy(attribute_t *attribute)
}
/* Delete val here, if required */
if (current_attribute->val.type == ESP_MATTER_VAL_TYPE_CHAR_STRING ||
current_attribute->val.type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING ||
current_attribute->val.type == ESP_MATTER_VAL_TYPE_OCTET_STRING ||
current_attribute->val.type == ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING ||
current_attribute->val.type == ESP_MATTER_VAL_TYPE_ARRAY) {
if (current_attribute->attribute_val_type == ESP_MATTER_VAL_TYPE_CHAR_STRING ||
current_attribute->attribute_val_type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING ||
current_attribute->attribute_val_type == ESP_MATTER_VAL_TYPE_OCTET_STRING ||
current_attribute->attribute_val_type == ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING ||
current_attribute->attribute_val_type == ESP_MATTER_VAL_TYPE_ARRAY) {
/* Free buf */
esp_matter_mem_free(current_attribute->val.val.a.b);
esp_matter_mem_free(current_attribute->attribute_val.a.b);
}
/* Erase the persistent data */
@@ -618,7 +626,7 @@ static void deferred_attribute_write(chip::System::Layer *layer, void *attribute
ESP_LOGI(TAG, "Store the deferred attribute 0x%" PRIx32 " of cluster 0x%" PRIX32 " on endpoint 0x%" PRIx16,
current_attribute->attribute_id, current_attribute->cluster_id, current_attribute->endpoint_id);
store_val_in_nvs(current_attribute->endpoint_id, current_attribute->cluster_id, current_attribute->attribute_id,
current_attribute->val);
{current_attribute->attribute_val_type, current_attribute->attribute_val});
}
esp_err_t set_val(attribute_t *attribute, esp_matter_attr_val_t *val, bool call_callbacks)
@@ -628,15 +636,19 @@ esp_err_t set_val(attribute_t *attribute, esp_matter_attr_val_t *val, bool call_
ESP_RETURN_ON_FALSE(!(current_attribute->flags & ATTRIBUTE_FLAG_MANAGED_INTERNALLY), ESP_ERR_NOT_SUPPORTED, TAG,
"Attribute is not managed by esp matter data model");
VerifyOrReturnError(current_attribute->val.type == val->type, ESP_ERR_INVALID_ARG,
ESP_LOGE(TAG, "Different value type : Expected Type : %u Attempted Type: %u", current_attribute->val.type, val->type));
VerifyOrReturnError(current_attribute->attribute_val_type == val->type, ESP_ERR_INVALID_ARG,
ESP_LOGE(TAG, "Different value type : Expected Type : %u Attempted Type: %u",
current_attribute->attribute_val_type, val->type));
if ((current_attribute->flags & ATTRIBUTE_FLAG_MIN_MAX) && current_attribute->bounds) {
if (compare_attr_val_with_bounds(*val, *current_attribute->bounds) != 0) {
return ESP_ERR_INVALID_ARG;
}
}
if (val_compare(val, &current_attribute->val)) {
esp_matter_attr_val_t temp_val;
temp_val.type = current_attribute->attribute_val_type;
temp_val.val = current_attribute->attribute_val;
if (val_compare(val, &temp_val)) {
// If the value is not changed, return ESP_ERR_NOT_FINISHED directly.
return ESP_ERR_NOT_FINISHED;
}
@@ -656,12 +668,12 @@ esp_err_t set_val(attribute_t *attribute, esp_matter_attr_val_t *val, bool call_
if (val->val.a.s > 0) {
uint8_t *new_buf = nullptr;
if (val->val.a.s != null_len) {
if (val->val.a.s > current_attribute->val.val.a.max) {
if (val->val.a.s > current_attribute->attribute_val.a.max) {
return ESP_ERR_NO_MEM;
}
/* Free old buf */
esp_matter_mem_free(current_attribute->val.val.a.b);
current_attribute->val.val.a.b = nullptr;
esp_matter_mem_free(current_attribute->attribute_val.a.b);
current_attribute->attribute_val.a.b = nullptr;
bool null_reserve =
val->type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING || val->type == ESP_MATTER_VAL_TYPE_CHAR_STRING;
@@ -671,14 +683,14 @@ esp_err_t set_val(attribute_t *attribute, esp_matter_attr_val_t *val, bool call_
/* Copy to new buf and assign */
memcpy(new_buf, val->val.a.b, val->val.a.s);
}
current_attribute->val.val.a.b = new_buf;
current_attribute->val.val.a.s = val->val.a.s;
current_attribute->val.val.a.t = val->val.a.t;
current_attribute->attribute_val.a.b = new_buf;
current_attribute->attribute_val.a.s = val->val.a.s;
current_attribute->attribute_val.a.t = val->val.a.t;
} else {
ESP_LOGD(TAG, "Set val called with string with size 0");
}
} else {
memcpy((void *)&current_attribute->val, (void *)val, sizeof(esp_matter_attr_val_t));
memcpy((void *)&current_attribute->attribute_val, (void *)&val->val, sizeof(esp_matter_val_t));
}
/* Callback to application */
if (call_callbacks) {
@@ -702,8 +714,11 @@ esp_err_t set_val(attribute_t *attribute, esp_matter_attr_val_t *val, bool call_
deferred_attribute_write, current_attribute);
}
} else {
esp_matter_attr_val_t temp_val;
temp_val.type = current_attribute->attribute_val_type;
temp_val.val = current_attribute->attribute_val;
store_val_in_nvs(current_attribute->endpoint_id, current_attribute->cluster_id,
current_attribute->attribute_id, current_attribute->val);
current_attribute->attribute_id, temp_val);
}
}
@@ -717,7 +732,8 @@ esp_err_t get_val(attribute_t *attribute, esp_matter_attr_val_t *val)
ESP_RETURN_ON_FALSE(!(current_attribute->flags & ATTRIBUTE_FLAG_MANAGED_INTERNALLY), ESP_ERR_NOT_SUPPORTED, TAG,
"Attribute is not managed by esp matter data model");
memcpy((void *)val, (void *)&current_attribute->val, sizeof(esp_matter_attr_val_t));
memcpy((void *)&val->type, (void *)&current_attribute->attribute_val_type, sizeof(esp_matter_val_type_t));
memcpy((void *)&val->val, (void *)&current_attribute->attribute_val, sizeof(esp_matter_val_t));
return ESP_OK;
}
@@ -730,19 +746,19 @@ esp_err_t add_bounds(attribute_t *attribute, esp_matter_attr_val_t min, esp_matt
"Attribute is not managed by esp matter data model");
/* Check if bounds can be set */
if (current_attribute->val.type == ESP_MATTER_VAL_TYPE_CHAR_STRING ||
current_attribute->val.type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING ||
current_attribute->val.type == ESP_MATTER_VAL_TYPE_OCTET_STRING ||
current_attribute->val.type == ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING ||
current_attribute->val.type == ESP_MATTER_VAL_TYPE_ARRAY ||
current_attribute->val.type == ESP_MATTER_VAL_TYPE_BOOLEAN) {
if (current_attribute->attribute_val_type == ESP_MATTER_VAL_TYPE_CHAR_STRING ||
current_attribute->attribute_val_type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING ||
current_attribute->attribute_val_type == ESP_MATTER_VAL_TYPE_OCTET_STRING ||
current_attribute->attribute_val_type == ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING ||
current_attribute->attribute_val_type == ESP_MATTER_VAL_TYPE_ARRAY ||
current_attribute->attribute_val_type == ESP_MATTER_VAL_TYPE_BOOLEAN) {
ESP_LOGE(TAG, "Bounds cannot be set for string/array/boolean type attributes");
return ESP_ERR_INVALID_ARG;
}
VerifyOrReturnError(((current_attribute->val.type == min.type) && (current_attribute->val.type == max.type)),
VerifyOrReturnError(((current_attribute->attribute_val_type == min.type) && (current_attribute->attribute_val_type == max.type)),
ESP_ERR_INVALID_ARG,
ESP_LOGE(TAG, "Cannot set bounds because of val type mismatch: expected: %d, min: %d, max: %d",
current_attribute->val.type, min.type, max.type));
current_attribute->attribute_val_type, min.type, max.type));
current_attribute->bounds = (esp_matter_attr_bounds_t *)esp_matter_mem_calloc(1, sizeof(esp_matter_attr_bounds_t));
if (!current_attribute->bounds) {
ESP_LOGE(TAG, "Failed to allocate bounds for attribute");
@@ -791,11 +807,11 @@ esp_err_t set_override_callback(attribute_t *attribute, callback_t callback)
ESP_RETURN_ON_FALSE(!(current_attribute->flags & ATTRIBUTE_FLAG_MANAGED_INTERNALLY), ESP_ERR_NOT_SUPPORTED, TAG,
"Attribute is not managed by esp matter data model");
if (current_attribute->val.type == ESP_MATTER_VAL_TYPE_ARRAY ||
current_attribute->val.type == ESP_MATTER_VAL_TYPE_OCTET_STRING ||
current_attribute->val.type == ESP_MATTER_VAL_TYPE_CHAR_STRING ||
current_attribute->val.type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING ||
current_attribute->val.type == ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING) {
if (current_attribute->attribute_val_type == ESP_MATTER_VAL_TYPE_ARRAY ||
current_attribute->attribute_val_type == ESP_MATTER_VAL_TYPE_OCTET_STRING ||
current_attribute->attribute_val_type == ESP_MATTER_VAL_TYPE_CHAR_STRING ||
current_attribute->attribute_val_type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING ||
current_attribute->attribute_val_type == ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING) {
// The override callback might allocate memory and we have no way to free the memory
// TODO: Add memory-safe override callback for these attribute types
ESP_LOGE(TAG, "Cannot set override callback for attribute 0x%" PRIX32, current_attribute->attribute_id);