diff --git a/components/esp_matter/data_model/esp_matter_data_model.cpp b/components/esp_matter/data_model/esp_matter_data_model.cpp index 44e9859d9..413c26eb8 100644 --- a/components/esp_matter/data_model/esp_matter_data_model.cpp +++ b/components/esp_matter/data_model/esp_matter_data_model.cpp @@ -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, ¤t_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 *)¤t_attribute->val, (void *)val, sizeof(esp_matter_attr_val_t)); + memcpy((void *)¤t_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 *)¤t_attribute->val, sizeof(esp_matter_attr_val_t)); + memcpy((void *)&val->type, (void *)¤t_attribute->attribute_val_type, sizeof(esp_matter_val_type_t)); + memcpy((void *)&val->val, (void *)¤t_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);