diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index fd6099385..770992240 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,7 @@ +# 4-Feb-2026 +### API Changes +- Removed APIs: `plugin_init_callback_common()`, `add_bounds_callback_common()` and `delegate_init_callback_common()`. + # 27-Nov-2025 ### Feature: attribute::get_val() and attribute::set_val() APIs diff --git a/components/esp_matter/data_model/esp_matter_cluster.cpp b/components/esp_matter/data_model/esp_matter_cluster.cpp index cfaa0dda5..7c9b39fe3 100644 --- a/components/esp_matter/data_model/esp_matter_cluster.cpp +++ b/components/esp_matter/data_model/esp_matter_cluster.cpp @@ -121,20 +121,6 @@ cluster_t * ABORT_CLUSTER_CREATE(cluster_t *cluster) } } // anonymous namespace -void delegate_init_callback_common(endpoint_t *endpoint) -{ - uint16_t endpoint_id = endpoint::get_id(endpoint); - cluster_t *cluster = get_first(endpoint); - while (cluster) { - /* Delegate server init callback */ - delegate_init_callback_t delegate_init_callback = get_delegate_init_callback(cluster); - if (delegate_init_callback) { - delegate_init_callback(get_delegate_impl(cluster), endpoint_id); - } - cluster = get_next(cluster); - } -} - cluster_t *create_default_binding_cluster(endpoint_t *endpoint) { /* Don't create binding cluster if it already exists on the endpoint */ 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 cb4f8994e..80cc0fb17 100644 --- a/components/esp_matter/data_model/esp_matter_data_model.cpp +++ b/components/esp_matter/data_model/esp_matter_data_model.cpp @@ -213,11 +213,36 @@ esp_err_t read_min_unused_endpoint_id() namespace endpoint { +static void report_parts_list_change_internal(endpoint_t *endpoint) +{ + chip::EndpointId parent_endpoint_id = endpoint::get_parent_endpoint_id(endpoint); + while (parent_endpoint_id != chip::kInvalidEndpointId) { + MatterReportingAttributeChangeCallback(parent_endpoint_id, chip::app::Clusters::Descriptor::Id, + chip::app::Clusters::Descriptor::Attributes::PartsList::Id); + parent_endpoint_id = endpoint::get_parent_endpoint_id(endpoint::get(parent_endpoint_id)); + } + MatterReportingAttributeChangeCallback(/* endpoint = */ 0, chip::app::Clusters::Descriptor::Id, + chip::app::Clusters::Descriptor::Attributes::PartsList::Id); +} + esp_err_t disable(endpoint_t *endpoint) { VerifyOrReturnError(endpoint, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Endpoint cannot be NULL")); _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; current_endpoint->enabled = false; + { + esp_matter::lock::ScopedChipStackLock lock(portMAX_DELAY); + report_parts_list_change_internal(endpoint); + cluster_t *cluster = cluster::get_first(endpoint); + while (cluster) { + /* kClusterShutdown type shutdown callback */ + cluster::shutdown_callback_t shutdown_callback = cluster::get_shutdown_callback(cluster); + if (shutdown_callback) { + shutdown_callback(endpoint::get_id(endpoint), chip::app::ClusterShutdownType::kClusterShutdown); + } + cluster = cluster::get_next(cluster); + } + } return ESP_OK; } @@ -241,43 +266,62 @@ static esp_err_t init_identification(endpoint_t *endpoint) return ESP_OK; } +static void invoke_init_callbacks_internal(endpoint_t *endpoint) +{ + cluster_t *cluster = cluster::get_first(endpoint); + while (cluster) { + /* Delegate server init callback */ + cluster::delegate_init_callback_t delegate_init_callback = cluster::get_delegate_init_callback(cluster); + if (delegate_init_callback) { + delegate_init_callback(cluster::get_delegate_impl(cluster), endpoint::get_id(endpoint)); + } + + /* Add bounds callback */ + cluster::add_bounds_callback_t add_bounds_callback = cluster::get_add_bounds_callback(cluster); + if (add_bounds_callback) { + add_bounds_callback(cluster); + } + + /* Plugin server init callback */ + cluster::plugin_server_init_callback_t plugin_server_init_callback = + cluster::get_plugin_server_init_callback(cluster); + if (plugin_server_init_callback) { + plugin_server_init_callback(); + } + + /* Initialization callback */ + uint8_t flags = cluster::get_flags(cluster); + cluster::initialization_callback_t init_callback = cluster::get_init_callback(cluster); + if (init_callback) { + init_callback(endpoint::get_id(endpoint)); + } + + /* Init function */ + if ((flags & CLUSTER_FLAG_SERVER) && (flags & CLUSTER_FLAG_INIT_FUNCTION)) { + cluster::function_cluster_init_t init_function = + (cluster::function_cluster_init_t)cluster::get_function(cluster, CLUSTER_FLAG_INIT_FUNCTION); + if (init_function) { + init_function(endpoint::get_id(endpoint)); + } + } + cluster = cluster::get_next(cluster); + } +} + esp_err_t enable(endpoint_t *endpoint) { VerifyOrReturnError(endpoint, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Endpoint cannot be NULL")); _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; current_endpoint->enabled = true; init_identification(endpoint); - esp_matter::cluster::delegate_init_callback_common(endpoint); - chip::DeviceLayer::SystemLayer().ScheduleLambda([endpoint] { - cluster_t *cluster = cluster::get_first(endpoint); - while (cluster) { - /* Add bounds callback */ - cluster::add_bounds_callback_t add_bounds_callback = cluster::get_add_bounds_callback(cluster); - if (add_bounds_callback) { - add_bounds_callback(cluster); - } - /* Plugin server init callback */ - cluster::plugin_server_init_callback_t plugin_server_init_callback = - cluster::get_plugin_server_init_callback(cluster); - if (plugin_server_init_callback) { - plugin_server_init_callback(); - } - /* Initialization callback */ - uint8_t flags = cluster::get_flags(cluster); - cluster::initialization_callback_t init_callback = cluster::get_init_callback(cluster); - if (init_callback) { - init_callback(endpoint::get_id(endpoint)); - } - if ((flags & CLUSTER_FLAG_SERVER) && (flags & CLUSTER_FLAG_INIT_FUNCTION)) { - cluster::function_cluster_init_t init_function = - (cluster::function_cluster_init_t)cluster::get_function(cluster, CLUSTER_FLAG_INIT_FUNCTION); - if (init_function) { - init_function(endpoint::get_id(endpoint)); - } - } - cluster = cluster::get_next(cluster); - } - }); + { + // Use the lock instead of schedule lambda to ensure the callbacks are invoked before esp_matter::start() returns. + esp_matter::lock::ScopedChipStackLock lock(portMAX_DELAY); + invoke_init_callbacks_internal(endpoint); + // Mark the endpoint as dirty so that the data model provider will report the attribute changes. + MatterReportingAttributeChangeCallback(endpoint::get_id(endpoint)); + report_parts_list_change_internal(endpoint); + } return ESP_OK; } @@ -1726,6 +1770,25 @@ esp_err_t destroy(node_t *node, endpoint_t *endpoint) } VerifyOrReturnError(current_endpoint != NULL, ESP_FAIL, ESP_LOGE(TAG, "Could not find the endpoint to delete")); + { + esp_matter::lock::ScopedChipStackLock lock(portMAX_DELAY); + cluster_t *cluster = cluster::get_first(endpoint); + while (cluster) { + /* TODO: kPermanentRemove type shutdown callback is not implemented yet in upstream code */ + + /* Shutdown function */ + uint8_t flags = cluster::get_flags(cluster); + if ((flags & CLUSTER_FLAG_SERVER) && (flags & CLUSTER_FLAG_SHUTDOWN_FUNCTION)) { + cluster::function_cluster_shutdown_t shutdown_function = + (cluster::function_cluster_shutdown_t)cluster::get_function(cluster, CLUSTER_FLAG_SHUTDOWN_FUNCTION); + if (shutdown_function) { + shutdown_function(endpoint::get_id(endpoint)); + } + } + cluster = cluster::get_next(cluster); + } + } + /* Parse and delete all clusters */ _cluster_t *cluster = current_endpoint->cluster_list; while (cluster) { diff --git a/components/esp_matter/data_model/private/esp_matter_data_model_priv.h b/components/esp_matter/data_model/private/esp_matter_data_model_priv.h index 8f55761d2..6cd49d66f 100644 --- a/components/esp_matter/data_model/private/esp_matter_data_model_priv.h +++ b/components/esp_matter/data_model/private/esp_matter_data_model_priv.h @@ -40,15 +40,6 @@ esp_err_t enable_all(); } -namespace cluster { - -/** Common cluster delegate init callback - * - * This is the common delegate init callback which calls the delegate init callbacks in the clusters. - */ -void delegate_init_callback_common(endpoint_t *endpoint); -} - namespace attribute { /** Get the attribute value from the esp-matter storage diff --git a/components/esp_matter/data_model_provider/esp_matter_data_model_provider.cpp b/components/esp_matter/data_model_provider/esp_matter_data_model_provider.cpp index f90726c44..11fa93033 100644 --- a/components/esp_matter/data_model_provider/esp_matter_data_model_provider.cpp +++ b/components/esp_matter/data_model_provider/esp_matter_data_model_provider.cpp @@ -646,9 +646,13 @@ CHIP_ERROR provider::Attributes(const ConcreteClusterPath &path, ReadOnlyBufferB void provider::Temporary_ReportAttributeChanged(const AttributePathParams &path) { - cluster_t *cluster = cluster::get(path.mEndpointId, path.mClusterId); - VerifyOrReturn(cluster != nullptr); - VerifyOrReturn(cluster::increase_data_version(cluster) == ESP_OK); + VerifyOrReturn(!path.HasWildcardEndpointId()); + // If the cluster is not wildcard, increase the data version + if (!path.HasWildcardClusterId()) { + cluster_t *cluster = cluster::get(path.mEndpointId, path.mClusterId); + VerifyOrReturn(cluster != nullptr); + VerifyOrReturn(cluster::increase_data_version(cluster) == ESP_OK); + } mContext->dataModelChangeListener.MarkDirty(path); }