diff --git a/.codespellrc b/.codespellrc index 2ecb9230f..e348e72da 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,3 +1,3 @@ [codespell] ignore-regex = _ -ignore-words-list = ot, bootup, requestor, pase +ignore-words-list = ot, bootup, requestor, pase, lits diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 61d98b17e..831b506df 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -28,7 +28,7 @@ variables: IDF_CHECKOUT_REF: "v5.4.1" # This variable represents the short hash of the connectedhomeip submodule. # Note: Do change this short hash on submodule update MRs. - CHIP_SHORT_HASH: "320b9a6f6c" + CHIP_SHORT_HASH: "bdc38cd772" DOCKER_IMAGE_NAME: "espressif/chip-idf" .add_gitlab_ssh_key: &add_gitlab_ssh_key | diff --git a/README.md b/README.md index bfe9f9a25..fc08d78e1 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,15 @@ Espressif's SDK for Matter is the official Matter development framework for ESP3 ## Supported Matter specification versions -| Matter Specification Version | Supported Branch | -|:----------------------------:|:-------------------------------------------------------------------------:| -| v1.0 | [release/v1.0](https://github.com/espressif/esp-matter/tree/release/v1.0) | -| v1.1 | [release/v1.1](https://github.com/espressif/esp-matter/tree/release/v1.1) | -| v1.2 | [release/v1.2](https://github.com/espressif/esp-matter/tree/release/v1.2) | -| v1.3 | [release/v1.3](https://github.com/espressif/esp-matter/tree/release/v1.3) | -| v1.4 | [release/v1.4](https://github.com/espressif/esp-matter/tree/release/v1.4) | -| v1.5 (Ongoing effort) | [main](https://github.com/espressif/esp-matter/tree/main) | +| Matter Specification Version | Supported Branch | +|:----------------------------:|:-----------------------------------------------------------------------------:| +| v1.0 | [release/v1.0](https://github.com/espressif/esp-matter/tree/release/v1.0) | +| v1.1 | [release/v1.1](https://github.com/espressif/esp-matter/tree/release/v1.1) | +| v1.2 | [release/v1.2](https://github.com/espressif/esp-matter/tree/release/v1.2) | +| v1.3 | [release/v1.3](https://github.com/espressif/esp-matter/tree/release/v1.3) | +| v1.4 | [release/v1.4](https://github.com/espressif/esp-matter/tree/release/v1.4) | +| v1.4.2 | [release/v1.4.2](https://github.com/espressif/esp-matter/tree/release/v1.4.2) | +| v1.5 (Ongoing effort) | [main](https://github.com/espressif/esp-matter/tree/main) | ## Getting the repositories @@ -28,7 +29,7 @@ section in the ESP-Matter Programming Guide. ## Supported ESP-IDF and connectedhomeip versions -- This SDK currently works with commit [320b9a6f6c] (https://github.com/project-chip/connectedhomeip/tree/320b9a6f66) of connectedhomeip. +- This SDK currently works with commit [bdc38cd772] (https://github.com/project-chip/connectedhomeip/tree/bdc38cd772) of connectedhomeip. - For Matter projects development with this SDK, it is recommended to utilize ESP-IDF [v5.4.1](https://github.com/espressif/esp-idf/tree/v5.4.1). - For ESP32C5, it is recommended to utilize ESP-IDF [98cd765953](https://github.com/espressif/esp-idf/commit/98cd765953dfe0e7bb1c5df8367e1b54bd966cce). diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e3207f856..2a43dc3f8 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,10 @@ +# 2-Sep-2025 + +API change. + +Move the macros `REMAP_TO_RANGE()` and `REMAP_TO_RANGE_INVERSE()` to from the `esp_matter_attribute_utils.h` to `common_macros.h` +in `examples/common/utils` directory. + # 10-June-2025 API Change. @@ -14,7 +21,7 @@ For clusters with `O` feature conformance, feature should be added using `featur Cluster structure change. - `feature_flags` are now part of `cluster::config` to configure the features in the application. - - moved `features::config` frome `cluster::config` to `cluster::config::features` structure. + - moved `features::config` from `cluster::config` to `cluster::config::features` structure. # 27-December-2024 @@ -38,7 +45,7 @@ esp_err_t get_bounds(attribute_t *attribute, esp_matter_attr_bounds_t *bounds); # 08-July-2024 - Changed diagnostic cluster namespaces as per the matter specifications - - diagnostics_network_wifi -> wifi_network_diagnotics + - diagnostics_network_wifi -> wifi_network_diagnostics - diagnostics_network_thread -> thread_network_diagnostics - diagnostics_network_ethernet -> ethernet_network_diagnostics diff --git a/components/esp_matter/CMakeLists.txt b/components/esp_matter/CMakeLists.txt index fe0c88f8d..02a36278c 100644 --- a/components/esp_matter/CMakeLists.txt +++ b/components/esp_matter/CMakeLists.txt @@ -5,22 +5,21 @@ set(SRC_DIRS_LIST "." set(INCLUDE_DIRS_LIST "." "utils" + "data_model_provider" "${MATTER_SDK_PATH}/zzz_generated/app-common" "${MATTER_SDK_PATH}/third_party/nlfaultinjection/include" "${MATTER_SDK_PATH}/src") -# TODO: This file has compilation errors -set(EXCLUDE_SRCS_LIST "${MATTER_SDK_PATH}/src/app/clusters/closure-control-server/closure-control-server.cpp") -list(APPEND EXCLUDE_SRCS_LIST "${MATTER_SDK_PATH}/src/app/clusters/general-commissioning-server/TemporaryTestCoupling.cpp") +# TODO: These files have compilation errors +set(EXCLUDE_SRCS_LIST "${MATTER_SDK_PATH}/src/app/clusters/closure-control-server/closure-control-server.cpp" + "${MATTER_SDK_PATH}/src/app/clusters/commodity-tariff-server/commodity-tariff-server.cpp" + "${MATTER_SDK_PATH}/src/app/clusters/commodity-tariff-server/CommodityTariffAttrsDataMgmt.cpp") +set(PRIV_INCLUDE_DIRS_LIST ) if (CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER) list(APPEND SRC_DIRS_LIST "${MATTER_SDK_PATH}/src/app/server" "${MATTER_SDK_PATH}/src/app/reporting" - "${MATTER_SDK_PATH}/src/app/server-cluster" - # TODO Use esp-matter data model and remove ember codes - "${MATTER_SDK_PATH}/src/app/util" - "${MATTER_SDK_PATH}/src/app/util/persistence" - "${MATTER_SDK_PATH}/src/data-model-providers/codegen") + "${MATTER_SDK_PATH}/src/app/server-cluster") if (CONFIG_ESP_MATTER_ENABLE_DATA_MODEL) include("utils/cluster_select/cluster_dir.cmake") get_supported_cluster_dirs(SUPPORTED_CLUSTER_DIRS) @@ -30,26 +29,25 @@ if (CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER) if (C_CPP_FILES) list(APPEND SRC_DIRS_LIST "${CLUSTER_DIR}") endif() + file(GLOB_RECURSE CODEGEN_INTEGRATION_FILE "${CLUSTER_DIR}/CodegenIntegration.cpp") + if (CODEGEN_INTEGRATION_FILE) + list(APPEND EXCLUDE_SRCS_LIST "${CLUSTER_DIR}/CodegenIntegration.cpp") + endif() endforeach() - list(APPEND SRC_DIRS_LIST "zap_common/app" - "data_model" - "private") + list(APPEND SRC_DIRS_LIST "data_model" + "data_model_provider" + "data_model_provider/clusters" + "data_model/private") list(APPEND INCLUDE_DIRS_LIST "zap_common" "data_model") - list(APPEND EXCLUDE_SRCS_LIST "${MATTER_SDK_PATH}/src/app/clusters/software-diagnostics-server/CodegenIntegration.cpp") - list(APPEND EXCLUDE_SRCS_LIST "${MATTER_SDK_PATH}/src/app/clusters/administrator-commissioning-server/CodegenIntegration.cpp") - list(APPEND EXCLUDE_SRCS_LIST "${MATTER_SDK_PATH}/src/app/clusters/ota-provider/CodegenIntegration.cpp") - - if(NOT CONFIG_SUPPORT_SOFTWARE_DIAGNOSTICS_CLUSTER) - list(APPEND EXCLUDE_SRCS_LIST "data_model/software_diagnostics_codegen_integration.cpp") - endif() - + list(APPEND PRIV_INCLUDE_DIRS_LIST "data_model/private") + list(APPEND EXCLUDE_SRCS_LIST "${MATTER_SDK_PATH}/src/app/clusters/network-commissioning/CodegenInstance.cpp" + "${MATTER_SDK_PATH}/src/app/clusters/general-commissioning-server/TemporaryTestCoupling.cpp") endif(CONFIG_ESP_MATTER_ENABLE_DATA_MODEL) else() list(APPEND EXCLUDE_SRCS_LIST "esp_matter_identify.cpp" - "esp_matter_ota.cpp" - "esp_matter_attribute_utils.cpp") + "esp_matter_ota.cpp") endif(CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER) @@ -59,7 +57,7 @@ set(REQUIRES_LIST chip bt esp_matter_console nvs_flash app_update esp_secu idf_component_register( SRC_DIRS ${SRC_DIRS_LIST} INCLUDE_DIRS ${INCLUDE_DIRS_LIST} EXCLUDE_SRCS ${EXCLUDE_SRCS_LIST} - PRIV_INCLUDE_DIRS "private" "data_model/private" + PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST} REQUIRES ${REQUIRES_LIST}) # This has been added to fix the error and should be removed once fixed: diff --git a/components/esp_matter/Kconfig b/components/esp_matter/Kconfig index 7bcfbac8c..edf0317b6 100644 --- a/components/esp_matter/Kconfig +++ b/components/esp_matter/Kconfig @@ -180,13 +180,6 @@ menu "ESP Matter" help Size of the binding table. - config ESP_MATTER_UNICAST_MESSAGE_COUNT - int "Unicast message count" - range 1 255 - default 10 - help - APS unicast message count. - choice ESP_MATTER_MEM_ALLOC_MODE prompt "Memory allocation strategy" default ESP_MATTER_MEM_ALLOC_MODE_INTERNAL diff --git a/components/esp_matter/data_model/administrator_commissioning_codegen_integration.cpp b/components/esp_matter/data_model/administrator_commissioning_codegen_integration.cpp deleted file mode 100644 index 32e6b4879..000000000 --- a/components/esp_matter/data_model/administrator_commissioning_codegen_integration.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2025 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include - -using namespace chip; -using namespace chip::app; -using namespace chip::app::Clusters; -using namespace chip::app::Clusters::AdministratorCommissioning::Attributes; -using chip::Protocols::InteractionModel::Status; - -namespace { - -// AdministratorCommissioningCluster implementation is specifically implemented -// only for the root endpoint (endpoint 0) -// So either: -// - we have a fixed config and it is endpoint 0 OR -// - we have a fully dynamic config - -static constexpr size_t kAdministratorCommissioningFixedClusterCount = 0; - -using ClusterImpl = AdministratorCommissioningWithBasicCommissioningWindowCluster; -LazyRegisteredServerCluster gServer; - -} // namespace - -void emberAfAdministratorCommissioningClusterInitCallback(EndpointId endpointId) -{ - if (endpointId != kRootEndpointId) - { - return; - } - - uint32_t rawFeatureMap; - if (FeatureMap::Get(endpointId, &rawFeatureMap) != Status::Success) - { - ChipLogError(AppServer, "Failed to get feature map for endpoint %u", endpointId); - rawFeatureMap = 0; - } - - gServer.Create(endpointId, BitFlags(rawFeatureMap)); - CHIP_ERROR err = CodegenDataModelProvider::Instance().Registry().Register(gServer.Registration()); - if (err != CHIP_NO_ERROR) - { - ChipLogError(AppServer, "Admin Commissioning register error: endpoint %u, %" CHIP_ERROR_FORMAT, endpointId, err.Format()); - } -} - -void emberAfAdministratorCommissioningClusterShutdownCallback(EndpointId endpointId) -{ - if (endpointId != kRootEndpointId) - { - return; - } - - CHIP_ERROR err = CodegenDataModelProvider::Instance().Registry().Unregister(&gServer.Cluster()); - if (err != CHIP_NO_ERROR) - { - ChipLogError(AppServer, "Admin Commissioning unregister error: endpoint %u, %" CHIP_ERROR_FORMAT, endpointId, err.Format()); - } - gServer.Destroy(); -} - -void MatterAdministratorCommissioningPluginServerInitCallback() {} -void MatterAdministratorCommissioningPluginServerShutdownCallback() {} diff --git a/components/esp_matter/data_model/esp_matter_attribute_utils.cpp b/components/esp_matter/data_model/esp_matter_attribute_utils.cpp new file mode 100644 index 000000000..9e5fb3a15 --- /dev/null +++ b/components/esp_matter/data_model/esp_matter_attribute_utils.cpp @@ -0,0 +1,750 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp_check.h" +#include "esp_err.h" +#include "esp_matter_data_model.h" +#include "app/AttributePathParams.h" +#include "data_model_provider/esp_matter_data_model_provider.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "support/CodeUtils.h" + +using chip::AttributeId; +using chip::ClusterId; +using chip::EndpointId; +using chip::Protocols::InteractionModel::Status; + +using namespace esp_matter; + +static const char *TAG = "esp_matter_attribute"; + +esp_matter_attr_val_t esp_matter_invalid(void *val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_INVALID, + .val = { + .p = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_bool(bool val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_BOOLEAN, + .val = { + .b = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_int(int val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_INTEGER, + .val = { + .i = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_nullable_bool(nullable val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_BOOLEAN, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::SetNull(*(uint8_t *)(&(attr_val.val.b))); + } + else { + attr_val.val.b = val.value(); + } + return attr_val; +} + +esp_matter_attr_val_t esp_matter_nullable_int(nullable val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_INTEGER, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::SetNull(attr_val.val.i); + } else { + attr_val.val.i = val.value(); + } + return attr_val; +} + +esp_matter_attr_val_t esp_matter_float(float val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_FLOAT, + .val = { + .f = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_nullable_float(nullable val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::SetNull(attr_val.val.f); + } else { + attr_val.val.f = val.value(); + } + return attr_val; +} + +esp_matter_attr_val_t esp_matter_int8(int8_t val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_INT8, + .val = { + .i8 = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_nullable_int8(nullable val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_INT8, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::SetNull(attr_val.val.i8); + } else { + attr_val.val.i8 = val.value(); + } + return attr_val; +} + +esp_matter_attr_val_t esp_matter_uint8(uint8_t val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_UINT8, + .val = { + .u8 = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_nullable_uint8(nullable val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_UINT8, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::SetNull(attr_val.val.u8); + } else { + attr_val.val.u8 = val.value(); + } + return attr_val; +} + +esp_matter_attr_val_t esp_matter_int16(int16_t val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_INT16, + .val = { + .i16 = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_nullable_int16(nullable val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_INT16, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::SetNull(attr_val.val.i16); + } else { + attr_val.val.i16 = val.value(); + } + return attr_val; +} + +esp_matter_attr_val_t esp_matter_uint16(uint16_t val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_UINT16, + .val = { + .u16 = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_nullable_uint16(nullable val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_UINT16, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::SetNull(attr_val.val.u16); + } else { + attr_val.val.u16 = val.value(); + } + return attr_val; +} + +esp_matter_attr_val_t esp_matter_int32(int32_t val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_INT32, + .val = { + .i32 = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_nullable_int32(nullable val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_INT32, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::SetNull(attr_val.val.i32); + } else { + attr_val.val.i32 = val.value(); + } + return attr_val; +} + +esp_matter_attr_val_t esp_matter_uint32(uint32_t val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_UINT32, + .val = { + .u32 = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_nullable_uint32(nullable val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_UINT32, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::SetNull(attr_val.val.u32); + } else { + attr_val.val.u32 = val.value(); + } + return attr_val; +} + +esp_matter_attr_val_t esp_matter_int64(int64_t val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_INT64, + .val = { + .i64 = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_nullable_int64(nullable val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_INT64, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::SetNull(attr_val.val.i64); + } else { + attr_val.val.i64 = val.value(); + } + return attr_val; +} + +esp_matter_attr_val_t esp_matter_uint64(uint64_t val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_UINT64, + .val = { + .u64 = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_nullable_uint64(nullable val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_UINT64, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::SetNull(attr_val.val.u64); + } else { + attr_val.val.u64 = val.value(); + } + return attr_val; +} + +esp_matter_attr_val_t esp_matter_enum8(uint8_t val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_ENUM8, + .val = { + .u8 = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_nullable_enum8(nullable val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::SetNull(attr_val.val.u8); + } else { + attr_val.val.u8 = val.value(); + } + return attr_val; +} + +esp_matter_attr_val_t esp_matter_enum16(uint16_t val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_ENUM16, + .val = { + .u16 = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_nullable_enum16(nullable val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::SetNull(attr_val.val.u16); + } else { + attr_val.val.u16 = val.value(); + } + return attr_val; +} + +esp_matter_attr_val_t esp_matter_bitmap8(uint8_t val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_BITMAP8, + .val = { + .u8 = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_nullable_bitmap8(nullable val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::SetNull(attr_val.val.u8); + } else { + attr_val.val.u8 = val.value(); + } + return attr_val; +} + +esp_matter_attr_val_t esp_matter_bitmap16(uint16_t val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_BITMAP16, + .val = { + .u16 = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_nullable_bitmap16(nullable val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::SetNull(attr_val.val.u16); + } else { + attr_val.val.u16 = val.value(); + } + return attr_val; +} + +esp_matter_attr_val_t esp_matter_bitmap32(uint32_t val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_BITMAP32, + .val = { + .u32 = val, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_nullable_bitmap32(nullable val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::SetNull(attr_val.val.u32); + } else { + attr_val.val.u32 = val.value(); + } + return attr_val; +} + +esp_matter_attr_val_t esp_matter_char_str(char *val, uint16_t data_size) +{ + uint16_t data_size_len = 1; /* Number of bytes used to store the length */ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_CHAR_STRING, + .val = { + .a = { + .b = (uint8_t *)val, + .s = data_size, + .t = (uint16_t)(data_size + data_size_len), + }, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_long_char_str(char *val, uint16_t data_size) +{ + uint16_t data_size_len = 2; /* Number of bytes used to store the length */ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING, + .val = { + .a = { + .b = (uint8_t *)val, + .s = data_size, + .t = (uint16_t)(data_size + data_size_len), + }, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_octet_str(uint8_t *val, uint16_t data_size) +{ + uint16_t data_size_len = 1; /* Number of bytes used to store the length */ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_OCTET_STRING, + .val = { + .a = { + .b = val, + .s = data_size, + .t = (uint16_t)(data_size + data_size_len), + }, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_long_octet_str(uint8_t *val, uint16_t data_size) +{ + uint16_t data_size_len = 2; /* Number of bytes used to store the length */ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING, + .val = { + .a = { + .b = val, + .s = data_size, + .t = (uint16_t)(data_size + data_size_len), + }, + }, + }; + return attr_val; +} + +esp_matter_attr_val_t esp_matter_array(uint8_t *val, uint16_t data_size, uint16_t count) +{ + uint16_t data_size_len = 2; /* Number of bytes used to store the length */ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_ARRAY, + .val = { + .a = { + .b = val, + .s = data_size, + .t = (uint16_t)(data_size + data_size_len), + }, + }, + }; + return attr_val; +} + +namespace esp_matter { +namespace attribute { + + +bool val_is_null(esp_matter_attr_val_t *val) +{ + switch (val->type) { + case ESP_MATTER_VAL_TYPE_NULLABLE_BOOLEAN: + return chip::app::NumericAttributeTraits::IsNullValue(*(uint8_t *)(&(val->val.b))); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_INTEGER: + return chip::app::NumericAttributeTraits::IsNullValue(val->val.i); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT8: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8: + return chip::app::NumericAttributeTraits::IsNullValue(val->val.u8); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT16: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16: + return chip::app::NumericAttributeTraits::IsNullValue(val->val.u16); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT32: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32: + return chip::app::NumericAttributeTraits::IsNullValue(val->val.u32); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT64: + return chip::app::NumericAttributeTraits::IsNullValue(val->val.u64); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_INT8: + return chip::app::NumericAttributeTraits::IsNullValue(val->val.i8); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_INT16: + return chip::app::NumericAttributeTraits::IsNullValue(val->val.i16); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_INT32: + return chip::app::NumericAttributeTraits::IsNullValue(val->val.i32); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_INT64: + return chip::app::NumericAttributeTraits::IsNullValue(val->val.i64); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT: + return chip::app::NumericAttributeTraits::IsNullValue(val->val.f); + break; + default: + return false; + break; + } + return false; +} + +void val_print(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val, bool is_read) +{ + char action = (is_read) ? 'R' :'W'; + VerifyOrReturn(!val_is_null(val), ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is null **********", action, + endpoint_id, cluster_id, attribute_id)); + + if (val->type == ESP_MATTER_VAL_TYPE_BOOLEAN) { + ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %d **********", action, + endpoint_id, cluster_id, attribute_id, val->val.b); + } else if (val->type == ESP_MATTER_VAL_TYPE_INTEGER || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INTEGER) { + ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %d **********", action, + endpoint_id, cluster_id, attribute_id, val->val.i); + } else if (val->type == ESP_MATTER_VAL_TYPE_FLOAT || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT) { + ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %f **********", action, + endpoint_id, cluster_id, attribute_id, val->val.f); + } else if (val->type == ESP_MATTER_VAL_TYPE_INT8 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INT8) { + ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %i **********", action, + endpoint_id, cluster_id, attribute_id, val->val.i8); + } else if (val->type == ESP_MATTER_VAL_TYPE_UINT8 || val->type == ESP_MATTER_VAL_TYPE_BITMAP8 + || val->type == ESP_MATTER_VAL_TYPE_ENUM8 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_UINT8 + || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8) { + ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %u **********", action, + endpoint_id, cluster_id, attribute_id, val->val.u8); + } else if (val->type == ESP_MATTER_VAL_TYPE_INT16 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INT16) { + ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIi16 " **********", action, + endpoint_id, cluster_id, attribute_id, val->val.i16); + } else if (val->type == ESP_MATTER_VAL_TYPE_UINT16 || val->type == ESP_MATTER_VAL_TYPE_BITMAP16 + || val->type == ESP_MATTER_VAL_TYPE_ENUM16 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_UINT16 + || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16) { + ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIu16 " **********", action, + endpoint_id, cluster_id, attribute_id, val->val.u16); + } else if (val->type == ESP_MATTER_VAL_TYPE_INT32|| val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INT32) { + ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIi32 " **********", action, + endpoint_id, cluster_id, attribute_id, val->val.i32); + } else if (val->type == ESP_MATTER_VAL_TYPE_UINT32 || val->type == ESP_MATTER_VAL_TYPE_BITMAP32 + || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_UINT32 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32) { + ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIu32 " **********", action, + endpoint_id, cluster_id, attribute_id, val->val.u32); + } else if (val->type == ESP_MATTER_VAL_TYPE_INT64 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INT64) { + ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIi64 " **********", action, + endpoint_id, cluster_id, attribute_id, val->val.i64); + } else if (val->type == ESP_MATTER_VAL_TYPE_UINT64 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_UINT64) { + ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIu64 " **********", action, + endpoint_id, cluster_id, attribute_id, val->val.u64); + } else if (val->type == ESP_MATTER_VAL_TYPE_CHAR_STRING) { + const char *b = val->val.a.b ? (const char *)val->val.a.b : "(empty)"; + uint16_t s = val->val.a.b ? val->val.a.s : strlen("(empty)"); + ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %.*s **********", action, + endpoint_id, cluster_id, attribute_id, s, b); + } else if (val->type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING) { + const char *b = val->val.a.b ? (const char *)val->val.a.b : "(empty)"; + uint16_t s = val->val.a.b ? val->val.a.s : strlen("(empty)"); + ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %.*s **********", action, + endpoint_id, cluster_id, attribute_id, s, b); + } else { + ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is **********", action, + endpoint_id, cluster_id, attribute_id, val->type); + } +} + +esp_err_t update(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) +{ + VerifyOrReturnError(val, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "val cannot be NULL")); + attribute_t *attr = get(endpoint_id, cluster_id, attribute_id); + ESP_RETURN_ON_FALSE(attr, ESP_ERR_INVALID_ARG, TAG, "Failed to get attribute handle"); + + /* Take lock if not already taken */ + lock::status_t lock_status = lock::chip_stack_lock(portMAX_DELAY); + VerifyOrReturnError(lock_status != lock::FAILED, ESP_FAIL, ESP_LOGE(TAG, "Could not get task context")); + /* Here, the val_print function gets called on attribute write.*/ + attribute::val_print(endpoint_id, cluster_id, attribute_id, val, false); + + esp_err_t err = attribute::set_val(attr, val); + if (err == ESP_OK) { + data_model::provider::get_instance().Temporary_ReportAttributeChanged( + chip::app::AttributePathParams(endpoint_id, cluster_id, attribute_id)); + } else if (err == ESP_ERR_NOT_FINISHED) { + err = ESP_OK; + } + if (lock_status == lock::SUCCESS) { + lock::chip_stack_unlock(); + } + return err; +} + +esp_err_t report(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) +{ + VerifyOrReturnError(val, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "val cannot be NULL")); + attribute_t *attr = get(endpoint_id, cluster_id, attribute_id); + ESP_RETURN_ON_FALSE(attr, ESP_ERR_INVALID_ARG, TAG, "Failed to get attribute handle"); + + /* Take lock if not already taken */ + lock::status_t lock_status = lock::chip_stack_lock(portMAX_DELAY); + VerifyOrReturnError(lock_status != lock::FAILED, ESP_FAIL, ESP_LOGE(TAG, "Could not get task context")); + + /* Here, the val_print function gets called on attribute write.*/ + attribute::val_print(endpoint_id, cluster_id, attribute_id, val, false); + + esp_err_t err = attribute::set_val(attr, val, false); + if (err == ESP_OK) { + /* Report attribute */ + MatterReportingAttributeChangeCallback(endpoint_id, cluster_id, attribute_id); + } else if (err == ESP_ERR_NOT_FINISHED) { + err = ESP_OK; + } + + if (lock_status == lock::SUCCESS) { + lock::chip_stack_unlock(); + } + return ESP_OK; +} + +bool val_compare(const esp_matter_attr_val_t *val1, const esp_matter_attr_val_t *val2) +{ + if (val1 == nullptr || val2 == nullptr) { + return val1 == val2; + } + if (val1->type != val2->type) { + return false; + } + switch ((val1->type & (~ESP_MATTER_VAL_NULLABLE_BASE))) { + case ESP_MATTER_VAL_TYPE_CHAR_STRING: + case ESP_MATTER_VAL_TYPE_OCTET_STRING: + case ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING: + case ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING: { + uint16_t null_len = + (val1->type == ESP_MATTER_VAL_TYPE_CHAR_STRING || val1->type == ESP_MATTER_VAL_TYPE_OCTET_STRING) ? UINT8_MAX : UINT16_MAX; + if (val1->val.a.s != val2->val.a.s) { + return false; + } + if (val1->val.a.s == null_len || val1->val.a.s == 0) { + return true; + } + return memcmp(val1->val.a.b, val2->val.a.b, val1->val.a.s) == 0; + break; + } + case ESP_MATTER_VAL_TYPE_UINT8: + case ESP_MATTER_VAL_TYPE_ENUM8: + case ESP_MATTER_VAL_TYPE_BITMAP8: + return val1->val.u8 == val2->val.u8; + break; + case ESP_MATTER_VAL_TYPE_UINT16: + case ESP_MATTER_VAL_TYPE_ENUM16: + case ESP_MATTER_VAL_TYPE_BITMAP16: + return val1->val.u16 == val2->val.u16; + break; + case ESP_MATTER_VAL_TYPE_UINT32: + case ESP_MATTER_VAL_TYPE_BITMAP32: + return val1->val.u32 == val2->val.u32; + break; + case ESP_MATTER_VAL_TYPE_UINT64: + return val1->val.u64 == val2->val.u64; + break; + case ESP_MATTER_VAL_TYPE_INT8: + return val1->val.i8 == val2->val.i8; + break; + case ESP_MATTER_VAL_TYPE_INT16: + return val1->val.i16 == val2->val.i16; + break; + case ESP_MATTER_VAL_TYPE_INT32: + return val1->val.i32 == val2->val.i32; + break; + case ESP_MATTER_VAL_TYPE_INT64: + return val1->val.i64 == val2->val.i64; + break; + case ESP_MATTER_VAL_TYPE_BOOLEAN: + return val1->val.b == val2->val.b; + break; + case ESP_MATTER_VAL_TYPE_FLOAT: + return val1->val.f == val2->val.f; + break; + default: + ESP_LOGE(TAG, "Unsupported type to compare"); + } + return false; +} + +} /* attribute */ +} /* esp_matter */ diff --git a/components/esp_matter/esp_matter_attribute_utils.h b/components/esp_matter/data_model/esp_matter_attribute_utils.h similarity index 91% rename from components/esp_matter/esp_matter_attribute_utils.h rename to components/esp_matter/data_model/esp_matter_attribute_utils.h index 79ec698fa..0a7647bb4 100644 --- a/components/esp_matter/esp_matter_attribute_utils.h +++ b/components/esp_matter/data_model/esp_matter_attribute_utils.h @@ -20,21 +20,6 @@ #include -/** Remap attribute values - * - * This can be used to remap attribute values to different ranges. - * Example: To convert the brightness value (0-255) into brightness percentage (0-100) and vice-versa. - */ -#define REMAP_TO_RANGE(value, from, to) ((value * to) / from) - -/** Remap attribute values with inverse dependency - * - * This can be used to remap attribute values with inverse dependency to different ranges. - * Example: To convert the temperature mireds into temperature kelvin and vice-versa where the relation between them - * is: Mireds = 1,000,000/Kelvin. - */ -#define REMAP_TO_RANGE_INVERSE(value, factor) (factor / (value ? value : 1)) - /* Nullable base for nullable attribute */ #define ESP_MATTER_VAL_NULLABLE_BASE 0x80 @@ -134,8 +119,8 @@ typedef union { uint8_t *b; /** Data size */ uint16_t s; - /** Data count */ - uint16_t n; + /** Data max size */ + uint16_t max; /** Total size */ uint16_t t; } a; @@ -431,7 +416,6 @@ esp_err_t update(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_i * @param[in] endpoint_id Endpoint ID of the attribute. * @param[in] cluster_id Cluster ID of the attribute. * @param[in] attribute_id Attribute ID of the attribute. - * @param[in] val Pointer to new value to report, of type `esp_matter_attr_val_t`. Appropriate elements should be used as per the value type. * * @return ESP_OK on success. * @return error in case of failure. @@ -450,21 +434,17 @@ esp_err_t report(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_i */ void val_print(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val, bool is_read); -/** Get attribute val raw +/** Attribute value compare * - * Get the value of the attribute in the database, without the attribute handle. + * This API compares the two attribute values. * - * @param[in] endpoint_id Endpoint ID of the attribute. - * @param[in] cluster_id Cluster ID of the attribute. - * @param[in] attribute_id Attribute ID of the attribute. - * @param[out] value Pointer to an allocated buffer for the attribute value. - * @param[in] attribute_size Size of the allocated buffer. + * @param[in] val1 Pointer to the first attribute value. + * @param[in] val2 Pointer to the second attribute value. * - * @return ESP_OK on success. - * @return error in case of failure. + * @return true if the two values are the same. + * @return false if the two values are different. */ -esp_err_t get_val_raw(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, uint8_t *value, - uint16_t attribute_size); +bool val_compare(const esp_matter_attr_val_t *val1, const esp_matter_attr_val_t *val2); } /* attribute */ } /* esp_matter */ diff --git a/components/esp_matter/data_model/esp_matter_cluster.cpp b/components/esp_matter/data_model/esp_matter_cluster.cpp index 284dd2fa1..eb1849808 100644 --- a/components/esp_matter/data_model/esp_matter_cluster.cpp +++ b/components/esp_matter/data_model/esp_matter_cluster.cpp @@ -17,7 +17,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -25,6 +27,7 @@ #include #include #include +#include #include #include @@ -378,6 +381,8 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags) /* Attributes not managed internally */ global::attribute::create_cluster_revision(cluster, cluster_revision); + cluster::set_init_and_shutdown_callbacks(cluster, ESPMatterOtaSoftwareUpdateProviderClusterServerInitCallback, + ESPMatterOtaSoftwareUpdateProviderClusterServerShutdownCallback); } /* Commands */ @@ -461,6 +466,14 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags) } else { ESP_LOGE(TAG, "Config is NULL. Cannot add some attributes."); } + + /* Commands */ + command::create_arm_fail_safe(cluster); + command::create_arm_fail_safe_response(cluster); + command::create_set_regulatory_config(cluster); + command::create_set_regulatory_config_response(cluster); + command::create_commissioning_complete(cluster); + command::create_commissioning_complete_response(cluster); } return cluster; @@ -505,6 +518,18 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags) /* Attributes not managed internally */ global::attribute::create_cluster_revision(cluster, cluster_revision); + + /* Commands */ + command::create_scan_networks(cluster); + command::create_remove_network(cluster); + command::create_connect_network(cluster); + command::create_reorder_network(cluster); + command::create_scan_networks_response(cluster); + command::create_network_config_response(cluster); + command::create_connect_network_response(cluster); + + cluster::set_init_and_shutdown_callbacks(cluster, ESPMatterNetworkCommissioningClusterServerInitCallback, + ESPMatterNetworkCommissioningClusterServerShutdownCallback); } /* Commands */ @@ -542,6 +567,14 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags) /* Attributes not managed internally */ global::attribute::create_cluster_revision(cluster, cluster_revision); + + /* Commands */ + command::create_test_event_trigger(cluster); + command::create_time_snap_shot(cluster); + command::create_time_snap_shot_response(cluster); + + cluster::set_init_and_shutdown_callbacks(cluster, ESPMatterGeneralDiagnosticsClusterServerInitCallback, + ESPMatterGeneralDiagnosticsClusterServerShutdownCallback); } event::create_boot_reason(cluster); @@ -573,6 +606,13 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags) /* Attributes not managed internally */ global::attribute::create_cluster_revision(cluster, cluster_revision); + + /* Commands */ + command::create_open_commissioning_window(cluster); + command::create_revoke_commissioning(cluster); + + cluster::set_init_and_shutdown_callbacks(cluster, ESPMatterAdministratorCommissioningClusterServerInitCallback, + ESPMatterAdministratorCommissioningClusterServerShutdownCallback); } return cluster; @@ -605,6 +645,23 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags) /* Attributes not managed internally */ global::attribute::create_cluster_revision(cluster, cluster_revision); + + /* Commands */ + command::create_attestation_request(cluster); + command::create_attestation_response(cluster); + command::create_certificate_chain_request(cluster); + command::create_certificate_chain_response(cluster); + command::create_csr_request(cluster); + command::create_csr_response(cluster); + command::create_add_noc(cluster); + command::create_update_noc(cluster); + command::create_noc_response(cluster); + command::create_update_fabric_label(cluster); + command::create_remove_fabric(cluster); + command::create_add_trusted_root_certificate(cluster); + command::create_set_vid_verification_statement(cluster); + command::create_sign_vid_verification_request(cluster); + command::create_sign_vid_verification_response(cluster); } return cluster; @@ -633,6 +690,13 @@ cluster_t *create(endpoint_t *endpoint, uint8_t flags) attribute::create_group_table(cluster, NULL, 0, 0); attribute::create_max_groups_per_fabric(cluster, 0); attribute::create_max_group_keys_per_fabric(cluster, 0); + + command::create_key_set_write(cluster); + command::create_key_set_read(cluster); + command::create_key_set_remove(cluster); + command::create_key_set_read_all_indices(cluster); + command::create_key_set_read_response(cluster); + command::create_key_set_read_all_indices_response(cluster); } return cluster; @@ -2649,6 +2713,8 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags) /* Attributes not managed internally */ global::attribute::create_cluster_revision(cluster, cluster_revision); + cluster::set_init_and_shutdown_callbacks(cluster, ESPMatterSoftwareDiagnosticsClusterServerInitCallback, + ESPMatterSoftwareDiagnosticsClusterServerShutdownCallback); } return cluster; @@ -3446,6 +3512,9 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags) /** Attributes not managed internally **/ global::attribute::create_cluster_revision(cluster, cluster_revision); + + cluster::set_init_and_shutdown_callbacks(cluster, ESPMatterWiFiNetworkDiagnosticsClusterServerInitCallback, + ESPMatterWiFiNetworkDiagnosticsClusterServerShutdownCallback); } /* Commands */ diff --git a/components/esp_matter/data_model/esp_matter_command.cpp b/components/esp_matter/data_model/esp_matter_command.cpp index 15dee78a0..a4f929492 100644 --- a/components/esp_matter/data_model/esp_matter_command.cpp +++ b/components/esp_matter/data_model/esp_matter_command.cpp @@ -26,16 +26,12 @@ using chip::app::CommandHandler; using chip::app::DataModel::Decode; using chip::TLV::TLVReader; -#if (FIXED_ENDPOINT_COUNT == 0) - static const char *TAG = "esp_matter_command"; namespace esp_matter { namespace command { -static callback_t get_cluster_accepted_command(uint32_t cluster_id, uint32_t command_id); - -void DispatchSingleClusterCommandCommon(const ConcreteCommandPath &command_path, TLVReader &tlv_data, void *opaque_ptr) +void dispatch_single_cluster_command(const ConcreteCommandPath &command_path, TLVReader &tlv_data, void *opaque_ptr) { uint16_t endpoint_id = command_path.mEndpointId; uint32_t cluster_id = command_path.mClusterId; @@ -45,14 +41,10 @@ void DispatchSingleClusterCommandCommon(const ConcreteCommandPath &command_path, cluster_t *cluster = cluster::get(endpoint_id, cluster_id); VerifyOrReturn(cluster); command_t *command = get(cluster, command_id, COMMAND_FLAG_ACCEPTED); - callback_t standard_callback = get_cluster_accepted_command(cluster_id, command_id); - VerifyOrReturn((command || standard_callback), ESP_LOGE(TAG, "Command 0x%08" PRIX32 " not found", command_id)); + VerifyOrReturn(command, ESP_LOGE(TAG, "Command 0x%08" PRIX32 " not found", command_id)); esp_err_t err = ESP_OK; TLVReader tlv_reader; tlv_reader.Init(tlv_data); - if (standard_callback) { - standard_callback(command_path, tlv_data, opaque_ptr); - } if (command) { callback_t callback = get_user_callback(command); if (callback) { @@ -78,18 +70,6 @@ void DispatchSingleClusterCommandCommon(const ConcreteCommandPath &command_path, } /* command */ } /* esp_matter */ -namespace chip { -namespace app { - -void DispatchSingleClusterCommand(const ConcreteCommandPath &command_path, TLVReader &tlv_data, - CommandHandler *command_obj) -{ - esp_matter::command::DispatchSingleClusterCommandCommon(command_path, tlv_data, command_obj); -} - -} /* namespace app */ -} /* namespace chip */ - static esp_err_t esp_matter_command_callback_key_set_write(const ConcreteCommandPath &command_path, TLVReader &tlv_data, void *opaque_ptr) { @@ -1679,15 +1659,6 @@ command_t *create_retrieve_logs_response(cluster_t *cluster) namespace general_diagnostics { namespace command { -constexpr const command_entry_t accepted_command_list[] = { - {GeneralDiagnostics::Commands::TestEventTrigger::Id, COMMAND_FLAG_ACCEPTED, nullptr}, - {GeneralDiagnostics::Commands::TimeSnapshot::Id, COMMAND_FLAG_ACCEPTED, nullptr}, -}; - -constexpr const command_entry_t generated_command_list[] = { - {GeneralDiagnostics::Commands::TimeSnapshotResponse::Id, COMMAND_FLAG_GENERATED, NULL}, -}; - command_t *create_test_event_trigger(cluster_t *cluster) { return esp_matter::command::create(cluster, GeneralDiagnostics::Commands::TestEventTrigger::Id, COMMAND_FLAG_ACCEPTED, nullptr); @@ -1722,18 +1693,6 @@ command_t *create_reset_watermarks(cluster_t *cluster) namespace group_key_management { namespace command { -constexpr const command_entry_t accepted_command_list[] = { - {GroupKeyManagement::Commands::KeySetWrite::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_key_set_write}, - {GroupKeyManagement::Commands::KeySetRead::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_key_set_read}, - {GroupKeyManagement::Commands::KeySetRemove::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_key_set_remove}, - {GroupKeyManagement::Commands::KeySetReadAllIndices::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_key_set_read_all_indices}, -}; - -constexpr const command_entry_t generated_command_list[] = { - {GroupKeyManagement::Commands::KeySetReadResponse::Id, COMMAND_FLAG_GENERATED, NULL}, - {GroupKeyManagement::Commands::KeySetReadAllIndicesResponse::Id, COMMAND_FLAG_GENERATED, NULL}, -}; - command_t *create_key_set_write(cluster_t *cluster) { return esp_matter::command::create(cluster, GroupKeyManagement::Commands::KeySetWrite::Id, COMMAND_FLAG_ACCEPTED, @@ -1776,18 +1735,6 @@ command_t *create_key_set_read_all_indices_response(cluster_t *cluster) namespace general_commissioning { namespace command { -constexpr const command_entry_t accepted_command_list[] = { - {GeneralCommissioning::Commands::ArmFailSafe::Id, COMMAND_FLAG_ACCEPTED, nullptr}, - {GeneralCommissioning::Commands::SetRegulatoryConfig::Id, COMMAND_FLAG_ACCEPTED, nullptr}, - {GeneralCommissioning::Commands::CommissioningComplete::Id, COMMAND_FLAG_ACCEPTED, nullptr}, -}; - -constexpr const command_entry_t generated_command_list[] = { - {GeneralCommissioning::Commands::ArmFailSafeResponse::Id, COMMAND_FLAG_GENERATED, NULL}, - {GeneralCommissioning::Commands::SetRegulatoryConfigResponse::Id, COMMAND_FLAG_GENERATED, NULL}, - {GeneralCommissioning::Commands::CommissioningCompleteResponse::Id, COMMAND_FLAG_GENERATED, NULL}, -}; - command_t *create_arm_fail_safe(cluster_t *cluster) { return esp_matter::command::create(cluster, GeneralCommissioning::Commands::ArmFailSafe::Id, COMMAND_FLAG_ACCEPTED, @@ -1842,19 +1789,6 @@ command_t *create_set_tc_acknowledgements_response(cluster_t *cluster) namespace network_commissioning { namespace command { -constexpr const command_entry_t accepted_command_list[] = { - {NetworkCommissioning::Commands::ScanNetworks::Id, COMMAND_FLAG_ACCEPTED, NULL}, - {NetworkCommissioning::Commands::RemoveNetwork::Id, COMMAND_FLAG_ACCEPTED, NULL}, - {NetworkCommissioning::Commands::ConnectNetwork::Id, COMMAND_FLAG_ACCEPTED, NULL}, - {NetworkCommissioning::Commands::ReorderNetwork::Id, COMMAND_FLAG_ACCEPTED, NULL}, -}; - -constexpr const command_entry_t generated_command_list[] = { - {NetworkCommissioning::Commands::ScanNetworksResponse::Id, COMMAND_FLAG_GENERATED, NULL}, - {NetworkCommissioning::Commands::NetworkConfigResponse::Id, COMMAND_FLAG_GENERATED, NULL}, - {NetworkCommissioning::Commands::ConnectNetworkResponse::Id, COMMAND_FLAG_GENERATED, NULL}, -}; - command_t *create_scan_networks(cluster_t *cluster) { return esp_matter::command::create(cluster, NetworkCommissioning::Commands::ScanNetworks::Id, COMMAND_FLAG_ACCEPTED, @@ -1915,13 +1849,6 @@ command_t *create_connect_network_response(cluster_t *cluster) namespace administrator_commissioning { namespace command { -constexpr const command_entry_t accepted_command_list[] = { - {AdministratorCommissioning::Commands::OpenCommissioningWindow::Id, COMMAND_FLAG_ACCEPTED, nullptr}, - {AdministratorCommissioning::Commands::RevokeCommissioning::Id, COMMAND_FLAG_ACCEPTED, nullptr}, -}; - -constexpr const command_entry_t generated_command_list[] = {}; - command_t *create_open_commissioning_window(cluster_t *cluster) { return esp_matter::command::create(cluster, AdministratorCommissioning::Commands::OpenCommissioningWindow::Id, @@ -1946,27 +1873,6 @@ command_t *create_revoke_commissioning(cluster_t *cluster) namespace operational_credentials { namespace command { -constexpr const command_entry_t accepted_command_list[] = { - {OperationalCredentials::Commands::AttestationRequest::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_attestation_request}, - {OperationalCredentials::Commands::CertificateChainRequest::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_certificate_chain_request}, - {OperationalCredentials::Commands::CSRRequest::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_csr_request}, - {OperationalCredentials::Commands::AddNOC::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_add_noc}, - {OperationalCredentials::Commands::UpdateNOC::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_update_noc}, - {OperationalCredentials::Commands::UpdateFabricLabel::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_update_fabric_label}, - {OperationalCredentials::Commands::RemoveFabric::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_remove_fabric}, - {OperationalCredentials::Commands::AddTrustedRootCertificate::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_add_trusted_root_certificate}, - {OperationalCredentials::Commands::SetVIDVerificationStatement::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_set_vid_verification_statement}, - {OperationalCredentials::Commands::SignVIDVerificationRequest::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_sign_vid_verification_request}, -}; - -constexpr const command_entry_t generated_command_list[] = { - {OperationalCredentials::Commands::AttestationResponse::Id, COMMAND_FLAG_GENERATED, NULL}, - {OperationalCredentials::Commands::CertificateChainResponse::Id, COMMAND_FLAG_GENERATED, NULL}, - {OperationalCredentials::Commands::CSRResponse::Id, COMMAND_FLAG_GENERATED, NULL}, - {OperationalCredentials::Commands::NOCResponse::Id, COMMAND_FLAG_GENERATED, NULL}, - {OperationalCredentials::Commands::SignVIDVerificationResponse::Id, COMMAND_FLAG_GENERATED, NULL}, -}; - command_t *create_attestation_request(cluster_t *cluster) { return esp_matter::command::create(cluster, OperationalCredentials::Commands::AttestationRequest::Id, @@ -3254,86 +3160,3 @@ command_t *create_set_default_ntp(cluster_t *cluster) } /* cluster */ } /* esp_matter */ - -namespace esp_matter { -namespace command { -#define GET_ACCEPTED_COMMAND_COUNT(cluster) sizeof(cluster::command::accepted_command_list) / sizeof(command_entry_t) -#define GET_ACCEPTED_COMMAND_LIST(cluster) \ - static_cast(&cluster::command::accepted_command_list[0]) - -#define GET_GENERATED_COMMAND_COUNT(cluster) sizeof(cluster::command::generated_command_list) / sizeof(command_entry_t) -#define GET_GENERATED_COMMAND_LIST(cluster) \ - static_cast(&cluster::command::generated_command_list[0]) - -#define GET_COMMAND_COUNT_LIST(cluster) \ - GET_ACCEPTED_COMMAND_COUNT(cluster), GET_GENERATED_COMMAND_COUNT(cluster), GET_ACCEPTED_COMMAND_LIST(cluster), \ - GET_GENERATED_COMMAND_LIST(cluster) - -/* Instead of adding the standard commands dynamically, place them in the .rodata section to save RAM. */ -constexpr const cluster_command_t cluster_command_table[] = { - {GeneralCommissioning::Id, GET_COMMAND_COUNT_LIST(cluster::general_commissioning)}, - {NetworkCommissioning::Id, GET_COMMAND_COUNT_LIST(cluster::network_commissioning)}, - {GeneralDiagnostics::Id, GET_COMMAND_COUNT_LIST(cluster::general_diagnostics)}, - {AdministratorCommissioning::Id, GET_COMMAND_COUNT_LIST(cluster::administrator_commissioning)}, - {OperationalCredentials::Id, GET_COMMAND_COUNT_LIST(cluster::operational_credentials)}, - {GroupKeyManagement::Id, GET_COMMAND_COUNT_LIST(cluster::group_key_management)}, -}; - -const command_entry_t *get_cluster_accepted_command_list(uint32_t cluster_id) -{ - for (auto const &cluster_command : cluster_command_table) { - if (cluster_command.cluster_id == cluster_id) { - return cluster_command.accepted_command_list; - } - } - return nullptr; -} - -size_t get_cluster_accepted_command_count(uint32_t cluster_id) -{ - for (auto const &cluster_command : cluster_command_table) { - if (cluster_command.cluster_id == cluster_id) { - return cluster_command.accepted_command_count; - } - } - return 0; -} - -const command_entry_t *get_cluster_generated_command_list(uint32_t cluster_id) -{ - for (auto const &cluster_command : cluster_command_table) { - if (cluster_command.cluster_id == cluster_id) { - return cluster_command.generated_command_list; - } - } - return nullptr; -} - -size_t get_cluster_generated_command_count(uint32_t cluster_id) -{ - for (auto const &cluster_command : cluster_command_table) { - if (cluster_command.cluster_id == cluster_id) { - return cluster_command.generated_command_count; - } - } - return 0; -} - -static callback_t get_cluster_accepted_command(uint32_t cluster_id, uint32_t command_id) -{ - for (auto const &cluster_command : cluster_command_table) { - if (cluster_command.cluster_id == cluster_id) { - for (size_t index = 0; index < cluster_command.accepted_command_count; ++index){ - if (cluster_command.accepted_command_list[index].command_id == command_id) { - return cluster_command.accepted_command_list[index].callback; - } - } - } - } - return nullptr; -} - -} /* command */ -} /* esp_matter */ - -#endif /* FIXED_ENDPOINT_COUNT */ diff --git a/components/esp_matter/data_model/esp_matter_command.h b/components/esp_matter/data_model/esp_matter_command.h index a47e9ccc3..190467827 100644 --- a/components/esp_matter/data_model/esp_matter_command.h +++ b/components/esp_matter/data_model/esp_matter_command.h @@ -17,20 +17,6 @@ #include namespace esp_matter { -struct command_entry_t { - uint32_t command_id; - uint8_t flags; - command::callback_t callback; -}; - -struct cluster_command_t { - uint32_t cluster_id; - size_t accepted_command_count; - size_t generated_command_count; - const command_entry_t *accepted_command_list; - const command_entry_t *generated_command_list; -}; - namespace cluster { /** Specific command create APIs 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 d7b30ba13..33be6c576 100644 --- a/components/esp_matter/data_model/esp_matter_data_model.cpp +++ b/components/esp_matter/data_model/esp_matter_data_model.cpp @@ -12,25 +12,33 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include +#include #include +#include #include #include +#include #include #include #include #include #include +#include #include #include -#include -#include #include +#include +#include +#include +#include #include -#include "app/server/Server.h" -#include "credentials/GroupDataProviderImpl.h" +#include +#include #define ESP_MATTER_MAX_DEVICE_TYPE_COUNT CONFIG_ESP_MATTER_MAX_DEVICE_TYPE_COUNT +#define ESP_MATTER_MAX_SEMANTIC_TAG_COUNT 3 static const char *TAG = "data_model"; @@ -38,23 +46,25 @@ using chip::CommandId; using chip::DataVersion; using chip::EventId; using chip::kInvalidAttributeId; -using chip::kInvalidCommandId; using chip::kInvalidClusterId; +using chip::kInvalidCommandId; using chip::kInvalidEndpointId; +using chip::app::DataModel::EndpointCompositionPattern; namespace esp_matter { + struct _attribute_base_t { uint16_t flags; // This struct is for attributes managed internally. - uint16_t index; uint32_t attribute_id; struct _attribute_base_t *next; }; struct _attribute_t : public _attribute_base_t { - uint32_t cluster_id; // This struct is for attributes not managed internally. esp_matter_attr_val_t val; - attribute::callback_t override_callback; + esp_matter_attr_bounds_t *bounds; uint16_t endpoint_id; + uint32_t cluster_id; + attribute::callback_t override_callback; }; typedef struct _command { @@ -71,34 +81,42 @@ typedef struct _event { } _event_t; typedef struct _cluster { - uint8_t index; + uint32_t cluster_id; uint16_t endpoint_id; + uint8_t flags; + const cluster::function_generic_t *functions; cluster::plugin_server_init_callback_t plugin_server_init_callback; cluster::delegate_init_callback_t delegate_init_callback; - void * delegate_pointer; + void *delegate_pointer; cluster::add_bounds_callback_t add_bounds_callback; - _attribute_base_t *attribute_list; /* If attribute is managed internally, the actual pointer type is _internal_attribute_t. - When operating attribute_list, do check the flags first! */ - EmberAfAttributeMetadata *matter_attributes; + cluster::initialization_callback_t init_callback; + cluster::shutdown_callback_t shutdown_callback; + chip::DataVersion data_version; + _attribute_base_t *attribute_list; /* If attribute is managed internally, the actual pointer type is + _internal_attribute_t. When operating attribute_list, do check the flags first! */ _command_t *command_list; _event_t *event_list; struct _cluster *next; } _cluster_t; +typedef struct device_type { + uint8_t version; + uint32_t id; +} device_type_t; + typedef struct _endpoint { uint16_t endpoint_id; + bool enabled; uint8_t device_type_count; - uint8_t cluster_count; - uint8_t device_type_versions[ESP_MATTER_MAX_DEVICE_TYPE_COUNT]; - uint32_t device_type_ids[ESP_MATTER_MAX_DEVICE_TYPE_COUNT]; + device_type_t device_types[ESP_MATTER_MAX_DEVICE_TYPE_COUNT]; uint16_t flags; uint16_t parent_endpoint_id; - _cluster_t *cluster_list; - EmberAfEndpointType *endpoint_type; - chip::DataVersion *data_versions_ptr; - EmberAfDeviceType *device_types_ptr; void *priv_data; Identify *identify; + EndpointCompositionPattern composition_pattern; + uint8_t semantic_tag_count; + chip::app::DataModel::Provider::SemanticTag semantic_tags[ESP_MATTER_MAX_SEMANTIC_TAG_COUNT]; + _cluster_t *cluster_list; struct _endpoint *next; } _endpoint_t; @@ -107,6 +125,21 @@ typedef struct _node { uint16_t min_unused_endpoint_id; } _node_t; +namespace { +// Treat 0xFFFF'FFFF as wildcard cluster +inline bool is_wildcard_cluster_id(uint32_t cluster_id) +{ + return cluster_id == chip::kInvalidClusterId; +} + +// Treat 0xFFFF as wildcard endpoint +inline bool is_wildcard_endpoint_id(uint16_t endpoint_id) +{ + return endpoint_id == chip::kInvalidEndpointId; +} + +} // namespace + namespace node { static _node_t *node = NULL; @@ -114,10 +147,10 @@ static _node_t *node = NULL; // If Matter server or ESP-Matter data model is not enabled. we will never use minimum unused endpoint id. esp_err_t store_min_unused_endpoint_id() { - VerifyOrReturnError((node && esp_matter::is_started()), ESP_ERR_INVALID_STATE, ESP_LOGE(TAG, "Node does not exist or esp_matter does not start")); + VerifyOrReturnError((node && esp_matter::is_started()), ESP_ERR_INVALID_STATE, + ESP_LOGE(TAG, "Node does not exist or esp_matter does not start")); nvs_handle_t handle; - esp_err_t err = nvs_open_from_partition(ESP_MATTER_NVS_PART_NAME, ESP_MATTER_KVS_NAMESPACE, - NVS_READWRITE, &handle); + esp_err_t err = nvs_open_from_partition(ESP_MATTER_NVS_PART_NAME, ESP_MATTER_KVS_NAMESPACE, NVS_READWRITE, &handle); VerifyOrReturnError(err == ESP_OK, err, ESP_LOGE(TAG, "Failed to open the node nvs_namespace")); err = nvs_set_u16(handle, "min_uu_ep_id", node->min_unused_endpoint_id); @@ -128,11 +161,11 @@ esp_err_t store_min_unused_endpoint_id() esp_err_t read_min_unused_endpoint_id() { - VerifyOrReturnError((node && esp_matter::is_started()), ESP_ERR_INVALID_STATE, ESP_LOGE(TAG, "Node does not exist or esp_matter does not start")); + VerifyOrReturnError((node && esp_matter::is_started()), ESP_ERR_INVALID_STATE, + ESP_LOGE(TAG, "Node does not exist or esp_matter does not start")); nvs_handle_t handle; - esp_err_t err = nvs_open_from_partition(ESP_MATTER_NVS_PART_NAME, ESP_MATTER_KVS_NAMESPACE, - NVS_READONLY, &handle); + esp_err_t err = nvs_open_from_partition(ESP_MATTER_NVS_PART_NAME, ESP_MATTER_KVS_NAMESPACE, NVS_READONLY, &handle); if (err == ESP_OK) { err = nvs_get_u16(handle, "min_uu_ep_id", &node->min_unused_endpoint_id); nvs_close(handle); @@ -164,161 +197,39 @@ esp_err_t read_min_unused_endpoint_id() return err; } -} /* node */ - -namespace command { -command_entry_t *get_cluster_accepted_command_list(uint32_t cluster_id); -size_t get_cluster_accepted_command_count(uint32_t cluster_id); -command_entry_t *get_cluster_generated_command_list(uint32_t cluster_id); -size_t get_cluster_generated_command_count(uint32_t cluster_id); -} /* command */ - -namespace attribute { - -static EmberAfAttributeMetadata *get_external_attribute_metadata(_attribute_t * attribute) -{ - if (NULL == attribute || (attribute->flags & ATTRIBUTE_FLAG_MANAGED_INTERNALLY)) { - return NULL; - } - _cluster_t *cluster = (_cluster_t *)cluster::get(attribute->endpoint_id, attribute->cluster_id); - if (NULL == cluster) { - return NULL; - } - return &cluster->matter_attributes[attribute->index]; -} - -static esp_err_t free_default_value(attribute_t *attribute) -{ - VerifyOrReturnError(attribute, ESP_FAIL, ESP_LOGE(TAG, "Attribute cannot be NULL")); - _attribute_t *current_attribute = (_attribute_t *)attribute; - EmberAfAttributeMetadata *matter_attribute = get_external_attribute_metadata(current_attribute); - if (!matter_attribute) { - ESP_LOGE(TAG, "Attribute Metadata is not found"); - return ESP_ERR_NOT_FOUND; - } - - /* Free value if data is more than 2 bytes or if it is min max attribute */ - if (current_attribute->flags & ATTRIBUTE_FLAG_MIN_MAX) { - if (matter_attribute->size > 2) { - esp_matter_mem_free((void *)matter_attribute->defaultValue.ptrToMinMaxValue->defaultValue.ptrToDefaultValue); - esp_matter_mem_free((void *)matter_attribute->defaultValue.ptrToMinMaxValue->minValue.ptrToDefaultValue); - esp_matter_mem_free((void *)matter_attribute->defaultValue.ptrToMinMaxValue->maxValue.ptrToDefaultValue); - } - esp_matter_mem_free((void *)matter_attribute->defaultValue.ptrToMinMaxValue); - } else if (matter_attribute->size > 2) { - esp_matter_mem_free((void *)matter_attribute->defaultValue.ptrToDefaultValue); - } - return ESP_OK; -} - -static EmberAfDefaultAttributeValue get_default_value_from_data(esp_matter_attr_val_t *val, - EmberAfAttributeType attribute_type, - uint16_t attribute_size) -{ - EmberAfDefaultAttributeValue default_value = (uint16_t)0; - uint8_t *value = (uint8_t *)esp_matter_mem_calloc(1, attribute_size); - VerifyOrReturnValue(value, default_value, ESP_LOGE(TAG, "Could not allocate value buffer for default value")); - get_data_from_attr_val(val, &attribute_type, &attribute_size, value); - - if (attribute_size > 2) { - /* Directly set the pointer */ - default_value = value; - } else { - /* This data is 2 bytes or less. This should be represented as uint16. Copy the bytes appropriately - for 0 or 1 or 2 bytes to be converted to uint16. Then free the allocated buffer. */ - uint16_t int_value = 0; - if (attribute_size == 2) { - memcpy(&int_value, value, attribute_size); - } else if (attribute_size == 1) { - int_value = (uint16_t)*value; - } - default_value = int_value; - esp_matter_mem_free(value); - } - return default_value; -} - -static esp_err_t set_default_value_from_current_val(attribute_t *attribute, esp_matter_attr_val_t *min, esp_matter_attr_val_t *max) -{ - VerifyOrReturnError(attribute, ESP_FAIL, ESP_LOGE(TAG, "Attribute cannot be NULL")); - _attribute_t *current_attribute = (_attribute_t *)attribute; - - EmberAfAttributeMetadata *matter_attribute = get_external_attribute_metadata(current_attribute); - if (!matter_attribute) { - ESP_LOGE(TAG, "Attribute Metadata is not found"); - return ESP_ERR_NOT_FOUND; - } - - esp_matter_attr_val_t *val = ¤t_attribute->val; - - /* Get size */ - EmberAfAttributeType attribute_type = 0; - uint16_t attribute_size = 0; - get_data_from_attr_val(val, &attribute_type, &attribute_size, NULL); - - /* Get and set value */ - if (current_attribute->flags & ATTRIBUTE_FLAG_MIN_MAX) { - EmberAfAttributeMinMaxValue *temp_value = (EmberAfAttributeMinMaxValue *)esp_matter_mem_calloc(1, - sizeof(EmberAfAttributeMinMaxValue)); - VerifyOrReturnError(temp_value, ESP_FAIL, ESP_LOGE(TAG, "Could not allocate ptrToMinMaxValue for default value")); - temp_value->defaultValue = get_default_value_from_data(val, attribute_type, attribute_size); - temp_value->minValue = get_default_value_from_data(min, attribute_type, attribute_size); - temp_value->maxValue = get_default_value_from_data(max, attribute_type, attribute_size); - matter_attribute->defaultValue.ptrToMinMaxValue = temp_value; - } else if (attribute_size > 2) { - EmberAfDefaultAttributeValue temp_value = get_default_value_from_data(val, attribute_type, attribute_size); - matter_attribute->defaultValue.ptrToDefaultValue = temp_value.ptrToDefaultValue; - } else { - EmberAfDefaultAttributeValue temp_value = get_default_value_from_data(val, attribute_type, attribute_size); - matter_attribute->defaultValue.defaultValue = temp_value.defaultValue; - } - return ESP_OK; -} -} /* attribute */ +} // namespace node namespace endpoint { -static int get_next_index() +esp_err_t disable(endpoint_t *endpoint) { - uint16_t endpoint_id = 0; - for (int index = 0; index < MAX_ENDPOINT_COUNT; index++) { - endpoint_id = emberAfEndpointFromIndex(index); - if (endpoint_id == kInvalidEndpointId) { - return index; - } - } - return 0xFFFF; + VerifyOrReturnError(endpoint, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Endpoint cannot be NULL")); + _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; + current_endpoint->enabled = false; + return ESP_OK; } -static esp_err_t disable(endpoint_t *endpoint) +static esp_err_t init_identification(endpoint_t *endpoint) { - /* Take lock if not already taken */ - lock::status_t lock_status = lock::chip_stack_lock(portMAX_DELAY); - - VerifyOrReturnError(lock_status != lock::FAILED, ESP_FAIL, ESP_LOGE(TAG, "Could not get task context")); - - /* Remove endpoint */ + VerifyOrReturnError(endpoint, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Endpoint cannot be NULL")); _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; - int endpoint_index = emberAfGetDynamicIndexFromEndpoint(current_endpoint->endpoint_id); - if (endpoint_index == 0xFFFF) { - ESP_LOGE(TAG, "Could not find endpoint index"); - if (lock_status == lock::SUCCESS) { - lock::chip_stack_unlock(); + _cluster_t *cluster = current_endpoint->cluster_list; + while (cluster) { + uint32_t cluster_id = cluster::get_id((cluster_t *)cluster); + /* Init identify if exists and not initialized */ + if (cluster_id == chip::app::Clusters::Identify::Id && current_endpoint->identify == NULL) { + _attribute_t *identify_type_attr = (_attribute_t *)attribute::get( + current_endpoint->endpoint_id, cluster_id, chip::app::Clusters::Identify::Attributes::IdentifyType::Id); + if (identify_type_attr) { + return identification::init(current_endpoint->endpoint_id, identify_type_attr->val.val.u8); + } else { + ESP_LOGE(TAG, "Can't get IdentifyType attribute in Identify cluster"); + return ESP_ERR_INVALID_STATE; + } } - return ESP_FAIL; + cluster = cluster->next; } - emberAfClearDynamicEndpoint(endpoint_index); - - if (lock_status == lock::SUCCESS) { - lock::chip_stack_unlock(); - } - - /* Delete identify */ - if (current_endpoint->identify) { - chip::Platform::Delete(current_endpoint->identify); - current_endpoint->identify = NULL; - } - + // Return ESP_OK when identify cluster is not on the endpoint. return ESP_OK; } @@ -326,232 +237,9 @@ 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; - - /* Device types */ - EmberAfDeviceType *device_types_ptr = (EmberAfDeviceType *)esp_matter_mem_calloc(current_endpoint->device_type_count, sizeof(EmberAfDeviceType)); - if (!device_types_ptr) { - ESP_LOGE(TAG, "Couldn't allocate device_types"); - /* goto cleanup is not used here to avoid 'crosses initialization' of device_types below */ - return ESP_ERR_NO_MEM; - } - for (size_t i = 0; i < current_endpoint->device_type_count; ++i) { - device_types_ptr[i].deviceTypeId = current_endpoint->device_type_ids[i]; - device_types_ptr[i].deviceTypeRevision = current_endpoint->device_type_versions[i]; - } - chip::Span device_types(device_types_ptr, current_endpoint->device_type_count); - current_endpoint->device_types_ptr = device_types_ptr; - - /* Clusters */ - _cluster_t *cluster = current_endpoint->cluster_list; - int cluster_count = SinglyLinkedList<_cluster_t>::count(cluster); - int cluster_index = 0; - - DataVersion *data_versions_ptr = (DataVersion *)esp_matter_mem_calloc(1, cluster_count * sizeof(DataVersion)); - if (!data_versions_ptr) { - ESP_LOGE(TAG, "Couldn't allocate data_versions"); - esp_matter_mem_free(device_types_ptr); - current_endpoint->device_types_ptr = NULL; - /* goto cleanup is not used here to avoid 'crosses initialization' of data_versions below */ - return ESP_ERR_NO_MEM; - } - chip::Span data_versions(data_versions_ptr, cluster_count); - current_endpoint->data_versions_ptr = data_versions_ptr; - - /* Variables */ - /* This is needed to avoid 'crosses initialization' errors because of goto */ - esp_err_t err = ESP_OK; - lock::status_t lock_status = lock::FAILED; - CHIP_ERROR status = CHIP_NO_ERROR; - CommandId *accepted_command_ids = NULL; - CommandId *generated_command_ids = NULL; - _command_t *command = NULL; - command_entry_t *command_list = NULL; - uint32_t cluster_id = kInvalidClusterId; - int command_count = 0; - int command_index = 0; - int command_flag = COMMAND_FLAG_NONE; - EventId *event_ids = NULL; - _event_t *event = NULL; - int event_count = 0; - int event_index = 0; - int endpoint_index = 0; - - while (cluster) { - /* Attributes */ - /* Handled in attribute::create() */ - - /* Commands */ - command = NULL; - command_count = 0; - command_index = 0; - command_flag = COMMAND_FLAG_NONE; - accepted_command_ids = NULL; - generated_command_ids = NULL; - cluster_id = cluster::get_id((cluster_t*)cluster); - - /* Init identify if exists and not initialized */ - if (cluster_id == chip::app::Clusters::Identify::Id && current_endpoint->identify == NULL) { - _attribute_t *identify_type_attr = (_attribute_t *)attribute::get( - current_endpoint->endpoint_id, cluster_id, chip::app::Clusters::Identify::Attributes::IdentifyType::Id); - if (identify_type_attr) { - if (identification::init(current_endpoint->endpoint_id, identify_type_attr->val.val.u8) != ESP_OK) { - ESP_LOGE(TAG, "Failed to init identification"); - err = ESP_FAIL; - break; - } - } else { - ESP_LOGE(TAG, "Can't get IdentifyType attribute in Identify cluster"); - err = ESP_ERR_INVALID_STATE; - break; - } - } - - /* Client Generated Commands */ - command_flag = COMMAND_FLAG_ACCEPTED; - command = cluster->command_list; - command_count = SinglyLinkedList<_command_t>::count_with_flag(command, command_flag); - command_count += command::get_cluster_accepted_command_count(cluster_id); - if (command_count > 0) { - command_index = 0; - accepted_command_ids = (CommandId *)esp_matter_mem_calloc(1, (command_count + 1) * sizeof(CommandId)); - if (!accepted_command_ids) { - ESP_LOGE(TAG, "Couldn't allocate accepted_command_ids"); - err = ESP_ERR_NO_MEM; - break; - } - while (command) { - if (command->flags & command_flag) { - accepted_command_ids[command_index] = command->command_id; - command_index++; - } - command = command->next; - } - command_list = command::get_cluster_accepted_command_list(cluster_id); - for(size_t index = 0; command_index < command_count && command_list; index++) { - accepted_command_ids[command_index] = command_list[index].command_id; - command_index++; - } - accepted_command_ids[command_index] = kInvalidCommandId; - } - - /* Server Generated Commands */ - command_flag = COMMAND_FLAG_GENERATED; - command = cluster->command_list; - command_count = SinglyLinkedList<_command_t>::count_with_flag(command, command_flag); - command_count += command::get_cluster_generated_command_count(cluster_id); - if (command_count > 0) { - command_index = 0; - generated_command_ids = (CommandId *)esp_matter_mem_calloc(1, (command_count + 1) * sizeof(CommandId)); - if (!generated_command_ids) { - ESP_LOGE(TAG, "Couldn't allocate generated_command_ids"); - err = ESP_ERR_NO_MEM; - break; - } - while (command) { - if (command->flags & command_flag) { - generated_command_ids[command_index] = command->command_id; - command_index++; - } - command = command->next; - } - command_list = command::get_cluster_generated_command_list(cluster_id); - for(size_t index = 0; command_index < command_count && command_list; index++) { - generated_command_ids[command_index] = command_list[index].command_id; - command_index++; - } - generated_command_ids[command_index] = kInvalidCommandId; - } - - /* Event */ - event = cluster->event_list; - event_count = SinglyLinkedList<_event_t>::count(event); - if (event_count > 0) { - event_index = 0; - event_ids = (EventId *)esp_matter_mem_calloc(1, (event_count + 1) * sizeof(EventId)); - if (!event_ids) { - ESP_LOGE(TAG, "Couldn't allocate event_ids"); - err = ESP_ERR_NO_MEM; - break; - } - while (event) { - event_ids[event_index] = event->event_id; - event_index++; - event = event->next; - } - event_ids[event_index] = chip::kInvalidEventId; - } - - /* Fill up the cluster */ - EmberAfCluster *matter_clusters = (EmberAfCluster *)(¤t_endpoint->endpoint_type->cluster[cluster_index]); - matter_clusters->attributes = cluster->matter_attributes; - matter_clusters->acceptedCommandList = accepted_command_ids; - matter_clusters->generatedCommandList = generated_command_ids; - matter_clusters->eventList = event_ids; - matter_clusters->eventCount = event_count; - - /* Get next cluster */ - current_endpoint->endpoint_type->endpointSize += matter_clusters->clusterSize; - cluster = cluster->next; - cluster_index++; - - /* This is to avoid double free in case of errors */ - accepted_command_ids = NULL; - generated_command_ids = NULL; - event_ids = NULL; - } - if (err != ESP_OK) { - goto cleanup; - } - - current_endpoint->endpoint_type->clusterCount = cluster_count; - - /* Take lock if not already taken */ - lock_status = lock::chip_stack_lock(portMAX_DELAY); - if (lock_status == lock::FAILED) { - ESP_LOGE(TAG, "Could not get task context"); - goto cleanup; - } - - /* Add Endpoint */ - endpoint_index = endpoint::get_next_index(); - status = emberAfSetDynamicEndpoint(endpoint_index, current_endpoint->endpoint_id, current_endpoint->endpoint_type, data_versions, - device_types, current_endpoint->parent_endpoint_id); - if (status != CHIP_NO_ERROR) { - ESP_LOGE(TAG, "Error adding dynamic endpoint %" PRIu16 ": %" CHIP_ERROR_FORMAT, current_endpoint->endpoint_id, status.Format()); - err = ESP_FAIL; - if (lock_status == lock::SUCCESS) { - lock::chip_stack_unlock(); - } - goto cleanup; - } - if (lock_status == lock::SUCCESS) { - lock::chip_stack_unlock(); - } - ESP_LOGI(TAG, "Dynamic endpoint %" PRIu16 " added", current_endpoint->endpoint_id); - - return err; - -cleanup: - esp_matter_mem_free(generated_command_ids); - esp_matter_mem_free(accepted_command_ids); - esp_matter_mem_free(event_ids); - if (current_endpoint->endpoint_type->cluster) { - for (int cluster_index = 0; cluster_index < cluster_count; cluster_index++) { - /* Free attributes */ - esp_matter_mem_free((void *)current_endpoint->endpoint_type->cluster[cluster_index].attributes); - /* Free commands */ - esp_matter_mem_free((void *)current_endpoint->endpoint_type->cluster[cluster_index].acceptedCommandList); - esp_matter_mem_free((void *)current_endpoint->endpoint_type->cluster[cluster_index].generatedCommandList); - /* Free events */ -esp_matter_mem_free((void *)current_endpoint->endpoint_type->cluster[cluster_index].eventList); - } - - } - esp_matter_mem_free(data_versions_ptr); - current_endpoint->data_versions_ptr = NULL; - esp_matter_mem_free(device_types_ptr); - current_endpoint->device_types_ptr = NULL; - return err; + current_endpoint->enabled = true; + init_identification(endpoint); + return ESP_OK; } esp_err_t enable_all() @@ -579,9 +267,218 @@ bool is_command_enabled(uint16_t endpoint_id, uint32_t cluster_id, uint32_t comm command_t *cmd = command::get(endpoint_id, cluster_id, command_id); return (cmd != nullptr); } + +bool is_enabled(endpoint_t *endpoint) +{ + VerifyOrReturnError(endpoint, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Endpoint cannot be NULL")); + _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; + return current_endpoint->enabled; +} } /* endpoint */ namespace attribute { + +static callback_t attribute_callback = NULL; +esp_err_t set_callback(callback_t callback) +{ + attribute_callback = callback; + return ESP_OK; +} + +static esp_err_t execute_callback(callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id, + uint32_t attribute_id, esp_matter_attr_val_t *val) +{ + if (attribute_callback) { +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + void *priv_data = endpoint::get_priv_data(endpoint_id); +#else + void *priv_data = nullptr; +#endif + return attribute_callback(type, endpoint_id, cluster_id, attribute_id, val, priv_data); + } + return ESP_OK; +} + +/** + * Check whether the attribute value is in the range of attribute bounds + * + * @param[in] val Attribute value. + * @param[in] bounds Attribute bounds. + * + * @return 0 if val is in the range of attribute bounds. + * @return 1 if val is more than bounds.max + * @return -1 if val is less than bounds.min + * @return -2 if val type is wrong + */ +static int compare_attr_val_with_bounds(esp_matter_attr_val_t val, esp_matter_attr_bounds_t bounds) +{ + switch (val.type) { + case ESP_MATTER_VAL_TYPE_UINT8: + case ESP_MATTER_VAL_TYPE_ENUM8: + case ESP_MATTER_VAL_TYPE_BITMAP8: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT8: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8: { + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.u8)) { + return 0; + } + if (val.val.u8 < bounds.min.val.u8) { + return -1; + } else if (val.val.u8 > bounds.max.val.u8) { + return 1; + } else { + return 0; + } + break; + } + case ESP_MATTER_VAL_TYPE_UINT16: + case ESP_MATTER_VAL_TYPE_ENUM16: + case ESP_MATTER_VAL_TYPE_BITMAP16: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT16: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16: { + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.u16)) { + return 0; + } + if (val.val.u16 < bounds.min.val.u16) { + return -1; + } else if (val.val.u16 > bounds.max.val.u16) { + return 1; + } else { + return 0; + } + break; + } + case ESP_MATTER_VAL_TYPE_UINT32: + case ESP_MATTER_VAL_TYPE_BITMAP32: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT32: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32: { + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.u32)) { + return 0; + } + if (val.val.u32 < bounds.min.val.u32) { + return -1; + } else if (val.val.u32 > bounds.max.val.u32) { + return 1; + } else { + return 0; + } + break; + } + case ESP_MATTER_VAL_TYPE_UINT64: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT64: { + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.u64)) { + return 0; + } + if (val.val.u64 < bounds.min.val.u64) { + return -1; + } else if (val.val.u64 > bounds.max.val.u64) { + return 1; + } else { + return 0; + } + break; + } + case ESP_MATTER_VAL_TYPE_INT8: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT8: { + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.i8)) { + return 0; + } + if (val.val.i8 < bounds.min.val.i8) { + return -1; + } else if (val.val.i8 > bounds.max.val.i8) { + return 1; + } else { + return 0; + } + break; + } + case ESP_MATTER_VAL_TYPE_INT16: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT16: { + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.i16)) { + return 0; + } + if (val.val.i16 < bounds.min.val.i16) { + return -1; + } else if (val.val.i16 > bounds.max.val.i16) { + return 1; + } else { + return 0; + } + break; + } + case ESP_MATTER_VAL_TYPE_INT32: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT32: { + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.i32)) { + return 0; + } + if (val.val.i32 < bounds.min.val.i32) { + return -1; + } else if (val.val.i32 > bounds.max.val.i32) { + return 1; + } else { + return 0; + } + break; + } + case ESP_MATTER_VAL_TYPE_INT64: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT64: { + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.i64)) { + return 0; + } + if (val.val.i64 < bounds.min.val.i64) { + return -1; + } else if (val.val.i64 > bounds.max.val.i64) { + return 1; + } else { + return 0; + } + break; + } + case ESP_MATTER_VAL_TYPE_FLOAT: + case ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT: { + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.f)) { + return 0; + } + if (val.val.f < bounds.min.val.f) { + return -1; + } else if (val.val.f > bounds.max.val.f) { + return 1; + } else { + return 0; + } + break; + } + default: + ESP_LOGE(TAG, "Failed to compare_attr_val_with_bounds as the attribute value type is wrong"); + break; + } + return -2; +} + +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); + if (compare_result == 1) { + current_attribute->val = current_attribute->bounds->max; + } else if (compare_result == -1) { + current_attribute->val = current_attribute->bounds->min; + } else if (compare_result != 0) { + return ESP_ERR_INVALID_ARG; + } + return ESP_OK; +} + attribute_t *create(cluster_t *cluster, uint32_t attribute_id, uint16_t flags, esp_matter_attr_val_t val, uint16_t max_val_size) { @@ -590,73 +487,45 @@ attribute_t *create(cluster_t *cluster, uint32_t attribute_id, uint16_t flags, e _cluster_t *current_cluster = (_cluster_t *)cluster; attribute_t *existing_attribute = get(cluster, attribute_id); if (existing_attribute) { - ESP_LOGW(TAG, "Attribute 0x%08" PRIX32 " on cluster 0x%08" PRIX32 " already exists. Not creating again.", attribute_id, - cluster::get_id(cluster)); + ESP_LOGW(TAG, "Attribute 0x%08" PRIX32 " on cluster 0x%08" PRIX32 " already exists. Not creating again.", + attribute_id, cluster::get_id(cluster)); return existing_attribute; } - - endpoint_t *endpoint = endpoint::get(current_cluster->endpoint_id); - _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; - - /* Matter attributes */ - EmberAfCluster *matter_clusters = (EmberAfCluster *)(¤t_endpoint->endpoint_type->cluster[current_cluster->index]); - matter_clusters->attributeCount++; - int attribute_count = matter_clusters->attributeCount; - - if (current_cluster->matter_attributes) { - current_cluster->matter_attributes = (EmberAfAttributeMetadata *)esp_matter_mem_realloc(current_cluster->matter_attributes, attribute_count * sizeof(EmberAfAttributeMetadata)); - } else { - current_cluster->matter_attributes = (EmberAfAttributeMetadata *)esp_matter_mem_calloc(1, attribute_count * sizeof(EmberAfAttributeMetadata)); - } - if (!current_cluster->matter_attributes) { - ESP_LOGE(TAG, "Couldn't allocate matter_attributes"); - return NULL; - } - - /* Set */ - EmberAfAttributeMetadata *matter_attribute = ¤t_cluster->matter_attributes[attribute_count - 1]; - matter_attribute->attributeId = attribute_id; - - /* esp-matter uses uint16_t as the flags for the extras, EmberAfAttributeMetadata uses uint8_t as the mask. - The conversion from uint16 to uint8 is as expected for that the extra flags are only used in esp-matter. */ - matter_attribute->mask = static_cast(flags); - if (!(flags & ATTRIBUTE_FLAG_MANAGED_INTERNALLY)) { - matter_attribute->mask |= ATTRIBUTE_FLAG_EXTERNAL_STORAGE; - } - matter_attribute->attributeType = 0; - matter_attribute->size = 0; _attribute_t *attribute = NULL; - if (!(flags & ATTRIBUTE_FLAG_MANAGED_INTERNALLY)) { - /* Allocate */ + + if (flags & ATTRIBUTE_FLAG_MANAGED_INTERNALLY) { + /* Create */ + attribute = (_attribute_t *)esp_matter_mem_calloc(1, sizeof(_attribute_base_t)); + if (!attribute) { + return nullptr; + } + + /* Set */ + attribute->flags = flags; + attribute->attribute_id = attribute_id; + } else { attribute = (_attribute_t *)esp_matter_mem_calloc(1, sizeof(_attribute_t)); if (!attribute) { - ESP_LOGE(TAG, "Couldn't allocate _attribute_t"); - return NULL; + return nullptr; } - attribute->index = attribute_count - 1; - attribute->attribute_id = attribute_id; - attribute->cluster_id = matter_clusters->clusterId; - attribute->endpoint_id = current_cluster->endpoint_id; + + /* Set */ attribute->flags = flags; - attribute->flags |= ATTRIBUTE_FLAG_EXTERNAL_STORAGE; - - // After reboot, string and array are treated as Invalid. So need to store val.type and size of attribute value. + attribute->attribute_id = attribute_id; + attribute->override_callback = nullptr; + attribute->cluster_id = current_cluster->cluster_id; + attribute->endpoint_id = current_cluster->endpoint_id; 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 || - val.type == ESP_MATTER_VAL_TYPE_ARRAY) { - attribute->val.val.a.s = val.val.a.s; - attribute->val.val.a.n = val.val.a.n; - attribute->val.val.a.t = val.val.a.t; + 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; + 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. - esp_err_t err = get_val_from_nvs(attribute->endpoint_id, attribute->cluster_id, attribute_id, - attribute->val); + esp_err_t err = + get_val_from_nvs(attribute->endpoint_id, attribute->cluster_id, attribute_id, attribute->val); if (err == ESP_OK) { attribute_updated = true; } @@ -664,22 +533,6 @@ attribute_t *create(cluster_t *cluster, uint32_t attribute_id, uint16_t flags, e if (!attribute_updated) { set_val((attribute_t *)attribute, &val); } - - set_default_value_from_current_val((attribute_t *)attribute, NULL, NULL); - - attribute::get_data_from_attr_val(&attribute->val, &matter_attribute->attributeType, - &matter_attribute->size, NULL); - if (attribute->val.type == ESP_MATTER_VAL_TYPE_CHAR_STRING || - attribute->val.type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING) { - uint16_t size_for_storing_str_len = attribute->val.val.a.t - attribute->val.val.a.s; - matter_attribute->size = max_val_size + size_for_storing_str_len; - } - matter_clusters->clusterSize += matter_attribute->size; - } else { - attribute = (_attribute_t *)esp_matter_mem_calloc(1, sizeof(_attribute_base_t)); - attribute->attribute_id = attribute_id; - attribute->index = attribute_count - 1; - attribute->flags = flags; } /* Add */ @@ -698,9 +551,6 @@ static esp_err_t destroy(attribute_t *attribute) return ESP_OK; } - /* Default value needs to be deleted first since it uses the current val. */ - free_default_value(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 || @@ -713,7 +563,8 @@ static esp_err_t destroy(attribute_t *attribute) /* Erase the persistent data */ if (attribute::get_flags(attribute) & ATTRIBUTE_FLAG_NONVOLATILE) { - erase_val_in_nvs(current_attribute->endpoint_id, current_attribute->cluster_id, current_attribute->attribute_id); + erase_val_in_nvs(current_attribute->endpoint_id, current_attribute->cluster_id, + current_attribute->attribute_id); } /* Free */ @@ -774,29 +625,58 @@ static void deferred_attribute_write(chip::System::Layer *layer, void *attribute current_attribute->val); } -esp_err_t set_val(attribute_t *attribute, esp_matter_attr_val_t *val) +esp_err_t set_val(attribute_t *attribute, esp_matter_attr_val_t *val, bool call_callbacks) { - VerifyOrReturnError(attribute, ESP_FAIL, ESP_LOGE(TAG, "Attribute cannot be NULL")); + VerifyOrReturnError(attribute && val, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Attribute and val cannot be NULL")); _attribute_t *current_attribute = (_attribute_t *)attribute; 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")); + 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)) { + // If the value is not changed, return ESP_ERR_NOT_FINISHED directly. + return ESP_ERR_NOT_FINISHED; + } + /* Callback to application */ + if (call_callbacks) { + ESP_RETURN_ON_ERROR(execute_callback(attribute::PRE_UPDATE, current_attribute->endpoint_id, + current_attribute->cluster_id, current_attribute->attribute_id, val), + TAG, "Failed to execute pre update callback"); + } + // TODO: call pre attribute change function is the cluster has the flag if (val->type == ESP_MATTER_VAL_TYPE_CHAR_STRING || val->type == ESP_MATTER_VAL_TYPE_OCTET_STRING || - val->type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING || val->type == ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING || - val->type == ESP_MATTER_VAL_TYPE_ARRAY) { - /* Free old buf */ - esp_matter_mem_free(current_attribute->val.val.a.b); - current_attribute->val.val.a.b = NULL; + val->type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING || val->type == ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING) { + uint16_t null_len = + (val->type == ESP_MATTER_VAL_TYPE_CHAR_STRING || val->type == ESP_MATTER_VAL_TYPE_OCTET_STRING) + ? UINT8_MAX + : UINT16_MAX; if (val->val.a.s > 0) { - /* Alloc new buf */ - uint8_t *new_buf = (uint8_t *)esp_matter_mem_calloc(1, val->val.a.s); - VerifyOrReturnError(new_buf, ESP_ERR_NO_MEM, ESP_LOGE(TAG, "Could not allocate new buffer")); - /* Copy to new buf and assign */ - memcpy(new_buf, val->val.a.b, val->val.a.s); + uint8_t *new_buf = nullptr; + if (val->val.a.s != null_len) { + if (val->val.a.s > current_attribute->val.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; + + bool null_reserve = + val->type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING || val->type == ESP_MATTER_VAL_TYPE_CHAR_STRING; + /* Alloc new buf */ + new_buf = (uint8_t *)esp_matter_mem_calloc(1, val->val.a.s + (null_reserve ? 1 : 0)); + VerifyOrReturnError(new_buf, ESP_ERR_NO_MEM, ESP_LOGE(TAG, "Could not allocate new buffer")); + /* 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.n = val->val.a.n; current_attribute->val.val.a.t = val->val.a.t; } else { ESP_LOGD(TAG, "Set val called with string with size 0"); @@ -804,11 +684,24 @@ esp_err_t set_val(attribute_t *attribute, esp_matter_attr_val_t *val) } else { memcpy((void *)¤t_attribute->val, (void *)val, sizeof(esp_matter_attr_val_t)); } + /* Callback to application */ + if (call_callbacks) { + execute_callback(attribute::POST_UPDATE, current_attribute->endpoint_id, current_attribute->cluster_id, + current_attribute->attribute_id, val); + cluster_t *cluster = cluster::get(current_attribute->endpoint_id, current_attribute->cluster_id); + cluster::function_attribute_change_t attr_change_function = + (cluster::function_attribute_change_t)cluster::get_function(cluster, CLUSTER_FLAG_ATTRIBUTE_CHANGED_FUNCTION); + + if (attr_change_function) { + attr_change_function(chip::app::ConcreteAttributePath( + current_attribute->endpoint_id, current_attribute->cluster_id, current_attribute->attribute_id)); + } + } if (current_attribute->flags & ATTRIBUTE_FLAG_NONVOLATILE) { if (current_attribute->flags & ATTRIBUTE_FLAG_DEFERRED) { if (!chip::DeviceLayer::SystemLayer().IsTimerActive(deferred_attribute_write, current_attribute)) { - auto & system_layer = chip::DeviceLayer::SystemLayer(); + auto &system_layer = chip::DeviceLayer::SystemLayer(); system_layer.StartTimer(chip::System::Clock::Milliseconds16(k_deferred_attribute_persistence_time_ms), deferred_attribute_write, current_attribute); } @@ -817,6 +710,7 @@ esp_err_t set_val(attribute_t *attribute, esp_matter_attr_val_t *val) current_attribute->attribute_id, current_attribute->val); } } + return ESP_OK; } @@ -844,24 +738,24 @@ esp_err_t add_bounds(attribute_t *attribute, esp_matter_attr_val_t min, esp_matt 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) { - ESP_LOGE(TAG, "Bounds cannot be set for string/array type attributes"); + current_attribute->val.type == ESP_MATTER_VAL_TYPE_ARRAY || + current_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)), 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)); - - EmberAfAttributeMetadata *matter_attribute= get_external_attribute_metadata(current_attribute); - if (!matter_attribute) { - ESP_LOGE(TAG, "Attribute Metadata is not found"); - return ESP_ERR_NOT_FOUND; + VerifyOrReturnError(((current_attribute->val.type == min.type) && (current_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->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"); + return ESP_ERR_NO_MEM; } - matter_attribute->mask |= ATTRIBUTE_FLAG_MIN_MAX; current_attribute->flags |= ATTRIBUTE_FLAG_MIN_MAX; - - /* Set the default value again after setting the bounds and the flag */ - set_default_value_from_current_val(attribute, &min, &max); - return ESP_OK; + current_attribute->bounds->min = min; + current_attribute->bounds->max = max; + return bound_attribute_val(attribute); } esp_err_t get_bounds(attribute_t *attribute, esp_matter_attr_bounds_t *bounds) @@ -871,31 +765,18 @@ esp_err_t get_bounds(attribute_t *attribute, esp_matter_attr_bounds_t *bounds) return ESP_ERR_INVALID_ARG; } _attribute_t *current_attribute = (_attribute_t *)attribute; - - EmberAfAttributeMetadata *matter_attribute= get_external_attribute_metadata(current_attribute); - if (!matter_attribute) { - ESP_LOGE(TAG, "Attribute Metadata is not found"); - return ESP_ERR_NOT_FOUND; - } - - if (!(matter_attribute->mask & ATTRIBUTE_FLAG_MIN_MAX)) { - ESP_LOGW(TAG, "Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " has not set bounds", - current_attribute->endpoint_id, current_attribute->cluster_id, matter_attribute->attributeId); + if (current_attribute->flags & ATTRIBUTE_FLAG_MANAGED_INTERNALLY) { + ESP_LOGE(TAG, "Cannot get bounds for attribute managed internally"); return ESP_ERR_INVALID_ARG; } - if (matter_attribute->size > 2) { - get_attr_val_from_data(&bounds->min, matter_attribute->attributeType, matter_attribute->size, (uint8_t *)matter_attribute->defaultValue.ptrToMinMaxValue->minValue.ptrToDefaultValue, matter_attribute); - get_attr_val_from_data(&bounds->max, matter_attribute->attributeType, matter_attribute->size, (uint8_t *)matter_attribute->defaultValue.ptrToMinMaxValue->maxValue.ptrToDefaultValue, matter_attribute); - } else { - uint8_t value[2]; - uint16_t min_value = matter_attribute->defaultValue.ptrToMinMaxValue->minValue.defaultValue; - memcpy(value, &min_value, matter_attribute->size); - get_attr_val_from_data(&bounds->min, matter_attribute->attributeType, matter_attribute->size, value, matter_attribute); - uint16_t max_value = matter_attribute->defaultValue.ptrToMinMaxValue->maxValue.defaultValue; - memcpy(value, &max_value, matter_attribute->size); - get_attr_val_from_data(&bounds->max, matter_attribute->attributeType, matter_attribute->size, value, matter_attribute); + if (!(current_attribute->flags & ATTRIBUTE_FLAG_MIN_MAX)) { + ESP_LOGW(TAG, + "Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " has not set bounds", + current_attribute->endpoint_id, current_attribute->cluster_id, current_attribute->attribute_id); + return ESP_ERR_INVALID_ARG; } + *bounds = *current_attribute->bounds; return ESP_OK; } @@ -914,8 +795,6 @@ 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"); - cluster_t *cluster = cluster::get(current_attribute->endpoint_id, current_attribute->cluster_id); - 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 || @@ -923,8 +802,7 @@ esp_err_t set_override_callback(attribute_t *attribute, callback_t callback) current_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 " on cluster 0x%" PRIX32, - current_attribute->attribute_id, cluster::get_id(cluster)); + ESP_LOGE(TAG, "Cannot set override callback for attribute 0x%" PRIX32, current_attribute->attribute_id); return ESP_ERR_NOT_SUPPORTED; } current_attribute->override_callback = callback; @@ -937,7 +815,8 @@ callback_t get_override_callback(attribute_t *attribute) VerifyOrReturnValue(attribute, NULL, ESP_LOGE(TAG, "Attribute cannot be NULL")); _attribute_t *current_attribute = (_attribute_t *)attribute; - VerifyOrReturnValue(!(current_attribute->flags & ATTRIBUTE_FLAG_MANAGED_INTERNALLY), NULL, ESP_LOGE(TAG, "Attribute is not managed by esp matter data model")); + VerifyOrReturnValue(!(current_attribute->flags & ATTRIBUTE_FLAG_MANAGED_INTERNALLY), NULL, + ESP_LOGE(TAG, "Attribute is not managed by esp matter data model")); return current_attribute->override_callback; } @@ -958,7 +837,7 @@ esp_err_t set_deferred_persistence(attribute_t *attribute) return ESP_OK; } -} /* attribute */ +} // namespace attribute namespace command { command_t *create(cluster_t *cluster, uint32_t command_id, uint8_t flags, callback_t callback) @@ -968,8 +847,8 @@ command_t *create(cluster_t *cluster, uint32_t command_id, uint8_t flags, callba _cluster_t *current_cluster = (_cluster_t *)cluster; command_t *existing_command = get(cluster, command_id, flags); if (existing_command) { - ESP_LOGW(TAG, "Command 0x%08" PRIX32 " on cluster 0x%08" PRIX32 " already exists. Not creating again.", command_id, - cluster::get_id(cluster)); + ESP_LOGW(TAG, "Command 0x%08" PRIX32 " on cluster 0x%08" PRIX32 " already exists. Not creating again.", + command_id, cluster::get_id(cluster)); return existing_command; } @@ -1068,7 +947,7 @@ uint16_t get_flags(command_t *command) return current_command->flags; } -} /* command */ +} // namespace command namespace event { @@ -1131,8 +1010,7 @@ uint32_t get_id(event_t *event) return current_event->event_id; } -} /* event */ - +} // namespace event namespace cluster { @@ -1140,31 +1018,13 @@ cluster_t *create(endpoint_t *endpoint, uint32_t cluster_id, uint8_t flags) { /* Find */ VerifyOrReturnValue(endpoint, NULL, ESP_LOGE(TAG, "Endpoint cannot be NULL")); - VerifyOrReturnValue(((flags & CLUSTER_FLAG_SERVER) || (flags & CLUSTER_FLAG_CLIENT)), NULL, ESP_LOGE(TAG, "Server or client cluster flag not set")); + VerifyOrReturnValue(((flags & CLUSTER_FLAG_SERVER) || (flags & CLUSTER_FLAG_CLIENT)), NULL, + ESP_LOGE(TAG, "Server or client cluster flag not set")); _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; cluster_t *existing_cluster = get(endpoint, cluster_id); if (existing_cluster) { - /* If a server already exists, do not create it again */ _cluster_t *_existing_cluster = (_cluster_t *)existing_cluster; - // The member EmberAfCluster * in EmberAfEndpointType is const, do a non-const cast to change the mask. - EmberAfClusterMask *cluster_flags = (EmberAfClusterMask *)¤t_endpoint->endpoint_type->cluster[_existing_cluster->index].mask; - if ((*cluster_flags & CLUSTER_FLAG_SERVER) && (flags & CLUSTER_FLAG_SERVER)) { - ESP_LOGW(TAG, "Server Cluster 0x%08" PRIX32 " on endpoint 0x%04" PRIx16 " already exists. Not creating again.", cluster_id, - current_endpoint->endpoint_id); - return existing_cluster; - } - - /* If a client already exists, do not create it again */ - if ((*cluster_flags & CLUSTER_FLAG_CLIENT) && (flags & CLUSTER_FLAG_CLIENT)) { - ESP_LOGW(TAG, "Client Cluster 0x%08" PRIX32 " on endpoint 0x%04" PRIx16 " already exists. Not creating again.", cluster_id, - current_endpoint->endpoint_id); - return existing_cluster; - } - - /* The cluster already exists, but is of a different type. Just update the 'Set' part from below. */ - ESP_LOGI(TAG, "Cluster 0x%08" PRIX32 " on endpoint 0x%04" PRIx16 " already exists. Updating values.", cluster_id, - current_endpoint->endpoint_id); - *cluster_flags |= flags; + _existing_cluster->flags |= flags; return existing_cluster; } @@ -1175,30 +1035,18 @@ cluster_t *create(endpoint_t *endpoint, uint32_t cluster_id, uint8_t flags) return NULL; } - /* Matter clusters */ - EmberAfCluster *matter_clusters = (EmberAfCluster *)current_endpoint->endpoint_type->cluster; - current_endpoint->cluster_count++; - cluster->index = current_endpoint->cluster_count - 1; - if (matter_clusters) { - matter_clusters = (EmberAfCluster *)esp_matter_mem_realloc(matter_clusters, current_endpoint->cluster_count * sizeof(EmberAfCluster)); - } else { - matter_clusters = (EmberAfCluster *)esp_matter_mem_calloc(1, current_endpoint->cluster_count * sizeof(EmberAfCluster)); - } - if (!matter_clusters) { - ESP_LOGE(TAG, "Couldn't allocate EmberAfCluster"); - return NULL; - } - current_endpoint->endpoint_type->cluster = matter_clusters; - /* Set */ - EmberAfCluster *matter_cluster = (EmberAfCluster *)¤t_endpoint->endpoint_type->cluster[cluster->index]; + cluster->cluster_id = cluster_id; cluster->endpoint_id = current_endpoint->endpoint_id; - - matter_cluster->clusterId = cluster_id; - matter_cluster->mask = flags; - matter_cluster->clusterSize = 0; - matter_cluster->attributeCount = 0; - matter_cluster->functions = NULL; + cluster->flags = flags; + cluster->add_bounds_callback = nullptr; + cluster->attribute_list = nullptr; + cluster->delegate_init_callback = nullptr; + cluster->data_version = esp_random(); // Generate a random 32-bit number + cluster->functions = nullptr; + cluster->plugin_server_init_callback = nullptr; + cluster->init_callback = nullptr; + cluster->shutdown_callback = nullptr; /* Add */ SinglyLinkedList<_cluster_t>::append(¤t_endpoint->cluster_list, cluster); @@ -1224,12 +1072,6 @@ esp_err_t destroy(cluster_t *cluster) /* Parse and delete all events */ SinglyLinkedList<_event_t>::delete_list(¤t_cluster->event_list); - /* Free matter_attributes if allocated */ - if (current_cluster->matter_attributes) { - esp_matter_mem_free(current_cluster->matter_attributes); - current_cluster->matter_attributes = NULL; - } - /* Free */ esp_matter_mem_free(current_cluster); return ESP_OK; @@ -1241,19 +1083,8 @@ cluster_t *get(endpoint_t *endpoint, uint32_t cluster_id) _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; _cluster_t *current_cluster = (_cluster_t *)current_endpoint->cluster_list; - uint8_t cluster_index = 0; - for (cluster_index = 0; cluster_index < current_endpoint->cluster_count; cluster_index++) { - if (current_endpoint->endpoint_type->cluster[cluster_index].clusterId == cluster_id) { - break; - } - } - if (cluster_index == current_endpoint->cluster_count) { - ESP_LOGD(TAG, "Cluster not found"); - return NULL; - } - while (current_cluster) { - if (current_cluster->index == cluster_index) { + if (current_cluster->cluster_id == cluster_id) { break; } current_cluster = current_cluster->next; @@ -1285,9 +1116,30 @@ uint32_t get_id(cluster_t *cluster) { VerifyOrReturnValue(cluster, kInvalidClusterId, ESP_LOGE(TAG, "Cluster cannot be NULL")); _cluster_t *current_cluster = (_cluster_t *)cluster; - endpoint_t *endpoint = endpoint::get(current_cluster->endpoint_id); - _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; - return current_endpoint->endpoint_type->cluster[current_cluster->index].clusterId; + return current_cluster->cluster_id; +} + +uint8_t get_flags(cluster_t *cluster) +{ + VerifyOrReturnValue(cluster, 0, ESP_LOGE(TAG, "Cluster cannot be NULL")); + _cluster_t *current_cluster = (_cluster_t *)cluster; + return current_cluster->flags; +} + +esp_err_t get_data_version(cluster_t *cluster, chip::DataVersion &data_version) +{ + VerifyOrReturnValue(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL")); + _cluster_t *current_cluster = (_cluster_t *)cluster; + data_version = current_cluster->data_version; + return ESP_OK; +} + +esp_err_t increase_data_version(cluster_t *cluster) +{ + VerifyOrReturnValue(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL")); + _cluster_t *current_cluster = (_cluster_t *)cluster; + current_cluster->data_version++; + return ESP_OK; } void *get_delegate_impl(cluster_t *cluster) @@ -1347,16 +1199,54 @@ esp_err_t add_function_list(cluster_t *cluster, const function_generic_t *functi { VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL")); _cluster_t *current_cluster = (_cluster_t *)cluster; - - endpoint_t *endpoint = endpoint::get(current_cluster->endpoint_id); - _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; - EmberAfCluster *matter_clusters = (EmberAfCluster *)current_endpoint->endpoint_type->cluster; - matter_clusters[current_cluster->index].mask |= function_flags; - matter_clusters[current_cluster->index].functions = (const EmberAfGenericClusterFunction *)function_list; + current_cluster->flags |= function_flags; + current_cluster->functions = function_list; return ESP_OK; } -} /* cluster */ +function_generic_t get_function(cluster_t *cluster, uint8_t function_flag) +{ + VerifyOrReturnValue(cluster, nullptr, ESP_LOGE(TAG, "Cluster cannot be NULL")); + _cluster_t *current_cluster = (_cluster_t *)cluster; + if ((current_cluster->flags & function_flag) == 0) { + return nullptr; + } + uint8_t flag = 0x01; + uint8_t index = 0; + while (flag < function_flag) { + if ((current_cluster->flags & flag) != 0) { + index++; + } + flag = flag << 1; + } + return current_cluster->functions[index]; +} + +esp_err_t set_init_and_shutdown_callbacks(cluster_t *cluster, initialization_callback_t init_callback, + shutdown_callback_t shutdown_callback) +{ + VerifyOrReturnValue(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL")); + _cluster_t *current_cluster = (_cluster_t *)cluster; + current_cluster->init_callback = init_callback; + current_cluster->shutdown_callback = shutdown_callback; + return ESP_OK; +} + +initialization_callback_t get_init_callback(cluster_t *cluster) +{ + VerifyOrReturnValue(cluster, nullptr, ESP_LOGE(TAG, "Cluster cannot be NULL")); + _cluster_t *current_cluster = (_cluster_t *)cluster; + return current_cluster->init_callback; +} + +shutdown_callback_t get_shutdown_callback(cluster_t *cluster) +{ + VerifyOrReturnValue(cluster, nullptr, ESP_LOGE(TAG, "Cluster cannot be NULL")); + _cluster_t *current_cluster = (_cluster_t *)cluster; + return current_cluster->shutdown_callback; +} + +} // namespace cluster namespace endpoint { @@ -1366,26 +1256,24 @@ endpoint_t *create(node_t *node, uint8_t flags, void *priv_data) VerifyOrReturnValue(node, NULL, ESP_LOGE(TAG, "Node cannot be NULL")); _node_t *current_node = (_node_t *)node; - VerifyOrReturnValue(get_count(node) < CONFIG_ESP_MATTER_MAX_DYNAMIC_ENDPOINT_COUNT, NULL, ESP_LOGE(TAG, "Dynamic endpoint count cannot be greater than CONFIG_ESP_MATTER_MAX_DYNAMIC_ENDPOINT_COUNT:%u", - CONFIG_ESP_MATTER_MAX_DYNAMIC_ENDPOINT_COUNT)); + VerifyOrReturnValue( + get_count(node) < CONFIG_ESP_MATTER_MAX_DYNAMIC_ENDPOINT_COUNT, NULL, + ESP_LOGE(TAG, "Dynamic endpoint count cannot be greater than CONFIG_ESP_MATTER_MAX_DYNAMIC_ENDPOINT_COUNT:%u", + CONFIG_ESP_MATTER_MAX_DYNAMIC_ENDPOINT_COUNT)); /* Allocate */ _endpoint_t *endpoint = (_endpoint_t *)esp_matter_mem_calloc(1, sizeof(_endpoint_t)); VerifyOrReturnValue(endpoint, NULL, ESP_LOGE(TAG, "Couldn't allocate _endpoint_t")); - endpoint->endpoint_type = (EmberAfEndpointType *)esp_matter_mem_calloc(1, sizeof(EmberAfEndpointType)); - if (!endpoint->endpoint_type) { - ESP_LOGE(TAG, "Couldn't allocate EmberAfEndpointType"); - esp_matter_mem_free(endpoint); - return NULL; - } - /* Set */ endpoint->endpoint_id = current_node->min_unused_endpoint_id++; endpoint->device_type_count = 0; endpoint->parent_endpoint_id = chip::kInvalidEndpointId; endpoint->flags = flags; endpoint->priv_data = priv_data; + endpoint->composition_pattern = EndpointCompositionPattern::kFullFamily; + endpoint->semantic_tag_count = 0; + endpoint->enabled = true; /* Store */ if (esp_matter::is_started()) { node::store_min_unused_endpoint_id(); @@ -1393,6 +1281,7 @@ endpoint_t *create(node_t *node, uint8_t flags, void *priv_data) /* Add */ SinglyLinkedList<_endpoint_t>::append(¤t_node->endpoint_list, endpoint); + return (endpoint_t *)endpoint; } @@ -1404,32 +1293,28 @@ endpoint_t *resume(node_t *node, uint8_t flags, uint16_t endpoint_id, void *priv _endpoint_t *previous_endpoint = NULL; _endpoint_t *current_endpoint = current_node->endpoint_list; while (current_endpoint) { - VerifyOrReturnValue(current_endpoint->endpoint_id != endpoint_id, NULL, ESP_LOGE(TAG, "Could not resume an endpoint that has been added to the node")); + VerifyOrReturnValue(current_endpoint->endpoint_id != endpoint_id, NULL, + ESP_LOGE(TAG, "Could not resume an endpoint that has been added to the node")); previous_endpoint = current_endpoint; current_endpoint = current_endpoint->next; } /* Check */ - VerifyOrReturnError(endpoint_id < current_node->min_unused_endpoint_id, NULL, ESP_LOGE(TAG, "The endpoint_id of the resumed endpoint should have been used")); + VerifyOrReturnError(endpoint_id < current_node->min_unused_endpoint_id, NULL, + ESP_LOGE(TAG, "The endpoint_id of the resumed endpoint should have been used")); - /* Allocate */ - _endpoint_t *endpoint = (_endpoint_t *)esp_matter_mem_calloc(1, sizeof(_endpoint_t)); - VerifyOrReturnValue(endpoint, NULL, ESP_LOGE(TAG, "Couldn't allocate _endpoint_t")); + /* Allocate */ + _endpoint_t *endpoint = (_endpoint_t *)esp_matter_mem_calloc(1, sizeof(_endpoint_t)); + VerifyOrReturnValue(endpoint, NULL, ESP_LOGE(TAG, "Couldn't allocate _endpoint_t")); - endpoint->endpoint_type = (EmberAfEndpointType *)esp_matter_mem_calloc(1, sizeof(EmberAfEndpointType)); - if (!endpoint->endpoint_type) { - ESP_LOGE(TAG, "Couldn't allocate EmberAfEndpointType"); - esp_matter_mem_free(endpoint); - return NULL; - } + /* Set */ + endpoint->endpoint_id = endpoint_id; + endpoint->device_type_count = 0; + endpoint->flags = flags; + endpoint->priv_data = priv_data; + endpoint->composition_pattern = EndpointCompositionPattern::kFullFamily; - /* Set */ - endpoint->endpoint_id = endpoint_id; - endpoint->device_type_count = 0; - endpoint->flags = flags; - endpoint->priv_data = priv_data; - - /* Add */ + /* Add */ if (previous_endpoint == NULL) { current_node->endpoint_list = endpoint; } else { @@ -1445,7 +1330,9 @@ esp_err_t destroy(node_t *node, endpoint_t *endpoint) _node_t *current_node = (_node_t *)node; _endpoint_t *_endpoint = (_endpoint_t *)endpoint; - VerifyOrReturnError((_endpoint->flags & ENDPOINT_FLAG_DESTROYABLE), ESP_FAIL, ESP_LOGE(TAG, "This endpoint cannot be deleted since the ENDPOINT_FLAG_DESTROYABLE is not set")); + VerifyOrReturnError( + (_endpoint->flags & ENDPOINT_FLAG_DESTROYABLE), ESP_FAIL, + ESP_LOGE(TAG, "This endpoint cannot be deleted since the ENDPOINT_FLAG_DESTROYABLE is not set")); /* Disable */ disable(endpoint); @@ -1472,44 +1359,6 @@ esp_err_t destroy(node_t *node, endpoint_t *endpoint) current_endpoint->cluster_list = cluster; } - /* Free endpoint_type after freeing cluster_list */ - { - /* Free all clusters in endpoint_type */ - EmberAfEndpointType *endpoint_type = current_endpoint->endpoint_type; - VerifyOrReturnError(endpoint_type, ESP_ERR_INVALID_STATE, ESP_LOGE(TAG, "endpoint %" PRIu16 "'s endpoint_type is NULL", current_endpoint->endpoint_id)); - int cluster_count = endpoint_type->clusterCount; - for (int cluster_index = 0; cluster_index < cluster_count; cluster_index++) { - /* Free commands */ - if (endpoint_type->cluster[cluster_index].acceptedCommandList) { - esp_matter_mem_free((void *)endpoint_type->cluster[cluster_index].acceptedCommandList); - } - if (endpoint_type->cluster[cluster_index].generatedCommandList) { - esp_matter_mem_free((void *)endpoint_type->cluster[cluster_index].generatedCommandList); - } - /* Free events */ - if (endpoint_type->cluster[cluster_index].eventList) { - esp_matter_mem_free((void *)endpoint_type->cluster[cluster_index].eventList); - } - } - esp_matter_mem_free((void *)endpoint_type->cluster); - - /* Free data versions */ - if (current_endpoint->data_versions_ptr) { - esp_matter_mem_free(current_endpoint->data_versions_ptr); - current_endpoint->data_versions_ptr = NULL; - } - - /* Free device types */ - if (current_endpoint->device_types_ptr) { - esp_matter_mem_free(current_endpoint->device_types_ptr); - current_endpoint->device_types_ptr = NULL; - } - - /* Free endpoint type */ - esp_matter_mem_free(endpoint_type); - current_endpoint->endpoint_type = NULL; - } - /* Remove from list */ if (previous_endpoint == NULL) { current_node->endpoint_list = current_endpoint->next; @@ -1547,7 +1396,6 @@ endpoint_t *get(uint16_t endpoint_id) return get(node, endpoint_id); } - endpoint_t *get_first(node_t *node) { VerifyOrReturnValue(node, NULL, ESP_LOGE(TAG, "Node cannot be NULL")); @@ -1572,7 +1420,6 @@ uint16_t get_count(node_t *node) endpoint = get_next(endpoint); } return count; - } uint16_t get_id(endpoint_t *endpoint) @@ -1588,37 +1435,172 @@ esp_err_t add_device_type(endpoint_t *endpoint, uint32_t device_type_id, uint8_t _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; VerifyOrReturnError(current_endpoint->device_type_count < ESP_MATTER_MAX_DEVICE_TYPE_COUNT, ESP_FAIL, ESP_LOGE(TAG, "Could not add a new device-type:%" PRIu32 " to the endpoint", device_type_id)); - current_endpoint->device_type_ids[current_endpoint->device_type_count] = device_type_id; - current_endpoint->device_type_versions[current_endpoint->device_type_count] = device_type_version; + current_endpoint->device_types[current_endpoint->device_type_count].id = device_type_id; + current_endpoint->device_types[current_endpoint->device_type_count].version = device_type_version; current_endpoint->device_type_count++; return ESP_OK; } -uint32_t *get_device_type_ids(endpoint_t *endpoint, uint8_t *device_type_count_ptr) +size_t get_device_type_count(endpoint_t *endpoint) { - VerifyOrReturnValue((endpoint && device_type_count_ptr), NULL, ESP_LOGE(TAG, "Endpoint and device type count pointer cannot be NULL")); + VerifyOrReturnValue(endpoint, 0, ESP_LOGE(TAG, "Endpoint cannot be NULL")); _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; - *device_type_count_ptr = current_endpoint->device_type_count; - return current_endpoint->device_type_ids; + return current_endpoint->device_type_count; } -uint8_t *get_device_type_versions(endpoint_t *endpoint, uint8_t *device_type_count_ptr) +esp_err_t get_device_type_at_index(endpoint_t *endpoint, size_t index, uint32_t &out_device_type_id, + uint8_t &out_device_type_version) { - VerifyOrReturnValue((endpoint && device_type_count_ptr), NULL, ESP_LOGE(TAG, "Endpoint and device type count pointer cannot be NULL")); + VerifyOrReturnValue(endpoint, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Endpoint cannot be NULL")); _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; - *device_type_count_ptr = current_endpoint->device_type_count; - return current_endpoint->device_type_versions; + VerifyOrReturnValue(index < current_endpoint->device_type_count, ESP_ERR_INVALID_ARG, + ESP_LOGE(TAG, "Index should be less than device_type_count")); + out_device_type_id = current_endpoint->device_types[index].id; + out_device_type_version = current_endpoint->device_types[index].version; + return ESP_OK; } esp_err_t set_parent_endpoint(endpoint_t *endpoint, endpoint_t *parent_endpoint) { - VerifyOrReturnError((endpoint && parent_endpoint), ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Endpoint or parent_endpoint cannot be NULL")); + VerifyOrReturnError((endpoint && parent_endpoint), ESP_ERR_INVALID_ARG, + ESP_LOGE(TAG, "Endpoint or parent_endpoint cannot be NULL")); _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; _endpoint_t *current_parent_endpoint = (_endpoint_t *)parent_endpoint; current_endpoint->parent_endpoint_id = current_parent_endpoint->endpoint_id; return ESP_OK; } +uint16_t get_parent_endpoint_id(endpoint_t *endpoint) +{ + VerifyOrReturnValue(endpoint, 0xFFFF, ESP_LOGE(TAG, "Endpoint cannot be NULL")); + _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; + return current_endpoint->parent_endpoint_id; +} + +EndpointCompositionPattern get_composition_pattern(endpoint_t *endpoint) +{ + VerifyOrReturnValue(endpoint, EndpointCompositionPattern::kFullFamily, ESP_LOGE(TAG, "Endpoint cannot be NULL")); + _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; + return current_endpoint->composition_pattern; +} + +esp_err_t set_semantic_tags(endpoint_t *endpoint, chip::app::DataModel::Provider::SemanticTag *tags, size_t tag_count) +{ + VerifyOrReturnValue(endpoint, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Endpoint cannot be NULL")); + VerifyOrReturnValue(tag_count <= ESP_MATTER_MAX_SEMANTIC_TAG_COUNT, ESP_ERR_INVALID_ARG, + ESP_LOGE(TAG, "Tag count should be no more than %d", ESP_MATTER_MAX_SEMANTIC_TAG_COUNT)); + _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; + if (tags != nullptr) { + for (size_t i = 0; i < tag_count; ++i) { + current_endpoint->semantic_tags[i] = tags[i]; + } + } + current_endpoint->semantic_tag_count = tags ? tag_count : 0; + return ESP_OK; +} + +int get_semantic_tag_count(endpoint_t *endpoint) +{ + VerifyOrReturnValue(endpoint, -1, ESP_LOGE(TAG, "Endpoint cannot be NULL")); + _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; + return current_endpoint->semantic_tag_count; +} + +esp_err_t get_semantic_tag_at_index(endpoint_t *endpoint, size_t index, + chip::app::DataModel::Provider::SemanticTag &tag) +{ + VerifyOrReturnValue(endpoint, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Endpoint cannot be NULL")); + _endpoint_t *current_endpoint = (_endpoint_t *)endpoint; + if (index >= current_endpoint->semantic_tag_count) { + return ESP_ERR_NOT_FOUND; + } + tag = current_endpoint->semantic_tags[index]; + return ESP_OK; +} + +/** + * @brief Get the number of clusters that match the given flags + * + * @param endpoint_id: The endpoint ID to check, 0xFFFF is treated as wildcard endpoint id + * @param cluster_id: The cluster ID to check, 0xFFFF is treated as wildcard cluster id + * @param cluster_flags: The flags to check + * @return The number of clusters that match the given flags + */ +uint32_t get_cluster_count(uint32_t endpoint_id, uint32_t cluster_id, uint8_t cluster_flags) +{ + uint32_t count = 0; + node_t *node = node::get(); + VerifyOrReturnValue(node, count, ESP_LOGE(TAG, "Node cannot be NULL")); + + // lambda to check if cluster matches flags and return 1 if it does, 0 otherwise + auto check_cluster_flags = [cluster_flags](const cluster_t *cluster) -> uint32_t { + if (cluster) { + const _cluster_t *_cluster = (_cluster_t *)cluster; + return (_cluster->flags & cluster_flags) ? 1 : 0; + } + return 0; + }; + + // lambda to count all matching clusters for an endpoint + auto get_count_on_all_clusters = [&check_cluster_flags](endpoint_t *endpoint) -> uint32_t { + uint32_t result = 0; + if (!endpoint) + return result; + + cluster_t *cluster = cluster::get_first(endpoint); + while (cluster) { + result += check_cluster_flags(cluster); + cluster = cluster::get_next(cluster); + } + return result; + }; + + // lambda to find and count a specific cluster + auto get_count_on_specific_cluster = [&check_cluster_flags](const endpoint_t *endpoint, + uint32_t cluster_id) -> uint32_t { + if (!endpoint) + return 0; + cluster_t *cluster = cluster::get((endpoint_t *)endpoint, cluster_id); + return check_cluster_flags(cluster); + }; + + // Case 1: Wildcard endpoint + if (is_wildcard_endpoint_id(endpoint_id)) { + endpoint_t *endpoint = endpoint::get_first(node); + while (endpoint) { + if (endpoint::is_enabled(endpoint)) { + // Case 1.1: Wildcard cluster - count all clusters with matching flags + if (is_wildcard_cluster_id(cluster_id)) { + count += get_count_on_all_clusters(endpoint); + } + // Case 1.2: Specific cluster - count if it exists and has matching flags + else { + count += get_count_on_specific_cluster(endpoint, cluster_id); + } + } + endpoint = endpoint::get_next(endpoint); + } + } + // Case 2: Specific endpoint + else { + endpoint_t *endpoint = endpoint::get(endpoint_id); + if (!endpoint || !endpoint::is_enabled(endpoint)) { + return count; + } + + // Case 2.1: Wildcard cluster - count all clusters with matching flags + if (is_wildcard_cluster_id(cluster_id)) { + count += get_count_on_all_clusters(endpoint); + } + // Case 2.2: Specific cluster - count if it exists and has matching flags + else { + count += get_count_on_specific_cluster(endpoint, cluster_id); + } + } + + return count; +} + void *get_priv_data(uint16_t endpoint_id) { endpoint_t *endpoint = get(endpoint_id); @@ -1645,13 +1627,13 @@ esp_err_t set_identify(uint16_t endpoint_id, void *identify) return ESP_OK; } -} /* endpoint */ +} // namespace endpoint namespace node { node_t *create_raw() { - VerifyOrReturnValue(!node, (node_t*) node, ESP_LOGE(TAG, "Node already exists")); + VerifyOrReturnValue(!node, (node_t *)node, ESP_LOGE(TAG, "Node already exists")); node = (_node_t *)esp_matter_mem_calloc(1, sizeof(_node_t)); VerifyOrReturnValue(node, NULL, ESP_LOGE(TAG, "Couldn't allocate _node_t")); return (node_t *)node; @@ -1695,107 +1677,15 @@ esp_err_t destroy() return destroy_raw(); } -// Treat 0xFFFF'FFFF as wildcard cluster -static inline bool is_wildcard_cluster_id(uint32_t cluster_id) -{ - return cluster_id == chip::kInvalidClusterId; -} - -// Treat 0xFFFF as wildcard endpoint -static inline bool is_wildcard_endpoint_id(uint16_t endpoint_id) -{ - return endpoint_id == chip::kInvalidEndpointId; -} - -/** - * @brief Get the number of clusters that match the given flags - * - * @param endpoint_id: The endpoint ID to check, 0xFFFF is treated as wildcard endpoint id - * @param cluster_id: The cluster ID to check, 0xFFFF is treated as wildcard cluster id - * @param cluster_flags: The flags to check - * @return The number of clusters that match the given flags - */ -static uint32_t get_cluster_count(uint32_t endpoint_id, uint32_t cluster_id, uint8_t cluster_flags) -{ - uint32_t count = 0; - node_t *node = get(); - VerifyOrReturnValue(node, count, ESP_LOGE(TAG, "Node cannot be NULL")); - - // lambda to check if cluster matches flags and return 1 if it does, 0 otherwise - auto check_cluster_flags = [cluster_flags](const endpoint_t *endpoint, const cluster_t *cluster) -> uint32_t { - if (cluster && endpoint) { - const _endpoint_t *_endpoint = (_endpoint_t *)endpoint; - const _cluster_t *_cluster = (_cluster_t *)cluster; - EmberAfClusterMask flags = _endpoint->endpoint_type->cluster[_cluster->index].mask; - return (flags & cluster_flags) ? 1 : 0; - } - return 0; - }; - - // lambda to count all matching clusters for an endpoint - auto get_count_on_all_clusters = [&check_cluster_flags](endpoint_t *endpoint) -> uint32_t { - uint32_t result = 0; - if (!endpoint) return result; - - cluster_t *cluster = cluster::get_first(endpoint); - while (cluster) { - result += check_cluster_flags(endpoint, cluster); - cluster = cluster::get_next(cluster); - } - return result; - }; - - // lambda to find and count a specific cluster - auto get_count_on_specific_cluster = [&check_cluster_flags](const endpoint_t *endpoint, uint32_t cluster_id) -> uint32_t { - if (!endpoint) return 0; - cluster_t *cluster = cluster::get((endpoint_t *)endpoint, cluster_id); - return check_cluster_flags(endpoint, cluster); - }; - - // Case 1: Wildcard endpoint - if (is_wildcard_endpoint_id(endpoint_id)) { - endpoint_t *endpoint = endpoint::get_first(node); - while (endpoint) { - // Case 1.1: Wildcard cluster - count all clusters with matching flags - if (is_wildcard_cluster_id(cluster_id)) { - count += get_count_on_all_clusters(endpoint); - } - // Case 1.2: Specific cluster - count if it exists and has matching flags - else { - count += get_count_on_specific_cluster(endpoint, cluster_id); - } - endpoint = endpoint::get_next(endpoint); - } - } - // Case 2: Specific endpoint - else { - endpoint_t *endpoint = endpoint::get(endpoint_id); - if (!endpoint) { - return count; - } - - // Case 2.1: Wildcard cluster - count all clusters with matching flags - if (is_wildcard_cluster_id(cluster_id)) { - count += get_count_on_all_clusters(endpoint); - } - // Case 2.2: Specific cluster - count if it exists and has matching flags - else { - count += get_count_on_specific_cluster(endpoint, cluster_id); - } - } - - return count; -} - uint32_t get_server_cluster_endpoint_count(uint32_t cluster_id) { - return get_cluster_count(chip::kInvalidEndpointId, cluster_id, CLUSTER_FLAG_SERVER); + return endpoint::get_cluster_count(chip::kInvalidEndpointId, cluster_id, CLUSTER_FLAG_SERVER); } uint32_t get_client_cluster_endpoint_count(uint32_t cluster_id) { - return get_cluster_count(chip::kInvalidEndpointId, cluster_id, CLUSTER_FLAG_CLIENT); + return endpoint::get_cluster_count(chip::kInvalidEndpointId, cluster_id, CLUSTER_FLAG_CLIENT); } -} /* node */ -} /* esp_matter */ +} // namespace node +} // namespace esp_matter diff --git a/components/esp_matter/data_model/esp_matter_data_model.h b/components/esp_matter/data_model/esp_matter_data_model.h index 6917ad345..c0f1f5041 100644 --- a/components/esp_matter/data_model/esp_matter_data_model.h +++ b/components/esp_matter/data_model/esp_matter_data_model.h @@ -15,9 +15,12 @@ #pragma once #include #include +#include #include "app/ConcreteCommandPath.h" #include "app/util/af-types.h" +#include "lib/core/DataModelTypes.h" #include "lib/core/TLVReader.h" +#include "protocols/interaction_model/StatusCode.h" #define ESP_MATTER_NVS_PART_NAME CONFIG_ESP_MATTER_NVS_PART_NAME @@ -84,7 +87,7 @@ typedef enum attribute_flags { /** The attribute uses external storage for its value. If attributes have this flag enabled, as all of them are stored in the ESP Matter database. */ ATTRIBUTE_FLAG_EXTERNAL_STORAGE = MATTER_ATTRIBUTE_FLAG_EXTERNAL_STORAGE, /* 0x10 */ - ATTRIBUTE_FLAG_SINGLETON = MATTER_ATTRIBUTE_FLAG_SINGLETON, /* 0x20 */ + ATTRIBUTE_FLAG_READABLE = MATTER_ATTRIBUTE_FLAG_READABLE, /* 0x20 */ ATTRIBUTE_FLAG_NULLABLE = MATTER_ATTRIBUTE_FLAG_NULLABLE, /* 0x40 */ /** The attribute read and write are overridden. The attribute value will be fetched from and will be updated using the override callback. The value of this attribute is not maintained internally. */ @@ -293,29 +296,29 @@ uint16_t get_id(endpoint_t *endpoint); */ esp_err_t add_device_type(endpoint_t *endpoint, uint32_t device_type_id, uint8_t device_type_version); -/** Get device type ID array - * - * Get the device type ID array for the endpoint. This array is aligned with the device type version array. +/** Get device type count * * @param[in] endpoint Endpoint handle. - * @param[out] device_type_count_ptr the pointer of device type ID array length. * - * @return device type ID array on success. - * @return NULL when the endpoint or the device_type_count_ptr is NULL. + * @return device type count on success + * @return 0 on failure */ -uint32_t *get_device_type_ids(endpoint_t *endpoint, uint8_t *device_type_count_ptr); +size_t get_device_type_count(endpoint_t *endpoint); -/** Get device type version array +/** Get device type at index * - * Get the device type version array for the endpoint. This array is aligned with the device type ID array. + * Get the device type ID and version for the endpoint at index. * * @param[in] endpoint Endpoint handle. - * @param[out] device_type_count_ptr the pointer of device type version array length. + * @param[in] index Index of got device type ID and version. + * @param[out] out_device_type_id Device type ID at index. + * @param[out] out_device_type_version Device type version at index. * - * @return device type version array on success. - * @return NULL when the endpoint or the device_type_count_ptr is NULL. + * @return ESP_OK on success. + * @return error in case of failure. */ -uint8_t *get_device_type_versions(endpoint_t *endpoint, uint8_t *device_type_count_ptr); +esp_err_t get_device_type_at_index(endpoint_t *endpoint, size_t index, uint32_t &out_device_type_id, + uint8_t &out_device_type_version); /** Set parent endpoint * @@ -330,6 +333,67 @@ uint8_t *get_device_type_versions(endpoint_t *endpoint, uint8_t *device_type_cou */ esp_err_t set_parent_endpoint(endpoint_t *endpoint, endpoint_t *parent_endpoint); +/** Get parent endpoint id + * + * @param[in] endpoint Endpoint handle. + * + * @return parent_endpoint id on success + * @return 0xFFFF in case of failure or the endpoint handle is root node endpoint + */ +uint16_t get_parent_endpoint_id(endpoint_t *endpoint); + +/** Get CompositionPattern for endpoint + * + * @param[in] endpoint Endpoint handle. + * + * @return CompositionPattern of the endpoint + */ +chip::app::DataModel::EndpointCompositionPattern get_composition_pattern(endpoint_t *endpoint); + +/** Set SemanticTags for endpoint + * + * Note: The label buffer should not be released after this function. + * + * @param[in] endpoint Endpoint handle. + * @param[in] tags Tags array. + * @param[in] tag_count Tag count. + * + * @return ESP_OK on success. + * @return error in case of failure. + */ +esp_err_t set_semantic_tags(endpoint_t *endpoint, chip::app::DataModel::Provider::SemanticTag *tags, size_t tag_count); + +/** Get SemanticTag count + * + * @param[in] endpoint Endpoint handle. + * + * @return SemanticTag count on success + * @return -1 on failure + */ +int get_semantic_tag_count(endpoint_t *endpoint); + +/** Get SemanticTag for endpoint at index + * + * @param[in] endpoint Endpoint handle. + * @param[in] index Tag index. + * @param[out] tag Tag output. + * + * @return ESP_OK on success. + * @return ESP_ERR_NOT_FOUND if index is more than or equal to tag count. + * @return other error in case of failure. + */ +esp_err_t get_semantic_tag_at_index(endpoint_t *endpoint, size_t index, chip::app::DataModel::Provider::SemanticTag &tag); + +/** + * @brief Get the number of clusters that match the given flags + * + * @param endpoint_id: The endpoint ID to check, 0xFFFF is treated as wildcard endpoint id + * @param cluster_id: The cluster ID to check, 0xFFFF is treated as wildcard cluster id + * @param cluster_flags: The flags to check + * @return The number of clusters that match the given flags + */ +uint32_t get_cluster_count(uint32_t endpoint_id, uint32_t cluster_id, uint8_t cluster_flags); + /** Get private data * * Get the private data passed while creating the endpoint. @@ -370,9 +434,6 @@ esp_err_t set_identify(uint16_t endpoint_id, void *identify); * * Enable the endpoint which has been previously created. * - * @note: This API only needs to be called for endpoints created after calling esp_matter::start(). It should be - * called after all the clusters, attributes and commands have been added to the created endpoint. - * * @param[in] endpoint Endpoint handle. * * @return ESP_OK on success. @@ -380,6 +441,7 @@ esp_err_t set_identify(uint16_t endpoint_id, void *identify); */ esp_err_t enable(endpoint_t *endpoint); + /** Check if attribute is enabled * * Check if the attribute of a cluster is enabled on an endpoint. @@ -403,6 +465,27 @@ bool is_attribute_enabled(uint16_t endpoint_id, uint32_t cluster_id, uint32_t at * @return true if a command is enabled otherwise false. */ bool is_command_enabled(uint16_t endpoint_id, uint32_t cluster_id, uint32_t command_id); + +/** Disable endpoint + * + * Disable the endpoint which has been previously created. + * + * @param[in] endpoint Endpoint handle. + * + * @return ESP_OK on success. + * @return error in case of failure. + */ +esp_err_t disable(endpoint_t *endpoint); + +/** Get whether an endpoint is enabled + * + * @param[in] endpoint Endpoint handle. + * + * @return true if the endpoint is enabled. + * @return false if the endpoint is disable or Endpoint handle is invalid. + */ +bool is_enabled(endpoint_t *endpoint); + } /* endpoint */ namespace cluster { @@ -432,6 +515,43 @@ typedef void (*add_bounds_callback_t)(cluster_t *cluster); */ typedef void (*function_generic_t)(); +/** Cluster initialization function + * + * This will be called when data model is initialized. + */ +typedef void (*function_cluster_init_t)(uint16_t endpoint_id); + +/** Cluster shutdown function + * + * This will be called when data model is shutdown. + */ +typedef void (*function_cluster_shutdown_t)(uint16_t endpoint_id); + +/** Attribute change function + * + * This will be called when attributes are change for the cluster. + */ +typedef void (*function_attribute_change_t)(const chip::app::ConcreteAttributePath & attributePath); + +/** Pre attribute change function + * + * This function is called before an attribute changes. + */ +typedef chip::Protocols::InteractionModel::Status (*function_pre_attribute_change_t)( + const chip::app::ConcreteAttributePath & attributePath, EmberAfAttributeType attributeType, uint16_t size, uint8_t * value); + +/** Initialization callback + * + * This callback will be called when the data model is initialized. + */ +typedef void (*initialization_callback_t)(uint16_t endpoint_id); + +/** Shutdown callback + * + * This callback will be called when the data model is shutdown. + */ +typedef void (*shutdown_callback_t)(uint16_t endpoint_id); + /** Create cluster * * This will create a new cluster and add it to the endpoint. @@ -514,6 +634,40 @@ cluster_t *get_next(cluster_t *cluster); */ uint32_t get_id(cluster_t *cluster); +/** Get cluster flags + * + * Get the cluster flags for the cluster. + * + * @param[in] cluster Cluster handle. + * + * @return cluster flags on success. + * @return 0 in case of failure. + */ +uint8_t get_flags(cluster_t *cluster); + +/** Get cluster data version + * + * Get the cluster data version for the cluster. + * + * @param[in] cluster Cluster handle. + * @param[out] data_version Cluster data version. + * + * @return ESP_OK on success. + * @return error in case of failure. + */ +esp_err_t get_data_version(cluster_t *cluster, chip::DataVersion &data_version); + +/** Increase cluster data version + * + * Increase the cluster data version for the cluster. + * + * @param[in] cluster Cluster handle. + * + * @return ESP_OK on success. + * @return error in case of failure. + */ +esp_err_t increase_data_version(cluster_t *cluster); + /** Get delegate pointer * * Get the delegate pointer for the cluster. @@ -605,6 +759,50 @@ add_bounds_callback_t get_add_bounds_callback(cluster_t *cluster); */ esp_err_t add_function_list(cluster_t *cluster, const function_generic_t *function_list, int function_flags); +/** Get function from cluster function list + * + * This API can be used to get additional cluster function based on cluster flags. This is to get upstream's + * `MatterServerCallback` or `emberAfServerCallback` API, + * The function_flag should have only one of the function bits set. + * + * @param[in] cluster Cluster handle. + * @param[in] function_flag Bitmap of cluster flag corresponding to the function_list. + * + * @return the function on success + * @return null in case of failure + */ +function_generic_t get_function(cluster_t *cluster, uint8_t function_flag); + +/** Set initialization and shutdown callback for the cluster + * + * @param[in] cluster Cluster handle. + * @param[in] init_callback Initialization callback. + * @param[in] shutdown_callback Shutdown callback. + * + * @return ESP_OK on success. + * @return error in case of failure. + */ +esp_err_t set_init_and_shutdown_callbacks(cluster_t *cluster, initialization_callback_t init_callback, + shutdown_callback_t shutdown_callback); + +/** Get initialization callback for the cluster + * + * @param[in] cluster Cluster handle. + * + * @return initialization callback on success. + * @return NULL in case of failure or not set. + */ +initialization_callback_t get_init_callback(cluster_t *cluster); + +/** Get shutdown callback for the cluster + * + * @param[in] cluster Cluster handle. + * + * @return shutdown callback on success. + * @return NULL in case of failure or not set. + */ +shutdown_callback_t get_shutdown_callback(cluster_t *cluster); + } /* cluster */ namespace attribute { @@ -694,11 +892,13 @@ uint32_t get_id(attribute_t *attribute); * * @param[in] attribute Attribute handle. * @param[in] val Pointer to `esp_matter_attr_val_t`. Use appropriate elements as per the value type. + * @param[in] call_callbacks Whether to call attribute change pre/post callbacks. * * @return ESP_OK on success. + * @return ESP_ERR_NOT_FINISHED if the value is not changed. * @return error in case of failure. */ -esp_err_t set_val(attribute_t *attribute, esp_matter_attr_val_t *val); +esp_err_t set_val(attribute_t *attribute, esp_matter_attr_val_t *val, bool call_callbacks = true); /** Get attribute val * diff --git a/components/esp_matter/data_model/esp_matter_data_model_utils.cpp b/components/esp_matter/data_model/esp_matter_data_model_utils.cpp deleted file mode 100644 index 0c1d86a85..000000000 --- a/components/esp_matter/data_model/esp_matter_data_model_utils.cpp +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2025 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include -#include - -#include -#include - -using chip::Protocols::InteractionModel::Status; -using namespace chip; - -static const char *TAG = "data_model"; - -namespace esp_matter { - -static esp_err_t execute_override_callback(attribute_t *attribute, attribute::callback_type_t type, - uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, - esp_matter_attr_val_t *val) -{ - attribute::callback_t override_callback = attribute::get_override_callback(attribute); - void *priv_data = endpoint::get_priv_data(endpoint_id); - if (override_callback) { - return override_callback(type, endpoint_id, cluster_id, attribute_id, val, priv_data); - } else { - ESP_LOGW(TAG, - "Attribute override callback not set for Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 - "'s Attribute 0x%08" PRIX32 ", calling the common callback", - endpoint_id, cluster_id, attribute_id); - } - return ESP_OK; -} -} // namespace esp_matter - -using namespace esp_matter; - -Status emberAfExternalAttributeReadCallback(EndpointId endpoint_id, ClusterId cluster_id, - const EmberAfAttributeMetadata *matter_attribute, uint8_t *buffer, - uint16_t max_read_length) -{ - /* Get value */ - uint32_t attribute_id = matter_attribute->attributeId; - attribute_t *attribute = attribute::get(endpoint_id, cluster_id, attribute_id); - VerifyOrReturnError(attribute, Status::Failure); - esp_matter_attr_val_t val = esp_matter_invalid(NULL); - - int flags = attribute::get_flags(attribute); - if (flags & ATTRIBUTE_FLAG_OVERRIDE) { - esp_err_t err = - execute_override_callback(attribute, attribute::READ, endpoint_id, cluster_id, attribute_id, &val); - VerifyOrReturnValue(err == ESP_OK, Status::Failure); - } else { - attribute::get_val(attribute, &val); - } - - /* Here, the val_print function gets called on attribute read. */ - attribute::val_print(endpoint_id, cluster_id, attribute_id, &val, true); - - /* Get size */ - uint16_t attribute_size = 0; - attribute::get_data_from_attr_val(&val, NULL, &attribute_size, NULL); - VerifyOrReturnValue(attribute_size <= max_read_length, Status::ResourceExhausted, - ESP_LOGE(TAG, - "Insufficient space for reading Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 - "'s Attribute 0x%08" PRIX32 ": required: %" PRIu16 ", max: %" PRIu16 "", - endpoint_id, cluster_id, attribute_id, attribute_size, max_read_length)); - - /* Assign value */ - attribute::get_data_from_attr_val(&val, NULL, &attribute_size, buffer); - return Status::Success; -} - -Status emberAfExternalAttributeWriteCallback(EndpointId endpoint_id, ClusterId cluster_id, - const EmberAfAttributeMetadata *matter_attribute, uint8_t *buffer) -{ - /* Get value */ - uint32_t attribute_id = matter_attribute->attributeId; - attribute_t *attribute = attribute::get(endpoint_id, cluster_id, attribute_id); - VerifyOrReturnError(attribute, Status::Failure); - - /* Get val */ - /* This creates a new variable val, and stores the new attribute value in the new variable. - The value in esp-matter data model is updated only when attribute::set_val() is called */ - esp_matter_attr_val_t val = esp_matter_invalid(NULL); - attribute::get_attr_val_from_data(&val, matter_attribute->attributeType, matter_attribute->size, buffer, - matter_attribute); - - int flags = attribute::get_flags(attribute); - if (flags & ATTRIBUTE_FLAG_OVERRIDE) { - esp_err_t err = - execute_override_callback(attribute, attribute::WRITE, endpoint_id, cluster_id, attribute_id, &val); - Status status = (err == ESP_OK) ? Status::Success : Status::Failure; - return status; - } - - /* Update val */ - VerifyOrReturnValue(val.type != ESP_MATTER_VAL_TYPE_INVALID, Status::Failure); - attribute::set_val(attribute, &val); - return Status::Success; -} - -// No-op function, used to force linking this file, instead of the weak functions from other files. -extern "C" void data_model_utils_impl(void) {} diff --git a/components/esp_matter/data_model/esp_matter_endpoint.cpp b/components/esp_matter/data_model/esp_matter_endpoint.cpp index e821de00b..b0fa4eb32 100644 --- a/components/esp_matter/data_model/esp_matter_endpoint.cpp +++ b/components/esp_matter/data_model/esp_matter_endpoint.cpp @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "esp_matter_cluster.h" #include #include #include @@ -355,7 +356,6 @@ esp_err_t add(endpoint_t *endpoint, config_t *config) cluster_t *scenes_management_cluster = scenes_management::create(endpoint, &(config->scenes_management), CLUSTER_FLAG_SERVER); scenes_management::command::create_copy_scene(scenes_management_cluster); scenes_management::command::create_copy_scene_response(scenes_management_cluster); - return ESP_OK; } } /* extended_color_light */ diff --git a/components/esp_matter/data_model/ota_provider_integration.cpp b/components/esp_matter/data_model/ota_provider_integration.cpp deleted file mode 100644 index 2a6ee8173..000000000 --- a/components/esp_matter/data_model/ota_provider_integration.cpp +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2025 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#include - -using namespace chip; -using namespace chip::app; -using namespace chip::app::Clusters; - -namespace { - -static constexpr size_t kOtaProviderFixedClusterCount = 0; -static constexpr size_t kOtaProviderMaxClusterCount = kOtaProviderFixedClusterCount + CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; - -LazyRegisteredServerCluster gServers[kOtaProviderMaxClusterCount]; - -// Find the 0-based array index corresponding to the given endpoint id. -// Log an error if not found. -bool findEndpointWithLog(EndpointId endpointId, uint16_t & outArrayIndex) -{ - uint16_t arrayIndex = - emberAfGetClusterServerEndpointIndex(endpointId, OtaSoftwareUpdateProvider::Id, kOtaProviderFixedClusterCount); - - if (arrayIndex >= kOtaProviderMaxClusterCount) - { - ChipLogError(AppServer, "Could not find endpoint index for endpoint %u", endpointId); - return false; - } - return true; -} - -} // namespace - -void emberAfOtaSoftwareUpdateProviderClusterInitCallback(EndpointId endpointId) -{ - uint16_t arrayIndex = 0; - if (!findEndpointWithLog(endpointId, arrayIndex)) - { - return; - } - gServers[arrayIndex].Create(endpointId); - CHIP_ERROR err = CodegenDataModelProvider::Instance().Registry().Register(gServers[arrayIndex].Registration()); - if (err != CHIP_NO_ERROR) - { - ChipLogError(AppServer, "Failed to register OTA on endpoint %u: %" CHIP_ERROR_FORMAT, endpointId, err.Format()); - } -} - -void emberAfOtaSoftwareUpdateProviderClusterShutdownCallback(EndpointId endpointId) -{ - uint16_t arrayIndex = 0; - if (!findEndpointWithLog(endpointId, arrayIndex)) - { - return; - } - - CHIP_ERROR err = CodegenDataModelProvider::Instance().Registry().Unregister(&gServers[arrayIndex].Cluster()); - if (err != CHIP_NO_ERROR) - { - ChipLogError(AppServer, "Failed to unregister OTA on endpoint %u: %" CHIP_ERROR_FORMAT, endpointId, err.Format()); - } - gServers[arrayIndex].Destroy(); -} - -void MatterOtaSoftwareUpdateProviderPluginServerInitCallback() {} - -void MatterOtaSoftwareUpdateProviderPluginServerShutdownCallback() {} - -namespace chip { -namespace app { -namespace Clusters { -namespace OTAProvider { - -void SetDelegate(EndpointId endpointId, OTAProviderDelegate * delegate) -{ - uint16_t arrayIndex = 0; - if (!findEndpointWithLog(endpointId, arrayIndex)) - { - return; - } - gServers[arrayIndex].Cluster().SetDelegate(delegate); -} - -} // namespace OTAProvider -} // namespace Clusters -} // namespace app -} // namespace chip diff --git a/components/esp_matter/private/esp_matter_cluster_revisions.h b/components/esp_matter/data_model/private/esp_matter_cluster_revisions.h similarity index 100% rename from components/esp_matter/private/esp_matter_cluster_revisions.h rename to components/esp_matter/data_model/private/esp_matter_cluster_revisions.h 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 7c39a6fad..cdb9448bb 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 @@ -17,8 +17,14 @@ #include #include #include +#include namespace esp_matter { +namespace command { +void dispatch_single_cluster_command(const chip::app::ConcreteCommandPath &command_path, chip::TLV::TLVReader &tlv_data, + void *opaque_ptr); +} // command + namespace node { esp_err_t store_min_unused_endpoint_id(); @@ -31,13 +37,4 @@ namespace endpoint { esp_err_t enable_all(); } - -namespace attribute { -esp_err_t get_data_from_attr_val(esp_matter_attr_val_t *val, EmberAfAttributeType *attribute_type, - uint16_t *attribute_size, uint8_t *value); - -esp_err_t get_attr_val_from_data(esp_matter_attr_val_t *val, EmberAfAttributeType attribute_type, - uint16_t attribute_size, uint8_t *value, - const EmberAfAttributeMetadata * attribute_metadata); -} } // namespace esp_matter diff --git a/components/esp_matter/private/esp_matter_nvs.cpp b/components/esp_matter/data_model/private/esp_matter_nvs.cpp similarity index 98% rename from components/esp_matter/private/esp_matter_nvs.cpp rename to components/esp_matter/data_model/private/esp_matter_nvs.cpp index 4a77e22b5..0221615fa 100644 --- a/components/esp_matter/private/esp_matter_nvs.cpp +++ b/components/esp_matter/data_model/private/esp_matter_nvs.cpp @@ -66,12 +66,12 @@ static esp_err_t nvs_get_val(const char *nvs_namespace, const char *attribute_ke // This function will only be called when recovering the non-volatile attributes during reboot // Add we should not decrease the size of the attribute value len = std::max(len, static_cast(val.val.a.s)); - uint8_t *buffer = (uint8_t *)esp_matter_mem_calloc(1, len); + bool null_reserve = (val.type == ESP_MATTER_VAL_TYPE_CHAR_STRING) || (val.type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING); + uint8_t *buffer = (uint8_t *)esp_matter_mem_calloc(1, len + (null_reserve ? 1 : 0)); if (!buffer) { err = ESP_ERR_NO_MEM; } else { val.val.a.b = buffer; - val.val.a.n = len; val.val.a.t = len + (val.val.a.t - val.val.a.s); val.val.a.s = len; err = nvs_get_blob(handle, attribute_key, buffer, &len); diff --git a/components/esp_matter/private/esp_matter_nvs.h b/components/esp_matter/data_model/private/esp_matter_nvs.h similarity index 100% rename from components/esp_matter/private/esp_matter_nvs.h rename to components/esp_matter/data_model/private/esp_matter_nvs.h diff --git a/components/esp_matter/private/singly_linked_list.h b/components/esp_matter/data_model/private/singly_linked_list.h similarity index 100% rename from components/esp_matter/private/singly_linked_list.h rename to components/esp_matter/data_model/private/singly_linked_list.h diff --git a/components/esp_matter/data_model/software_diagnostics_codegen_integration.cpp b/components/esp_matter/data_model/software_diagnostics_codegen_integration.cpp deleted file mode 100644 index f037ed10d..000000000 --- a/components/esp_matter/data_model/software_diagnostics_codegen_integration.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2025 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "esp_matter_core.h" -#include -#include -#include -#include -#include "clusters/SoftwareDiagnostics/AttributeIds.h" -#include "clusters/SoftwareDiagnostics/ClusterId.h" -#include - -using namespace chip; -using namespace chip::app; -using namespace chip::app::Clusters; -using namespace chip::app::Clusters::SoftwareDiagnostics; - -namespace { -LazyRegisteredServerCluster> gServer; -} - -bool isAttributeEnabled(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id) -{ - esp_matter::attribute_t *attr = esp_matter::attribute::get(endpoint_id, cluster_id, attribute_id); - printf("attr %ld enabled %d", attribute_id, attr != nullptr); - return attr != nullptr; -} - -void emberAfSoftwareDiagnosticsClusterInitCallback(chip::EndpointId endpointId) -{ - VerifyOrReturn(endpointId == chip::kRootEndpointId); - SoftwareDiagnosticsEnabledAttributes enabledAttributes{ - .enableThreadMetrics = isAttributeEnabled(endpointId, Id, Attributes::ThreadMetrics::Id), - .enableCurrentHeapFree = isAttributeEnabled(endpointId, Id, Attributes::CurrentHeapFree::Id), - .enableCurrentHeapUsed = isAttributeEnabled(endpointId, Id, Attributes::CurrentHeapUsed::Id), - .enableCurrentWatermarks = isAttributeEnabled(endpointId, Id, Attributes::CurrentHeapHighWatermark::Id), - }; - - gServer.Create(enabledAttributes); - - CHIP_ERROR err = CodegenDataModelProvider::Instance().Registry().Register(gServer.Registration()); - if (err != CHIP_NO_ERROR) - { - ChipLogError(AppServer, "Failed to register SoftwareDiagnostics on endpoint %u: %" CHIP_ERROR_FORMAT, endpointId, - err.Format()); - } -} - -void emberAfSoftwareDiagnosticsClusterShutdownCallback(EndpointId endpointId) -{ - VerifyOrReturn(endpointId == kRootEndpointId); - CHIP_ERROR err = CodegenDataModelProvider::Instance().Registry().Unregister(&gServer.Cluster()); - if (err != CHIP_NO_ERROR) - { - ChipLogError(AppServer, "Failed to unregister SoftwareDiagnostics on endpoint %u: %" CHIP_ERROR_FORMAT, endpointId, - err.Format()); - } - gServer.Destroy(); -} - -void MatterSoftwareDiagnosticsPluginServerInitCallback() {} - -void MatterSoftwareDiagnosticsPluginServerShutdownCallback() {} diff --git a/components/esp_matter/data_model_provider/clusters/administrator_commissioning_integration.cpp b/components/esp_matter/data_model_provider/clusters/administrator_commissioning_integration.cpp new file mode 100644 index 000000000..8c5a6cd0d --- /dev/null +++ b/components/esp_matter/data_model_provider/clusters/administrator_commissioning_integration.cpp @@ -0,0 +1,68 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include +#include +#include + +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::AdministratorCommissioning::Attributes; +namespace { +using ClusterImpl = AdministratorCommissioningWithBasicCommissioningWindowCluster; + +LazyRegisteredServerCluster gServer; +} // namespace + +void ESPMatterAdministratorCommissioningClusterServerInitCallback(EndpointId endpointId) +{ + if (endpointId != kRootEndpointId) { + return; + } + esp_matter::attribute_t *attribute = + esp_matter::attribute::get(endpointId, AdministratorCommissioning::Id, Globals::Attributes::FeatureMap::Id); + if (attribute) { + esp_matter_attr_val_t val = esp_matter_invalid(nullptr); + if (esp_matter::attribute::get_val(attribute, &val) == ESP_OK && val.type == ESP_MATTER_VAL_TYPE_BITMAP32) { + gServer.Create(endpointId, BitFlags(val.val.u32)); + CHIP_ERROR err = + esp_matter::data_model::provider::get_instance().registry().Register(gServer.Registration()); + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "Admin Commissioning register error: %" CHIP_ERROR_FORMAT, err.Format()); + } + } + } +} + +void ESPMatterAdministratorCommissioningClusterServerShutdownCallback(EndpointId endpointId) +{ + CHIP_ERROR err = esp_matter::data_model::provider::get_instance().registry().Unregister(&gServer.Cluster()); + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "Admin Commissioning unregister error: %" CHIP_ERROR_FORMAT, err.Format()) + } + gServer.Destroy(); +} + +void MatterAdministratorCommissioningPluginServerInitCallback() +{ +} +void MatterAdministratorCommissioningPluginServerShutdownCallback() +{ +} diff --git a/components/esp_matter/data_model_provider/clusters/general_diagnostics_integration.cpp b/components/esp_matter/data_model_provider/clusters/general_diagnostics_integration.cpp new file mode 100644 index 000000000..898ef6b36 --- /dev/null +++ b/components/esp_matter/data_model_provider/clusters/general_diagnostics_integration.cpp @@ -0,0 +1,182 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace esp_matter; + +namespace { + +struct cluster_server { + cluster_server() + : isFullConfigurable(false) + { + } + ~cluster_server() + { + if (isFullConfigurable && fullConfigurableServer.IsConstructed()) { + fullConfigurableServer.Destroy(); + } else if (!isFullConfigurable && server.IsConstructed()) { + server.Destroy(); + } + } + + bool isFullConfigurable; + union { + LazyRegisteredServerCluster fullConfigurableServer; + LazyRegisteredServerCluster server; + }; +}; + +cluster_server gServer; + +bool IsAttributeEnabled(EndpointId endpointId, AttributeId attributeId) +{ + return endpoint::is_attribute_enabled(endpointId, GeneralDiagnostics::Id, attributeId); +} + +bool IsCommandEnabled(EndpointId endpointId, CommandId commandId, uint16_t commandFlag) +{ + cluster_t *cluster = cluster::get(endpointId, GeneralDiagnostics::Id); + command_t *command = command::get(cluster, commandId, commandFlag); + return command != nullptr; +} + +bool IsClusterEnabled(EndpointId endpointId, ClusterId clusterId) +{ + cluster_t *cluster = cluster::get(endpointId, clusterId); + return cluster != nullptr; +} + +} // namespace + +void ESPMatterGeneralDiagnosticsClusterServerInitCallback(EndpointId endpointId) +{ + VerifyOrDie(endpointId == kRootEndpointId); + GeneralDiagnosticsEnabledAttributes enabledAttributes{ + .enableTotalOperationalHours = + IsAttributeEnabled(endpointId, GeneralDiagnostics::Attributes::TotalOperationalHours::Id), + .enableBootReason = IsAttributeEnabled(endpointId, GeneralDiagnostics::Attributes::BootReason::Id), + .enableActiveHardwareFaults = + IsAttributeEnabled(endpointId, GeneralDiagnostics::Attributes::ActiveHardwareFaults::Id), + .enableActiveRadioFaults = + IsAttributeEnabled(endpointId, GeneralDiagnostics::Attributes::ActiveRadioFaults::Id), + .enableActiveNetworkFaults = + IsAttributeEnabled(endpointId, GeneralDiagnostics::Attributes::ActiveNetworkFaults::Id), + }; + + CHIP_ERROR err = CHIP_NO_ERROR; + if (IsCommandEnabled(endpointId, GeneralDiagnostics::Commands::PayloadTestRequest::Id, COMMAND_FLAG_ACCEPTED) || + IsClusterEnabled(endpointId, TimeSynchronization::Id)) { + gServer.isFullConfigurable = true; + GeneralDiagnosticsFunctionsConfig functionsConfig{ + /* + Only consider real time if time sync cluster is actually enabled. If it's not + enabled, this avoids likelihood of frequently reporting unusable unsynched time. + */ + IsClusterEnabled(endpointId, TimeSynchronization::Id), + IsCommandEnabled(endpointId, GeneralDiagnostics::Commands::PayloadTestRequest::Id, COMMAND_FLAG_ACCEPTED), + }; + + gServer.fullConfigurableServer.Create(enabledAttributes, functionsConfig); + err = esp_matter::data_model::provider::get_instance().registry().Register( + gServer.fullConfigurableServer.Registration()); + } else { + gServer.server.Create(enabledAttributes); + err = esp_matter::data_model::provider::get_instance().registry().Register(gServer.server.Registration()); + } + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "Failed to register GeneralDiagnostics on endpoint %u: %" CHIP_ERROR_FORMAT, endpointId, + err.Format()); + } +} + +void ESPMatterGeneralDiagnosticsClusterServerShutdownCallback(EndpointId endpointId) +{ + VerifyOrReturn(endpointId == kRootEndpointId); + CHIP_ERROR err = CHIP_NO_ERROR; + if (gServer.isFullConfigurable) { + err = esp_matter::data_model::provider::get_instance().registry().Unregister( + &gServer.fullConfigurableServer.Cluster()); + gServer.fullConfigurableServer.Destroy(); + } else { + err = esp_matter::data_model::provider::get_instance().registry().Unregister(&gServer.server.Cluster()); + gServer.server.Destroy(); + } + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "Failed to unregister GeneralDiagnostics on endpoint %u: %" CHIP_ERROR_FORMAT, + endpointId, err.Format()); + } +} + +void MatterGeneralDiagnosticsPluginServerInitCallback() +{ +} + +void MatterGeneralDiagnosticsPluginServerShutdownCallback() +{ +} + +namespace chip::app::Clusters::GeneralDiagnostics { +void GlobalNotifyDeviceReboot(GeneralDiagnostics::BootReasonEnum bootReason) +{ + if (gServer.isFullConfigurable && gServer.fullConfigurableServer.IsConstructed()) { + gServer.fullConfigurableServer.Cluster().OnDeviceReboot(bootReason); + } + if (!gServer.isFullConfigurable && gServer.server.IsConstructed()) { + gServer.server.Cluster().OnDeviceReboot(bootReason); + } +} + +void GlobalNotifyHardwareFaultsDetect(const DeviceLayer::GeneralFaults &previous, + const DeviceLayer::GeneralFaults ¤t) +{ + if (gServer.isFullConfigurable && gServer.fullConfigurableServer.IsConstructed()) { + gServer.fullConfigurableServer.Cluster().OnHardwareFaultsDetect(previous, current); + } + if (!gServer.isFullConfigurable && gServer.server.IsConstructed()) { + gServer.server.Cluster().OnHardwareFaultsDetect(previous, current); + } +} + +void GlobalNotifyRadioFaultsDetect(const DeviceLayer::GeneralFaults &previous, + const DeviceLayer::GeneralFaults ¤t) +{ + if (gServer.isFullConfigurable && gServer.fullConfigurableServer.IsConstructed()) { + gServer.fullConfigurableServer.Cluster().OnRadioFaultsDetect(previous, current); + } + if (!gServer.isFullConfigurable && gServer.server.IsConstructed()) { + gServer.server.Cluster().OnRadioFaultsDetect(previous, current); + } +} + +void GlobalNotifyNetworkFaultsDetect(const DeviceLayer::GeneralFaults &previous, + const DeviceLayer::GeneralFaults ¤t) +{ + if (gServer.isFullConfigurable && gServer.fullConfigurableServer.IsConstructed()) { + gServer.fullConfigurableServer.Cluster().OnNetworkFaultsDetect(previous, current); + } + if (!gServer.isFullConfigurable && gServer.server.IsConstructed()) { + gServer.server.Cluster().OnNetworkFaultsDetect(previous, current); + } +} +} // namespace chip::app::Clusters::GeneralDiagnostics diff --git a/components/esp_matter/data_model_provider/clusters/network_commissioning_integration.cpp b/components/esp_matter/data_model_provider/clusters/network_commissioning_integration.cpp new file mode 100644 index 000000000..44656ab55 --- /dev/null +++ b/components/esp_matter/data_model_provider/clusters/network_commissioning_integration.cpp @@ -0,0 +1,128 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; + +namespace { +#ifdef CONFIG_THREAD_NETWORK_COMMISSIONING_DRIVER +constexpr size_t kThreadNetworkCommissioningClusterCount = 1; +#else +constexpr size_t kThreadNetworkCommissioningClusterCount = 0; +#endif +#ifdef CONFIG_WIFI_NETWORK_COMMISSIONING_DRIVER +constexpr size_t kWifiNetworkCommissioningClusterCount = 1; +#else +constexpr size_t kWifiNetworkCommissioningClusterCount = 0; +#endif + +#ifdef CONFIG_ETHERNET_NETWORK_COMMISSIONING_DRIVER +constexpr size_t kEthernetNetworkCommissioningClusterCount = 1; +#else +constexpr size_t kEthernetNetworkCommissioningClusterCount = 0; +#endif + +constexpr size_t kNetworkCommissioningClusterCount = kThreadNetworkCommissioningClusterCount + + kWifiNetworkCommissioningClusterCount + kEthernetNetworkCommissioningClusterCount; + +static_assert(kNetworkCommissioningClusterCount > 0, "NetworkCommissioningCluster count must be more than 0"); + +LazyRegisteredServerCluster gServers[kNetworkCommissioningClusterCount]; + +uint16_t GetServerIndex(EndpointId endpointId) +{ + esp_matter::endpoint_t *ep = esp_matter::endpoint::get(endpointId); + if (ep) { + esp_matter::cluster_t *cluster = esp_matter::cluster::get(ep, NetworkCommissioning::Id); + if (!cluster) { + return UINT16_MAX; + } + ep = esp_matter::endpoint::get_first(esp_matter::node::get()); + uint16_t ret = 0; + while (ep && esp_matter::endpoint::get_id(ep) != endpointId) { + if (esp_matter::cluster::get(ep, NetworkCommissioning::Id)) { + ret++; + } + ep = esp_matter::endpoint::get_next(ep); + } + return ret; + } + return UINT16_MAX; +} + +} // namespace + +void ESPMatterNetworkCommissioningClusterServerInitCallback(EndpointId endpointId) +{ + uint16_t index = GetServerIndex(endpointId); + VerifyOrReturn(index != UINT16_MAX); +#ifdef CONFIG_THREAD_NETWORK_COMMISSIONING_DRIVER + if (endpointId == CONFIG_THREAD_NETWORK_ENDPOINT_ID) { + static DeviceLayer::NetworkCommissioning::GenericThreadDriver sThreadDriver; + gServers[index].Create(endpointId, &sThreadDriver); + (void)esp_matter::data_model::provider::get_instance().registry().Register(gServers[index].Registration()); + } +#endif +#ifdef CONFIG_WIFI_NETWORK_COMMISSIONING_DRIVER + if (endpointId == CONFIG_WIFI_NETWORK_ENDPOINT_ID) { + gServers[index].Create(endpointId, &(DeviceLayer::NetworkCommissioning::ESPWiFiDriver::GetInstance())); + (void)esp_matter::data_model::provider::get_instance().registry().Register(gServers[index].Registration()); + } +#endif +#ifdef CONFIG_ETHERNET_NETWORK_COMMISSIONING_DRIVER + if (endpointId == CONFIG_ETHERNET_NETWORK_ENDPOINT_ID) { + gServers[index].Create(endpointId, &(DeviceLayer::NetworkCommissioning::ESPEthernetDriver::GetInstance())); + (void)esp_matter::data_model::provider::get_instance().registry().Register(gServers[index].Registration()); + } +#endif +} + +void ESPMatterNetworkCommissioningClusterServerShutdownCallback(EndpointId endpointId) +{ + uint16_t index = GetServerIndex(endpointId); + VerifyOrReturn(index != UINT16_MAX); +#ifdef CONFIG_THREAD_NETWORK_COMMISSIONING_DRIVER + if (endpointId == CONFIG_THREAD_NETWORK_ENDPOINT_ID) { + (void)esp_matter::data_model::provider::get_instance().registry().Unregister(&gServers[index].Cluster()); + } +#endif +#ifdef CONFIG_WIFI_NETWORK_COMMISSIONING_DRIVER + if (endpointId == CONFIG_WIFI_NETWORK_ENDPOINT_ID) { + (void)esp_matter::data_model::provider::get_instance().registry().Unregister(&gServers[index].Cluster()); + } +#endif +#ifdef CONFIG_ETHERNET_NETWORK_COMMISSIONING_DRIVER + if (endpointId == CONFIG_ETHERNET_NETWORK_ENDPOINT_ID) { + (void)esp_matter::data_model::provider::get_instance().registry().Unregister(&gServers[index].Cluster()); + } +#endif +} + +void MatterNetworkCommissioningPluginServerInitCallback() +{ +} +void MatterNetworkCommissioningPluginServerShutdownCallback() +{ +} diff --git a/components/esp_matter/data_model_provider/clusters/ota_provider_integration.cpp b/components/esp_matter/data_model_provider/clusters/ota_provider_integration.cpp new file mode 100644 index 000000000..2ed114027 --- /dev/null +++ b/components/esp_matter/data_model_provider/clusters/ota_provider_integration.cpp @@ -0,0 +1,70 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; + +namespace { +std::unordered_map> gServers; +} // namespace + +void ESPMatterOtaSoftwareUpdateProviderClusterServerInitCallback(EndpointId endpointId) +{ + if (gServers[endpointId].IsConstructed()) { + return; + } + + gServers[endpointId].Create(endpointId); + CHIP_ERROR err = + esp_matter::data_model::provider::get_instance().registry().Register(gServers[endpointId].Registration()); + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "Failed to register OTA on endpoint %u: %" CHIP_ERROR_FORMAT, endpointId, err.Format()); + } +} + +void ESPMatterOtaSoftwareUpdateProviderClusterServerShutdownCallback(EndpointId endpointId) +{ + CHIP_ERROR err = + esp_matter::data_model::provider::get_instance().registry().Unregister(&gServers[endpointId].Cluster()); + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "Failed to unregister OTA on endpoint %u: %" CHIP_ERROR_FORMAT, endpointId, + err.Format()); + } + gServers[endpointId].Destroy(); +} + +void MatterOtaSoftwareUpdateProviderPluginServerInitCallback() {} + +void MatterOtaSoftwareUpdateProviderPluginServerShutdownCallback() {} + +namespace chip { +namespace app { +namespace Clusters { +namespace OTAProvider { + +void SetDelegate(EndpointId endpointId, OTAProviderDelegate *delegate) +{ + gServers[endpointId].Cluster().SetDelegate(delegate); +} + +} // namespace OTAProvider +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/components/esp_matter/data_model_provider/clusters/push_av_stream_transport_integration.cpp b/components/esp_matter/data_model_provider/clusters/push_av_stream_transport_integration.cpp new file mode 100644 index 000000000..dd9ca3a6c --- /dev/null +++ b/components/esp_matter/data_model_provider/clusters/push_av_stream_transport_integration.cpp @@ -0,0 +1,97 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::PushAvStreamTransport::Attributes; +using namespace esp_matter; + +namespace { +std::unordered_map> gServers; + +bool IsClusterEnabled(EndpointId endpointId) +{ + cluster_t *cluster = cluster::get(endpointId, PushAvStreamTransport::Id); + return cluster != nullptr; +} + +uint32_t GetFeatureMap(EndpointId endpointId) +{ + attribute_t *attribute = attribute::get(endpointId, PushAvStreamTransport::Id, Globals::Attributes::FeatureMap::Id); + + VerifyOrReturnError(attribute, ESP_ERR_INVALID_STATE); + + /* Update the value if the attribute already exists */ + esp_matter_attr_val_t val = esp_matter_invalid(NULL); + attribute::get_val(attribute, &val); + return val.val.u32; +} +} // namespace + +void ESPMatterPushAvStreamTransportClusterServerInitCallback(EndpointId endpointId) +{ + if (!IsClusterEnabled(endpointId) || gServers[endpointId].IsConstructed()) { + return; + } + uint32_t rawFeatureMap = GetFeatureMap(endpointId); + ChipLogProgress(AppServer, "Registering Push AV Stream Transport on endpoint %u", endpointId); + gServers[endpointId].Create(endpointId, BitFlags(rawFeatureMap)); + CHIP_ERROR err = data_model::provider::get_instance().registry().Register(gServers[endpointId].Registration()); + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "Failed to register Push AV Stream Transport on endpoint %u: %" CHIP_ERROR_FORMAT, + endpointId, err.Format()); + } +} + +void ESPMatterPushAvStreamTransportClusterServerShutdownCallback(EndpointId endpointId) +{ + if (!IsClusterEnabled(endpointId) || !gServers[endpointId].IsConstructed()) { + return; + } + + CHIP_ERROR err = data_model::provider::get_instance().registry().Unregister(&gServers[endpointId].Cluster()); + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "Failed to unregister Push AV Stream Transport on endpoint %u: %" CHIP_ERROR_FORMAT, + endpointId, err.Format()); + } + gServers[endpointId].Cluster().Deinit(); + gServers[endpointId].Destroy(); +} + +void MatterPushAvStreamTransportPluginServerInitCallback() {} + +void MatterPushAvStreamTransportPluginServerShutdownCallback() {} + +namespace chip { +namespace app { +namespace Clusters { +namespace PushAvStreamTransport { + +void SetDelegate(EndpointId endpointId, PushAvStreamTransportDelegate *delegate) +{ + gServers[endpointId].Cluster().SetDelegate(endpointId, delegate); + gServers[endpointId].Cluster().Init(); +} + +} // namespace PushAvStreamTransport +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/components/esp_matter/data_model_provider/clusters/software_diagnostics_integration.cpp b/components/esp_matter/data_model_provider/clusters/software_diagnostics_integration.cpp new file mode 100644 index 000000000..0be65ae6c --- /dev/null +++ b/components/esp_matter/data_model_provider/clusters/software_diagnostics_integration.cpp @@ -0,0 +1,70 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include + +using namespace esp_matter; +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::SoftwareDiagnostics; + +namespace { + +LazyRegisteredServerCluster gServer; + +bool IsAttributeEnabled(EndpointId endpointId, AttributeId attributeId) +{ + return endpoint::is_attribute_enabled(endpointId, GeneralDiagnostics::Id, attributeId); +} + +} // namespace + +void ESPMatterSoftwareDiagnosticsClusterServerInitCallback(EndpointId endpointId) +{ + VerifyOrReturn(endpointId == kRootEndpointId); + const SoftwareDiagnosticsEnabledAttributes enabledAttributes{ + .enableThreadMetrics = IsAttributeEnabled(kRootEndpointId, Attributes::ThreadMetrics::Id), + .enableCurrentHeapFree = IsAttributeEnabled(kRootEndpointId, Attributes::CurrentHeapFree::Id), + .enableCurrentHeapUsed = IsAttributeEnabled(kRootEndpointId, Attributes::CurrentHeapUsed::Id), + .enableCurrentWatermarks = IsAttributeEnabled(kRootEndpointId, Attributes::CurrentHeapHighWatermark::Id), + }; + + gServer.Create(enabledAttributes); + + CHIP_ERROR err = esp_matter::data_model::provider::get_instance().registry().Register(gServer.Registration()); + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "Failed to register SoftwareDiagnostics on endpoint %u: %" CHIP_ERROR_FORMAT, + endpointId, err.Format()); + } +} + +void ESPMatterSoftwareDiagnosticsClusterServerShutdownCallback(EndpointId endpointId) +{ + VerifyOrReturn(endpointId == kRootEndpointId); + CHIP_ERROR err = esp_matter::data_model::provider::get_instance().registry().Unregister(&gServer.Cluster()); + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "Failed to unregister SoftwareDiagnostics on endpoint %u: %" CHIP_ERROR_FORMAT, + endpointId, err.Format()); + } + gServer.Destroy(); +} + +void MatterSoftwareDiagnosticsPluginServerInitCallback() {} + +void MatterSoftwareDiagnosticsPluginServerShutdownCallback() {} diff --git a/components/esp_matter/data_model_provider/clusters/wifi_network_diagnostic_integration.cpp b/components/esp_matter/data_model_provider/clusters/wifi_network_diagnostic_integration.cpp new file mode 100644 index 000000000..8c509bb6e --- /dev/null +++ b/components/esp_matter/data_model_provider/clusters/wifi_network_diagnostic_integration.cpp @@ -0,0 +1,95 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace esp_matter; + +namespace { +std::unordered_map> gServers; + +bool IsClusterEnabled(EndpointId endpointId) +{ + cluster_t *cluster = cluster::get(endpointId, WiFiNetworkDiagnostics::Id); + return cluster != nullptr; +} + +bool IsAttributeEnabled(EndpointId endpointId, AttributeId attributeId) +{ + return endpoint::is_attribute_enabled(endpointId, WiFiNetworkDiagnostics::Id, attributeId); +} + +uint32_t GetFeatureMap(EndpointId endpointId) +{ + attribute_t *attribute = attribute::get(endpointId, WiFiNetworkDiagnostics::Id, Globals::Attributes::FeatureMap::Id); + + VerifyOrReturnError(attribute, ESP_ERR_INVALID_STATE); + + /* Update the value if the attribute already exists */ + esp_matter_attr_val_t val = esp_matter_invalid(NULL); + attribute::get_val(attribute, &val); + return val.val.u32; +} + +} // namespace + +void ESPMatterWiFiNetworkDiagnosticsClusterServerInitCallback(EndpointId endpointId) +{ + if (!IsClusterEnabled(endpointId) && gServers[endpointId].IsConstructed()) { + return; + } + WiFiNetworkDiagnosticsEnabledAttributes enabledAttributes{ + .enableCurrentMaxRate = IsAttributeEnabled(endpointId, WiFiNetworkDiagnostics::Attributes::CurrentMaxRate::Id), + }; + + // NOTE: Currently, diagnostics only support a single provider (DeviceLayer::GetDiagnosticDataProvider()) + // and do not properly support secondary network interfaces or per-endpoint diagnostics. + // See issue:#40317 + gServers[endpointId].Create(endpointId, DeviceLayer::GetDiagnosticDataProvider(), enabledAttributes, + BitFlags(GetFeatureMap(endpointId))); + + CHIP_ERROR err = esp_matter::data_model::provider::get_instance().registry().Register(gServers[endpointId].Registration()); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "Failed to register WiFiNetworkDiagnostics on endpoint %u: %" CHIP_ERROR_FORMAT, endpointId, + err.Format()); + } +} + +// This callback is called for any endpoint (fixed or dynamic) that is registered with the Ember machinery. +void ESPMatterWiFiNetworkDiagnosticsClusterServerShutdownCallback(EndpointId endpointId) +{ + + CHIP_ERROR err = esp_matter::data_model::provider::get_instance().registry().Unregister(&gServers[endpointId].Cluster()); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "Failed to unregister WiFiNetworkDiagnostics on endpoint %u: %" CHIP_ERROR_FORMAT, endpointId, + err.Format()); + } + + gServers[endpointId].Destroy(); +} + +void MatterWiFiNetworkDiagnosticsPluginServerInitCallback() {} + +void MatterWiFiNetworkDiagnosticsPluginServerShutdownCallback() {} diff --git a/components/esp_matter/data_model_provider/esp_matter_attr_data_buffer.cpp b/components/esp_matter/data_model_provider/esp_matter_attr_data_buffer.cpp new file mode 100644 index 000000000..4fe1c0631 --- /dev/null +++ b/components/esp_matter/data_model_provider/esp_matter_attr_data_buffer.cpp @@ -0,0 +1,297 @@ +#include "esp_matter_attr_data_buffer.h" +#include "esp_matter_attribute_utils.h" +#include "esp_matter_mem.h" +#include "support/CHIPMemString.h" +#include "support/CodeUtils.h" + +namespace esp_matter { +namespace data_model { + +CHIP_ERROR attribute_data_decode_buffer::Decode(chip::TLV::TLVReader &reader) +{ + switch (m_attr_val.type) { + case ESP_MATTER_VAL_TYPE_NULLABLE_BOOLEAN: + if (reader.GetType() == chip::TLV::kTLVType_Null) { + chip::app::NumericAttributeTraits::SetNull(*(uint8_t *)(&(m_attr_val.val.b))); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_BOOLEAN: + ReturnErrorOnFailure(reader.Get(m_attr_val.val.b)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT8: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8: + if (reader.GetType() == chip::TLV::kTLVType_Null) { + chip::app::NumericAttributeTraits::SetNull(m_attr_val.val.u8); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_UINT8: + case ESP_MATTER_VAL_TYPE_ENUM8: + case ESP_MATTER_VAL_TYPE_BITMAP8: + ReturnErrorOnFailure(reader.Get(m_attr_val.val.u8)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT16: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16: + if (reader.GetType() == chip::TLV::kTLVType_Null) { + chip::app::NumericAttributeTraits::SetNull(m_attr_val.val.u16); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_UINT16: + case ESP_MATTER_VAL_TYPE_ENUM16: + case ESP_MATTER_VAL_TYPE_BITMAP16: + ReturnErrorOnFailure(reader.Get(m_attr_val.val.u16)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT32: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32: + if (reader.GetType() == chip::TLV::kTLVType_Null) { + chip::app::NumericAttributeTraits::SetNull(m_attr_val.val.u32); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_UINT32: + case ESP_MATTER_VAL_TYPE_BITMAP32: + ReturnErrorOnFailure(reader.Get(m_attr_val.val.u32)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT64: + if (reader.GetType() == chip::TLV::kTLVType_Null) { + chip::app::NumericAttributeTraits::SetNull(m_attr_val.val.u64); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_UINT64: + ReturnErrorOnFailure(reader.Get(m_attr_val.val.u64)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_INT8: + if (reader.GetType() == chip::TLV::kTLVType_Null) { + chip::app::NumericAttributeTraits::SetNull(m_attr_val.val.i8); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_INT8: + ReturnErrorOnFailure(reader.Get(m_attr_val.val.i8)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_INT16: + if (reader.GetType() == chip::TLV::kTLVType_Null) { + chip::app::NumericAttributeTraits::SetNull(m_attr_val.val.i16); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_INT16: + ReturnErrorOnFailure(reader.Get(m_attr_val.val.i16)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_INT32: + if (reader.GetType() == chip::TLV::kTLVType_Null) { + chip::app::NumericAttributeTraits::SetNull(m_attr_val.val.i32); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_INT32: + ReturnErrorOnFailure(reader.Get(m_attr_val.val.i32)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_INT64: + if (reader.GetType() == chip::TLV::kTLVType_Null) { + chip::app::NumericAttributeTraits::SetNull(m_attr_val.val.i64); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_INT64: + ReturnErrorOnFailure(reader.Get(m_attr_val.val.i64)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT: + if (reader.GetType() == chip::TLV::kTLVType_Null) { + chip::app::NumericAttributeTraits::SetNull(m_attr_val.val.f); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_FLOAT: + ReturnErrorOnFailure(reader.Get(m_attr_val.val.f)); + break; + case ESP_MATTER_VAL_TYPE_CHAR_STRING: + case ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING: { + if (reader.GetType() == chip::TLV::kTLVType_Null) { + m_attr_val.val.a.b = nullptr; + m_attr_val.val.a.s = (m_attr_val.type == ESP_MATTER_VAL_TYPE_CHAR_STRING ? 0xFF : 0xFFFF); + m_attr_val.val.a.t = m_attr_val.val.a.s; + break; + } + uint32_t len = reader.GetLength(); + if (len > 0xFF && m_attr_val.type == ESP_MATTER_VAL_TYPE_CHAR_STRING) { + return CHIP_ERROR_INVALID_ARGUMENT; + } + // The allocated buffer will be freed in destructor + m_attr_val.val.a.b = (uint8_t *)esp_matter_mem_calloc(len + 1, sizeof(char)); + if (!m_attr_val.val.a.b) { + return CHIP_ERROR_NO_MEMORY; + } + ReturnErrorOnFailure(reader.GetString((char *)m_attr_val.val.a.b, len + 1)); + m_attr_val.val.a.s = len; + m_attr_val.val.a.t = len + (m_attr_val.type == ESP_MATTER_VAL_TYPE_CHAR_STRING ? 1 : 2); + break; + } + case ESP_MATTER_VAL_TYPE_OCTET_STRING: + case ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING: { + if (reader.GetType() == chip::TLV::kTLVType_Null) { + m_attr_val.val.a.b = nullptr; + m_attr_val.val.a.s = (m_attr_val.type == ESP_MATTER_VAL_TYPE_OCTET_STRING ? 0xFF : 0xFFFF); + m_attr_val.val.a.t = m_attr_val.val.a.s; + break; + } + uint32_t len = reader.GetLength(); + if (len > 0xFF && m_attr_val.type == ESP_MATTER_VAL_TYPE_OCTET_STRING) { + return CHIP_ERROR_INVALID_ARGUMENT; + } + // The allocated buffer will be freed in destructor + m_attr_val.val.a.b = (uint8_t *)esp_matter_mem_calloc(len, sizeof(uint8_t)); + if (!m_attr_val.val.a.b) { + return CHIP_ERROR_NO_MEMORY; + } + ReturnErrorOnFailure(reader.GetBytes(m_attr_val.val.a.b, len)); + m_attr_val.val.a.s = len; + m_attr_val.val.a.t = len + (m_attr_val.type == ESP_MATTER_VAL_TYPE_OCTET_STRING ? 1 : 2); + break; + } + default: + return CHIP_ERROR_INVALID_ARGUMENT; + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR attribute_data_encode_buffer::Encode(chip::TLV::TLVWriter &writer, chip::TLV::Tag tag) const +{ + switch (m_attr_val.type) { + case ESP_MATTER_VAL_TYPE_NULLABLE_BOOLEAN: + if (chip::app::NumericAttributeTraits::IsNullValue(m_attr_val.val.b)) { + writer.PutNull(tag); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_BOOLEAN: + ReturnErrorOnFailure(writer.Put(tag, m_attr_val.val.b)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT8: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8: + if (chip::app::NumericAttributeTraits::IsNullValue(m_attr_val.val.u8)) { + writer.PutNull(tag); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_UINT8: + case ESP_MATTER_VAL_TYPE_ENUM8: + case ESP_MATTER_VAL_TYPE_BITMAP8: + ReturnErrorOnFailure(writer.Put(tag, m_attr_val.val.u8)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT16: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16: + if (chip::app::NumericAttributeTraits::IsNullValue(m_attr_val.val.u16)) { + writer.PutNull(tag); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_UINT16: + case ESP_MATTER_VAL_TYPE_ENUM16: + case ESP_MATTER_VAL_TYPE_BITMAP16: + ReturnErrorOnFailure(writer.Put(tag, m_attr_val.val.u16)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT32: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32: + if (chip::app::NumericAttributeTraits::IsNullValue(m_attr_val.val.u32)) { + writer.PutNull(tag); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_UINT32: + case ESP_MATTER_VAL_TYPE_BITMAP32: + ReturnErrorOnFailure(writer.Put(tag, m_attr_val.val.u32)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT64: + if (chip::app::NumericAttributeTraits::IsNullValue(m_attr_val.val.u64)) { + writer.PutNull(tag); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_UINT64: + ReturnErrorOnFailure(writer.Put(tag, m_attr_val.val.u64)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_INT8: + if (chip::app::NumericAttributeTraits::IsNullValue(m_attr_val.val.i8)) { + writer.PutNull(tag); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_INT8: + ReturnErrorOnFailure(writer.Put(tag, m_attr_val.val.i8)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_INT16: + if (chip::app::NumericAttributeTraits::IsNullValue(m_attr_val.val.i16)) { + writer.PutNull(tag); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_INT16: + ReturnErrorOnFailure(writer.Put(tag, m_attr_val.val.i16)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_INT32: + if (chip::app::NumericAttributeTraits::IsNullValue(m_attr_val.val.i32)) { + writer.PutNull(tag); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_INT32: + ReturnErrorOnFailure(writer.Put(tag, m_attr_val.val.i32)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_INT64: + if (chip::app::NumericAttributeTraits::IsNullValue(m_attr_val.val.i64)) { + writer.PutNull(tag); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_INT64: + ReturnErrorOnFailure(writer.Put(tag, m_attr_val.val.i64)); + break; + case ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT: + if (chip::app::NumericAttributeTraits::IsNullValue(m_attr_val.val.f)) { + writer.PutNull(tag); + break; + } + // Fall through + case ESP_MATTER_VAL_TYPE_FLOAT: + ReturnErrorOnFailure(writer.Put(tag, m_attr_val.val.f)); + break; + case ESP_MATTER_VAL_TYPE_CHAR_STRING: + case ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING: { + if (m_attr_val.val.a.b == nullptr && + m_attr_val.val.a.s == (m_attr_val.type == ESP_MATTER_VAL_TYPE_CHAR_STRING ? 0xFF : 0xFFFF)) { + writer.PutNull(tag); + break; + } + if (m_attr_val.val.a.b == nullptr) { + ReturnErrorOnFailure(writer.PutString(tag, "")); + } else { + ReturnErrorOnFailure(writer.PutString(tag, (char *)m_attr_val.val.a.b)); + } + break; + } + case ESP_MATTER_VAL_TYPE_OCTET_STRING: + case ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING: { + if (m_attr_val.val.a.b == nullptr && + m_attr_val.val.a.s == (m_attr_val.type == ESP_MATTER_VAL_TYPE_OCTET_STRING ? 0xFF : 0xFFFF)) { + writer.PutNull(tag); + break; + } + ReturnErrorOnFailure(writer.PutBytes(tag, m_attr_val.val.a.b, m_attr_val.val.a.s)); + break; + } + default: + return CHIP_ERROR_INVALID_ARGUMENT; + } + return CHIP_NO_ERROR; +} + +} // namespace data_model +} // namespace esp_matter diff --git a/components/esp_matter/data_model_provider/esp_matter_attr_data_buffer.h b/components/esp_matter/data_model_provider/esp_matter_attr_data_buffer.h new file mode 100644 index 000000000..4b5032360 --- /dev/null +++ b/components/esp_matter/data_model_provider/esp_matter_attr_data_buffer.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +#include + +#include + +namespace esp_matter { +namespace data_model { +class attribute_data_encode_buffer { +public: + static constexpr bool kIsFabricScoped = false; + attribute_data_encode_buffer(const esp_matter_attr_val_t attr_val) + : m_attr_val(attr_val) + { + } + + CHIP_ERROR Encode(chip::TLV::TLVWriter &writer, chip::TLV::Tag tag) const; + +private: + const esp_matter_attr_val_t m_attr_val; +}; + +class attribute_data_decode_buffer { +public: + static constexpr bool kIsFabricScoped = false; + attribute_data_decode_buffer(esp_matter_val_type_t attr_val_type) + { + m_attr_val.type = attr_val_type; + memset(&m_attr_val.val, 0, sizeof(m_attr_val.val)); + } + + ~attribute_data_decode_buffer() + { + if (m_attr_val.type == ESP_MATTER_VAL_TYPE_OCTET_STRING || + m_attr_val.type == ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING || + m_attr_val.type == ESP_MATTER_VAL_TYPE_CHAR_STRING || + m_attr_val.type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING) { + if (m_attr_val.val.a.b) { + esp_matter_mem_free(m_attr_val.val.a.b); + } + } + } + + esp_matter_attr_val_t &get_attr_val() { return m_attr_val; } + + CHIP_ERROR Decode(chip::TLV::TLVReader &reader); + +private: + esp_matter_attr_val_t m_attr_val; +}; +} // namespace data_model +} // namespace esp_matter 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 new file mode 100644 index 000000000..614d32a2e --- /dev/null +++ b/components/esp_matter/data_model_provider/esp_matter_data_model_provider.cpp @@ -0,0 +1,734 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; + +constexpr char TAG[] = "DataModelProvider"; + +namespace chip { +namespace app { +class ContextAttributesChangeListener : public AttributesChangedListener { +public: + ContextAttributesChangeListener(const DataModel::InteractionModelContext &context) + : mListener(context.dataModelChangeListener) + { + } + void MarkDirty(const AttributePathParams &path) override { mListener->MarkDirty(path); } + +private: + DataModel::ProviderChangeListener *mListener; +}; + +namespace { +/// Attempts to read via an attribute access interface (AAI) +/// +/// If it returns a CHIP_ERROR, then this is a FINAL result (i.e. either failure or success). +/// +/// If it returns std::nullopt, then there is no AAI to handle the given path +/// and processing should figure out the value otherwise (generally from esp_matter data) +std::optional TryReadViaAccessInterface(const ConcreteAttributePath &path, AttributeAccessInterface *aai, + AttributeValueEncoder &encoder) +{ + // Processing can happen only if an attribute access interface actually exists.. + if (aai == nullptr) { + return std::nullopt; + } + CHIP_ERROR err = aai->Read(path, encoder); + if (err != CHIP_NO_ERROR) { + // Implementation of 8.4.3.2 of the spec for path expansion + if (path.mExpanded && (err == CHIP_IM_GLOBAL_STATUS(UnsupportedRead))) { + return CHIP_NO_ERROR; + } + return err; + } + + // If the encoder tried to encode, then a value should have been written. + // - if encode, assume DONE (i.e. FINAL CHIP_NO_ERROR) + // - if no encode, say that processing must continue + return encoder.TriedEncode() ? std::make_optional(CHIP_NO_ERROR) : std::nullopt; +} + +/// Attempts to write via an attribute access interface (AAI) +/// +/// If it returns a CHIP_ERROR, then this is a FINAL result (i.e. either failure or success) +/// +/// If it returns std::nullopt, then there is no AAI to handle the given path +/// and processing should figure out the value otherwise (generally from other esp_matter data) +std::optional TryWriteViaAccessInterface(const ConcreteDataAttributePath &path, + AttributeAccessInterface *aai, AttributeValueDecoder &decoder) +{ + // Processing can happen only if an attribute access interface actually exists.. + if (aai == nullptr) { + return std::nullopt; + } + + CHIP_ERROR err = aai->Write(path, decoder); + + if (err != CHIP_NO_ERROR) { + return std::make_optional(err); + } + + // If the decoder tried to decode, then a value should have been read for processing. + // - if decoding was done, assume DONE (i.e. final CHIP_NO_ERROR) + // - otherwise, if no decoding done, return that processing must continue via nullopt + return decoder.TriedDecode() ? std::make_optional(CHIP_NO_ERROR) : std::nullopt; +} +} // namespace +} // namespace app +} // namespace chip + +namespace { + +#ifdef GENERATED_ACCESS_READ_ATTRIBUTE__CLUSTER +namespace GeneratedAccessReadAttribute { +constexpr ClusterId kCluster[] = GENERATED_ACCESS_READ_ATTRIBUTE__CLUSTER; +constexpr AttributeId kAttribute[] = GENERATED_ACCESS_READ_ATTRIBUTE__ATTRIBUTE; +constexpr chip::Access::Privilege kPrivilege[] = GENERATED_ACCESS_READ_ATTRIBUTE__PRIVILEGE; +static_assert(MATTER_ARRAY_SIZE(kCluster) == MATTER_ARRAY_SIZE(kAttribute) && + MATTER_ARRAY_SIZE(kAttribute) == MATTER_ARRAY_SIZE(kPrivilege), + "Generated parallel arrays must be same size"); +} // namespace GeneratedAccessReadAttribute +#endif + +#ifdef GENERATED_ACCESS_WRITE_ATTRIBUTE__CLUSTER +namespace GeneratedAccessWriteAttribute { +constexpr ClusterId kCluster[] = GENERATED_ACCESS_WRITE_ATTRIBUTE__CLUSTER; +constexpr AttributeId kAttribute[] = GENERATED_ACCESS_WRITE_ATTRIBUTE__ATTRIBUTE; +constexpr chip::Access::Privilege kPrivilege[] = GENERATED_ACCESS_WRITE_ATTRIBUTE__PRIVILEGE; +static_assert(MATTER_ARRAY_SIZE(kCluster) == MATTER_ARRAY_SIZE(kAttribute) && + MATTER_ARRAY_SIZE(kAttribute) == MATTER_ARRAY_SIZE(kPrivilege), + "Generated parallel arrays must be same size"); +} // namespace GeneratedAccessWriteAttribute +#endif + +#ifdef GENERATED_ACCESS_INVOKE_COMMAND__CLUSTER +namespace GeneratedAccessInvokeCommand { +constexpr ClusterId kCluster[] = GENERATED_ACCESS_INVOKE_COMMAND__CLUSTER; +constexpr CommandId kCommand[] = GENERATED_ACCESS_INVOKE_COMMAND__COMMAND; +constexpr chip::Access::Privilege kPrivilege[] = GENERATED_ACCESS_INVOKE_COMMAND__PRIVILEGE; +static_assert(MATTER_ARRAY_SIZE(kCluster) == MATTER_ARRAY_SIZE(kCommand) && + MATTER_ARRAY_SIZE(kCommand) == MATTER_ARRAY_SIZE(kPrivilege), + "Generated parallel arrays must be same size"); +} // namespace GeneratedAccessInvokeCommand +#endif + +#ifdef GENERATED_ACCESS_READ_EVENT__CLUSTER +namespace GeneratedAccessReadEvent { +constexpr ClusterId kCluster[] = GENERATED_ACCESS_READ_EVENT__CLUSTER; +constexpr EventId kEvent[] = GENERATED_ACCESS_READ_EVENT__EVENT; +constexpr chip::Access::Privilege kPrivilege[] = GENERATED_ACCESS_READ_EVENT__PRIVILEGE; +static_assert(MATTER_ARRAY_SIZE(kCluster) == MATTER_ARRAY_SIZE(kEvent) && + MATTER_ARRAY_SIZE(kEvent) == MATTER_ARRAY_SIZE(kPrivilege), + "Generated parallel arrays must be same size"); +} // namespace GeneratedAccessReadEvent +#endif + +chip::Access::Privilege MatterGetAccessPrivilegeForReadAttribute(ClusterId cluster, AttributeId attribute) +{ +#ifdef GENERATED_ACCESS_READ_ATTRIBUTE__CLUSTER + using namespace GeneratedAccessReadAttribute; + for (size_t i = 0; i < MATTER_ARRAY_SIZE(kCluster); ++i) { + if (kCluster[i] == cluster && kAttribute[i] == attribute) { + return kPrivilege[i]; + } + } +#endif + return chip::Access::Privilege::kView; +} + +chip::Access::Privilege MatterGetAccessPrivilegeForWriteAttribute(ClusterId cluster, AttributeId attribute) +{ +#ifdef GENERATED_ACCESS_WRITE_ATTRIBUTE__CLUSTER + using namespace GeneratedAccessWriteAttribute; + for (size_t i = 0; i < MATTER_ARRAY_SIZE(kCluster); ++i) { + if (kCluster[i] == cluster && kAttribute[i] == attribute) { + return kPrivilege[i]; + } + } +#endif + return chip::Access::Privilege::kOperate; +} + +chip::Access::Privilege MatterGetAccessPrivilegeForInvokeCommand(ClusterId cluster, CommandId command) +{ +#ifdef GENERATED_ACCESS_INVOKE_COMMAND__CLUSTER + using namespace GeneratedAccessInvokeCommand; + for (size_t i = 0; i < MATTER_ARRAY_SIZE(kCluster); ++i) { + if (kCluster[i] == cluster && kCommand[i] == command) { + return kPrivilege[i]; + } + } +#endif + return chip::Access::Privilege::kOperate; +} + +chip::Access::Privilege MatterGetAccessPrivilegeForReadEvent(ClusterId cluster, EventId event) +{ +#ifdef GENERATED_ACCESS_READ_EVENT__CLUSTER + using namespace GeneratedAccessReadEvent; + for (size_t i = 0; i < MATTER_ARRAY_SIZE(kCluster); ++i) { + if (kCluster[i] == cluster && kEvent[i] == event) { + return kPrivilege[i]; + } + } +#endif + return chip::Access::Privilege::kView; +} + +size_t get_command_count(esp_matter::cluster_t *cluster, uint8_t flag) +{ + size_t ret = 0; + esp_matter::command_t *command = esp_matter::command::get_first(cluster); + while (command) { + if (esp_matter::command::get_flags(command) & flag) { + ret++; + } + command = esp_matter::command::get_next(command); + } + return ret; +} + +size_t get_attribute_count(esp_matter::cluster_t *cluster) +{ + size_t ret = 0; + esp_matter::attribute_t *attribute = esp_matter::attribute::get_first(cluster); + while (attribute) { + ret++; + attribute = esp_matter::attribute::get_next(attribute); + } + return ret; +} + +} // anonymous namespace + +namespace esp_matter { +namespace data_model { + +provider &provider::get_instance() +{ + static provider instance; + return instance; +} + +/// Generic model implementations +CHIP_ERROR provider::Startup(InteractionModelContext context) +{ + ReturnErrorOnFailure(DataModel::Provider::Startup(context)); + esp_matter::cluster::add_bounds_callback_common(); + esp_matter::cluster::plugin_init_callback_common(); + endpoint_t *ep = endpoint::get_first(node::get()); + while (ep) { + cluster_t *cluster = cluster::get_first(ep); + while (cluster) { + 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(ep)); + } + 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(ep)); + } + } + cluster = cluster::get_next(cluster); + } + ep = endpoint::get_next(ep); + } + + return m_registry.SetContext(ServerClusterContext{ + .provider = this, + .storage = nullptr, + .attributeStorage = nullptr, + .interactionContext = &mContext, + }); +} + +CHIP_ERROR provider::Shutdown() +{ + m_registry.ClearContext(); + return CHIP_NO_ERROR; +} + +ActionReturnStatus provider::ReadAttribute(const ReadAttributeRequest &request, AttributeValueEncoder &encoder) +{ + if (auto *cluster = m_registry.Get(request.path); cluster != nullptr) { + return cluster->ReadAttribute(request, encoder); + } + Status status = CheckDataModelPath(request.path); + VerifyOrReturnValue(status == Protocols::InteractionModel::Status::Success, + CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status)); + attribute_t *attribute = + attribute::get(request.path.mEndpointId, request.path.mClusterId, request.path.mAttributeId); + + std::optional aai_result = TryReadViaAccessInterface( + request.path, + AttributeAccessInterfaceRegistry::Instance().Get(request.path.mEndpointId, request.path.mClusterId), encoder); + VerifyOrReturnError(!aai_result.has_value(), *aai_result); + + esp_matter_attr_val_t val = esp_matter_invalid(nullptr); + attribute::get_val(attribute, &val); + attribute_data_encode_buffer data_buffer(val); + return encoder.Encode(data_buffer); +} + +ActionReturnStatus provider::WriteAttribute(const WriteAttributeRequest &request, AttributeValueDecoder &decoder) +{ + if (auto *cluster = m_registry.Get(request.path); cluster != nullptr) { + return cluster->WriteAttribute(request, decoder); + } + Status status = CheckDataModelPath(request.path); + VerifyOrReturnValue(status == Protocols::InteractionModel::Status::Success, + CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status)); + cluster_t *cluster = cluster::get(request.path.mEndpointId, request.path.mClusterId); + attribute_t *attribute = attribute::get(cluster, request.path.mAttributeId); + if (request.path.mDataVersion.HasValue()) { + chip::DataVersion data_version; + VerifyOrReturnValue(cluster::get_data_version(cluster, data_version) == ESP_OK, + Protocols::InteractionModel::Status::DataVersionMismatch); + VerifyOrReturnValue(data_version == request.path.mDataVersion.Value(), + Protocols::InteractionModel::Status::DataVersionMismatch); + } + ContextAttributesChangeListener change_listener(CurrentContext()); + + AttributeAccessInterface *aai = + AttributeAccessInterfaceRegistry::Instance().Get(request.path.mEndpointId, request.path.mClusterId); + std::optional aai_result = TryWriteViaAccessInterface(request.path, aai, decoder); + if (aai_result.has_value()) { + if (*aai_result == CHIP_NO_ERROR) { + cluster::increase_data_version(cluster); + AttributePathParams path(request.path.mEndpointId, request.path.mClusterId, request.path.mAttributeId); + change_listener.MarkDirty(path); + } + return *aai_result; + } + + esp_matter_attr_val_t val = esp_matter_invalid(nullptr); + attribute::get_val(attribute, &val); + attribute_data_decode_buffer data_buffer(val.type); + ReturnErrorOnFailure(decoder.Decode(data_buffer)); + esp_err_t err = + attribute::update(request.path.mEndpointId, request.path.mClusterId, request.path.mAttributeId, &data_buffer.get_attr_val()); + if (err == ESP_ERR_NO_MEM) { + return Protocols::InteractionModel::Status::ResourceExhausted; + } else if (err != ESP_OK) { + return Protocols::InteractionModel::Status::Failure; + } + return Protocols::InteractionModel::Status::Success; +} + +void provider::ListAttributeWriteNotification(const ConcreteAttributePath &aPath, ListWriteOperation opType) +{ + if (auto *cluster = m_registry.Get(aPath); cluster != nullptr) { + return cluster->ListAttributeWriteNotification(aPath, opType); + } + AttributeAccessInterface *aai = + AttributeAccessInterfaceRegistry::Instance().Get(aPath.mEndpointId, aPath.mClusterId); + if (aai != nullptr) { + switch (opType) { + case DataModel::ListWriteOperation::kListWriteBegin: + aai->OnListWriteBegin(aPath); + break; + case DataModel::ListWriteOperation::kListWriteFailure: + aai->OnListWriteEnd(aPath, false); + break; + case DataModel::ListWriteOperation::kListWriteSuccess: + aai->OnListWriteEnd(aPath, true); + break; + } + } + return; +} + +std::optional provider::InvokeCommand(const InvokeRequest &request, + chip::TLV::TLVReader &input_arguments, + CommandHandler *handler) +{ + if (auto *cluster = m_registry.Get(request.path); cluster != nullptr) { + return cluster->InvokeCommand(request, input_arguments, handler); + } + Status status = CheckDataModelPath(request.path); + VerifyOrReturnValue(status == Protocols::InteractionModel::Status::Success, + CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status)); + CommandHandlerInterface *handler_interface = CommandHandlerInterfaceRegistry::Instance().GetCommandHandler( + request.path.mEndpointId, request.path.mClusterId); + + if (handler_interface) { + CommandHandlerInterface::HandlerContext context(*handler, request.path, input_arguments); + handler_interface->InvokeCommand(context); + + // If the command was handled, don't proceed any further and return successfully. + if (context.mCommandHandled) { + return std::nullopt; + } + } + + command::dispatch_single_cluster_command(request.path, input_arguments, handler); + return std::nullopt; +} + +/// attribute tree iteration +CHIP_ERROR provider::Endpoints(ReadOnlyBufferBuilder &builder) +{ + const uint16_t ep_count = endpoint::get_count(node::get()); + ReturnErrorOnFailure(builder.EnsureAppendCapacity(ep_count)); + endpoint_t *ep = endpoint::get_first(node::get()); + while (ep) { + if (endpoint::is_enabled(ep)) { + DataModel::EndpointEntry entry; + entry.id = endpoint::get_id(ep); + entry.parentId = endpoint::get_parent_endpoint_id(ep); + entry.compositionPattern = endpoint::get_composition_pattern(ep); + ReturnErrorOnFailure(builder.Append(entry)); + } + ep = endpoint::get_next(ep); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR provider::SemanticTags(EndpointId endpointId, ReadOnlyBufferBuilder &builder) +{ + Status status = CheckDataModelPath(endpointId); + VerifyOrReturnValue(status == Protocols::InteractionModel::Status::Success, + CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status)); + endpoint_t *ep = endpoint::get(endpointId); + int count = endpoint::get_semantic_tag_count(ep); + ReturnErrorOnFailure(builder.EnsureAppendCapacity(count)); + for (size_t idx = 0; idx < count; idx++) { + DataModel::Provider::SemanticTag semanticTag; + VerifyOrReturnError(endpoint::get_semantic_tag_at_index(ep, idx, semanticTag) == ESP_OK, CHIP_ERROR_INTERNAL, + ESP_LOGE(TAG, "Failed to get SemanticTag at %d", idx)); + ReturnErrorOnFailure(builder.Append(semanticTag)); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR provider::DeviceTypes(EndpointId endpointId, ReadOnlyBufferBuilder &builder) +{ + Status status = CheckDataModelPath(endpointId); + VerifyOrReturnValue(status == Protocols::InteractionModel::Status::Success, + CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status)); + endpoint_t *ep = endpoint::get(endpointId); + size_t count = endpoint::get_device_type_count(ep); + ReturnErrorOnFailure(builder.EnsureAppendCapacity(count)); + for (size_t idx = 0; idx < count; idx++) { + DeviceTypeEntry entry; + VerifyOrReturnError(endpoint::get_device_type_at_index(ep, idx, entry.deviceTypeId, entry.deviceTypeRevision) == + ESP_OK, + CHIP_ERROR_INTERNAL, ESP_LOGE(TAG, "Failed to get device type at %d", idx)); + ReturnErrorOnFailure(builder.Append(entry)); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR provider::ClientClusters(EndpointId endpointId, ReadOnlyBufferBuilder &builder) +{ + Status status = CheckDataModelPath(endpointId); + VerifyOrReturnValue(status == Protocols::InteractionModel::Status::Success, + CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status)); + endpoint_t *ep = endpoint::get(endpointId); + size_t count = endpoint::get_cluster_count(endpointId, chip::kInvalidClusterId, CLUSTER_FLAG_CLIENT); + ReturnErrorOnFailure(builder.EnsureAppendCapacity(count)); + cluster_t *cluster = cluster::get_first(ep); + while (cluster) { + if (cluster::get_flags(cluster) & CLUSTER_FLAG_CLIENT) { + ReturnErrorOnFailure(builder.Append(cluster::get_id(cluster))); + } + cluster = cluster::get_next(cluster); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR provider::ServerClusters(EndpointId endpointId, ReadOnlyBufferBuilder &builder) +{ + Status status = CheckDataModelPath(endpointId); + VerifyOrReturnValue(status == Protocols::InteractionModel::Status::Success, + CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status)); + endpoint_t *ep = endpoint::get(endpointId); + size_t count = endpoint::get_cluster_count(endpointId, chip::kInvalidClusterId, CLUSTER_FLAG_SERVER); + ReturnErrorOnFailure(builder.EnsureAppendCapacity(count)); + cluster_t *cluster = cluster::get_first(ep); + while (cluster) { + if (cluster::get_flags(cluster) & CLUSTER_FLAG_SERVER) { + ServerClusterEntry entry; + entry.clusterId = cluster::get_id(cluster); + entry.flags.ClearAll(); + VerifyOrReturnError(cluster::get_data_version(cluster, entry.dataVersion) == ESP_OK, CHIP_ERROR_INTERNAL); + ReturnErrorOnFailure(builder.Append(entry)); + } + cluster = cluster::get_next(cluster); + } + + return CHIP_NO_ERROR; +} + +#if CHIP_CONFIG_USE_ENDPOINT_UNIQUE_ID +CHIP_ERROR provider::EndpointUniqueID(EndpointId endpointId, MutableCharSpan &epUniqueId) +{ + // TODO: Support Endpoint Unique ID + return CHIP_NO_ERROR; +} +#endif + +CHIP_ERROR provider::EventInfo(const ConcreteEventPath &path, EventEntry &eventInfo) +{ + if (auto *cluster = m_registry.Get(path); cluster != nullptr) { + return cluster->EventInfo(path, eventInfo); + } + Status status = CheckDataModelPath(path); + VerifyOrReturnValue(status == Protocols::InteractionModel::Status::Success, + CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status)); + eventInfo.readPrivilege = MatterGetAccessPrivilegeForReadEvent(path.mClusterId, path.mEventId); + return CHIP_NO_ERROR; +} + +CHIP_ERROR provider::GeneratedCommands(const ConcreteClusterPath &path, ReadOnlyBufferBuilder &builder) +{ + if (auto *cluster = m_registry.Get(path); cluster != nullptr) { + return cluster->GeneratedCommands(path, builder); + } + Status status = CheckDataModelPath(path); + VerifyOrReturnValue(status == Protocols::InteractionModel::Status::Success, + CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status)); + cluster_t *cluster = cluster::get(path.mEndpointId, path.mClusterId); + size_t count = get_command_count(cluster, COMMAND_FLAG_GENERATED); + ReturnErrorOnFailure(builder.EnsureAppendCapacity(count)); + command_t *command = command::get_first(cluster); + while (command) { + if (command::get_flags(command) & COMMAND_FLAG_GENERATED) { + ReturnErrorOnFailure(builder.Append(command::get_id(command))); + } + command = command::get_next(command); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR provider::AcceptedCommands(const ConcreteClusterPath &path, + ReadOnlyBufferBuilder &builder) +{ + if (auto *cluster = m_registry.Get(path); cluster != nullptr) { + return cluster->AcceptedCommands(path, builder); + } + Status status = CheckDataModelPath(path); + VerifyOrReturnValue(status == Protocols::InteractionModel::Status::Success, + CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status)); + CommandHandlerInterface *interface = + CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(path.mEndpointId, path.mClusterId); + if (interface != nullptr) { + size_t commandCount = 0; + CHIP_ERROR err = interface->EnumerateAcceptedCommands( + path, + [](CommandId id, void *context) -> Loop { + *reinterpret_cast(context) += 1; + return Loop::Continue; + }, + reinterpret_cast(&commandCount)); + + if (err == CHIP_NO_ERROR) { + using EnumerationData = struct { + ConcreteCommandPath commandPath; + ReadOnlyBufferBuilder *acceptedCommandList; + CHIP_ERROR processingError; + }; + + EnumerationData enumerationData; + enumerationData.commandPath = ConcreteCommandPath(path.mEndpointId, path.mClusterId, kInvalidCommandId); + enumerationData.processingError = CHIP_NO_ERROR; + enumerationData.acceptedCommandList = &builder; + + ReturnErrorOnFailure(builder.EnsureAppendCapacity(commandCount)); + + ReturnErrorOnFailure(interface->EnumerateAcceptedCommands( + path, + [](CommandId commandId, void *context) -> Loop { + auto input = reinterpret_cast(context); + input->commandPath.mCommandId = commandId; + ClusterId clusterId = input->commandPath.mClusterId; + BitMask quality_flags; + quality_flags + .Set(DataModel::CommandQualityFlags::kFabricScoped, CommandIsFabricScoped(clusterId, commandId)) + .Set(DataModel::CommandQualityFlags::kTimed, CommandNeedsTimedInvoke(clusterId, commandId)) + .Set(DataModel::CommandQualityFlags::kLargeMessage, + CommandHasLargePayload(clusterId, commandId)); + AcceptedCommandEntry entry( + commandId, quality_flags, + MatterGetAccessPrivilegeForInvokeCommand(input->commandPath.mClusterId, commandId)); + CHIP_ERROR appendError = input->acceptedCommandList->Append(entry); + if (appendError != CHIP_NO_ERROR) { + input->processingError = appendError; + return Loop::Break; + } + return Loop::Continue; + }, + reinterpret_cast(&enumerationData))); + ReturnErrorOnFailure(enumerationData.processingError); + // the two invocations MUST return the same sizes. + VerifyOrReturnError(builder.Size() == commandCount, CHIP_ERROR_INTERNAL); + return CHIP_NO_ERROR; + } + VerifyOrReturnError(err == CHIP_ERROR_NOT_IMPLEMENTED, err); + } + // If we cannot get AcceptedCommands array from CommandHandlerinterface, get it from esp_matter data model. + cluster_t *cluster = cluster::get(path.mEndpointId, path.mClusterId); + size_t count = get_command_count(cluster, COMMAND_FLAG_ACCEPTED); + ReturnErrorOnFailure(builder.EnsureAppendCapacity(count)); + command_t *command = command::get_first(cluster); + while (command) { + if (command::get_flags(command) & COMMAND_FLAG_ACCEPTED) { + uint32_t command_id = command::get_id(command); + BitMask quality_flags; + quality_flags + .Set(DataModel::CommandQualityFlags::kFabricScoped, CommandIsFabricScoped(path.mClusterId, command_id)) + .Set(DataModel::CommandQualityFlags::kTimed, CommandNeedsTimedInvoke(path.mClusterId, command_id)) + .Set(DataModel::CommandQualityFlags::kLargeMessage, + CommandHasLargePayload(path.mClusterId, command_id)); + AcceptedCommandEntry entry(command_id, quality_flags, + MatterGetAccessPrivilegeForInvokeCommand(path.mClusterId, command_id)); + ReturnErrorOnFailure(builder.Append(entry)); + } + command = command::get_next(command); + } + return CHIP_NO_ERROR; +} + +static constexpr AttributeId k_global_attributes_not_in_metadata[] = { + Clusters::Globals::Attributes::AttributeList::Id, Clusters::Globals::Attributes::AcceptedCommandList::Id, + Clusters::Globals::Attributes::GeneratedCommandList::Id}; + +static constexpr size_t k_global_attributes_count = + sizeof(k_global_attributes_not_in_metadata) / sizeof(k_global_attributes_not_in_metadata[0]); + +CHIP_ERROR provider::Attributes(const ConcreteClusterPath &path, ReadOnlyBufferBuilder &builder) +{ + if (auto *cluster = m_registry.Get(path); cluster != nullptr) { + return cluster->Attributes(path, builder); + } + Status status = CheckDataModelPath(path); + VerifyOrReturnValue(status == Protocols::InteractionModel::Status::Success, + CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status)); + cluster_t *cluster = cluster::get(path.mEndpointId, path.mClusterId); + size_t count = get_attribute_count(cluster); + // There are three attributes(Attributes, AcceptedCommands, and GeneratedCommands) which are not + // in esp_matter data model metadata; + ReturnErrorOnFailure(builder.EnsureAppendCapacity(count + k_global_attributes_count)); + attribute_t *attribute = attribute::get_first(cluster); + while (attribute) { + uint32_t id = attribute::get_id(attribute); + uint16_t flags = attribute::get_flags(attribute); + chip::BitFlags attr_quality_flags; + // TODO Array + attr_quality_flags.Set(DataModel::AttributeQualityFlags::kTimed, flags & ATTRIBUTE_FLAG_MUST_USE_TIMED_WRITE); + chip::Access::Privilege read_privilege = MatterGetAccessPrivilegeForReadAttribute(path.mClusterId, id); + auto write_privilege = (flags & ATTRIBUTE_FLAG_WRITABLE) + ? std::make_optional(MatterGetAccessPrivilegeForWriteAttribute(path.mClusterId, id)) + : std::nullopt; + AttributeEntry entry(id, attr_quality_flags, read_privilege, write_privilege); + ReturnErrorOnFailure(builder.Append(entry)); + attribute = attribute::get_next(attribute); + } + // Append the three Global attributes + for (size_t index = 0; index < k_global_attributes_count; ++index) + { + AttributeEntry entry(k_global_attributes_not_in_metadata[index], + chip::BitFlags(), chip::Access::Privilege::kView, + std::nullopt); + ReturnErrorOnFailure(builder.Append(entry)); + } + + return CHIP_NO_ERROR; +} + +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); + ContextAttributesChangeListener change_listener(CurrentContext()); + change_listener.MarkDirty(path); +} + +Status provider::CheckDataModelPath(EndpointId endpointId) +{ + endpoint_t *endpoint = endpoint::get(endpointId); + VerifyOrReturnValue(endpoint != nullptr, Protocols::InteractionModel::Status::UnsupportedEndpoint); + return Protocols::InteractionModel::Status::Success; +} + +Status provider::CheckDataModelPath(const ConcreteClusterPath &path) +{ + endpoint_t *endpoint = endpoint::get(path.mEndpointId); + VerifyOrReturnValue(endpoint, Protocols::InteractionModel::Status::UnsupportedEndpoint); + cluster_t *cluster = cluster::get(path.mEndpointId, path.mClusterId); + VerifyOrReturnValue(cluster != nullptr, Protocols::InteractionModel::Status::UnsupportedCluster); + return Protocols::InteractionModel::Status::Success; +} + +Status provider::CheckDataModelPath(const ConcreteAttributePath &path) +{ + endpoint_t *endpoint = endpoint::get(path.mEndpointId); + VerifyOrReturnValue(endpoint, Protocols::InteractionModel::Status::UnsupportedEndpoint); + cluster_t *cluster = cluster::get(endpoint, path.mClusterId); + VerifyOrReturnValue(cluster != nullptr, Protocols::InteractionModel::Status::UnsupportedCluster); + attribute_t *attribute = attribute::get(cluster, path.mAttributeId); + VerifyOrReturnValue(attribute != nullptr, Protocols::InteractionModel::Status::UnsupportedAttribute); + return Protocols::InteractionModel::Status::Success; +} + +Status provider::CheckDataModelPath(const ConcreteEventPath &path) +{ + endpoint_t *endpoint = endpoint::get(path.mEndpointId); + VerifyOrReturnValue(endpoint, Protocols::InteractionModel::Status::UnsupportedEndpoint); + cluster_t *cluster = cluster::get(endpoint, path.mClusterId); + VerifyOrReturnValue(cluster != nullptr, Protocols::InteractionModel::Status::UnsupportedCluster); + event_t *event = event::get(cluster, path.mEventId); + VerifyOrReturnValue(event != nullptr, Protocols::InteractionModel::Status::UnsupportedEvent); + return Protocols::InteractionModel::Status::Success; +} + +Status provider::CheckDataModelPath(const chip::app::ConcreteCommandPath path) +{ + endpoint_t *endpoint = endpoint::get(path.mEndpointId); + VerifyOrReturnValue(endpoint, Protocols::InteractionModel::Status::UnsupportedEndpoint); + cluster_t *cluster = cluster::get(endpoint, path.mClusterId); + VerifyOrReturnValue(cluster != nullptr, Protocols::InteractionModel::Status::UnsupportedCluster); + command_t *command = command::get(cluster, path.mCommandId, COMMAND_FLAG_ACCEPTED | COMMAND_FLAG_GENERATED); + VerifyOrReturnValue(command != nullptr, Protocols::InteractionModel::Status::UnsupportedCommand); + return Protocols::InteractionModel::Status::Success; +} + +} // namespace data_model +} // namespace esp_matter diff --git a/components/esp_matter/data_model_provider/esp_matter_data_model_provider.h b/components/esp_matter/data_model_provider/esp_matter_data_model_provider.h new file mode 100644 index 000000000..7be3ada88 --- /dev/null +++ b/components/esp_matter/data_model_provider/esp_matter_data_model_provider.h @@ -0,0 +1,111 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace esp_matter { +namespace data_model { + +using chip::ClusterId; +using chip::CommandId; +using chip::EndpointId; +using chip::MutableCharSpan; +using chip::ReadOnlyBufferBuilder; +using chip::app::AttributePathParams; +using chip::app::AttributeValueDecoder; +using chip::app::AttributeValueEncoder; +using chip::app::CommandHandler; +using chip::app::ConcreteAttributePath; +using chip::app::ConcreteClusterPath; +using chip::app::ConcreteEventPath; +using chip::app::DataModel::AcceptedCommandEntry; +using chip::app::DataModel::ActionReturnStatus; +using chip::app::DataModel::AttributeEntry; +using chip::app::DataModel::DeviceTypeEntry; +using chip::app::DataModel::EndpointEntry; +using chip::app::DataModel::EventEntry; +using chip::app::DataModel::InteractionModelContext; +using chip::app::DataModel::InvokeRequest; +using chip::app::DataModel::ListWriteOperation; +using chip::app::DataModel::ReadAttributeRequest; +using chip::app::DataModel::ServerClusterEntry; +using chip::app::DataModel::WriteAttributeRequest; +using chip::Protocols::InteractionModel::Status; + +class provider : public chip::app::DataModel::Provider { +public: + // access to the typed global singleton of this class. + static provider &get_instance(); + + chip::app::ServerClusterInterfaceRegistry ®istry() { return m_registry; } + + /// Generic model implementations + CHIP_ERROR Startup(InteractionModelContext context) override; + CHIP_ERROR Shutdown() override; + + ActionReturnStatus ReadAttribute(const ReadAttributeRequest &request, AttributeValueEncoder &encoder) override; + ActionReturnStatus WriteAttribute(const WriteAttributeRequest &request, AttributeValueDecoder &decoder) override; + + void ListAttributeWriteNotification(const ConcreteAttributePath &aPath, ListWriteOperation opType) override; + std::optional InvokeCommand(const InvokeRequest &request, chip::TLV::TLVReader &input_arguments, + CommandHandler *handler) override; + + /// attribute tree iteration + CHIP_ERROR Endpoints(ReadOnlyBufferBuilder &out) override; + CHIP_ERROR SemanticTags(EndpointId endpointId, ReadOnlyBufferBuilder &builder) override; + CHIP_ERROR DeviceTypes(EndpointId endpointId, ReadOnlyBufferBuilder &builder) override; + CHIP_ERROR ClientClusters(EndpointId endpointId, ReadOnlyBufferBuilder &builder) override; + CHIP_ERROR ServerClusters(EndpointId endpointId, ReadOnlyBufferBuilder &builder) override; +#if CHIP_CONFIG_USE_ENDPOINT_UNIQUE_ID + CHIP_ERROR EndpointUniqueID(EndpointId endpointId, MutableCharSpan &epUniqueId) override; +#endif + CHIP_ERROR EventInfo(const ConcreteEventPath &path, EventEntry &eventInfo) override; + CHIP_ERROR GeneratedCommands(const ConcreteClusterPath &path, ReadOnlyBufferBuilder &builder) override; + CHIP_ERROR AcceptedCommands(const ConcreteClusterPath &path, + ReadOnlyBufferBuilder &builder) override; + CHIP_ERROR Attributes(const ConcreteClusterPath &path, ReadOnlyBufferBuilder &builder) override; + + void Temporary_ReportAttributeChanged(const AttributePathParams &path) override; + +private: + Status CheckDataModelPath(EndpointId endpointId); + Status CheckDataModelPath(const ConcreteClusterPath &path); + Status CheckDataModelPath(const ConcreteAttributePath &path); + Status CheckDataModelPath(const ConcreteEventPath &path); + Status CheckDataModelPath(const chip::app::ConcreteCommandPath path); + + chip::app::ServerClusterInterfaceRegistry m_registry; +}; + +} // namespace data_model +} // namespace esp_matter diff --git a/components/esp_matter/data_model_provider/esp_matter_ember_stubs.cpp b/components/esp_matter/data_model_provider/esp_matter_ember_stubs.cpp new file mode 100644 index 000000000..397110ed6 --- /dev/null +++ b/components/esp_matter/data_model_provider/esp_matter_ember_stubs.cpp @@ -0,0 +1,1385 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * Since we will not use ember data model anymore, but the upstream code still uses ember APIs so we define + * these stub functions to make upstream code access our esp_matter data model instead of ember data model. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using chip::Protocols::InteractionModel::Status; + +namespace { + +esp_matter::endpoint_t *get_endpoint_at_index(uint16_t index) +{ + esp_matter::endpoint_t *ep = esp_matter::endpoint::get_first(esp_matter::node::get()); + uint16_t idx = 0; + while (idx < index && ep) { + ep = esp_matter::endpoint::get_next(ep); + idx++; + } + return ep; +} + +Status get_raw_data_buffer_from_attr_val(const esp_matter_attr_val_t &val, uint8_t *dataPtr, uint16_t readLength) +{ + switch (val.type) { + case ESP_MATTER_VAL_TYPE_BOOLEAN: + case ESP_MATTER_VAL_TYPE_NULLABLE_BOOLEAN: { + if (readLength < sizeof(bool) || !dataPtr) { + return chip::Protocols::InteractionModel::Status::ResourceExhausted; + } + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(*(uint8_t *)(&(val.val.b)))) { + Traits::SetNull(*(uint8_t *)dataPtr); + } else { + Traits::WorkingToStorage(val.val.b, *dataPtr); + } + break; + } + + case ESP_MATTER_VAL_TYPE_FLOAT: + case ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT: { + if (readLength < sizeof(float) || !dataPtr) { + return chip::Protocols::InteractionModel::Status::ResourceExhausted; + } + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.f)) { + Traits::SetNull(*(float *)dataPtr); + } else { + Traits::WorkingToStorage(val.val.f, *(float *)dataPtr); + } + break; + } + + case ESP_MATTER_VAL_TYPE_OCTET_STRING: + case ESP_MATTER_VAL_TYPE_CHAR_STRING: { + if (readLength < val.val.a.t || !dataPtr) { + return chip::Protocols::InteractionModel::Status::ResourceExhausted; + } + uint8_t len = val.val.a.s; + memcpy(dataPtr, &len, sizeof(len)); + // UINT8_MAX is reserved for null value + if (len < UINT8_MAX) { + memcpy(dataPtr + sizeof(len), val.val.a.b, len); + } + break; + } + + case ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING: + case ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING: { + if (readLength < val.val.a.t || !dataPtr) { + return chip::Protocols::InteractionModel::Status::ResourceExhausted; + } + memcpy(dataPtr, &val.val.a.s, sizeof(val.val.a.s)); + // UINT16_MAX is reserved for null value + if (val.val.a.s < UINT16_MAX) { + memcpy(dataPtr + sizeof(val.val.a.s), val.val.a.b, val.val.a.s); + } + break; + } + + case ESP_MATTER_VAL_TYPE_INT8: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT8: { + if (readLength < sizeof(int8_t) || !dataPtr) { + return chip::Protocols::InteractionModel::Status::ResourceExhausted; + } + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.i8)) { + Traits::SetNull(*(int8_t *)dataPtr); + } else { + Traits::WorkingToStorage(val.val.i8, *(int8_t *)dataPtr); + } + break; + } + case ESP_MATTER_VAL_TYPE_BITMAP8: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8: + case ESP_MATTER_VAL_TYPE_ENUM8: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8: + case ESP_MATTER_VAL_TYPE_UINT8: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT8: { + if (readLength < sizeof(uint8_t) || !dataPtr) { + return chip::Protocols::InteractionModel::Status::ResourceExhausted; + } + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.u8)) { + Traits::SetNull(*dataPtr); + } else { + Traits::WorkingToStorage(val.val.u8, *dataPtr); + } + break; + } + + case ESP_MATTER_VAL_TYPE_INT16: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT16: { + if (readLength < sizeof(int16_t) || !dataPtr) { + return chip::Protocols::InteractionModel::Status::ResourceExhausted; + } + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.i16)) { + Traits::SetNull(*(int16_t *)dataPtr); + } else { + Traits::WorkingToStorage(val.val.i16, *(int16_t *)dataPtr); + } + break; + } + + case ESP_MATTER_VAL_TYPE_BITMAP16: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16: + case ESP_MATTER_VAL_TYPE_ENUM16: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16: + case ESP_MATTER_VAL_TYPE_UINT16: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT16: { + if (readLength < sizeof(uint16_t) || !dataPtr) { + return chip::Protocols::InteractionModel::Status::ResourceExhausted; + } + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.u16)) { + Traits::SetNull(*(uint16_t *)dataPtr); + } else { + Traits::WorkingToStorage(val.val.u16, *(uint16_t *)dataPtr); + } + break; + } + + case ESP_MATTER_VAL_TYPE_INT32: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT32: { + if (readLength < sizeof(int32_t) || !dataPtr) { + return chip::Protocols::InteractionModel::Status::ResourceExhausted; + } + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.i32)) { + Traits::SetNull(*(int32_t *)dataPtr); + } else { + Traits::WorkingToStorage(val.val.i32, *(int32_t *)dataPtr); + } + break; + } + + case ESP_MATTER_VAL_TYPE_BITMAP32: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32: + case ESP_MATTER_VAL_TYPE_UINT32: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT32: { + if (readLength < sizeof(uint32_t) || !dataPtr) { + return chip::Protocols::InteractionModel::Status::ResourceExhausted; + } + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.u32)) { + Traits::SetNull(*(uint32_t *)dataPtr); + } else { + Traits::WorkingToStorage(val.val.u32, *(uint32_t *)dataPtr); + } + break; + } + + case ESP_MATTER_VAL_TYPE_INT64: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT64: { + if (readLength < sizeof(int64_t) || !dataPtr) { + return chip::Protocols::InteractionModel::Status::ResourceExhausted; + } + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.i64)) { + Traits::SetNull(*(int64_t *)dataPtr); + } else { + Traits::WorkingToStorage(val.val.i64, *(int64_t *)dataPtr); + } + break; + } + + case ESP_MATTER_VAL_TYPE_UINT64: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT64: { + if (readLength < sizeof(uint8_t) || !dataPtr) { + return chip::Protocols::InteractionModel::Status::ResourceExhausted; + } + using Traits = chip::app::NumericAttributeTraits; + if ((val.type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val.val.u64)) { + Traits::SetNull(*(uint64_t *)dataPtr); + } else { + Traits::WorkingToStorage(val.val.u64, *(uint64_t *)dataPtr); + } + break; + } + + default: + return chip::Protocols::InteractionModel::Status::InvalidDataType; + } + return chip::Protocols::InteractionModel::Status::Success; +} + +Status get_attr_val_from_raw_data_buffer(uint8_t *value, EmberAfAttributeType dataType, esp_matter_attr_val_t &val, + bool is_nullable) +{ + switch (dataType) { + case ZCL_BOOLEAN_ATTRIBUTE_TYPE: { + using Traits = chip::app::NumericAttributeTraits; + Traits::StorageType attribute_value; + memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); + val = esp_matter_bool(attribute_value); + break; + } + + case ZCL_CHAR_STRING_ATTRIBUTE_TYPE: { + uint8_t data_count = 0; + memcpy(&data_count, &value[0], sizeof(uint8_t)); + if (is_nullable && data_count == UINT8_MAX) { + val = esp_matter_char_str(nullptr, data_count); + } else if (data_count < UINT8_MAX) { + val = esp_matter_char_str((char *)(value + sizeof(uint8_t)), data_count); + } + break; + } + + case ZCL_LONG_CHAR_STRING_ATTRIBUTE_TYPE: { + uint16_t data_count = 0; + memcpy(&data_count, &value[0], sizeof(uint16_t)); + if (is_nullable && data_count == UINT16_MAX) { + val = esp_matter_char_str(nullptr, data_count); + } else if (data_count < UINT16_MAX) { + val = esp_matter_long_char_str((char *)(value + sizeof(uint16_t)), data_count); + } + break; + } + + case ZCL_OCTET_STRING_ATTRIBUTE_TYPE: + case ZCL_IPADR_ATTRIBUTE_TYPE: + case ZCL_IPV4ADR_ATTRIBUTE_TYPE: + case ZCL_IPV6ADR_ATTRIBUTE_TYPE: + case ZCL_IPV6PRE_ATTRIBUTE_TYPE: + case ZCL_HWADR_ATTRIBUTE_TYPE: { + uint8_t data_count = 0; + memcpy(&data_count, &value[0], sizeof(uint8_t)); + if (is_nullable && data_count == UINT8_MAX) { + val = esp_matter_char_str(nullptr, data_count); + } else if (data_count < UINT8_MAX) { + val = esp_matter_octet_str((value + sizeof(uint8_t)), data_count); + } + break; + } + + case ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE: { + uint16_t data_count = 0; + memcpy(&data_count, &value[0], sizeof(uint16_t)); + if (is_nullable && data_count == UINT16_MAX) { + val = esp_matter_char_str(nullptr, data_count); + } else if (data_count < UINT16_MAX) { + val = esp_matter_long_octet_str((value + sizeof(uint16_t)), data_count); + } + break; + } + + case ZCL_INT8S_ATTRIBUTE_TYPE: { + using Traits = chip::app::NumericAttributeTraits; + Traits::StorageType attribute_value; + memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); + if (is_nullable) { + if (Traits::IsNullValue(attribute_value)) { + val = esp_matter_nullable_int8(nullable()); + } else { + val = esp_matter_nullable_int8(attribute_value); + } + } else { + val = esp_matter_int8(attribute_value); + } + break; + } + + case ZCL_INT8U_ATTRIBUTE_TYPE: + case ZCL_ACTION_ID_ATTRIBUTE_TYPE: + case ZCL_TAG_ATTRIBUTE_TYPE: + case ZCL_NAMESPACE_ATTRIBUTE_TYPE: + case ZCL_FABRIC_IDX_ATTRIBUTE_TYPE: + case ZCL_PERCENT_ATTRIBUTE_TYPE: { + using Traits = chip::app::NumericAttributeTraits; + Traits::StorageType attribute_value; + memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); + if (is_nullable) { + if (Traits::IsNullValue(attribute_value)) { + val = esp_matter_nullable_uint8(nullable()); + } else { + val = esp_matter_nullable_uint8(attribute_value); + } + } else { + val = esp_matter_uint8(attribute_value); + } + break; + } + + case ZCL_INT16S_ATTRIBUTE_TYPE: + case ZCL_TEMPERATURE_ATTRIBUTE_TYPE: { + using Traits = chip::app::NumericAttributeTraits; + Traits::StorageType attribute_value; + memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); + if (is_nullable) { + if (Traits::IsNullValue(attribute_value)) { + val = esp_matter_nullable_int16(nullable()); + } else { + val = esp_matter_nullable_int16(attribute_value); + } + } else { + val = esp_matter_int16(attribute_value); + } + break; + } + + case ZCL_INT16U_ATTRIBUTE_TYPE: + case ZCL_ENTRY_IDX_ATTRIBUTE_TYPE: + case ZCL_GROUP_ID_ATTRIBUTE_TYPE: + case ZCL_ENDPOINT_NO_ATTRIBUTE_TYPE: + case ZCL_VENDOR_ID_ATTRIBUTE_TYPE: + case ZCL_PERCENT100THS_ATTRIBUTE_TYPE: { + using Traits = chip::app::NumericAttributeTraits; + Traits::StorageType attribute_value; + memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); + if (is_nullable) { + if (Traits::IsNullValue(attribute_value)) { + val = esp_matter_nullable_uint16(nullable()); + } else { + val = esp_matter_nullable_uint16(attribute_value); + } + } else { + val = esp_matter_uint16(attribute_value); + } + break; + } + + case ZCL_INT32S_ATTRIBUTE_TYPE: + case ZCL_INT24S_ATTRIBUTE_TYPE: { + using Traits = chip::app::NumericAttributeTraits; + Traits::StorageType attribute_value; + memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); + if (is_nullable) { + if (Traits::IsNullValue(attribute_value)) { + val = esp_matter_nullable_int32(nullable()); + } else { + val = esp_matter_nullable_int32(attribute_value); + } + } else { + val = esp_matter_int32(attribute_value); + } + break; + } + + case ZCL_INT32U_ATTRIBUTE_TYPE: + case ZCL_TRANS_ID_ATTRIBUTE_TYPE: + case ZCL_CLUSTER_ID_ATTRIBUTE_TYPE: + case ZCL_ATTRIB_ID_ATTRIBUTE_TYPE: + case ZCL_FIELD_ID_ATTRIBUTE_TYPE: + case ZCL_EVENT_ID_ATTRIBUTE_TYPE: + case ZCL_COMMAND_ID_ATTRIBUTE_TYPE: + case ZCL_EPOCH_S_ATTRIBUTE_TYPE: + case ZCL_ELAPSED_S_ATTRIBUTE_TYPE: + case ZCL_DATA_VER_ATTRIBUTE_TYPE: + case ZCL_DEVTYPE_ID_ATTRIBUTE_TYPE: + case ZCL_INT24U_ATTRIBUTE_TYPE: { + using Traits = chip::app::NumericAttributeTraits; + Traits::StorageType attribute_value; + memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); + if (is_nullable) { + if (Traits::IsNullValue(attribute_value)) { + val = esp_matter_nullable_uint32(nullable()); + } else { + val = esp_matter_nullable_uint32(attribute_value); + } + } else { + val = esp_matter_uint32(attribute_value); + } + break; + } + + case ZCL_INT64S_ATTRIBUTE_TYPE: + case ZCL_ENERGY_MWH_ATTRIBUTE_TYPE: + case ZCL_AMPERAGE_MA_ATTRIBUTE_TYPE: + case ZCL_POWER_MW_ATTRIBUTE_TYPE: + case ZCL_INT56S_ATTRIBUTE_TYPE: + case ZCL_INT48S_ATTRIBUTE_TYPE: + case ZCL_INT40S_ATTRIBUTE_TYPE: { + using Traits = chip::app::NumericAttributeTraits; + Traits::StorageType attribute_value; + memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); + if (is_nullable) { + if (Traits::IsNullValue(attribute_value)) { + val = esp_matter_nullable_int64(nullable()); + } else { + val = esp_matter_nullable_int64(attribute_value); + } + } else { + val = esp_matter_int64(attribute_value); + } + break; + } + + case ZCL_INT64U_ATTRIBUTE_TYPE: + case ZCL_FABRIC_ID_ATTRIBUTE_TYPE: + case ZCL_NODE_ID_ATTRIBUTE_TYPE: + case ZCL_POSIX_MS_ATTRIBUTE_TYPE: + case ZCL_EPOCH_US_ATTRIBUTE_TYPE: + case ZCL_SYSTIME_US_ATTRIBUTE_TYPE: + case ZCL_SYSTIME_MS_ATTRIBUTE_TYPE: + case ZCL_EVENT_NO_ATTRIBUTE_TYPE: + case ZCL_INT56U_ATTRIBUTE_TYPE: + case ZCL_INT48U_ATTRIBUTE_TYPE: + case ZCL_INT40U_ATTRIBUTE_TYPE: { + using Traits = chip::app::NumericAttributeTraits; + Traits::StorageType attribute_value; + memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); + if (is_nullable) { + if (Traits::IsNullValue(attribute_value)) { + val = esp_matter_nullable_uint64(nullable()); + } else { + val = esp_matter_nullable_uint64(attribute_value); + } + } else { + val = esp_matter_uint64(attribute_value); + } + break; + } + + case ZCL_ENUM8_ATTRIBUTE_TYPE: + case ZCL_STATUS_ATTRIBUTE_TYPE: + case ZCL_PRIORITY_ATTRIBUTE_TYPE: { + using Traits = chip::app::NumericAttributeTraits; + Traits::StorageType attribute_value; + memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); + if (is_nullable) { + if (Traits::IsNullValue(attribute_value)) { + val = esp_matter_nullable_enum8(nullable()); + } else { + val = esp_matter_nullable_enum8(attribute_value); + } + } else { + val = esp_matter_enum8(attribute_value); + } + break; + } + + case ZCL_ENUM16_ATTRIBUTE_TYPE: { + using Traits = chip::app::NumericAttributeTraits; + Traits::StorageType attribute_value; + memcpy((uint16_t *)&attribute_value, value, sizeof(Traits::StorageType)); + if (is_nullable) { + if (Traits::IsNullValue(attribute_value)) { + val = esp_matter_nullable_enum16(nullable()); + } else { + val = esp_matter_nullable_enum16(attribute_value); + } + } else { + val = esp_matter_enum16(attribute_value); + } + break; + } + + case ZCL_BITMAP8_ATTRIBUTE_TYPE: { + using Traits = chip::app::NumericAttributeTraits; + Traits::StorageType attribute_value; + memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); + if (is_nullable) { + if (Traits::IsNullValue(attribute_value)) { + val = esp_matter_nullable_bitmap8(nullable()); + } else { + val = esp_matter_nullable_bitmap8(attribute_value); + } + } else { + val = esp_matter_bitmap8(attribute_value); + } + break; + } + + case ZCL_BITMAP16_ATTRIBUTE_TYPE: { + using Traits = chip::app::NumericAttributeTraits; + Traits::StorageType attribute_value; + memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); + if (is_nullable) { + if (Traits::IsNullValue(attribute_value)) { + val = esp_matter_nullable_bitmap16(nullable()); + } else { + val = esp_matter_nullable_bitmap16(attribute_value); + } + } else { + val = esp_matter_bitmap16(attribute_value); + } + break; + } + + case ZCL_BITMAP32_ATTRIBUTE_TYPE: { + using Traits = chip::app::NumericAttributeTraits; + Traits::StorageType attribute_value; + memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); + if (is_nullable) { + if (Traits::IsNullValue(attribute_value)) { + val = esp_matter_nullable_bitmap32(nullable()); + } else { + val = esp_matter_nullable_bitmap32(attribute_value); + } + } else { + val = esp_matter_bitmap32(attribute_value); + } + break; + } + + case ZCL_SINGLE_ATTRIBUTE_TYPE: { + using Traits = chip::app::NumericAttributeTraits; + Traits::StorageType attribute_value; + memcpy((float *)&attribute_value, value, sizeof(Traits::StorageType)); + if (is_nullable) { + if (Traits::IsNullValue(attribute_value)) { + val = esp_matter_nullable_float(nullable()); + } else { + val = esp_matter_nullable_float(attribute_value); + } + } else { + val = esp_matter_float(attribute_value); + } + break; + } + + default: + val = esp_matter_invalid(NULL); + break; + } + if (val.type == ESP_MATTER_VAL_TYPE_INVALID) { + return Status::InvalidDataType; + } + return Status::Success; +} + +EmberAfAttributeType get_ember_attr_type_from_val_type(esp_matter_val_type_t val_type) +{ + switch (val_type) { + case ESP_MATTER_VAL_TYPE_BOOLEAN: + case ESP_MATTER_VAL_TYPE_NULLABLE_BOOLEAN: + return ZCL_BOOLEAN_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_FLOAT: + case ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT: + return ZCL_SINGLE_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_OCTET_STRING: + return ZCL_OCTET_STRING_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_CHAR_STRING: + return ZCL_CHAR_STRING_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING: + return ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING: + return ZCL_LONG_CHAR_STRING_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_INT8: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT8: + return ZCL_INT8S_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_BITMAP8: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8: + return ZCL_BITMAP8_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_ENUM8: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8: + return ZCL_ENUM8_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_UINT8: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT8: + return ZCL_INT8U_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_INT16: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT16: + return ZCL_INT16S_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_BITMAP16: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16: + return ZCL_BITMAP16_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_ENUM16: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16: + return ZCL_ENUM16_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_UINT16: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT16: + return ZCL_INT16U_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_INT32: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT32: + return ZCL_INT32S_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_BITMAP32: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32: + return ZCL_BITMAP32_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_UINT32: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT32: + return ZCL_INT32U_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_INT64: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT64: + return ZCL_INT64S_ATTRIBUTE_TYPE; + case ESP_MATTER_VAL_TYPE_UINT64: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT64: + return ZCL_INT64U_ATTRIBUTE_TYPE; + default: + break; + } + return ZCL_NO_DATA_ATTRIBUTE_TYPE; +} + +uint16_t get_ember_attr_size_from_val(const esp_matter_attr_val_t &val) +{ + switch (val.type) { + case ESP_MATTER_VAL_TYPE_BOOLEAN: + case ESP_MATTER_VAL_TYPE_NULLABLE_BOOLEAN: + case ESP_MATTER_VAL_TYPE_INT8: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT8: + case ESP_MATTER_VAL_TYPE_BITMAP8: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8: + case ESP_MATTER_VAL_TYPE_ENUM8: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8: + case ESP_MATTER_VAL_TYPE_UINT8: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT8: + return 1; + case ESP_MATTER_VAL_TYPE_INT16: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT16: + case ESP_MATTER_VAL_TYPE_BITMAP16: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16: + case ESP_MATTER_VAL_TYPE_ENUM16: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16: + case ESP_MATTER_VAL_TYPE_UINT16: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT16: + return 2; + case ESP_MATTER_VAL_TYPE_INT32: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT32: + case ESP_MATTER_VAL_TYPE_BITMAP32: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32: + case ESP_MATTER_VAL_TYPE_UINT32: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT32: + return 4; + case ESP_MATTER_VAL_TYPE_INT64: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT64: + case ESP_MATTER_VAL_TYPE_UINT64: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT64: + return 8; + + case ESP_MATTER_VAL_TYPE_FLOAT: + case ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT: + return sizeof(float); + case ESP_MATTER_VAL_TYPE_OCTET_STRING: + case ESP_MATTER_VAL_TYPE_CHAR_STRING: + return (val.val.a.s == UINT8_MAX ? 0 : val.val.a.s) + 1; + case ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING: + case ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING: + return (val.val.a.s == UINT16_MAX ? 0 : val.val.a.s) + 1; + default: + break; + } + return 0; +} + +EmberAfDefaultAttributeValue get_default_attr_value_from_val(esp_matter_attr_val_t *val) +{ + switch (val->type) { + case ESP_MATTER_VAL_TYPE_BOOLEAN: + case ESP_MATTER_VAL_TYPE_NULLABLE_BOOLEAN: + return EmberAfDefaultAttributeValue((uint16_t)val->val.b); + case ESP_MATTER_VAL_TYPE_FLOAT: + case ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT: + return EmberAfDefaultAttributeValue((uint8_t *)&val->val.f); + case ESP_MATTER_VAL_TYPE_INT8: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT8: + return EmberAfDefaultAttributeValue((uint16_t)val->val.i8); + case ESP_MATTER_VAL_TYPE_BITMAP8: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8: + case ESP_MATTER_VAL_TYPE_ENUM8: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8: + case ESP_MATTER_VAL_TYPE_UINT8: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT8: + return EmberAfDefaultAttributeValue((uint16_t)val->val.u8); + case ESP_MATTER_VAL_TYPE_INT16: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT16: + return EmberAfDefaultAttributeValue((uint16_t)val->val.i16); + case ESP_MATTER_VAL_TYPE_BITMAP16: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16: + case ESP_MATTER_VAL_TYPE_ENUM16: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16: + case ESP_MATTER_VAL_TYPE_UINT16: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT16: + return EmberAfDefaultAttributeValue((uint16_t)val->val.u16); + case ESP_MATTER_VAL_TYPE_INT32: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT32: + return EmberAfDefaultAttributeValue((uint8_t *)&val->val.i32); + case ESP_MATTER_VAL_TYPE_BITMAP32: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32: + case ESP_MATTER_VAL_TYPE_UINT32: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT32: + return EmberAfDefaultAttributeValue((uint8_t *)&val->val.u32); + case ESP_MATTER_VAL_TYPE_INT64: + case ESP_MATTER_VAL_TYPE_NULLABLE_INT64: + return EmberAfDefaultAttributeValue((uint8_t *)&val->val.i64); + case ESP_MATTER_VAL_TYPE_UINT64: + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT64: + return EmberAfDefaultAttributeValue((uint8_t *)&val->val.u64); + default: + break; + } + return EmberAfDefaultAttributeValue(nullptr); +} + +class GlobalInteractionModelEngineChangedpathListener : public chip::app::AttributesChangedListener { +public: + ~GlobalInteractionModelEngineChangedpathListener() = default; + + void MarkDirty(const chip::app::AttributePathParams &path) override + { + chip::app::InteractionModelEngine::GetInstance()->GetReportingEngine().SetDirty(path); + } +}; + +static GlobalInteractionModelEngineChangedpathListener gListener; +} // namespace + +namespace chip { +namespace app { +EnabledEndpointsWithServerCluster::EnabledEndpointsWithServerCluster(ClusterId clusterId) + : mEndpointCount(esp_matter::endpoint::get_count(esp_matter::node::get())) + , mClusterId(clusterId) +{ + EnsureMatchingEndpoint(); +} + +EndpointId EnabledEndpointsWithServerCluster::operator*() const +{ + return emberAfEndpointFromIndex(mEndpointIndex); +} + +EnabledEndpointsWithServerCluster &EnabledEndpointsWithServerCluster::operator++() +{ + ++mEndpointIndex; + EnsureMatchingEndpoint(); + return *this; +} + +void EnabledEndpointsWithServerCluster::EnsureMatchingEndpoint() +{ + for (; mEndpointIndex < mEndpointCount; ++mEndpointIndex) { + esp_matter::endpoint_t *ep = get_endpoint_at_index(mEndpointIndex); + if (!esp_matter::endpoint::is_enabled(ep)) { + continue; + } + if (esp_matter::cluster::get(ep, mClusterId)) { + break; + } + } +} + +namespace Compatibility { +namespace Internal { + +EmberAfAttributeType AttributeBaseType(EmberAfAttributeType type) +{ + switch (type) { + case ZCL_ACTION_ID_ATTRIBUTE_TYPE: // Action Id + case ZCL_FABRIC_IDX_ATTRIBUTE_TYPE: // Fabric Index + case ZCL_BITMAP8_ATTRIBUTE_TYPE: // 8-bit bitmap + case ZCL_ENUM8_ATTRIBUTE_TYPE: // 8-bit enumeration + case ZCL_STATUS_ATTRIBUTE_TYPE: // Status Code + case ZCL_PERCENT_ATTRIBUTE_TYPE: // Percentage + static_assert(std::is_same::value, + "chip::Percent is expected to be uint8_t, change this when necessary"); + return ZCL_INT8U_ATTRIBUTE_TYPE; + + case ZCL_ENDPOINT_NO_ATTRIBUTE_TYPE: // Endpoint Number + case ZCL_GROUP_ID_ATTRIBUTE_TYPE: // Group Id + case ZCL_VENDOR_ID_ATTRIBUTE_TYPE: // Vendor Id + case ZCL_ENUM16_ATTRIBUTE_TYPE: // 16-bit enumeration + case ZCL_BITMAP16_ATTRIBUTE_TYPE: // 16-bit bitmap + case ZCL_PERCENT100THS_ATTRIBUTE_TYPE: // 100ths of a percent + static_assert(std::is_same::value, + "chip::EndpointId is expected to be uint16_t, change this when necessary"); + static_assert(std::is_same::value, + "chip::GroupId is expected to be uint16_t, change this when necessary"); + static_assert(std::is_same::value, + "chip::Percent100ths is expected to be uint16_t, change this when necessary"); + return ZCL_INT16U_ATTRIBUTE_TYPE; + + case ZCL_CLUSTER_ID_ATTRIBUTE_TYPE: // Cluster Id + case ZCL_ATTRIB_ID_ATTRIBUTE_TYPE: // Attribute Id + case ZCL_FIELD_ID_ATTRIBUTE_TYPE: // Field Id + case ZCL_EVENT_ID_ATTRIBUTE_TYPE: // Event Id + case ZCL_COMMAND_ID_ATTRIBUTE_TYPE: // Command Id + case ZCL_TRANS_ID_ATTRIBUTE_TYPE: // Transaction Id + case ZCL_DEVTYPE_ID_ATTRIBUTE_TYPE: // Device Type Id + case ZCL_DATA_VER_ATTRIBUTE_TYPE: // Data Version + case ZCL_BITMAP32_ATTRIBUTE_TYPE: // 32-bit bitmap + case ZCL_EPOCH_S_ATTRIBUTE_TYPE: // Epoch Seconds + case ZCL_ELAPSED_S_ATTRIBUTE_TYPE: // Elapsed Seconds + static_assert(std::is_same::value, + "chip::Cluster is expected to be uint32_t, change this when necessary"); + static_assert(std::is_same::value, + "chip::AttributeId is expected to be uint32_t, change this when necessary"); + static_assert(std::is_same::value, + "chip::AttributeId is expected to be uint32_t, change this when necessary"); + static_assert(std::is_same::value, + "chip::EventId is expected to be uint32_t, change this when necessary"); + static_assert(std::is_same::value, + "chip::CommandId is expected to be uint32_t, change this when necessary"); + static_assert(std::is_same::value, + "chip::TransactionId is expected to be uint32_t, change this when necessary"); + static_assert(std::is_same::value, + "chip::DeviceTypeId is expected to be uint32_t, change this when necessary"); + static_assert(std::is_same::value, + "chip::DataVersion is expected to be uint32_t, change this when necessary"); + return ZCL_INT32U_ATTRIBUTE_TYPE; + + case ZCL_AMPERAGE_MA_ATTRIBUTE_TYPE: // Amperage + case ZCL_ENERGY_MWH_ATTRIBUTE_TYPE: // Energy + case ZCL_ENERGY_MVAH_ATTRIBUTE_TYPE: // Apparent Energy + case ZCL_ENERGY_MVARH_ATTRIBUTE_TYPE: // Reactive Energy + case ZCL_POWER_MW_ATTRIBUTE_TYPE: // Power + case ZCL_POWER_MVA_ATTRIBUTE_TYPE: // Apparent Power + case ZCL_POWER_MVAR_ATTRIBUTE_TYPE: // Reactive Power + case ZCL_VOLTAGE_MV_ATTRIBUTE_TYPE: // Voltage + case ZCL_MONEY_ATTRIBUTE_TYPE: // Money + return ZCL_INT64S_ATTRIBUTE_TYPE; + + case ZCL_EVENT_NO_ATTRIBUTE_TYPE: // Event Number + case ZCL_FABRIC_ID_ATTRIBUTE_TYPE: // Fabric Id + case ZCL_NODE_ID_ATTRIBUTE_TYPE: // Node Id + case ZCL_BITMAP64_ATTRIBUTE_TYPE: // 64-bit bitmap + case ZCL_EPOCH_US_ATTRIBUTE_TYPE: // Epoch Microseconds + case ZCL_POSIX_MS_ATTRIBUTE_TYPE: // POSIX Milliseconds + case ZCL_SYSTIME_MS_ATTRIBUTE_TYPE: // System time Milliseconds + case ZCL_SYSTIME_US_ATTRIBUTE_TYPE: // System time Microseconds + static_assert(std::is_same::value, + "chip::EventNumber is expected to be uint64_t, change this when necessary"); + static_assert(std::is_same::value, + "chip::FabricId is expected to be uint64_t, change this when necessary"); + static_assert(std::is_same::value, + "chip::NodeId is expected to be uint64_t, change this when necessary"); + return ZCL_INT64U_ATTRIBUTE_TYPE; + + case ZCL_TEMPERATURE_ATTRIBUTE_TYPE: // Temperature + return ZCL_INT16S_ATTRIBUTE_TYPE; + + default: + return type; + } +} + +} // namespace Internal +} // namespace Compatibility +} // namespace app +} // namespace chip + +// TODO: Remove the BindingTable definition when binding cluster is decoupled from ember. +namespace chip { + +BindingTable BindingTable::sInstance; + +BindingTable::BindingTable() +{ + memset(mNextIndex, kNextNullIndex, sizeof(mNextIndex)); +} + +CHIP_ERROR BindingTable::Add(const EmberBindingTableEntry &entry) +{ + if (entry.type == MATTER_UNUSED_BINDING) { + return CHIP_ERROR_INVALID_ARGUMENT; + } + uint8_t newIndex = MATTER_BINDING_TABLE_SIZE; + for (uint8_t i = 0; i < MATTER_BINDING_TABLE_SIZE; i++) { + if (mBindingTable[i].type == MATTER_UNUSED_BINDING) { + newIndex = i; + } + } + if (newIndex >= MATTER_BINDING_TABLE_SIZE) { + return CHIP_ERROR_NO_MEMORY; + } + mBindingTable[newIndex] = entry; + CHIP_ERROR error = SaveEntryToStorage(newIndex, kNextNullIndex); + if (error == CHIP_NO_ERROR) { + if (mTail == kNextNullIndex) { + error = SaveListInfo(newIndex); + } else { + error = SaveEntryToStorage(mTail, newIndex); + } + if (error != CHIP_NO_ERROR) { + mStorage->SyncDeleteKeyValue(DefaultStorageKeyAllocator::BindingTableEntry(newIndex).KeyName()); + } + } + if (error != CHIP_NO_ERROR) { + // Roll back + mBindingTable[newIndex].type = MATTER_UNUSED_BINDING; + return error; + } + + if (mTail == kNextNullIndex) { + mTail = newIndex; + mHead = newIndex; + } else { + mNextIndex[mTail] = newIndex; + mNextIndex[newIndex] = kNextNullIndex; + mTail = newIndex; + } + + mSize++; + return CHIP_NO_ERROR; +} + +const EmberBindingTableEntry &BindingTable::GetAt(uint8_t index) +{ + return mBindingTable[index]; +} + +CHIP_ERROR BindingTable::SaveEntryToStorage(uint8_t index, uint8_t nextIndex) +{ + EmberBindingTableEntry &entry = mBindingTable[index]; + uint8_t buffer[kEntryStorageSize] = {0}; + TLV::TLVWriter writer; + writer.Init(buffer); + TLV::TLVType container; + ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::TLVType::kTLVType_Structure, container)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagFabricIndex), entry.fabricIndex)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagLocalEndpoint), entry.local)); + if (entry.clusterId.has_value()) { + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagCluster), *entry.clusterId)); + } + if (entry.type == MATTER_UNICAST_BINDING) { + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagRemoteEndpoint), entry.remote)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagNodeId), entry.nodeId)); + } else { + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagGroupId), entry.groupId)); + } + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagNextEntry), nextIndex)); + ReturnErrorOnFailure(writer.EndContainer(container)); + ReturnErrorOnFailure(writer.Finalize()); + return mStorage->SyncSetKeyValue(DefaultStorageKeyAllocator::BindingTableEntry(index).KeyName(), buffer, + static_cast(writer.GetLengthWritten())); +} + +CHIP_ERROR BindingTable::SaveListInfo(uint8_t head) +{ + uint8_t buffer[kListInfoStorageSize] = {0}; + TLV::TLVWriter writer; + writer.Init(buffer); + TLV::TLVType container; + ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::TLVType::kTLVType_Structure, container)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagStorageVersion), kStorageVersion)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagHead), head)); + ReturnErrorOnFailure(writer.EndContainer(container)); + ReturnErrorOnFailure(writer.Finalize()); + return mStorage->SyncSetKeyValue(DefaultStorageKeyAllocator::BindingTable().KeyName(), buffer, + static_cast(writer.GetLengthWritten())); +} + +CHIP_ERROR BindingTable::LoadFromStorage() +{ + VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE); + uint8_t buffer[kListInfoStorageSize] = {0}; + uint16_t size = sizeof(buffer); + CHIP_ERROR error; + + ReturnErrorOnFailure(mStorage->SyncGetKeyValue(DefaultStorageKeyAllocator::BindingTable().KeyName(), buffer, size)); + TLV::TLVReader reader; + reader.Init(buffer, size); + + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag())); + + TLV::TLVType container; + ReturnErrorOnFailure(reader.EnterContainer(container)); + + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagStorageVersion))); + uint32_t version; + ReturnErrorOnFailure(reader.Get(version)); + VerifyOrReturnError(version == kStorageVersion, CHIP_ERROR_VERSION_MISMATCH); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagHead))); + uint8_t index; + ReturnErrorOnFailure(reader.Get(index)); + mHead = index; + while (index != kNextNullIndex) { + uint8_t nextIndex; + error = LoadEntryFromStorage(index, nextIndex); + if (error != CHIP_NO_ERROR) { + mHead = kNextNullIndex; + mTail = kNextNullIndex; + return error; + } + mTail = index; + index = nextIndex; + mSize++; + } + error = reader.ExitContainer(container); + if (error != CHIP_NO_ERROR) { + mHead = kNextNullIndex; + mTail = kNextNullIndex; + } + return error; +} + +CHIP_ERROR BindingTable::LoadEntryFromStorage(uint8_t index, uint8_t &nextIndex) +{ + uint8_t buffer[kEntryStorageSize] = {0}; + uint16_t size = sizeof(buffer); + EmberBindingTableEntry entry; + + ReturnErrorOnFailure( + mStorage->SyncGetKeyValue(DefaultStorageKeyAllocator::BindingTableEntry(index).KeyName(), buffer, size)); + TLV::TLVReader reader; + reader.Init(buffer, size); + + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag())); + + TLV::TLVType container; + ReturnErrorOnFailure(reader.EnterContainer(container)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagFabricIndex))); + ReturnErrorOnFailure(reader.Get(entry.fabricIndex)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagLocalEndpoint))); + ReturnErrorOnFailure(reader.Get(entry.local)); + ReturnErrorOnFailure(reader.Next()); + if (reader.GetTag() == TLV::ContextTag(kTagCluster)) { + ClusterId clusterId; + ReturnErrorOnFailure(reader.Get(clusterId)); + entry.clusterId.emplace(clusterId); + ReturnErrorOnFailure(reader.Next()); + } else { + entry.clusterId = std::nullopt; + } + if (reader.GetTag() == TLV::ContextTag(kTagRemoteEndpoint)) { + entry.type = MATTER_UNICAST_BINDING; + ReturnErrorOnFailure(reader.Get(entry.remote)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagNodeId))); + ReturnErrorOnFailure(reader.Get(entry.nodeId)); + } else { + entry.type = MATTER_MULTICAST_BINDING; + VerifyOrReturnError(reader.GetTag() == TLV::ContextTag(kTagGroupId), CHIP_ERROR_INVALID_TLV_TAG); + ReturnErrorOnFailure(reader.Get(entry.groupId)); + } + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagNextEntry))); + ReturnErrorOnFailure(reader.Get(nextIndex)); + ReturnErrorOnFailure(reader.ExitContainer(container)); + mBindingTable[index] = entry; + mNextIndex[index] = nextIndex; + return CHIP_NO_ERROR; +} + +CHIP_ERROR BindingTable::RemoveAt(Iterator &iter) +{ + CHIP_ERROR error; + if (iter.mTable != this || iter.mIndex == kNextNullIndex) { + return CHIP_ERROR_INVALID_ARGUMENT; + } + if (iter.mIndex == mTail) { + mTail = iter.mPrevIndex; + } + uint8_t next = mNextIndex[iter.mIndex]; + if (iter.mIndex != mHead) { + error = SaveEntryToStorage(iter.mPrevIndex, next); + if (error == CHIP_NO_ERROR) { + mNextIndex[iter.mPrevIndex] = next; + } + } else { + error = SaveListInfo(next); + if (error == CHIP_NO_ERROR) { + mHead = next; + } + } + if (error == CHIP_NO_ERROR) { + // The remove is considered "submitted" once the change on prev node takes effect + if (mStorage->SyncDeleteKeyValue(DefaultStorageKeyAllocator::BindingTableEntry(iter.mIndex).KeyName()) != + CHIP_NO_ERROR) { + ChipLogError(AppServer, "Failed to remove binding table entry %u from storage", iter.mIndex); + } + mBindingTable[iter.mIndex].type = MATTER_UNUSED_BINDING; + mNextIndex[iter.mIndex] = kNextNullIndex; + mSize--; + } + iter.mIndex = next; + return error; +} + +BindingTable::Iterator BindingTable::begin() +{ + Iterator iter; + iter.mTable = this; + iter.mPrevIndex = kNextNullIndex; + iter.mIndex = mHead; + return iter; +} + +BindingTable::Iterator BindingTable::end() +{ + Iterator iter; + iter.mTable = this; + iter.mIndex = kNextNullIndex; + return iter; +} + +BindingTable::Iterator BindingTable::Iterator::operator++() +{ + if (mIndex != kNextNullIndex) { + mPrevIndex = mIndex; + mIndex = mTable->mNextIndex[mIndex]; + } + return *this; +} + +} // namespace chip + +// Override Ember functions + +// TODO: Remove the emberAfEndpointIndexIsEnabled and emberAfEndpointCount functions when FabricTableImpl is decoupled +// from ember +chip::EndpointId emberAfEndpointFromIndex(uint16_t index) +{ + esp_matter::endpoint_t *ep = get_endpoint_at_index(index); + if (ep) { + return esp_matter::endpoint::get_id(ep); + } + return chip::kInvalidEndpointId; +} + +bool emberAfEndpointIndexIsEnabled(uint16_t index) +{ + esp_matter::endpoint_t *ep = get_endpoint_at_index(index); + if (ep) { + return esp_matter::endpoint::is_enabled(ep); + } + return false; +} + +uint16_t emberAfEndpointCount() +{ + return esp_matter::endpoint::get_count(esp_matter::node::get()); +} + +// TODO: Remove the emberAfGetClusterCountForEndpoint when scenes cluster is decoupled from ember +uint8_t emberAfGetClusterCountForEndpoint(chip::EndpointId endpoint) +{ + esp_matter::endpoint_t *ep = esp_matter::endpoint::get(endpoint); + if (ep) { + esp_matter::cluster_t *cluster = esp_matter::cluster::get_first(ep); + if (cluster) { + uint8_t count = 0; + while (cluster) { + count++; + cluster = esp_matter::cluster::get_next(cluster); + } + return count; + } + } + return 0; +} + +// TODO: Remove the emberAfGetClustersFromEndpoint function when scenes cluster is decoupled from ember +uint8_t emberAfGetClustersFromEndpoint(chip::EndpointId endpoint, chip::ClusterId *clusterList, uint8_t listLen, + bool server) +{ + esp_matter::endpoint_t *ep = esp_matter::endpoint::get(endpoint); + if (ep) { + esp_matter::cluster_t *cluster = esp_matter::cluster::get_first(ep); + if (cluster) { + uint8_t count = 0; + while (cluster) { + if ((server && (esp_matter::cluster::get_flags(cluster) & esp_matter::CLUSTER_FLAG_SERVER)) || + (!server && (esp_matter::cluster::get_flags(cluster) & esp_matter::CLUSTER_FLAG_CLIENT))) { + clusterList[count++] = esp_matter::cluster::get_id(cluster); + if (count >= listLen) { + break; + } + } + cluster = esp_matter::cluster::get_next(cluster); + } + return count; + } + } + return 0; +} + +// TODO: Remove the emberAfGetClusterServerEndpointIndex function when laundry-dryer-controls, keypad-input, +// door-lock, level-control, target-navigator, fan-control, occupancy-sensor, valve-configuration-and-control, +// media-playback, content-launch, audio-output, power-source, application-basic, low-power, diagnostic-logs, +// scenes, color-control, channel, laundry-washer-controls, wake-on-lan, window-covering, content-control, +// dishwasher-alarm, on-off, media-input, application-launcher, account-login, thermostat, electrical-energy-measurement, +// content-app-observer, and boolean-state-configuration clusters are decoupled from ember. +uint16_t emberAfGetClusterServerEndpointIndex(chip::EndpointId endpoint, chip::ClusterId clusterId, + uint16_t fixedClusterServerEndpointCount) +{ + esp_matter::endpoint_t *ep = esp_matter::endpoint::get(endpoint); + if (ep) { + esp_matter::cluster_t *cluster = esp_matter::cluster::get(ep, clusterId); + if (!cluster) { + return 0xFFFF; + } + ep = esp_matter::endpoint::get_first(esp_matter::node::get()); + uint16_t ret = 0; + while (ep && esp_matter::endpoint::get_id(ep) != endpoint) { + if (esp_matter::cluster::get(ep, clusterId)) { + ret++; + } + ep = esp_matter::endpoint::get_next(ep); + } + return ret; + } + return 0xFFFF; +} + +// TODO: Remove the emberAfIsKnownVolatileAttribute function when level-control, mode-select, mode-base, and on-off +// clusters are decoupled from ember. +bool emberAfIsKnownVolatileAttribute(chip::EndpointId endpoint, chip::ClusterId clusterId, + chip::AttributeId attributeId) +{ + esp_matter::attribute_t *attr = esp_matter::attribute::get(endpoint, clusterId, attributeId); + if (!attr) { + return false; + } + return !(esp_matter::attribute::get_flags(attr) & esp_matter::ATTRIBUTE_FLAG_NONVOLATILE); +} + +// TODO: Remove the emberAfContainsServer function when soil-measurement, on-off, mode-base, resource-monitoring, +// mode-select, color-control, microwave-oven-control, concentration-measurement, air-quality, operational-state, +// thread-network-diagnostics, general-diagnostics, level-control, and service-area clusters are decoupled from ember. +bool emberAfContainsServer(chip::EndpointId endpoint, chip::ClusterId clusterId) +{ + esp_matter::cluster_t *cluster = esp_matter::cluster::get(endpoint, clusterId); + if (cluster && (esp_matter::cluster::get_flags(cluster) & esp_matter::CLUSTER_FLAG_SERVER)) { + return true; + } + return false; +} + +// TODO: Remove the emberAfContainsAttribute function when level-control, mode-select, resource-monitoring, mode-base, +// on-off, and pump-configuration-and-control clusters are decoupled from ember +bool emberAfContainsAttribute(chip::EndpointId endpoint, chip::ClusterId clusterId, chip::AttributeId attributeId) +{ + return esp_matter::attribute::get(endpoint, clusterId, attributeId); +} + +// TODO: Remove the emberAfContainsClient function when binding cluster is decoupled from ember +bool emberAfContainsClient(chip::EndpointId endpoint, chip::ClusterId clusterId) +{ + esp_matter::cluster_t *cluster = esp_matter::cluster::get(endpoint, clusterId); + if (cluster && (esp_matter::cluster::get_flags(cluster) & esp_matter::CLUSTER_FLAG_SERVER)) { + return true; + } + return false; +} + +// TODO: Remove the GetSemanticTagForEndpointAtIndex function when descriptor cluster is decoupled from ember +CHIP_ERROR GetSemanticTagForEndpointAtIndex(chip::EndpointId endpoint, size_t index, + chip::app::Clusters::Descriptor::Structs::SemanticTagStruct::Type &tag) +{ + esp_matter::endpoint_t *ep = esp_matter::endpoint::get(endpoint); + if (!ep || (esp_matter::endpoint::get_semantic_tag_at_index(ep, index, tag) != ESP_OK)) { + return CHIP_ERROR_NOT_FOUND; + } + return CHIP_NO_ERROR; +} + +// TODO: Remove the emberAfRead/Write functions when all the clusters are decoupled from ember. +chip::Protocols::InteractionModel::Status emberAfReadAttribute(chip::EndpointId endpointId, chip::ClusterId clusterId, + chip::AttributeId attributeId, uint8_t *dataPtr, + uint16_t readLength) +{ + esp_matter::endpoint_t *endpoint = esp_matter::endpoint::get(endpointId); + if (!endpoint) { + return chip::Protocols::InteractionModel::Status::UnsupportedEndpoint; + } + esp_matter::cluster_t *cluster = esp_matter::cluster::get(endpoint, clusterId); + if (!cluster) { + return chip::Protocols::InteractionModel::Status::UnsupportedCluster; + } + esp_matter::attribute_t *attribute = esp_matter::attribute::get(cluster, attributeId); + if (!attribute) { + return chip::Protocols::InteractionModel::Status::UnsupportedAttribute; + } + esp_matter_attr_val_t val = esp_matter_invalid(nullptr); + if (esp_matter::attribute::get_val(attribute, &val) != ESP_OK) { + return chip::Protocols::InteractionModel::Status::Failure; + } + return get_raw_data_buffer_from_attr_val(val, dataPtr, readLength); +} + +Status emberAfWriteAttribute(chip::EndpointId endpointId, chip::ClusterId clusterId, chip::AttributeId attributeId, + uint8_t *value, EmberAfAttributeType dataType) +{ + return emberAfWriteAttribute(chip::app::ConcreteAttributePath(endpointId, clusterId, attributeId), + EmberAfWriteDataInput(value, dataType).SetChangeListener(&gListener)); +} + +Status emberAfWriteAttribute(const chip::app::ConcreteAttributePath &path, const EmberAfWriteDataInput &input) +{ + esp_matter::endpoint_t *endpoint = esp_matter::endpoint::get(path.mEndpointId); + if (!endpoint) { + return chip::Protocols::InteractionModel::Status::UnsupportedEndpoint; + } + esp_matter::cluster_t *cluster = esp_matter::cluster::get(endpoint, path.mClusterId); + if (!cluster) { + return chip::Protocols::InteractionModel::Status::UnsupportedCluster; + } + esp_matter::attribute_t *attribute = esp_matter::attribute::get(cluster, path.mAttributeId); + if (!attribute) { + return chip::Protocols::InteractionModel::Status::UnsupportedAttribute; + } + esp_matter_attr_val_t val = esp_matter_invalid(nullptr); + Status status = get_attr_val_from_raw_data_buffer(input.dataPtr, input.dataType, val, + esp_matter::attribute::get_flags(attribute) & + esp_matter::ATTRIBUTE_FLAG_NULLABLE); + if (status != Status::Success) { + return status; + } + esp_err_t err = esp_matter::attribute::set_val(attribute, &val); + if (err != ESP_OK && err != ESP_ERR_NOT_FINISHED) { + status = Status::Failure; + } + if (status == Status::Success) { + if (input.markDirty == chip::app::MarkAttributeDirty::kYes || + ((err == ESP_OK) && (input.markDirty != chip::app::MarkAttributeDirty::kNo))) { + if (input.changeListener) { + input.changeListener->MarkDirty( + chip::app::AttributePathParams(path.mEndpointId, path.mClusterId, path.mAttributeId)); + } else { + gListener.MarkDirty( + chip::app::AttributePathParams(path.mEndpointId, path.mClusterId, path.mAttributeId)); + } + } + } + return status; +} + +// TODO: Remove this function when scenes and thermostat clusters are decoupled from ember APIs +// Since the attribute Metadata should always be accessed in Matter context, we return a pointer of static value. +// But it might be dangerous when the user use this API out of Matter context. +const EmberAfAttributeMetadata *emberAfLocateAttributeMetadata(chip::EndpointId endpointId, chip::ClusterId clusterId, + chip::AttributeId attributeId) +{ + static esp_matter_attr_bounds_t sBounds; + static EmberAfAttributeMinMaxValue sMinMaxValue{EmberAfDefaultAttributeValue(nullptr), + EmberAfDefaultAttributeValue(nullptr), + EmberAfDefaultAttributeValue(nullptr)}; + static EmberAfAttributeMetadata s_metadata{EmberAfDefaultOrMinMaxAttributeValue((uint32_t)0), attributeId, 0, 0, 0}; + + esp_matter::attribute_t *attribute = esp_matter::attribute::get(endpointId, clusterId, attributeId); + if (attribute) { + esp_matter_attr_val_t val = esp_matter_invalid(nullptr); + if (esp_matter::attribute::get_val(attribute, &val) == ESP_OK) { + s_metadata.attributeId = attributeId; + s_metadata.attributeType = get_ember_attr_type_from_val_type(val.type); + s_metadata.mask = esp_matter::attribute::get_flags(attribute) & 0xFF; + s_metadata.size = get_ember_attr_size_from_val(val); + if (s_metadata.HasMinMax() && esp_matter::attribute::get_bounds(attribute, &sBounds) == ESP_OK) { + sMinMaxValue.minValue = get_default_attr_value_from_val(&sBounds.min); + sMinMaxValue.maxValue = get_default_attr_value_from_val(&sBounds.max); + s_metadata.defaultValue.ptrToMinMaxValue = &sMinMaxValue; + } + return &s_metadata; + } + } + return nullptr; +} diff --git a/components/esp_matter/data_model_provider/esp_matter_plugin_server_init_callbacks.cpp b/components/esp_matter/data_model_provider/esp_matter_plugin_server_init_callbacks.cpp new file mode 100644 index 000000000..aaeae8720 --- /dev/null +++ b/components/esp_matter/data_model_provider/esp_matter_plugin_server_init_callbacks.cpp @@ -0,0 +1,73 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +// Cluster init functions that don't have a cluster implementation to define +// them in. +void MatterBallastConfigurationPluginServerInitCallback() {} +void MatterBooleanStatePluginServerInitCallback() {} +void MatterRelativeHumidityMeasurementPluginServerInitCallback() {} +void MatterIlluminanceMeasurementPluginServerInitCallback() {} +void MatterBinaryInputBasicPluginServerInitCallback() {} +void MatterPressureMeasurementPluginServerInitCallback() {} +void MatterTemperatureMeasurementPluginServerInitCallback() {} +void MatterFlowMeasurementPluginServerInitCallback() {} +void MatterThermostatUserInterfaceConfigurationPluginServerInitCallback() {} +void MatterBridgedDeviceBasicInformationPluginServerInitCallback() {} +void MatterPowerConfigurationPluginServerInitCallback() {} +void MatterPowerProfilePluginServerInitCallback() {} +void MatterPulseWidthModulationPluginServerInitCallback() {} +void MatterAlarmsPluginServerInitCallback() {} +void MatterTimePluginServerInitCallback() {} +void MatterAclPluginServerInitCallback() {} +void MatterPollControlPluginServerInitCallback() {} +void MatterProxyValidPluginServerInitCallback() {} +void MatterProxyDiscoveryPluginServerInitCallback() {} +void MatterProxyConfigurationPluginServerInitCallback() {} +void MatterFanControlPluginServerInitCallback() {} +void MatterActivatedCarbonFilterMonitoringPluginServerInitCallback() {} +void MatterHepaFilterMonitoringPluginServerInitCallback() {} +void MatterAirQualityPluginServerInitCallback() {} +void MatterCarbonMonoxideConcentrationMeasurementPluginServerInitCallback() {} +void MatterCarbonDioxideConcentrationMeasurementPluginServerInitCallback() {} +void MatterFormaldehydeConcentrationMeasurementPluginServerInitCallback() {} +void MatterNitrogenDioxideConcentrationMeasurementPluginServerInitCallback() {} +void MatterOzoneConcentrationMeasurementPluginServerInitCallback() {} +void MatterPm10ConcentrationMeasurementPluginServerInitCallback() {} +void MatterPm1ConcentrationMeasurementPluginServerInitCallback() {} +void MatterPm25ConcentrationMeasurementPluginServerInitCallback() {} +void MatterRadonConcentrationMeasurementPluginServerInitCallback() {} +void MatterTotalVolatileOrganicCompoundsConcentrationMeasurementPluginServerInitCallback() {} +void MatterRvcRunModePluginServerInitCallback() {} +void MatterRvcCleanModePluginServerInitCallback() {} +void MatterDishwasherModePluginServerInitCallback() {} +void MatterLaundryWasherModePluginServerInitCallback() {} +void MatterRefrigeratorAndTemperatureControlledCabinetModePluginServerInitCallback() {} +void MatterOperationalStatePluginServerInitCallback() {} +void MatterRvcOperationalStatePluginServerInitCallback() {} +void MatterOvenModePluginServerInitCallback() {} +void MatterOvenCavityOperationalStatePluginServerInitCallback() {} +void MatterDishwasherAlarmPluginServerInitCallback() {} +void MatterMicrowaveOvenModePluginServerInitCallback() {} +void MatterDeviceEnergyManagementModePluginServerInitCallback() {} +void MatterEnergyEvseModePluginServerInitCallback() {} +void MatterPowerTopologyPluginServerInitCallback() {} +void MatterElectricalEnergyMeasurementPluginServerInitCallback() {} +void MatterElectricalPowerMeasurementPluginServerInitCallback() {} +void MatterServiceAreaPluginServerInitCallback() {} +void MatterWaterHeaterManagementPluginServerInitCallback() {} +void MatterWaterHeaterModePluginServerInitCallback() {} +void MatterCommodityPricePluginServerInitCallback() {} +void MatterElectricalGridConditionsPluginServerInitCallback() {} +void MatterSoilMeasurementPluginServerInitCallback() {} diff --git a/components/esp_matter/esp_matter.h b/components/esp_matter/esp_matter.h index 9581274d3..ac69fac11 100644 --- a/components/esp_matter/esp_matter.h +++ b/components/esp_matter/esp_matter.h @@ -22,6 +22,7 @@ application. #ifdef CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER #ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL #include +#include #include #include #include @@ -30,7 +31,6 @@ application. #include #endif // CONFIG_ESP_MATTER_ENABLE_DATA_MODEL #include -#include #include #endif // CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER #include diff --git a/components/esp_matter/esp_matter_attribute_utils.cpp b/components/esp_matter/esp_matter_attribute_utils.cpp deleted file mode 100644 index 49b73ab6c..000000000 --- a/components/esp_matter/esp_matter_attribute_utils.cpp +++ /dev/null @@ -1,2171 +0,0 @@ -// Copyright 2021 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -using chip::AttributeId; -using chip::ClusterId; -using chip::EndpointId; -using chip::Protocols::InteractionModel::Status; - -using namespace esp_matter; - -static const char *TAG = "esp_matter_attribute"; - -esp_matter_attr_val_t esp_matter_invalid(void *val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_INVALID, - .val = { - .p = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_bool(bool val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_BOOLEAN, - .val = { - .b = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_int(int val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_INTEGER, - .val = { - .i = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_nullable_bool(nullable val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_NULLABLE_BOOLEAN, - }; - if (val.is_null()) { - chip::app::NumericAttributeTraits::SetNull(*(uint8_t *)(&(attr_val.val.b))); - } - else { - attr_val.val.b = val.value(); - } - return attr_val; -} - -esp_matter_attr_val_t esp_matter_nullable_int(nullable val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_NULLABLE_INTEGER, - }; - if (val.is_null()) { - chip::app::NumericAttributeTraits::SetNull(attr_val.val.i); - } else { - attr_val.val.i = val.value(); - } - return attr_val; -} - -esp_matter_attr_val_t esp_matter_float(float val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_FLOAT, - .val = { - .f = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_nullable_float(nullable val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT, - }; - if (val.is_null()) { - chip::app::NumericAttributeTraits::SetNull(attr_val.val.f); - } else { - attr_val.val.f = val.value(); - } - return attr_val; -} - -esp_matter_attr_val_t esp_matter_int8(int8_t val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_INT8, - .val = { - .i8 = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_nullable_int8(nullable val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_NULLABLE_INT8, - }; - if (val.is_null()) { - chip::app::NumericAttributeTraits::SetNull(attr_val.val.i8); - } else { - attr_val.val.i8 = val.value(); - } - return attr_val; -} - -esp_matter_attr_val_t esp_matter_uint8(uint8_t val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_UINT8, - .val = { - .u8 = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_nullable_uint8(nullable val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_NULLABLE_UINT8, - }; - if (val.is_null()) { - chip::app::NumericAttributeTraits::SetNull(attr_val.val.u8); - } else { - attr_val.val.u8 = val.value(); - } - return attr_val; -} - -esp_matter_attr_val_t esp_matter_int16(int16_t val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_INT16, - .val = { - .i16 = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_nullable_int16(nullable val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_NULLABLE_INT16, - }; - if (val.is_null()) { - chip::app::NumericAttributeTraits::SetNull(attr_val.val.i16); - } else { - attr_val.val.i16 = val.value(); - } - return attr_val; -} - -esp_matter_attr_val_t esp_matter_uint16(uint16_t val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_UINT16, - .val = { - .u16 = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_nullable_uint16(nullable val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_NULLABLE_UINT16, - }; - if (val.is_null()) { - chip::app::NumericAttributeTraits::SetNull(attr_val.val.u16); - } else { - attr_val.val.u16 = val.value(); - } - return attr_val; -} - -esp_matter_attr_val_t esp_matter_int32(int32_t val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_INT32, - .val = { - .i32 = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_nullable_int32(nullable val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_NULLABLE_INT32, - }; - if (val.is_null()) { - chip::app::NumericAttributeTraits::SetNull(attr_val.val.i32); - } else { - attr_val.val.i32 = val.value(); - } - return attr_val; -} - -esp_matter_attr_val_t esp_matter_uint32(uint32_t val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_UINT32, - .val = { - .u32 = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_nullable_uint32(nullable val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_NULLABLE_UINT32, - }; - if (val.is_null()) { - chip::app::NumericAttributeTraits::SetNull(attr_val.val.u32); - } else { - attr_val.val.u32 = val.value(); - } - return attr_val; -} - -esp_matter_attr_val_t esp_matter_int64(int64_t val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_INT64, - .val = { - .i64 = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_nullable_int64(nullable val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_NULLABLE_INT64, - }; - if (val.is_null()) { - chip::app::NumericAttributeTraits::SetNull(attr_val.val.i64); - } else { - attr_val.val.i64 = val.value(); - } - return attr_val; -} - -esp_matter_attr_val_t esp_matter_uint64(uint64_t val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_UINT64, - .val = { - .u64 = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_nullable_uint64(nullable val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_NULLABLE_UINT64, - }; - if (val.is_null()) { - chip::app::NumericAttributeTraits::SetNull(attr_val.val.u64); - } else { - attr_val.val.u64 = val.value(); - } - return attr_val; -} - -esp_matter_attr_val_t esp_matter_enum8(uint8_t val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_ENUM8, - .val = { - .u8 = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_nullable_enum8(nullable val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8, - }; - if (val.is_null()) { - chip::app::NumericAttributeTraits::SetNull(attr_val.val.u8); - } else { - attr_val.val.u8 = val.value(); - } - return attr_val; -} - -esp_matter_attr_val_t esp_matter_enum16(uint16_t val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_ENUM16, - .val = { - .u16 = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_nullable_enum16(nullable val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16, - }; - if (val.is_null()) { - chip::app::NumericAttributeTraits::SetNull(attr_val.val.u16); - } else { - attr_val.val.u16 = val.value(); - } - return attr_val; -} - -esp_matter_attr_val_t esp_matter_bitmap8(uint8_t val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_BITMAP8, - .val = { - .u8 = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_nullable_bitmap8(nullable val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8, - }; - if (val.is_null()) { - chip::app::NumericAttributeTraits::SetNull(attr_val.val.u8); - } else { - attr_val.val.u8 = val.value(); - } - return attr_val; -} - -esp_matter_attr_val_t esp_matter_bitmap16(uint16_t val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_BITMAP16, - .val = { - .u16 = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_nullable_bitmap16(nullable val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16, - }; - if (val.is_null()) { - chip::app::NumericAttributeTraits::SetNull(attr_val.val.u16); - } else { - attr_val.val.u16 = val.value(); - } - return attr_val; -} - -esp_matter_attr_val_t esp_matter_bitmap32(uint32_t val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_BITMAP32, - .val = { - .u32 = val, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_nullable_bitmap32(nullable val) -{ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32, - }; - if (val.is_null()) { - chip::app::NumericAttributeTraits::SetNull(attr_val.val.u32); - } else { - attr_val.val.u32 = val.value(); - } - return attr_val; -} - -esp_matter_attr_val_t esp_matter_char_str(char *val, uint16_t data_size) -{ - uint16_t data_size_len = 1; /* Number of bytes used to store the length */ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_CHAR_STRING, - .val = { - .a = { - .b = (uint8_t *)val, - .s = data_size, - .n = data_size, - .t = (uint16_t)(data_size + data_size_len), - }, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_long_char_str(char *val, uint16_t data_size) -{ - uint16_t data_size_len = 2; /* Number of bytes used to store the length */ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING, - .val = { - .a = { - .b = (uint8_t *)val, - .s = data_size, - .n = data_size, - .t = (uint16_t)(data_size + data_size_len), - }, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_octet_str(uint8_t *val, uint16_t data_size) -{ - uint16_t data_size_len = 1; /* Number of bytes used to store the length */ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_OCTET_STRING, - .val = { - .a = { - .b = val, - .s = data_size, - .n = data_size, - .t = (uint16_t)(data_size + data_size_len), - }, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_long_octet_str(uint8_t *val, uint16_t data_size) -{ - uint16_t data_size_len = 2; /* Number of bytes used to store the length */ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING, - .val = { - .a = { - .b = val, - .s = data_size, - .n = data_size, - .t = (uint16_t)(data_size + data_size_len), - }, - }, - }; - return attr_val; -} - -esp_matter_attr_val_t esp_matter_array(uint8_t *val, uint16_t data_size, uint16_t count) -{ - uint16_t data_size_len = 2; /* Number of bytes used to store the length */ - esp_matter_attr_val_t attr_val = { - .type = ESP_MATTER_VAL_TYPE_ARRAY, - .val = { - .a = { - .b = val, - .s = data_size, - .n = count, - .t = (uint16_t)(data_size + data_size_len), - }, - }, - }; - return attr_val; -} - -namespace esp_matter { -namespace attribute { - -static esp_matter_val_type_t get_val_type_from_attribute_type(int attribute_type); -static callback_t attribute_callback = NULL; -#if CONFIG_ENABLE_CHIP_SHELL -static esp_matter::console::engine attribute_console; - -static esp_err_t console_set_handler(int argc, char **argv) -{ - VerifyOrReturnError(argc >= 4, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "The arguments for this command is invalid")); - - uint16_t endpoint_id = strtoul((const char *)&argv[0][2], NULL, 16); - uint32_t cluster_id = strtoul((const char *)&argv[1][2], NULL, 16); - uint32_t attribute_id = strtoul((const char *)&argv[2][2], NULL, 16); - - /* Get type from matter_attribute */ - const EmberAfAttributeMetadata *matter_attribute = emberAfLocateAttributeMetadata(endpoint_id, cluster_id, - attribute_id); - VerifyOrReturnError(matter_attribute, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Matter attribute not found")); - - /* Use the type to create the val and then update te attribute */ - esp_matter_val_type_t type = get_val_type_from_attribute_type(matter_attribute->attributeType); - esp_matter_attr_val_t val = esp_matter_invalid(NULL); - if (type == ESP_MATTER_VAL_TYPE_BOOLEAN) { - bool value = atoi(argv[3]); - val = esp_matter_bool(value); - } else if (type == ESP_MATTER_VAL_TYPE_INT8) { - if (matter_attribute->IsNullable()) { - if (strncmp(argv[3], "null", sizeof("null")) == 0) { - val = esp_matter_nullable_int8(nullable()); - } else { - int8_t value = atoi(argv[3]); - val = esp_matter_nullable_int8(value); - } - } else { - int8_t value = atoi(argv[3]); - val = esp_matter_int8(value); - } - } else if (type == ESP_MATTER_VAL_TYPE_UINT8) { - if (matter_attribute->IsNullable()) { - if (strncmp(argv[3], "null", sizeof("null")) == 0) { - val = esp_matter_nullable_uint8(nullable()); - } else { - uint8_t value = atoi(argv[3]); - val = esp_matter_nullable_uint8(value); - } - } else { - uint8_t value = atoi(argv[3]); - val = esp_matter_uint8(value); - } - } else if (type == ESP_MATTER_VAL_TYPE_INT16) { - if (matter_attribute->IsNullable()) { - if (strncmp(argv[3], "null", sizeof("null")) == 0) { - val = esp_matter_nullable_int16(nullable()); - } else { - int16_t value = atoi(argv[3]); - val = esp_matter_nullable_int16(value); - } - } else { - int16_t value = atoi(argv[3]); - val = esp_matter_int16(value); - } - } else if (type == ESP_MATTER_VAL_TYPE_UINT16) { - if (matter_attribute->IsNullable()) { - if (strncmp(argv[3], "null", sizeof("null")) == 0) { - val = esp_matter_nullable_uint16(nullable()); - } else { - uint16_t value = atoi(argv[3]); - val = esp_matter_nullable_uint16(value); - } - } else { - uint16_t value = atoi(argv[3]); - val = esp_matter_uint16(value); - } - } else if (type == ESP_MATTER_VAL_TYPE_INT32) { - if (matter_attribute->IsNullable()) { - if (strncmp(argv[3], "null", sizeof("null")) == 0) { - val = esp_matter_nullable_int32(nullable()); - } else { - int32_t value = atoi(argv[3]); - val = esp_matter_nullable_int32(value); - } - } else { - int32_t value = atoi(argv[3]); - val = esp_matter_int32(value); - } - } else if (type == ESP_MATTER_VAL_TYPE_UINT32) { - if (matter_attribute->IsNullable()) { - if (strncmp(argv[3], "null", sizeof("null")) == 0) { - val = esp_matter_nullable_uint32(nullable()); - } else { - uint32_t value = atoi(argv[3]); - val = esp_matter_nullable_uint32(value); - } - } else { - uint32_t value = atoi(argv[3]); - val = esp_matter_uint32(value); - } - } else if (type == ESP_MATTER_VAL_TYPE_INT64) { - if (matter_attribute->IsNullable()) { - if (strncmp(argv[3], "null", sizeof("null")) == 0) { - val = esp_matter_nullable_int64(nullable()); - } else { - int64_t value = atoi(argv[3]); - val = esp_matter_nullable_int64(value); - } - } else { - int64_t value = atoi(argv[3]); - val = esp_matter_int64(value); - } - } else if (type == ESP_MATTER_VAL_TYPE_UINT64) { - if (matter_attribute->IsNullable()) { - if (strncmp(argv[3], "null", sizeof("null")) == 0) { - val = esp_matter_nullable_uint64(nullable()); - } else { - uint64_t value = atoi(argv[3]); - val = esp_matter_nullable_uint64(value); - } - } else { - uint64_t value = atoi(argv[3]); - val = esp_matter_uint64(value); - } - } else if (type == ESP_MATTER_VAL_TYPE_CHAR_STRING) { - char *value = argv[3]; - val = esp_matter_char_str(value, strlen(value)); - } else if (type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING) { - char *value = argv[3]; - val = esp_matter_long_char_str(value, strlen(value)); - } else if (type == ESP_MATTER_VAL_TYPE_BITMAP8) { - if (matter_attribute->IsNullable()) { - if (strncmp(argv[3], "null", sizeof("null")) == 0) { - val = esp_matter_nullable_bitmap8(nullable()); - } else { - uint8_t value = atoi(argv[3]); - val = esp_matter_nullable_bitmap8(value); - } - } else { - uint8_t value = atoi(argv[3]); - val = esp_matter_bitmap8(value); - } - } else if (type == ESP_MATTER_VAL_TYPE_BITMAP16) { - if (matter_attribute->IsNullable()) { - if (strncmp(argv[3], "null", sizeof("null")) == 0) { - val = esp_matter_nullable_bitmap16(nullable()); - } else { - uint16_t value = atoi(argv[3]); - val = esp_matter_nullable_bitmap16(value); - } - } else { - uint16_t value = atoi(argv[3]); - val = esp_matter_bitmap16(value); - } - } else if (type == ESP_MATTER_VAL_TYPE_BITMAP32) { - if (matter_attribute->IsNullable()) { - if (strncmp(argv[3], "null", sizeof("null")) == 0) { - val = esp_matter_nullable_bitmap32(nullable()); - } else { - uint32_t value = atoi(argv[3]); - val = esp_matter_nullable_bitmap32(value); - } - } else { - uint32_t value = atoi(argv[3]); - val = esp_matter_bitmap32(value); - } - } else if (type == ESP_MATTER_VAL_TYPE_ENUM8) { - if (matter_attribute->IsNullable()) { - if (strncmp(argv[3], "null", sizeof("null")) == 0) { - val = esp_matter_nullable_enum8(nullable()); - } else { - uint8_t value = atoi(argv[3]); - val = esp_matter_nullable_enum8(value); - } - } else { - uint8_t value = atoi(argv[3]); - val = esp_matter_enum8(value); - } - } else if (type == ESP_MATTER_VAL_TYPE_ENUM16) { - if (matter_attribute->IsNullable()) { - if (strncmp(argv[3], "null", sizeof("null")) == 0) { - val = esp_matter_nullable_enum16(nullable()); - } else { - uint16_t value = atoi(argv[3]); - val = esp_matter_nullable_enum16(value); - } - } else { - uint16_t value = atoi(argv[3]); - val = esp_matter_enum16(value); - } - } else if (type == ESP_MATTER_VAL_TYPE_FLOAT) { - if (matter_attribute->IsNullable()) { - if (strncmp(argv[3], "null", sizeof("null")) == 0) { - val = esp_matter_nullable_float(nullable()); - } else { - float value = (float)atof(argv[3]); - val = esp_matter_nullable_float(value); - } - } else { - float value = (float)atof(argv[3]); - val = esp_matter_float(value); - } - } else { - ESP_LOGE(TAG, "Type not handled: %d", type); - return ESP_ERR_INVALID_ARG; - } - return update(endpoint_id, cluster_id, attribute_id, &val); -} - -static esp_err_t console_get_handler(int argc, char **argv) -{ - VerifyOrReturnError(argc >= 3, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "The arguments for this command is invalid")); - uint16_t endpoint_id = strtoul((const char *)&argv[0][2], NULL, 16); - uint32_t cluster_id = strtoul((const char *)&argv[1][2], NULL, 16); - uint32_t attribute_id = strtoul((const char *)&argv[2][2], NULL, 16); - - /* Get type from matter_attribute */ - const EmberAfAttributeMetadata *matter_attribute = emberAfLocateAttributeMetadata(endpoint_id, cluster_id, - attribute_id); - VerifyOrReturnError(matter_attribute, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Matter attribute not found")); - - /* Use the type to read the raw value and then print */ - esp_matter_val_type_t type = get_val_type_from_attribute_type(matter_attribute->attributeType); - esp_matter_attr_val_t val = esp_matter_invalid(NULL); - if (type == ESP_MATTER_VAL_TYPE_BOOLEAN) { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType value; - uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value); - get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value)); - val = esp_matter_bool(Traits::StorageToWorking(value)); - } else if (type == ESP_MATTER_VAL_TYPE_INT8) { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType value; - uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value); - get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value)); - if (matter_attribute->IsNullable()) { - if (Traits::IsNullValue(value)) { - val = esp_matter_nullable_int8(nullable()); - } else { - val = esp_matter_nullable_int8(Traits::StorageToWorking(value)); - } - } else { - val = esp_matter_int8(Traits::StorageToWorking(value)); - } - } else if (type == ESP_MATTER_VAL_TYPE_UINT8) { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType value; - uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value); - get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value)); - if (matter_attribute->IsNullable()) { - if (Traits::IsNullValue(value)) { - val = esp_matter_nullable_uint8(nullable()); - } else { - val = esp_matter_nullable_uint8(Traits::StorageToWorking(value)); - } - } else { - val = esp_matter_uint8(Traits::StorageToWorking(value)); - } - } else if (type == ESP_MATTER_VAL_TYPE_INT16) { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType value; - uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value); - get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value)); - if (matter_attribute->IsNullable()) { - if (Traits::IsNullValue(value)) { - val = esp_matter_nullable_int16(nullable()); - } else { - val = esp_matter_nullable_int16(Traits::StorageToWorking(value)); - } - } else { - val = esp_matter_int16(Traits::StorageToWorking(value)); - } - } else if (type == ESP_MATTER_VAL_TYPE_UINT16) { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType value; - uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value); - get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value)); - if (matter_attribute->IsNullable()) { - if (Traits::IsNullValue(value)) { - val = esp_matter_nullable_uint16(nullable()); - } else { - val = esp_matter_nullable_uint16(Traits::StorageToWorking(value)); - } - } else { - val = esp_matter_uint16(Traits::StorageToWorking(value)); - } - } else if (type == ESP_MATTER_VAL_TYPE_INT32) { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType value; - uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value); - get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value)); - if (matter_attribute->IsNullable()) { - if (Traits::IsNullValue(value)) { - val = esp_matter_nullable_int32(nullable()); - } else { - val = esp_matter_nullable_int32(Traits::StorageToWorking(value)); - } - } else { - val = esp_matter_int32(Traits::StorageToWorking(value)); - } - } else if (type == ESP_MATTER_VAL_TYPE_UINT32) { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType value; - uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value); - get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value)); - if (matter_attribute->IsNullable()) { - if (Traits::IsNullValue(value)) { - val = esp_matter_nullable_uint32(nullable()); - } else { - val = esp_matter_nullable_uint32(Traits::StorageToWorking(value)); - } - } else { - val = esp_matter_uint32(Traits::StorageToWorking(value)); - } - } else if (type == ESP_MATTER_VAL_TYPE_INT64) { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType value; - uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value); - get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value)); - if (matter_attribute->IsNullable()) { - if (Traits::IsNullValue(value)) { - val = esp_matter_nullable_int64(nullable()); - } else { - val = esp_matter_nullable_int64(Traits::StorageToWorking(value)); - } - } else { - val = esp_matter_int64(Traits::StorageToWorking(value)); - } - } else if (type == ESP_MATTER_VAL_TYPE_UINT64) { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType value; - uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value); - get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value)); - if (matter_attribute->IsNullable()) { - if (Traits::IsNullValue(value)) { - val = esp_matter_nullable_uint64(nullable()); - } else { - val = esp_matter_nullable_uint64(Traits::StorageToWorking(value)); - } - } else { - val = esp_matter_uint64(Traits::StorageToWorking(value)); - } - } else if (type == ESP_MATTER_VAL_TYPE_CHAR_STRING) { - /* Get raw value */ - char value[256] = {0}; /* It can go upto 256 since only 1 byte (first) is used for size */ - get_val_raw(endpoint_id, cluster_id, attribute_id, (uint8_t *)&value, sizeof(value)); - /* Get val from raw value */ - val = esp_matter_char_str(NULL, 0); - int data_size_len = val.val.a.t - val.val.a.s; - int data_count = 0; - memcpy(&data_count, &value[0], data_size_len); - val = esp_matter_char_str((char *)(value + data_size_len), data_count); - } else if (type == ESP_MATTER_VAL_TYPE_BITMAP8) { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType value; - uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value); - get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value)); - if (matter_attribute->IsNullable()) { - if (Traits::IsNullValue(value)) { - val = esp_matter_nullable_bitmap8(nullable()); - } else { - val = esp_matter_nullable_bitmap8(Traits::StorageToWorking(value)); - } - } else { - val = esp_matter_bitmap8(Traits::StorageToWorking(value)); - } - } else if (type == ESP_MATTER_VAL_TYPE_BITMAP16) { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType value; - uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value); - get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value)); - if (matter_attribute->IsNullable()) { - if (Traits::IsNullValue(value)) { - val = esp_matter_nullable_bitmap16(nullable()); - } else { - val = esp_matter_nullable_bitmap16(Traits::StorageToWorking(value)); - } - } else { - val = esp_matter_bitmap16(Traits::StorageToWorking(value)); - } - } else if (type == ESP_MATTER_VAL_TYPE_BITMAP32) { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType value; - uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value); - get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value)); - if (matter_attribute->IsNullable()) { - if (Traits::IsNullValue(value)) { - val = esp_matter_nullable_bitmap32(nullable()); - } else { - val = esp_matter_nullable_bitmap32(Traits::StorageToWorking(value)); - } - } else { - val = esp_matter_bitmap32(Traits::StorageToWorking(value)); - } - } else if (type == ESP_MATTER_VAL_TYPE_ENUM8) { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType value; - uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value); - get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value)); - if (matter_attribute->IsNullable()) { - if (Traits::IsNullValue(value)) { - val = esp_matter_nullable_enum8(nullable()); - } else { - val = esp_matter_nullable_enum8(Traits::StorageToWorking(value)); - } - } else { - val = esp_matter_enum8(Traits::StorageToWorking(value)); - } - } else if (type == ESP_MATTER_VAL_TYPE_ENUM16) { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType value; - uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value); - get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value)); - if (matter_attribute->IsNullable()) { - if (Traits::IsNullValue(value)) { - val = esp_matter_nullable_enum16(nullable()); - } else { - val = esp_matter_nullable_enum16(Traits::StorageToWorking(value)); - } - } else { - val = esp_matter_enum16(Traits::StorageToWorking(value)); - } - } else if (type == ESP_MATTER_VAL_TYPE_FLOAT) { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType value; - uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value); - get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value)); - if (matter_attribute->IsNullable()) { - if (Traits::IsNullValue(value)) { - val = esp_matter_nullable_float(nullable()); - } else { - val = esp_matter_nullable_float(Traits::StorageToWorking(value)); - } - } else { - val = esp_matter_float(Traits::StorageToWorking(value)); - } - } else { - ESP_LOGE(TAG, "Type not handled: %d", type); - return ESP_ERR_INVALID_ARG; - } - /* Here, the val_print function gets called on attribute read. */ - val_print(endpoint_id, cluster_id, attribute_id, &val, true); - return ESP_OK; -} - -static esp_err_t console_dispatch(int argc, char **argv) -{ - VerifyOrReturnError(argc > 0, ESP_OK, attribute_console.for_each_command(esp_matter::console::print_description, NULL)); - return attribute_console.exec_command(argc, argv); -} - -static void register_console_commands() -{ - static bool init_done = false; - VerifyOrReturn(!init_done); - static const esp_matter::console::command_t command = { - .name = "attribute", - .description = "This can be used to simulate on-device control. ", - .handler = console_dispatch, - }; - - static const esp_matter::console::command_t attribute_commands[] = { - { - .name = "set", - .description = "Set an attribute value of a cluster on an endpoint. " - "Usage: matter esp attribute set . " - "Example: matter esp attribute set 0x0001 0x0006 0x0000 1.", - .handler = console_set_handler, - }, - { - .name = "get", - .description = "Get an attribute value of a cluster on an endpoint. " - "Usage: matter esp attribute get . " - "Example: matter esp attribute get 0x0001 0x0006 0x0000.", - .handler = console_get_handler, - }, - }; - attribute_console.register_commands(attribute_commands, sizeof(attribute_commands)/sizeof(esp_matter::console::command_t)); - esp_matter::console::add_commands(&command, 1); - init_done = true; -} -#endif // CONFIG_ENABLE_CHIP_SHELL - -esp_err_t set_callback(callback_t callback) -{ - attribute_callback = callback; - - /* Other initialisations */ -#if CONFIG_ENABLE_CHIP_SHELL - register_console_commands(); -#endif - return ESP_OK; -} - -static esp_err_t execute_callback(callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id, - uint32_t attribute_id, esp_matter_attr_val_t *val) -{ - if (attribute_callback) { -#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL - void *priv_data = endpoint::get_priv_data(endpoint_id); -#else - void *priv_data = nullptr; -#endif - return attribute_callback(type, endpoint_id, cluster_id, attribute_id, val, priv_data); - } - return ESP_OK; -} - -static esp_matter_val_type_t get_val_type_from_attribute_type(int attribute_type) -{ - switch (attribute_type) { - case ZCL_BOOLEAN_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_BOOLEAN; - break; - - case ZCL_SINGLE_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_FLOAT; - break; - - case ZCL_ARRAY_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_ARRAY; - break; - - case ZCL_CHAR_STRING_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_CHAR_STRING; - break; - - case ZCL_LONG_CHAR_STRING_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING; - break; - - case ZCL_OCTET_STRING_ATTRIBUTE_TYPE: - case ZCL_IPADR_ATTRIBUTE_TYPE: - case ZCL_IPV4ADR_ATTRIBUTE_TYPE: - case ZCL_IPV6ADR_ATTRIBUTE_TYPE: - case ZCL_IPV6PRE_ATTRIBUTE_TYPE: - case ZCL_HWADR_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_OCTET_STRING; - break; - - case ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING; - break; - - case ZCL_INT8S_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_INT8; - break; - - case ZCL_INT8U_ATTRIBUTE_TYPE: - case ZCL_ACTION_ID_ATTRIBUTE_TYPE: - case ZCL_TAG_ATTRIBUTE_TYPE: - case ZCL_NAMESPACE_ATTRIBUTE_TYPE: - case ZCL_FABRIC_IDX_ATTRIBUTE_TYPE: - case ZCL_PERCENT_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_UINT8; - break; - - case ZCL_INT16S_ATTRIBUTE_TYPE: - case ZCL_TEMPERATURE_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_INT16; - break; - - case ZCL_INT16U_ATTRIBUTE_TYPE: - case ZCL_ENTRY_IDX_ATTRIBUTE_TYPE: - case ZCL_GROUP_ID_ATTRIBUTE_TYPE: - case ZCL_ENDPOINT_NO_ATTRIBUTE_TYPE: - case ZCL_VENDOR_ID_ATTRIBUTE_TYPE: - case ZCL_PERCENT100THS_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_UINT16; - break; - - case ZCL_INT32S_ATTRIBUTE_TYPE: - case ZCL_INT24S_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_INT32; - break; - - case ZCL_INT32U_ATTRIBUTE_TYPE: - case ZCL_TRANS_ID_ATTRIBUTE_TYPE: - case ZCL_CLUSTER_ID_ATTRIBUTE_TYPE: - case ZCL_ATTRIB_ID_ATTRIBUTE_TYPE: - case ZCL_FIELD_ID_ATTRIBUTE_TYPE: - case ZCL_EVENT_ID_ATTRIBUTE_TYPE: - case ZCL_COMMAND_ID_ATTRIBUTE_TYPE: - case ZCL_EPOCH_S_ATTRIBUTE_TYPE: - case ZCL_ELAPSED_S_ATTRIBUTE_TYPE: - case ZCL_DATA_VER_ATTRIBUTE_TYPE: - case ZCL_DEVTYPE_ID_ATTRIBUTE_TYPE: - case ZCL_INT24U_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_UINT32; - break; - - case ZCL_INT64S_ATTRIBUTE_TYPE: - case ZCL_ENERGY_MWH_ATTRIBUTE_TYPE: - case ZCL_AMPERAGE_MA_ATTRIBUTE_TYPE: - case ZCL_POWER_MW_ATTRIBUTE_TYPE: - case ZCL_INT56S_ATTRIBUTE_TYPE: - case ZCL_INT48S_ATTRIBUTE_TYPE: - case ZCL_INT40S_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_INT64; - break; - - case ZCL_INT64U_ATTRIBUTE_TYPE: - case ZCL_FABRIC_ID_ATTRIBUTE_TYPE: - case ZCL_NODE_ID_ATTRIBUTE_TYPE: - case ZCL_POSIX_MS_ATTRIBUTE_TYPE: - case ZCL_EPOCH_US_ATTRIBUTE_TYPE: - case ZCL_SYSTIME_US_ATTRIBUTE_TYPE: - case ZCL_SYSTIME_MS_ATTRIBUTE_TYPE: - case ZCL_EVENT_NO_ATTRIBUTE_TYPE: - case ZCL_INT56U_ATTRIBUTE_TYPE: - case ZCL_INT48U_ATTRIBUTE_TYPE: - case ZCL_INT40U_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_UINT64; - break; - - case ZCL_ENUM8_ATTRIBUTE_TYPE: - case ZCL_STATUS_ATTRIBUTE_TYPE: - case ZCL_PRIORITY_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_ENUM8; - break; - - case ZCL_ENUM16_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_ENUM16; - break; - - case ZCL_BITMAP8_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_BITMAP8; - break; - - case ZCL_BITMAP16_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_BITMAP16; - break; - - case ZCL_BITMAP32_ATTRIBUTE_TYPE: - return ESP_MATTER_VAL_TYPE_BITMAP32; - break; - - default: - return ESP_MATTER_VAL_TYPE_INVALID; - break; - } - return ESP_MATTER_VAL_TYPE_INVALID; -} - -bool val_is_null(esp_matter_attr_val_t *val) -{ - switch (val->type) { - case ESP_MATTER_VAL_TYPE_NULLABLE_BOOLEAN: - return chip::app::NumericAttributeTraits::IsNullValue(*(uint8_t *)(&(val->val.b))); - break; - case ESP_MATTER_VAL_TYPE_NULLABLE_INTEGER: - return chip::app::NumericAttributeTraits::IsNullValue(val->val.i); - break; - case ESP_MATTER_VAL_TYPE_NULLABLE_UINT8: - case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8: - case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8: - return chip::app::NumericAttributeTraits::IsNullValue(val->val.u8); - break; - case ESP_MATTER_VAL_TYPE_NULLABLE_UINT16: - case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16: - case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16: - return chip::app::NumericAttributeTraits::IsNullValue(val->val.u16); - break; - case ESP_MATTER_VAL_TYPE_NULLABLE_UINT32: - case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32: - return chip::app::NumericAttributeTraits::IsNullValue(val->val.u32); - break; - case ESP_MATTER_VAL_TYPE_NULLABLE_UINT64: - return chip::app::NumericAttributeTraits::IsNullValue(val->val.u64); - break; - case ESP_MATTER_VAL_TYPE_NULLABLE_INT8: - return chip::app::NumericAttributeTraits::IsNullValue(val->val.i8); - break; - case ESP_MATTER_VAL_TYPE_NULLABLE_INT16: - return chip::app::NumericAttributeTraits::IsNullValue(val->val.i16); - break; - case ESP_MATTER_VAL_TYPE_NULLABLE_INT32: - return chip::app::NumericAttributeTraits::IsNullValue(val->val.i32); - break; - case ESP_MATTER_VAL_TYPE_NULLABLE_INT64: - return chip::app::NumericAttributeTraits::IsNullValue(val->val.i64); - break; - case ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT: - return chip::app::NumericAttributeTraits::IsNullValue(val->val.f); - break; - default: - return false; - break; - } - return false; -} - -esp_err_t get_data_from_attr_val(esp_matter_attr_val_t *val, EmberAfAttributeType *attribute_type, - uint16_t *attribute_size, uint8_t *value) -{ - switch (val->type) { - case ESP_MATTER_VAL_TYPE_BOOLEAN: - case ESP_MATTER_VAL_TYPE_NULLABLE_BOOLEAN: - if (attribute_type) { - *attribute_type = ZCL_BOOLEAN_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = sizeof(bool); - } - if (value) { - using Traits = chip::app::NumericAttributeTraits; - if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(*(uint8_t *)(&(val->val.b)))) { - Traits::SetNull(*(uint8_t *)value); - } else { - Traits::WorkingToStorage(val->val.b, *(uint8_t *)value); - } - } - break; - - case ESP_MATTER_VAL_TYPE_INTEGER: - case ESP_MATTER_VAL_TYPE_NULLABLE_INTEGER: - if (attribute_type) { - *attribute_type = ZCL_INT16U_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = sizeof(int); - } - if (value) { - using Traits = chip::app::NumericAttributeTraits; - if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val->val.i)) { - Traits::SetNull(*(int *)value); - } else { - Traits::WorkingToStorage(val->val.i, *(int *)value); - } - } - break; - - case ESP_MATTER_VAL_TYPE_FLOAT: - case ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT: - if (attribute_type) { - *attribute_type = ZCL_SINGLE_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = sizeof(float); - } - if (value) { - using Traits = chip::app::NumericAttributeTraits; - if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val->val.f)) { - Traits::SetNull(*(float *)value); - } else { - Traits::WorkingToStorage(val->val.f, *(float *)value); - } - } - break; - - case ESP_MATTER_VAL_TYPE_ARRAY: - if (attribute_type) { - *attribute_type = ZCL_ARRAY_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = val->val.a.t; - } - if (value) { - int data_size_len = val->val.a.t - val->val.a.s; - memcpy(value, (uint8_t *)&val->val.a.s, data_size_len); - if (*attribute_size > CONFIG_ESP_MATTER_ATTRIBUTE_BUFFER_LARGEST) - { - ESP_LOGE(TAG, "Attribute buffer not enough, cannot copy the data to the attribute buffer." - "Please configure the buffer size through menuconfig ESP_MATTER_ATTRIBUTE_BUFFER_LARGEST"); - return ESP_FAIL; - } - memcpy((value + data_size_len), (uint8_t *)val->val.a.b, (*attribute_size - data_size_len)); - } - break; - - case ESP_MATTER_VAL_TYPE_CHAR_STRING: - { - if (attribute_type) { - *attribute_type = ZCL_CHAR_STRING_ATTRIBUTE_TYPE; - } - size_t string_len = 0; - if (val->val.a.b) { - string_len = strnlen((const char *)val->val.a.b, val->val.a.s); - } - size_t data_size_len = val->val.a.t - val->val.a.s; - if (string_len >= UINT8_MAX || data_size_len != 1) { - return ESP_ERR_INVALID_ARG; - } - uint8_t data_size = string_len; - if (attribute_size) { - *attribute_size = string_len + data_size_len; - } - if (value) { - memcpy(value, (uint8_t *)&data_size, data_size_len); - if (*attribute_size > CONFIG_ESP_MATTER_ATTRIBUTE_BUFFER_LARGEST) - { - ESP_LOGE(TAG, "Attribute buffer not enough, cannot copy the data to the attribute buffer." - "Please configure the buffer size through menuconfig ESP_MATTER_ATTRIBUTE_BUFFER_LARGEST"); - return ESP_FAIL; - } - memcpy((value + data_size_len), (uint8_t *)val->val.a.b, (*attribute_size - data_size_len)); - } - } - break; - - case ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING: - { - if (attribute_type) { - *attribute_type = ZCL_LONG_CHAR_STRING_ATTRIBUTE_TYPE; - } - size_t string_len = 0; - if (val->val.a.b) { - string_len = strnlen((const char *)val->val.a.b, val->val.a.s); - } - size_t data_size_len = val->val.a.t - val->val.a.s; - if (string_len >= UINT16_MAX || data_size_len != 2) { - return ESP_ERR_INVALID_ARG; - } - uint16_t data_size = string_len; - if (attribute_size) { - *attribute_size = string_len + data_size_len; - } - if (value) { - memcpy(value, (uint8_t *)&data_size, data_size_len); - if (*attribute_size > CONFIG_ESP_MATTER_ATTRIBUTE_BUFFER_LARGEST) - { - ESP_LOGE(TAG, "Attribute buffer not enough, cannot copy the data to the attribute buffer." - "Please configure the buffer size through menuconfig ESP_MATTER_ATTRIBUTE_BUFFER_LARGEST"); - return ESP_FAIL; - } - memcpy((value + data_size_len), (uint8_t *)val->val.a.b, (*attribute_size - data_size_len)); - } - } - break; - - case ESP_MATTER_VAL_TYPE_OCTET_STRING: - if (attribute_type) { - *attribute_type = ZCL_OCTET_STRING_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = val->val.a.t; - } - if (value) { - int data_size_len = val->val.a.t - val->val.a.s; - memcpy(value, (uint8_t *)&val->val.a.s, data_size_len); - if (*attribute_size > CONFIG_ESP_MATTER_ATTRIBUTE_BUFFER_LARGEST) - { - ESP_LOGE(TAG, "Attribute buffer not enough, cannot copy the data to the attribute buffer." - "Please configure the buffer size through menuconfig ESP_MATTER_ATTRIBUTE_BUFFER_LARGEST"); - return ESP_FAIL; - } - memcpy((value + data_size_len), (uint8_t *)val->val.a.b, (*attribute_size - data_size_len)); - } - break; - - case ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING: - if (attribute_type) { - *attribute_type = ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = val->val.a.t; - } - if (value) { - int data_size_len = val->val.a.t - val->val.a.s; - memcpy(value, (uint8_t *)&val->val.a.s, data_size_len); - if (*attribute_size > CONFIG_ESP_MATTER_ATTRIBUTE_BUFFER_LARGEST) - { - ESP_LOGE(TAG, "Attribute buffer not enough, cannot copy the data to the attribute buffer." - "Please configure the buffer size through menuconfig ESP_MATTER_ATTRIBUTE_BUFFER_LARGEST"); - return ESP_FAIL; - } - memcpy((value + data_size_len), (uint8_t *)val->val.a.b, (*attribute_size - data_size_len)); - } - break; - - case ESP_MATTER_VAL_TYPE_INT8: - case ESP_MATTER_VAL_TYPE_NULLABLE_INT8: - if (attribute_type) { - *attribute_type = ZCL_INT8S_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = sizeof(int8_t); - } - if (value) { - using Traits = chip::app::NumericAttributeTraits; - if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val->val.i8)) { - Traits::SetNull(*(int8_t *)value); - } else { - Traits::WorkingToStorage(val->val.i8, *(int8_t *)value); - } - } - break; - - case ESP_MATTER_VAL_TYPE_UINT8: - case ESP_MATTER_VAL_TYPE_NULLABLE_UINT8: - if (attribute_type) { - *attribute_type = ZCL_INT8U_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = sizeof(uint8_t); - } - if (value) { - using Traits = chip::app::NumericAttributeTraits; - if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val->val.u8)) { - Traits::SetNull(*(uint8_t *)value); - } else { - Traits::WorkingToStorage(val->val.u8, *(uint8_t *)value); - } - } - break; - - case ESP_MATTER_VAL_TYPE_INT16: - case ESP_MATTER_VAL_TYPE_NULLABLE_INT16: - if (attribute_type) { - *attribute_type = ZCL_INT16S_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = sizeof(int16_t); - } - if (value) { - using Traits = chip::app::NumericAttributeTraits; - if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val->val.i16)) { - Traits::SetNull(*(int16_t *)value); - } else { - Traits::WorkingToStorage(val->val.i16, *(int16_t *)value); - } - } - break; - - case ESP_MATTER_VAL_TYPE_UINT16: - case ESP_MATTER_VAL_TYPE_NULLABLE_UINT16: - if (attribute_type) { - *attribute_type = ZCL_INT16U_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = sizeof(uint16_t); - } - if (value) { - using Traits = chip::app::NumericAttributeTraits; - if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val->val.u16)) { - Traits::SetNull(*(uint16_t *)value); - } else { - Traits::WorkingToStorage(val->val.u16, *(uint16_t *)value); - } - } - break; - - case ESP_MATTER_VAL_TYPE_INT32: - case ESP_MATTER_VAL_TYPE_NULLABLE_INT32: - if (attribute_type) { - *attribute_type = ZCL_INT32S_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = sizeof(int32_t); - } - if (value) { - using Traits = chip::app::NumericAttributeTraits; - if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val->val.i32)) { - Traits::SetNull(*(int32_t *)value); - } else { - Traits::WorkingToStorage(val->val.i32, *(int32_t *)value); - } - } - break; - - case ESP_MATTER_VAL_TYPE_UINT32: - case ESP_MATTER_VAL_TYPE_NULLABLE_UINT32: - if (attribute_type) { - *attribute_type = ZCL_INT32U_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = sizeof(uint32_t); - } - if (value) { - using Traits = chip::app::NumericAttributeTraits; - if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val->val.u32)) { - Traits::SetNull(*(uint32_t *)value); - } else { - Traits::WorkingToStorage(val->val.u32, *(uint32_t *)value); - } - } - break; - - case ESP_MATTER_VAL_TYPE_INT64: - case ESP_MATTER_VAL_TYPE_NULLABLE_INT64: - if (attribute_type) { - *attribute_type = ZCL_INT64S_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = sizeof(int64_t); - } - if (value) { - using Traits = chip::app::NumericAttributeTraits; - if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val->val.i64)) { - Traits::SetNull(*(int64_t *)value); - } else { - Traits::WorkingToStorage(val->val.i64, *(int64_t *)value); - } - } - break; - - case ESP_MATTER_VAL_TYPE_UINT64: - case ESP_MATTER_VAL_TYPE_NULLABLE_UINT64: - if (attribute_type) { - *attribute_type = ZCL_INT64U_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = sizeof(uint64_t); - } - if (value) { - using Traits = chip::app::NumericAttributeTraits; - if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val->val.u64)) { - Traits::SetNull(*(uint64_t *)value); - } else { - Traits::WorkingToStorage(val->val.u64, *(uint64_t *)value); - } - } - break; - - case ESP_MATTER_VAL_TYPE_ENUM8: - case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8: - if (attribute_type) { - *attribute_type = ZCL_ENUM8_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = sizeof(uint8_t); - } - if (value) { - using Traits = chip::app::NumericAttributeTraits; - if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val->val.u8)) { - Traits::SetNull(*(uint8_t *)value); - } else { - Traits::WorkingToStorage(val->val.u8, *(uint8_t *)value); - } - } - break; - - case ESP_MATTER_VAL_TYPE_ENUM16: - case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16: - if (attribute_type) { - *attribute_type = ZCL_ENUM16_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = sizeof(uint16_t); - } - if (value) { - using Traits = chip::app::NumericAttributeTraits; - if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val->val.u16)) { - Traits::SetNull(*(uint16_t *)value); - } else { - Traits::WorkingToStorage(val->val.u16, *(uint16_t *)value); - } - } - break; - - case ESP_MATTER_VAL_TYPE_BITMAP8: - case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8: - if (attribute_type) { - *attribute_type = ZCL_BITMAP8_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = sizeof(uint8_t); - } - if (value) { - using Traits = chip::app::NumericAttributeTraits; - if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val->val.u8)) { - Traits::SetNull(*(uint8_t *)value); - } else { - Traits::WorkingToStorage(val->val.u8, *(uint8_t *)value); - } - } - break; - - case ESP_MATTER_VAL_TYPE_BITMAP16: - case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16: - if (attribute_type) { - *attribute_type = ZCL_BITMAP16_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = sizeof(uint16_t); - } - if (value) { - using Traits = chip::app::NumericAttributeTraits; - if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val->val.u16)) { - Traits::SetNull(*(uint16_t *)value); - } else { - Traits::WorkingToStorage(val->val.u16, *(uint16_t *)value); - } - } - break; - - case ESP_MATTER_VAL_TYPE_BITMAP32: - case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32: - if (attribute_type) { - *attribute_type = ZCL_BITMAP32_ATTRIBUTE_TYPE; - } - if (attribute_size) { - *attribute_size = sizeof(uint32_t); - } - if (value) { - using Traits = chip::app::NumericAttributeTraits; - if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val->val.u32)) { - Traits::SetNull(*(uint32_t *)value); - } else { - Traits::WorkingToStorage(val->val.u32, *(uint32_t *)value); - } - } - break; - - default: - ESP_LOGE(TAG, "esp_matter_attr_val_type_t not handled: %d", val->type); - break; - } - - return ESP_OK; -} - -esp_err_t get_attr_val_from_data(esp_matter_attr_val_t *val, EmberAfAttributeType attribute_type, - uint16_t attribute_size, uint8_t *value, - const EmberAfAttributeMetadata * attribute_metadata) -{ - switch (attribute_type) { - case ZCL_BOOLEAN_ATTRIBUTE_TYPE: { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType attribute_value; - memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); - *val = esp_matter_bool(attribute_value); - break; - } - - case ZCL_ARRAY_ATTRIBUTE_TYPE: { - *val = esp_matter_array(NULL, 0, 0); - int data_size_len = val->val.a.t - val->val.a.s; - int data_count = 0; - memcpy(&data_count, &value[0], data_size_len); - *val = esp_matter_array((value + data_size_len), attribute_size, data_count); - break; - } - - case ZCL_CHAR_STRING_ATTRIBUTE_TYPE: { - *val = esp_matter_char_str(NULL, 0); - int data_size_len = val->val.a.t - val->val.a.s; - int data_count = 0; - memcpy(&data_count, &value[0], data_size_len); - *val = esp_matter_char_str((char *)(value + data_size_len), data_count); - break; - } - - case ZCL_LONG_CHAR_STRING_ATTRIBUTE_TYPE: { - *val = esp_matter_long_char_str(NULL, 0); - int data_size_len = val->val.a.t - val->val.a.s; - int data_count = 0; - memcpy(&data_count, &value[0], data_size_len); - *val = esp_matter_long_char_str((char *)(value + data_size_len), data_count); - break; - } - - case ZCL_OCTET_STRING_ATTRIBUTE_TYPE: - case ZCL_IPADR_ATTRIBUTE_TYPE: - case ZCL_IPV4ADR_ATTRIBUTE_TYPE: - case ZCL_IPV6ADR_ATTRIBUTE_TYPE: - case ZCL_IPV6PRE_ATTRIBUTE_TYPE: - case ZCL_HWADR_ATTRIBUTE_TYPE: { - *val = esp_matter_octet_str(NULL, 0); - int data_size_len = val->val.a.t - val->val.a.s; - int data_count = 0; - memcpy(&data_count, &value[0], data_size_len); - *val = esp_matter_octet_str((value + data_size_len), data_count); - break; - } - - case ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE: { - *val = esp_matter_long_octet_str(NULL, 0); - int data_size_len = val->val.a.t - val->val.a.s; - int data_count = 0; - memcpy(&data_count, &value[0], data_size_len); - *val = esp_matter_long_octet_str((value + data_size_len), data_count); - break; - } - - case ZCL_INT8S_ATTRIBUTE_TYPE: { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType attribute_value; - memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); - if (attribute_metadata->IsNullable()) { - if (Traits::IsNullValue(attribute_value)) { - *val = esp_matter_nullable_int8(nullable()); - } else { - *val = esp_matter_nullable_int8(attribute_value); - } - } else { - *val = esp_matter_int8(attribute_value); - } - break; - } - - case ZCL_INT8U_ATTRIBUTE_TYPE: - case ZCL_ACTION_ID_ATTRIBUTE_TYPE: - case ZCL_TAG_ATTRIBUTE_TYPE: - case ZCL_NAMESPACE_ATTRIBUTE_TYPE: - case ZCL_FABRIC_IDX_ATTRIBUTE_TYPE: - case ZCL_PERCENT_ATTRIBUTE_TYPE: { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType attribute_value; - memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); - if (attribute_metadata->IsNullable()) { - if (Traits::IsNullValue(attribute_value)) { - *val = esp_matter_nullable_uint8(nullable()); - } else { - *val = esp_matter_nullable_uint8(attribute_value); - } - } else { - *val = esp_matter_uint8(attribute_value); - } - break; - } - - case ZCL_INT16S_ATTRIBUTE_TYPE: - case ZCL_TEMPERATURE_ATTRIBUTE_TYPE: { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType attribute_value; - memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); - if (attribute_metadata->IsNullable()) { - if (Traits::IsNullValue(attribute_value)) { - *val = esp_matter_nullable_int16(nullable()); - } else { - *val = esp_matter_nullable_int16(attribute_value); - } - } else { - *val = esp_matter_int16(attribute_value); - } - break; - } - - case ZCL_INT16U_ATTRIBUTE_TYPE: - case ZCL_ENTRY_IDX_ATTRIBUTE_TYPE: - case ZCL_GROUP_ID_ATTRIBUTE_TYPE: - case ZCL_ENDPOINT_NO_ATTRIBUTE_TYPE: - case ZCL_VENDOR_ID_ATTRIBUTE_TYPE: - case ZCL_PERCENT100THS_ATTRIBUTE_TYPE: { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType attribute_value; - memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); - if (attribute_metadata->IsNullable()) { - if (Traits::IsNullValue(attribute_value)) { - *val = esp_matter_nullable_uint16(nullable()); - } else { - *val = esp_matter_nullable_uint16(attribute_value); - } - } else { - *val = esp_matter_uint16(attribute_value); - } - break; - } - - case ZCL_INT32S_ATTRIBUTE_TYPE: - case ZCL_INT24S_ATTRIBUTE_TYPE: { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType attribute_value; - memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); - if (attribute_metadata->IsNullable()) { - if (Traits::IsNullValue(attribute_value)) { - *val = esp_matter_nullable_int32(nullable()); - } else { - *val = esp_matter_nullable_int32(attribute_value); - } - } else { - *val = esp_matter_int32(attribute_value); - } - break; - } - - case ZCL_INT32U_ATTRIBUTE_TYPE: - case ZCL_TRANS_ID_ATTRIBUTE_TYPE: - case ZCL_CLUSTER_ID_ATTRIBUTE_TYPE: - case ZCL_ATTRIB_ID_ATTRIBUTE_TYPE: - case ZCL_FIELD_ID_ATTRIBUTE_TYPE: - case ZCL_EVENT_ID_ATTRIBUTE_TYPE: - case ZCL_COMMAND_ID_ATTRIBUTE_TYPE: - case ZCL_EPOCH_S_ATTRIBUTE_TYPE: - case ZCL_ELAPSED_S_ATTRIBUTE_TYPE: - case ZCL_DATA_VER_ATTRIBUTE_TYPE: - case ZCL_DEVTYPE_ID_ATTRIBUTE_TYPE: - case ZCL_INT24U_ATTRIBUTE_TYPE: { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType attribute_value; - memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); - if (attribute_metadata->IsNullable()) { - if (Traits::IsNullValue(attribute_value)) { - *val = esp_matter_nullable_uint32(nullable()); - } else { - *val = esp_matter_nullable_uint32(attribute_value); - } - } else { - *val = esp_matter_uint32(attribute_value); - } - break; - } - - case ZCL_INT64S_ATTRIBUTE_TYPE: - case ZCL_ENERGY_MWH_ATTRIBUTE_TYPE: - case ZCL_AMPERAGE_MA_ATTRIBUTE_TYPE: - case ZCL_POWER_MW_ATTRIBUTE_TYPE: - case ZCL_INT56S_ATTRIBUTE_TYPE: - case ZCL_INT48S_ATTRIBUTE_TYPE: - case ZCL_INT40S_ATTRIBUTE_TYPE: { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType attribute_value; - memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); - if (attribute_metadata->IsNullable()) { - if (Traits::IsNullValue(attribute_value)) { - *val = esp_matter_nullable_int64(nullable()); - } else { - *val = esp_matter_nullable_int64(attribute_value); - } - } else { - *val = esp_matter_int64(attribute_value); - } - break; - } - - case ZCL_INT64U_ATTRIBUTE_TYPE: - case ZCL_FABRIC_ID_ATTRIBUTE_TYPE: - case ZCL_NODE_ID_ATTRIBUTE_TYPE: - case ZCL_POSIX_MS_ATTRIBUTE_TYPE: - case ZCL_EPOCH_US_ATTRIBUTE_TYPE: - case ZCL_SYSTIME_US_ATTRIBUTE_TYPE: - case ZCL_SYSTIME_MS_ATTRIBUTE_TYPE: - case ZCL_EVENT_NO_ATTRIBUTE_TYPE: - case ZCL_INT56U_ATTRIBUTE_TYPE: - case ZCL_INT48U_ATTRIBUTE_TYPE: - case ZCL_INT40U_ATTRIBUTE_TYPE: { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType attribute_value; - memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); - if (attribute_metadata->IsNullable()) { - if (Traits::IsNullValue(attribute_value)) { - *val = esp_matter_nullable_uint64(nullable()); - } else { - *val = esp_matter_nullable_uint64(attribute_value); - } - } else { - *val = esp_matter_uint64(attribute_value); - } - break; - } - - case ZCL_ENUM8_ATTRIBUTE_TYPE: - case ZCL_STATUS_ATTRIBUTE_TYPE: - case ZCL_PRIORITY_ATTRIBUTE_TYPE: { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType attribute_value; - memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); - if (attribute_metadata->IsNullable()) { - if (Traits::IsNullValue(attribute_value)) { - *val = esp_matter_nullable_enum8(nullable()); - } else { - *val = esp_matter_nullable_enum8(attribute_value); - } - } else { - *val = esp_matter_enum8(attribute_value); - } - break; - } - - case ZCL_ENUM16_ATTRIBUTE_TYPE: { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType attribute_value; - memcpy((uint16_t *)&attribute_value, value, sizeof(Traits::StorageType)); - if (attribute_metadata->IsNullable()) { - if (Traits::IsNullValue(attribute_value)) { - *val = esp_matter_nullable_enum16(nullable()); - } else { - *val = esp_matter_nullable_enum16(attribute_value); - } - } else { - *val = esp_matter_enum16(attribute_value); - } - break; - } - - case ZCL_BITMAP8_ATTRIBUTE_TYPE: { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType attribute_value; - memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); - if (attribute_metadata->IsNullable()) { - if (Traits::IsNullValue(attribute_value)) { - *val = esp_matter_nullable_bitmap8(nullable()); - } else { - *val = esp_matter_nullable_bitmap8(attribute_value); - } - } else { - *val = esp_matter_bitmap8(attribute_value); - } - break; - } - - case ZCL_BITMAP16_ATTRIBUTE_TYPE: { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType attribute_value; - memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); - if (attribute_metadata->IsNullable()) { - if (Traits::IsNullValue(attribute_value)) { - *val = esp_matter_nullable_bitmap16(nullable()); - } else { - *val = esp_matter_nullable_bitmap16(attribute_value); - } - } else { - *val = esp_matter_bitmap16(attribute_value); - } - break; - } - - case ZCL_BITMAP32_ATTRIBUTE_TYPE: { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType attribute_value; - memcpy((uint8_t *)&attribute_value, value, sizeof(Traits::StorageType)); - if (attribute_metadata->IsNullable()) { - if (Traits::IsNullValue(attribute_value)) { - *val = esp_matter_nullable_bitmap32(nullable()); - } else { - *val = esp_matter_nullable_bitmap32(attribute_value); - } - } else { - *val = esp_matter_bitmap32(attribute_value); - } - break; - } - - case ZCL_SINGLE_ATTRIBUTE_TYPE: { - using Traits = chip::app::NumericAttributeTraits; - Traits::StorageType attribute_value; - memcpy((float *)&attribute_value, value, sizeof(Traits::StorageType)); - if (attribute_metadata->IsNullable()) { - if (Traits::IsNullValue(attribute_value)) { - *val = esp_matter_nullable_float(nullable()); - } else { - *val = esp_matter_nullable_float(attribute_value); - } - } else { - *val = esp_matter_float(attribute_value); - } - break; - } - - default: - *val = esp_matter_invalid(NULL); - break; - } - - return ESP_OK; -} - -void val_print(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val, bool is_read) -{ - char action = (is_read) ? 'R' :'W'; - VerifyOrReturn(!val_is_null(val), ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is null **********", action, - endpoint_id, cluster_id, attribute_id)); - - if (val->type == ESP_MATTER_VAL_TYPE_BOOLEAN) { - ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %d **********", action, - endpoint_id, cluster_id, attribute_id, val->val.b); - } else if (val->type == ESP_MATTER_VAL_TYPE_INTEGER || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INTEGER) { - ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %d **********", action, - endpoint_id, cluster_id, attribute_id, val->val.i); - } else if (val->type == ESP_MATTER_VAL_TYPE_FLOAT || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT) { - ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %f **********", action, - endpoint_id, cluster_id, attribute_id, val->val.f); - } else if (val->type == ESP_MATTER_VAL_TYPE_INT8 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INT8) { - ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %i **********", action, - endpoint_id, cluster_id, attribute_id, val->val.i8); - } else if (val->type == ESP_MATTER_VAL_TYPE_UINT8 || val->type == ESP_MATTER_VAL_TYPE_BITMAP8 - || val->type == ESP_MATTER_VAL_TYPE_ENUM8 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_UINT8 - || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8) { - ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %u **********", action, - endpoint_id, cluster_id, attribute_id, val->val.u8); - } else if (val->type == ESP_MATTER_VAL_TYPE_INT16 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INT16) { - ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIi16 " **********", action, - endpoint_id, cluster_id, attribute_id, val->val.i16); - } else if (val->type == ESP_MATTER_VAL_TYPE_UINT16 || val->type == ESP_MATTER_VAL_TYPE_BITMAP16 - || val->type == ESP_MATTER_VAL_TYPE_ENUM16 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_UINT16 - || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16) { - ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIu16 " **********", action, - endpoint_id, cluster_id, attribute_id, val->val.u16); - } else if (val->type == ESP_MATTER_VAL_TYPE_INT32|| val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INT32) { - ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIi32 " **********", action, - endpoint_id, cluster_id, attribute_id, val->val.i32); - } else if (val->type == ESP_MATTER_VAL_TYPE_UINT32 || val->type == ESP_MATTER_VAL_TYPE_BITMAP32 - || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_UINT32 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32) { - ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIu32 " **********", action, - endpoint_id, cluster_id, attribute_id, val->val.u32); - } else if (val->type == ESP_MATTER_VAL_TYPE_INT64 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INT64) { - ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIi64 " **********", action, - endpoint_id, cluster_id, attribute_id, val->val.i64); - } else if (val->type == ESP_MATTER_VAL_TYPE_UINT64 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_UINT64) { - ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIu64 " **********", action, - endpoint_id, cluster_id, attribute_id, val->val.u64); - } else if (val->type == ESP_MATTER_VAL_TYPE_CHAR_STRING) { - const char *b = val->val.a.b ? (const char *)val->val.a.b : "(empty)"; - uint16_t s = val->val.a.b ? val->val.a.s : strlen("(empty)"); - ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %.*s **********", action, - endpoint_id, cluster_id, attribute_id, s, b); - } else if (val->type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING) { - const char *b = val->val.a.b ? (const char *)val->val.a.b : "(empty)"; - uint16_t s = val->val.a.b ? val->val.a.s : strlen("(empty)"); - ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %.*s **********", action, - endpoint_id, cluster_id, attribute_id, s, b); - } else { - ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is **********", action, - endpoint_id, cluster_id, attribute_id, val->type); - } -} - -esp_err_t get_val_raw(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, uint8_t *value, - uint16_t attribute_size) -{ - /* Take lock if not already taken */ - lock::status_t lock_status = lock::chip_stack_lock(portMAX_DELAY); - VerifyOrReturnError(lock_status != lock::FAILED, ESP_FAIL, ESP_LOGE(TAG, "Could not get task context")); - - esp_err_t err = ESP_OK; - Status status = emberAfReadAttribute(endpoint_id, cluster_id, attribute_id, value, attribute_size); - if (status != Status::Success) { - ESP_LOGE(TAG, "Error getting Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 "'s raw value from matter: 0x%x", - endpoint_id, cluster_id, attribute_id, static_cast(status)); - err = ESP_FAIL; - } - if (lock_status == lock::SUCCESS) { - lock::chip_stack_unlock(); - } - return err; -} - -esp_err_t update(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) -{ - /* Take lock if not already taken */ - lock::status_t lock_status = lock::chip_stack_lock(portMAX_DELAY); - VerifyOrReturnError(lock_status != lock::FAILED, ESP_FAIL, ESP_LOGE(TAG, "Could not get task context")); - - /* Get size */ - EmberAfAttributeType attribute_type = 0; - uint16_t attribute_size = 0; - esp_err_t err = get_data_from_attr_val(val, &attribute_type, &attribute_size, NULL); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Error getting data from attribute value: %d", err); - if (lock_status == lock::SUCCESS) { - lock::chip_stack_unlock(); - } - return err; - } - - /* Get value */ - uint8_t *value = (uint8_t *)esp_matter_mem_calloc(1, attribute_size); - if (!value) { - ESP_LOGE(TAG, "Could not allocate value buffer, size: %u", attribute_size); - if (lock_status == lock::SUCCESS) { - lock::chip_stack_unlock(); - } - return ESP_ERR_NO_MEM; - } - get_data_from_attr_val(val, &attribute_type, &attribute_size, value); - - /* Update matter */ - Status status = Status::Success; - if (emberAfContainsServer(endpoint_id, cluster_id)) { - status = emberAfWriteAttribute(endpoint_id, cluster_id, attribute_id, value, attribute_type); - if (status != Status::Success) { - ESP_LOGE(TAG, "Error updating Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " to matter: 0x%X", endpoint_id, - cluster_id, attribute_id, static_cast(status)); - esp_matter_mem_free(value); - if (lock_status == lock::SUCCESS) { - lock::chip_stack_unlock(); - } - return ESP_FAIL; - } - } - esp_matter_mem_free(value); - if (lock_status == lock::SUCCESS) { - lock::chip_stack_unlock(); - } - return ESP_OK; -} - -esp_err_t report(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) -{ - /* Take lock if not already taken */ - lock::status_t lock_status = lock::chip_stack_lock(portMAX_DELAY); - VerifyOrReturnError(lock_status != lock::FAILED, ESP_FAIL, ESP_LOGE(TAG, "Could not get task context")); - -#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL - /* Get attribute */ - attribute_t *attribute = attribute::get(endpoint_id, cluster_id, attribute_id); - if (!attribute) { - ESP_LOGE(TAG, "Could not find Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32, endpoint_id, cluster_id, - attribute_id); - if (lock_status == lock::SUCCESS) { - lock::chip_stack_unlock(); - } - return ESP_FAIL; - } - - /* Update attribute */ - esp_matter_attr_val_t raw_val = esp_matter_invalid(NULL); - attribute::get_val(attribute, &raw_val); - if (val->type != raw_val.type) { - ESP_LOGE(TAG, "Attribute type mismatch when trying to report Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32, - endpoint_id, cluster_id, attribute_id); - if (lock_status == lock::SUCCESS) { - lock::chip_stack_unlock(); - } - return ESP_FAIL; - } - attribute::set_val(attribute, val); -#endif - /* Report attribute */ - MatterReportingAttributeChangeCallback(endpoint_id, cluster_id, attribute_id); - - if (lock_status == lock::SUCCESS) { - lock::chip_stack_unlock(); - } - return ESP_OK; -} - -} /* attribute */ -} /* esp_matter */ - -Status MatterPreAttributeChangeCallback(const chip::app::ConcreteAttributePath &path, uint8_t type, - uint16_t size, uint8_t *value) -{ - uint16_t endpoint_id = path.mEndpointId; - uint32_t cluster_id = path.mClusterId; - uint32_t attribute_id = path.mAttributeId; - const EmberAfAttributeMetadata *attribute_metadata = emberAfLocateAttributeMetadata(endpoint_id, cluster_id, - attribute_id); - esp_matter_attr_val_t val = esp_matter_invalid(NULL); - attribute::get_attr_val_from_data(&val, type, size, value, attribute_metadata); - - /* Here, the val_print function gets called on attribute write.*/ - attribute::val_print(endpoint_id, cluster_id, attribute_id, &val, false); - - /* Callback to application */ - esp_err_t err = execute_callback(attribute::PRE_UPDATE, endpoint_id, cluster_id, attribute_id, &val); - VerifyOrReturnValue(err == ESP_OK, Status::Failure); - return Status::Success; -} - -void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath &path, uint8_t type, - uint16_t size, uint8_t *value) -{ - uint16_t endpoint_id = path.mEndpointId; - uint32_t cluster_id = path.mClusterId; - uint32_t attribute_id = path.mAttributeId; - const EmberAfAttributeMetadata *attribute_metadata = emberAfLocateAttributeMetadata(endpoint_id, cluster_id, - attribute_id); - esp_matter_attr_val_t val = esp_matter_invalid(NULL); - attribute::get_attr_val_from_data(&val, type, size, value, attribute_metadata); - - /* Callback to application */ - execute_callback(attribute::POST_UPDATE, endpoint_id, cluster_id, attribute_id, &val); -} diff --git a/components/esp_matter/esp_matter_core.cpp b/components/esp_matter/esp_matter_core.cpp index d1450682b..abe6a9667 100644 --- a/components/esp_matter/esp_matter_core.cpp +++ b/components/esp_matter/esp_matter_core.cpp @@ -20,23 +20,22 @@ #include #include -#include -#include #include #ifdef CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER -#include #include #include -#include #ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL +#include +#include #include +#else +#include #endif // CONFIG_ESP_MATTER_ENABLE_DATA_MODEL #endif // CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER #include #include #include #include -#include #include #include #include @@ -228,7 +227,11 @@ static void esp_matter_chip_init_task(intptr_t context) initParams.testEventTriggerDelegate = test_event_trigger::get_delegate(); } if (!initParams.dataModelProvider) { +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + initParams.dataModelProvider = &esp_matter::data_model::provider::get_instance(); +#else initParams.dataModelProvider = chip::app::CodegenDataModelProviderInstance(initParams.persistentStorageDelegate); +#endif } #ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL @@ -251,21 +254,11 @@ static void esp_matter_chip_init_task(intptr_t context) ESP_LOGE(TAG, "Failed to add fabric delegate, err:%" CHIP_ERROR_FORMAT, ret.Format()); } chip::Server::GetInstance().Init(initParams); - network_commissioning_instance_init(); #ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL if (endpoint::enable_all() != ESP_OK) { ESP_LOGE(TAG, "Enable all endpoints failure"); } - // The following two events can't be recorded when we start the server because the endpoints are not enabled. - // TODO: Find a better way to record the events which should be recorded in matter server init - // Record start up event in basic information cluster. - PlatformMgr().HandleServerStarted(); - // Record boot reason event in general diagnostics cluster. - chip::app::Clusters::GeneralDiagnostics::BootReasonEnum bootReason; - if (GetDiagnosticDataProvider().GetBootReason(bootReason) == CHIP_NO_ERROR) { - chip::app::Clusters::GeneralDiagnosticsServer::Instance().OnDeviceReboot(bootReason); - } // Initialise clusters which have delegate implemented esp_matter::cluster::delegate_init_callback_common(); #endif // CONFIG_ESP_MATTER_ENABLE_DATA_MODEL diff --git a/components/esp_matter/esp_matter_core.h b/components/esp_matter/esp_matter_core.h index 490a17a62..420bebd29 100644 --- a/components/esp_matter/esp_matter_core.h +++ b/components/esp_matter/esp_matter_core.h @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -82,13 +81,6 @@ esp_err_t set_server_init_params(chip::CommonCaseDeviceServerInitParams *server_ */ esp_err_t start(event_callback_t callback, intptr_t callback_arg = static_cast(NULL)); -/** Return whether the Matter is initialized and started - * - * @return true if Matter is started - * @return false if Matter is not started - */ -bool is_started(); - /** Factory reset * * Perform factory reset and erase the data stored in the non volatile storage. This also restarts the device. @@ -98,15 +90,6 @@ bool is_started(); */ esp_err_t factory_reset(); -#ifdef CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER -/** - * - * Initialize WiFi, Ethernet, and Thread network commissioning instances. - * This function is called internally during Matter initialization. - */ -void network_commissioning_instance_init(); -#endif // CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER - namespace lock { /** Lock status */ diff --git a/components/esp_matter/network_commissioning_instance.cpp b/components/esp_matter/network_commissioning_instance.cpp deleted file mode 100644 index a0c3b2966..000000000 --- a/components/esp_matter/network_commissioning_instance.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2025 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#ifdef CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER - -#include -#include - -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD && CONFIG_THREAD_NETWORK_COMMISSIONING_DRIVER -#include -#endif - -namespace esp_matter { - -void network_commissioning_instance_init() -{ -#if CHIP_DEVICE_CONFIG_ENABLE_WIFI && CHIP_DEVICE_CONFIG_WIFI_NETWORK_DRIVER - static chip::app::Clusters::NetworkCommissioning::Instance sWiFiNetworkCommissioningInstance(CONFIG_WIFI_NETWORK_ENDPOINT_ID /* Endpoint Id */, - &(chip::DeviceLayer::NetworkCommissioning::ESPWiFiDriver::GetInstance())); - sWiFiNetworkCommissioningInstance.Init(); -#endif // CHIP_DEVICE_CONFIG_WIFI_NETWORK_DRIVER - -#if CHIP_DEVICE_CONFIG_ENABLE_ETHERNET && CHIP_DEVICE_CONFIG_ETHERNET_NETWORK_DRIVER - static chip::app::Clusters::NetworkCommissioning::Instance sEthernetNetworkCommissioningInstance(CONFIG_ETHERNET_NETWORK_ENDPOINT_ID /* Endpoint Id */, - &(chip::DeviceLayer::NetworkCommissioning::ESPEthernetDriver::GetInstance())); - sEthernetNetworkCommissioningInstance.Init(); -#endif // CHIP_DEVICE_CONFIG_ETHERNET_NETWORK_DRIVER - -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD && CONFIG_THREAD_NETWORK_COMMISSIONING_DRIVER - static chip::app::Clusters::NetworkCommissioning::InstanceAndDriver sThreadNetworkDriver(CONFIG_THREAD_NETWORK_ENDPOINT_ID); - sThreadNetworkDriver.Init(); -#endif -} - -} // namespace esp_matter - -#endif // CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER diff --git a/components/esp_matter/utils/cluster_select/Kconfig.in b/components/esp_matter/utils/cluster_select/Kconfig.in index 7ea700b8a..67ccf557b 100644 --- a/components/esp_matter/utils/cluster_select/Kconfig.in +++ b/components/esp_matter/utils/cluster_select/Kconfig.in @@ -93,10 +93,18 @@ config SUPPORT_COMMISSIONER_CONTROL_CLUSTER bool "Support COMMISSIONER_CONTROL_CLUSTER" default y +config SUPPORT_COMMODITY_METERING_CLUSTER + bool "Support COMMODITY_METERING_CLUSTER" + default y + config SUPPORT_COMMODITY_PRICE_CLUSTER bool "Support COMMODITY_PRICE_CLUSTER" default y +config SUPPORT_COMMODITY_TARIFF_CLUSTER + bool "Support COMMODITY_TARIFF_CLUSTER" + default y + config SUPPORT_CONTENT_LAUNCHER_CLUSTER bool "Support CONTENT_LAUNCHER_CLUSTER" default y @@ -277,6 +285,10 @@ config SUPPORT_NITROGEN_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER bool "Support NITROGEN_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER" default y +config SUPPORT_PUSH_AV_STREAM_TRANSPORT_CLUSTER + bool "Support PUSH_AV_STREAM_TRANSPORT_CLUSTER" + default y + config SUPPORT_SAMPLE_MEI_CLUSTER bool "Support SAMPLE_MEI_CLUSTER" default y @@ -433,6 +445,10 @@ config SUPPORT_TIMER_CLUSTER bool "Support TIMER_CLUSTER" default y +config SUPPORT_TLS_CLIENT_MANAGEMENT_CLUSTER + bool "Support TLS_CLIENT_MANAGEMENT_CLUSTER" + default y + config SUPPORT_TVOC_CONCENTRATION_MEASUREMENT_CLUSTER bool "Support TVOC_CONCENTRATION_MEASUREMENT_CLUSTER" default y @@ -493,3 +509,7 @@ config SUPPORT_WATER_HEATER_MODE_CLUSTER bool "Support WATER_HEATER_MODE_CLUSTER" default y +config SUPPORT_ZONE_MANAGEMENT_CLUSTER + bool "Support ZONE_MANAGEMENT_CLUSTER" + default y + diff --git a/components/esp_matter/utils/cluster_select/cluster_dir.cmake b/components/esp_matter/utils/cluster_select/cluster_dir.cmake index 6f8ebe67e..a9e2e33b8 100644 --- a/components/esp_matter/utils/cluster_select/cluster_dir.cmake +++ b/components/esp_matter/utils/cluster_select/cluster_dir.cmake @@ -72,9 +72,15 @@ function(get_supported_cluster_dirs source_dirs) if(CONFIG_SUPPORT_COMMISSIONER_CONTROL_CLUSTER) list(APPEND temp_list "${MATTER_SDK_PATH}/src/app/clusters/commissioner-control-server") endif() + if(CONFIG_SUPPORT_COMMODITY_METERING_CLUSTER) + list(APPEND temp_list "${MATTER_SDK_PATH}/src/app/clusters/commodity-metering-server") + endif() if(CONFIG_SUPPORT_COMMODITY_PRICE_CLUSTER) list(APPEND temp_list "${MATTER_SDK_PATH}/src/app/clusters/commodity-price-server") endif() + if(CONFIG_SUPPORT_COMMODITY_TARIFF_CLUSTER) + list(APPEND temp_list "${MATTER_SDK_PATH}/src/app/clusters/commodity-tariff-server") + endif() if(CONFIG_SUPPORT_CONTENT_LAUNCHER_CLUSTER) list(APPEND temp_list "${MATTER_SDK_PATH}/src/app/clusters/content-launch-server") endif() @@ -210,6 +216,9 @@ function(get_supported_cluster_dirs source_dirs) if(CONFIG_SUPPORT_NITROGEN_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER) list(APPEND temp_list "${MATTER_SDK_PATH}/src/app/clusters/concentration-measurement-server") endif() + if(CONFIG_SUPPORT_PUSH_AV_STREAM_TRANSPORT_CLUSTER) + list(APPEND temp_list "${MATTER_SDK_PATH}/src/app/clusters/push-av-stream-transport-server") + endif() if(CONFIG_SUPPORT_SAMPLE_MEI_CLUSTER) list(APPEND temp_list "${MATTER_SDK_PATH}/src/app/clusters/sample-mei-server") endif() @@ -327,6 +336,9 @@ function(get_supported_cluster_dirs source_dirs) if(CONFIG_SUPPORT_TIMER_CLUSTER) list(APPEND temp_list "${MATTER_SDK_PATH}/src/app/clusters/timer-server") endif() + if(CONFIG_SUPPORT_TLS_CLIENT_MANAGEMENT_CLUSTER) + list(APPEND temp_list "${MATTER_SDK_PATH}/src/app/clusters/tls-client-management-server") + endif() if(CONFIG_SUPPORT_TVOC_CONCENTRATION_MEASUREMENT_CLUSTER) list(APPEND temp_list "${MATTER_SDK_PATH}/src/app/clusters/concentration-measurement-server") endif() @@ -372,5 +384,8 @@ function(get_supported_cluster_dirs source_dirs) if(CONFIG_SUPPORT_WATER_HEATER_MODE_CLUSTER) list(APPEND temp_list "${MATTER_SDK_PATH}/src/app/clusters/mode-base-server") endif() + if(CONFIG_SUPPORT_ZONE_MANAGEMENT_CLUSTER) + list(APPEND temp_list "${MATTER_SDK_PATH}/src/app/clusters/zone-management-server") + endif() set(${source_dirs} ${temp_list} PARENT_SCOPE) endfunction() \ No newline at end of file diff --git a/components/esp_matter/zap_common/app/ClusterCallbacks.h b/components/esp_matter/zap_common/app/ClusterCallbacks.h new file mode 100644 index 000000000..38851c38e --- /dev/null +++ b/components/esp_matter/zap_common/app/ClusterCallbacks.h @@ -0,0 +1,423 @@ +#pragma once + +#include + +using chip::EndpointId; + +void ESPMatterAccessControlClusterServerInitCallback(EndpointId endpoint); +void ESPMatterAccessControlClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterAccountLoginClusterServerInitCallback(EndpointId endpoint); +void ESPMatterAccountLoginClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterActionsClusterServerInitCallback(EndpointId endpoint); +void ESPMatterActionsClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterActivatedCarbonFilterMonitoringClusterServerInitCallback(EndpointId endpoint); +void ESPMatterActivatedCarbonFilterMonitoringClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterAdministratorCommissioningClusterServerInitCallback(EndpointId endpoint); +void ESPMatterAdministratorCommissioningClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterAirQualityClusterServerInitCallback(EndpointId endpoint); +void ESPMatterAirQualityClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterApplicationBasicClusterServerInitCallback(EndpointId endpoint); +void ESPMatterApplicationBasicClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterApplicationLauncherClusterServerInitCallback(EndpointId endpoint); +void ESPMatterApplicationLauncherClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterAudioOutputClusterServerInitCallback(EndpointId endpoint); +void ESPMatterAudioOutputClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterBallastConfigurationClusterServerInitCallback(EndpointId endpoint); +void ESPMatterBallastConfigurationClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterBasicInformationClusterServerInitCallback(EndpointId endpoint); +void ESPMatterBasicInformationClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterBindingClusterServerInitCallback(EndpointId endpoint); +void ESPMatterBindingClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterBooleanStateClusterServerInitCallback(EndpointId endpoint); +void ESPMatterBooleanStateClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterBooleanStateConfigurationClusterServerInitCallback(EndpointId endpoint); +void ESPMatterBooleanStateConfigurationClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterBridgedDeviceBasicInformationClusterServerInitCallback(EndpointId endpoint); +void ESPMatterBridgedDeviceBasicInformationClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterCameraAvSettingsUserLevelManagementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterCameraAvSettingsUserLevelManagementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterCameraAvStreamManagementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterCameraAvStreamManagementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterCarbonDioxideConcentrationMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterCarbonDioxideConcentrationMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterCarbonMonoxideConcentrationMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterCarbonMonoxideConcentrationMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterChannelClusterServerInitCallback(EndpointId endpoint); +void ESPMatterChannelClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterChimeClusterServerInitCallback(EndpointId endpoint); +void ESPMatterChimeClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterClosureControlClusterServerInitCallback(EndpointId endpoint); +void ESPMatterClosureControlClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterClosureDimensionClusterServerInitCallback(EndpointId endpoint); +void ESPMatterClosureDimensionClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterColorControlClusterServerInitCallback(EndpointId endpoint); +void ESPMatterColorControlClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterCommissionerControlClusterServerInitCallback(EndpointId endpoint); +void ESPMatterCommissionerControlClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterCommodityMeteringClusterServerInitCallback(EndpointId endpoint); +void ESPMatterCommodityMeteringClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterCommodityPriceClusterServerInitCallback(EndpointId endpoint); +void ESPMatterCommodityPriceClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterCommodityTariffClusterServerInitCallback(EndpointId endpoint); +void ESPMatterCommodityTariffClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterContentAppObserverClusterServerInitCallback(EndpointId endpoint); +void ESPMatterContentAppObserverClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterContentControlClusterServerInitCallback(EndpointId endpoint); +void ESPMatterContentControlClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterContentLauncherClusterServerInitCallback(EndpointId endpoint); +void ESPMatterContentLauncherClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterDescriptorClusterServerInitCallback(EndpointId endpoint); +void ESPMatterDescriptorClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterDeviceEnergyManagementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterDeviceEnergyManagementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterDeviceEnergyManagementModeClusterServerInitCallback(EndpointId endpoint); +void ESPMatterDeviceEnergyManagementModeClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterDiagnosticLogsClusterServerInitCallback(EndpointId endpoint); +void ESPMatterDiagnosticLogsClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterDishwasherAlarmClusterServerInitCallback(EndpointId endpoint); +void ESPMatterDishwasherAlarmClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterDishwasherModeClusterServerInitCallback(EndpointId endpoint); +void ESPMatterDishwasherModeClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterDoorLockClusterServerInitCallback(EndpointId endpoint); +void ESPMatterDoorLockClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterEcosystemInformationClusterServerInitCallback(EndpointId endpoint); +void ESPMatterEcosystemInformationClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterElectricalEnergyMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterElectricalEnergyMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterElectricalGridConditionsClusterServerInitCallback(EndpointId endpoint); +void ESPMatterElectricalGridConditionsClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterElectricalPowerMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterElectricalPowerMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterEnergyEvseClusterServerInitCallback(EndpointId endpoint); +void ESPMatterEnergyEvseClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterEnergyEvseModeClusterServerInitCallback(EndpointId endpoint); +void ESPMatterEnergyEvseModeClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterEnergyPreferenceClusterServerInitCallback(EndpointId endpoint); +void ESPMatterEnergyPreferenceClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterEthernetNetworkDiagnosticsClusterServerInitCallback(EndpointId endpoint); +void ESPMatterEthernetNetworkDiagnosticsClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterFanControlClusterServerInitCallback(EndpointId endpoint); +void ESPMatterFanControlClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterFaultInjectionClusterServerInitCallback(EndpointId endpoint); +void ESPMatterFaultInjectionClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterFixedLabelClusterServerInitCallback(EndpointId endpoint); +void ESPMatterFixedLabelClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterFlowMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterFlowMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterFormaldehydeConcentrationMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterFormaldehydeConcentrationMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterGeneralCommissioningClusterServerInitCallback(EndpointId endpoint); +void ESPMatterGeneralCommissioningClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterGeneralDiagnosticsClusterServerInitCallback(EndpointId endpoint); +void ESPMatterGeneralDiagnosticsClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterGroupKeyManagementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterGroupKeyManagementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterGroupsClusterServerInitCallback(EndpointId endpoint); +void ESPMatterGroupsClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterHepaFilterMonitoringClusterServerInitCallback(EndpointId endpoint); +void ESPMatterHepaFilterMonitoringClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterIcdManagementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterIcdManagementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterIdentifyClusterServerInitCallback(EndpointId endpoint); +void ESPMatterIdentifyClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterIlluminanceMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterIlluminanceMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterJointFabricAdministratorClusterServerInitCallback(EndpointId endpoint); +void ESPMatterJointFabricAdministratorClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterJointFabricDatastoreClusterServerInitCallback(EndpointId endpoint); +void ESPMatterJointFabricDatastoreClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterKeypadInputClusterServerInitCallback(EndpointId endpoint); +void ESPMatterKeypadInputClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterLaundryDryerControlsClusterServerInitCallback(EndpointId endpoint); +void ESPMatterLaundryDryerControlsClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterLaundryWasherControlsClusterServerInitCallback(EndpointId endpoint); +void ESPMatterLaundryWasherControlsClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterLaundryWasherModeClusterServerInitCallback(EndpointId endpoint); +void ESPMatterLaundryWasherModeClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterLevelControlClusterServerInitCallback(EndpointId endpoint); +void ESPMatterLevelControlClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterLocalizationConfigurationClusterServerInitCallback(EndpointId endpoint); +void ESPMatterLocalizationConfigurationClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterLowPowerClusterServerInitCallback(EndpointId endpoint); +void ESPMatterLowPowerClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterMediaInputClusterServerInitCallback(EndpointId endpoint); +void ESPMatterMediaInputClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterMediaPlaybackClusterServerInitCallback(EndpointId endpoint); +void ESPMatterMediaPlaybackClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterMessagesClusterServerInitCallback(EndpointId endpoint); +void ESPMatterMessagesClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterMeterIdentificationClusterServerInitCallback(EndpointId endpoint); +void ESPMatterMeterIdentificationClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterMicrowaveOvenControlClusterServerInitCallback(EndpointId endpoint); +void ESPMatterMicrowaveOvenControlClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterMicrowaveOvenModeClusterServerInitCallback(EndpointId endpoint); +void ESPMatterMicrowaveOvenModeClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterModeSelectClusterServerInitCallback(EndpointId endpoint); +void ESPMatterModeSelectClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterNetworkCommissioningClusterServerInitCallback(EndpointId endpoint); +void ESPMatterNetworkCommissioningClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterNitrogenDioxideConcentrationMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterNitrogenDioxideConcentrationMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterOccupancySensingClusterServerInitCallback(EndpointId endpoint); +void ESPMatterOccupancySensingClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterOnOffClusterServerInitCallback(EndpointId endpoint); +void ESPMatterOnOffClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterOperationalCredentialsClusterServerInitCallback(EndpointId endpoint); +void ESPMatterOperationalCredentialsClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterOperationalStateClusterServerInitCallback(EndpointId endpoint); +void ESPMatterOperationalStateClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterOtaSoftwareUpdateProviderClusterServerInitCallback(EndpointId endpoint); +void ESPMatterOtaSoftwareUpdateProviderClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterOtaSoftwareUpdateRequestorClusterServerInitCallback(EndpointId endpoint); +void ESPMatterOtaSoftwareUpdateRequestorClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterOvenCavityOperationalStateClusterServerInitCallback(EndpointId endpoint); +void ESPMatterOvenCavityOperationalStateClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterOvenModeClusterServerInitCallback(EndpointId endpoint); +void ESPMatterOvenModeClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterOzoneConcentrationMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterOzoneConcentrationMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterPm10ConcentrationMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterPm10ConcentrationMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterPm1ConcentrationMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterPm1ConcentrationMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterPm25ConcentrationMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterPm25ConcentrationMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterPowerSourceClusterServerInitCallback(EndpointId endpoint); +void ESPMatterPowerSourceClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterPowerSourceConfigurationClusterServerInitCallback(EndpointId endpoint); +void ESPMatterPowerSourceConfigurationClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterPowerTopologyClusterServerInitCallback(EndpointId endpoint); +void ESPMatterPowerTopologyClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterPressureMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterPressureMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterProxyConfigurationClusterServerInitCallback(EndpointId endpoint); +void ESPMatterProxyConfigurationClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterProxyDiscoveryClusterServerInitCallback(EndpointId endpoint); +void ESPMatterProxyDiscoveryClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterProxyValidClusterServerInitCallback(EndpointId endpoint); +void ESPMatterProxyValidClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterPulseWidthModulationClusterServerInitCallback(EndpointId endpoint); +void ESPMatterPulseWidthModulationClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterPumpConfigurationAndControlClusterServerInitCallback(EndpointId endpoint); +void ESPMatterPumpConfigurationAndControlClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterPushAvStreamTransportClusterServerInitCallback(EndpointId endpoint); +void ESPMatterPushAvStreamTransportClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterRadonConcentrationMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterRadonConcentrationMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterRefrigeratorAlarmClusterServerInitCallback(EndpointId endpoint); +void ESPMatterRefrigeratorAlarmClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterRefrigeratorAndTemperatureControlledCabinetModeClusterServerInitCallback(EndpointId endpoint); +void ESPMatterRefrigeratorAndTemperatureControlledCabinetModeClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterRelativeHumidityMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterRelativeHumidityMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterRvcCleanModeClusterServerInitCallback(EndpointId endpoint); +void ESPMatterRvcCleanModeClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterRvcOperationalStateClusterServerInitCallback(EndpointId endpoint); +void ESPMatterRvcOperationalStateClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterRvcRunModeClusterServerInitCallback(EndpointId endpoint); +void ESPMatterRvcRunModeClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterSampleMeiClusterServerInitCallback(EndpointId endpoint); +void ESPMatterSampleMeiClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterScenesManagementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterScenesManagementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterServiceAreaClusterServerInitCallback(EndpointId endpoint); +void ESPMatterServiceAreaClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterSmokeCoAlarmClusterServerInitCallback(EndpointId endpoint); +void ESPMatterSmokeCoAlarmClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterSoftwareDiagnosticsClusterServerInitCallback(EndpointId endpoint); +void ESPMatterSoftwareDiagnosticsClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterSoilMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterSoilMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterSwitchClusterServerInitCallback(EndpointId endpoint); +void ESPMatterSwitchClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterTargetNavigatorClusterServerInitCallback(EndpointId endpoint); +void ESPMatterTargetNavigatorClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterTemperatureControlClusterServerInitCallback(EndpointId endpoint); +void ESPMatterTemperatureControlClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterTemperatureMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterTemperatureMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterThermostatClusterServerInitCallback(EndpointId endpoint); +void ESPMatterThermostatClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterThermostatUserInterfaceConfigurationClusterServerInitCallback(EndpointId endpoint); +void ESPMatterThermostatUserInterfaceConfigurationClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterThreadBorderRouterManagementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterThreadBorderRouterManagementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterThreadNetworkDiagnosticsClusterServerInitCallback(EndpointId endpoint); +void ESPMatterThreadNetworkDiagnosticsClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterThreadNetworkDirectoryClusterServerInitCallback(EndpointId endpoint); +void ESPMatterThreadNetworkDirectoryClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterTimeFormatLocalizationClusterServerInitCallback(EndpointId endpoint); +void ESPMatterTimeFormatLocalizationClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterTimeSynchronizationClusterServerInitCallback(EndpointId endpoint); +void ESPMatterTimeSynchronizationClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterTlsCertificateManagementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterTlsCertificateManagementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterTlsClientManagementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterTlsClientManagementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterTotalVolatileOrganicCompoundsConcentrationMeasurementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterTotalVolatileOrganicCompoundsConcentrationMeasurementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterUnitLocalizationClusterServerInitCallback(EndpointId endpoint); +void ESPMatterUnitLocalizationClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterUnitTestingClusterServerInitCallback(EndpointId endpoint); +void ESPMatterUnitTestingClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterUserLabelClusterServerInitCallback(EndpointId endpoint); +void ESPMatterUserLabelClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterValveConfigurationAndControlClusterServerInitCallback(EndpointId endpoint); +void ESPMatterValveConfigurationAndControlClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterWakeOnLanClusterServerInitCallback(EndpointId endpoint); +void ESPMatterWakeOnLanClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterWaterHeaterManagementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterWaterHeaterManagementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterWaterHeaterModeClusterServerInitCallback(EndpointId endpoint); +void ESPMatterWaterHeaterModeClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterWebRTCTransportProviderClusterServerInitCallback(EndpointId endpoint); +void ESPMatterWebRTCTransportProviderClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterWebRTCTransportRequestorClusterServerInitCallback(EndpointId endpoint); +void ESPMatterWebRTCTransportRequestorClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterWiFiNetworkDiagnosticsClusterServerInitCallback(EndpointId endpoint); +void ESPMatterWiFiNetworkDiagnosticsClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterWiFiNetworkManagementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterWiFiNetworkManagementClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterWindowCoveringClusterServerInitCallback(EndpointId endpoint); +void ESPMatterWindowCoveringClusterServerShutdownCallback(EndpointId endpoint); + +void ESPMatterZoneManagementClusterServerInitCallback(EndpointId endpoint); +void ESPMatterZoneManagementClusterServerShutdownCallback(EndpointId endpoint); + diff --git a/components/esp_matter/zap_common/app/PluginApplicationCallbacks.h b/components/esp_matter/zap_common/app/PluginApplicationCallbacks.h index b8535b5ad..bbfeb2c72 100644 --- a/components/esp_matter/zap_common/app/PluginApplicationCallbacks.h +++ b/components/esp_matter/zap_common/app/PluginApplicationCallbacks.h @@ -138,7 +138,3 @@ void MatterWiFiNetworkDiagnosticsPluginServerInitCallback(); void MatterWiFiNetworkManagementPluginServerInitCallback(); void MatterWindowCoveringPluginServerInitCallback(); void MatterZoneManagementPluginServerInitCallback(); - -#include - -#define MATTER_PLUGINS_INIT esp_matter::cluster::plugin_init_callback_common(); diff --git a/components/esp_matter/zap_common/app/callback-stub.cpp b/components/esp_matter/zap_common/app/callback-stub.cpp deleted file mode 100644 index 81432252b..000000000 --- a/components/esp_matter/zap_common/app/callback-stub.cpp +++ /dev/null @@ -1,698 +0,0 @@ -#include - -using namespace chip; -void __attribute__((weak)) emberAfAccessControlClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfAccountLoginClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfActionsClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfActivatedCarbonFilterMonitoringClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfAdministratorCommissioningClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfAirQualityClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfApplicationBasicClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfApplicationLauncherClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfAudioOutputClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfBallastConfigurationClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfBasicInformationClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfBindingClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfBooleanStateClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfBooleanStateConfigurationClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfBridgedDeviceBasicInformationClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfCameraAvSettingsUserLevelManagementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfCameraAvStreamManagementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfCarbonDioxideConcentrationMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfCarbonMonoxideConcentrationMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfChannelClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfChimeClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfClosureControlClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfClosureDimensionClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfColorControlClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfCommissionerControlClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfCommodityMeteringClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfCommodityPriceClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfCommodityTariffClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfContentAppObserverClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfContentControlClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfContentLauncherClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfDescriptorClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfDeviceEnergyManagementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfDeviceEnergyManagementModeClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfDiagnosticLogsClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfDishwasherAlarmClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfDishwasherModeClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfDoorLockClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfEcosystemInformationClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfElectricalEnergyMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfElectricalGridConditionsClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfElectricalPowerMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfEnergyEvseClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfEnergyEvseModeClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfEnergyPreferenceClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfEthernetNetworkDiagnosticsClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfFanControlClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfFaultInjectionClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfFixedLabelClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfFlowMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfFormaldehydeConcentrationMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfGeneralCommissioningClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfGeneralDiagnosticsClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfGroupKeyManagementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfGroupsClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfHepaFilterMonitoringClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfIcdManagementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfIdentifyClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfIlluminanceMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfJointFabricAdministratorClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfJointFabricDatastoreClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfKeypadInputClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfLaundryDryerControlsClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfLaundryWasherControlsClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfLaundryWasherModeClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfLevelControlClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfLocalizationConfigurationClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfLowPowerClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfMediaInputClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfMediaPlaybackClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfMessagesClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfMeterIdentificationClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfMicrowaveOvenControlClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfMicrowaveOvenModeClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfModeSelectClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfNetworkCommissioningClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfNitrogenDioxideConcentrationMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfOccupancySensingClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfOnOffClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfOperationalCredentialsClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfOperationalStateClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfOtaSoftwareUpdateProviderClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfOtaSoftwareUpdateRequestorClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfOvenCavityOperationalStateClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfOvenModeClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfOzoneConcentrationMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfPm10ConcentrationMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfPm1ConcentrationMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfPm25ConcentrationMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfPowerSourceClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfPowerSourceConfigurationClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfPowerTopologyClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfPressureMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfProxyConfigurationClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfProxyDiscoveryClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfProxyValidClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfPulseWidthModulationClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfPumpConfigurationAndControlClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfPushAvStreamTransportClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfRadonConcentrationMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfRefrigeratorAlarmClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfRefrigeratorAndTemperatureControlledCabinetModeClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfRelativeHumidityMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfRvcCleanModeClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfRvcOperationalStateClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfRvcRunModeClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfSampleMeiClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfScenesManagementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfServiceAreaClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfSmokeCoAlarmClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfSoftwareDiagnosticsClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfSoilMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfSwitchClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfTargetNavigatorClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfTemperatureControlClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfTemperatureMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfThermostatClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfThermostatUserInterfaceConfigurationClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfThreadBorderRouterManagementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfThreadNetworkDiagnosticsClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfThreadNetworkDirectoryClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfTimeFormatLocalizationClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfTimeSynchronizationClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfTlsCertificateManagementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfTlsClientManagementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfTotalVolatileOrganicCompoundsConcentrationMeasurementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfUnitLocalizationClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfUnitTestingClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfUserLabelClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfValveConfigurationAndControlClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfWakeOnLanClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfWaterHeaterManagementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfWaterHeaterModeClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfWebRTCTransportProviderClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfWebRTCTransportRequestorClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfWiFiNetworkDiagnosticsClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfWiFiNetworkManagementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfWindowCoveringClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} -void __attribute__((weak)) emberAfZoneManagementClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} diff --git a/components/esp_matter/zap_common/app/cluster-init-callback.cpp b/components/esp_matter/zap_common/app/cluster-init-callback.cpp deleted file mode 100644 index de22ca245..000000000 --- a/components/esp_matter/zap_common/app/cluster-init-callback.cpp +++ /dev/null @@ -1,434 +0,0 @@ -#include -#include -#include -#include - -using namespace chip; - -// Cluster Init Functions -void emberAfClusterInitCallback(EndpointId endpoint, ClusterId clusterId) -{ - switch (clusterId) - { - case app::Clusters::AccessControl::Id: - emberAfAccessControlClusterInitCallback(endpoint); - break; - case app::Clusters::AccountLogin::Id: - emberAfAccountLoginClusterInitCallback(endpoint); - break; - case app::Clusters::Actions::Id: - emberAfActionsClusterInitCallback(endpoint); - break; - case app::Clusters::ActivatedCarbonFilterMonitoring::Id: - emberAfActivatedCarbonFilterMonitoringClusterInitCallback(endpoint); - break; - case app::Clusters::AdministratorCommissioning::Id: - emberAfAdministratorCommissioningClusterInitCallback(endpoint); - break; - case app::Clusters::AirQuality::Id: - emberAfAirQualityClusterInitCallback(endpoint); - break; - case app::Clusters::ApplicationBasic::Id: - emberAfApplicationBasicClusterInitCallback(endpoint); - break; - case app::Clusters::ApplicationLauncher::Id: - emberAfApplicationLauncherClusterInitCallback(endpoint); - break; - case app::Clusters::AudioOutput::Id: - emberAfAudioOutputClusterInitCallback(endpoint); - break; - case app::Clusters::BallastConfiguration::Id: - emberAfBallastConfigurationClusterInitCallback(endpoint); - break; - case app::Clusters::BasicInformation::Id: - emberAfBasicInformationClusterInitCallback(endpoint); - break; - case app::Clusters::Binding::Id: - emberAfBindingClusterInitCallback(endpoint); - break; - case app::Clusters::BooleanState::Id: - emberAfBooleanStateClusterInitCallback(endpoint); - break; - case app::Clusters::BooleanStateConfiguration::Id: - emberAfBooleanStateConfigurationClusterInitCallback(endpoint); - break; - case app::Clusters::BridgedDeviceBasicInformation::Id: - emberAfBridgedDeviceBasicInformationClusterInitCallback(endpoint); - break; - case app::Clusters::CameraAvSettingsUserLevelManagement::Id: - emberAfCameraAvSettingsUserLevelManagementClusterInitCallback(endpoint); - break; - case app::Clusters::CameraAvStreamManagement::Id: - emberAfCameraAvStreamManagementClusterInitCallback(endpoint); - break; - case app::Clusters::CarbonDioxideConcentrationMeasurement::Id: - emberAfCarbonDioxideConcentrationMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::CarbonMonoxideConcentrationMeasurement::Id: - emberAfCarbonMonoxideConcentrationMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::Channel::Id: - emberAfChannelClusterInitCallback(endpoint); - break; - case app::Clusters::Chime::Id: - emberAfChimeClusterInitCallback(endpoint); - break; - case app::Clusters::ClosureControl::Id: - emberAfClosureControlClusterInitCallback(endpoint); - break; - case app::Clusters::ClosureDimension::Id: - emberAfClosureDimensionClusterInitCallback(endpoint); - break; - case app::Clusters::ColorControl::Id: - emberAfColorControlClusterInitCallback(endpoint); - break; - case app::Clusters::CommissionerControl::Id: - emberAfCommissionerControlClusterInitCallback(endpoint); - break; - case app::Clusters::CommodityMetering::Id: - emberAfCommodityMeteringClusterInitCallback(endpoint); - break; - case app::Clusters::CommodityPrice::Id: - emberAfCommodityPriceClusterInitCallback(endpoint); - break; - case app::Clusters::CommodityTariff::Id: - emberAfCommodityTariffClusterInitCallback(endpoint); - break; - case app::Clusters::ContentAppObserver::Id: - emberAfContentAppObserverClusterInitCallback(endpoint); - break; - case app::Clusters::ContentControl::Id: - emberAfContentControlClusterInitCallback(endpoint); - break; - case app::Clusters::ContentLauncher::Id: - emberAfContentLauncherClusterInitCallback(endpoint); - break; - case app::Clusters::Descriptor::Id: - emberAfDescriptorClusterInitCallback(endpoint); - break; - case app::Clusters::DeviceEnergyManagement::Id: - emberAfDeviceEnergyManagementClusterInitCallback(endpoint); - break; - case app::Clusters::DeviceEnergyManagementMode::Id: - emberAfDeviceEnergyManagementModeClusterInitCallback(endpoint); - break; - case app::Clusters::DiagnosticLogs::Id: - emberAfDiagnosticLogsClusterInitCallback(endpoint); - break; - case app::Clusters::DishwasherAlarm::Id: - emberAfDishwasherAlarmClusterInitCallback(endpoint); - break; - case app::Clusters::DishwasherMode::Id: - emberAfDishwasherModeClusterInitCallback(endpoint); - break; - case app::Clusters::DoorLock::Id: - emberAfDoorLockClusterInitCallback(endpoint); - break; - case app::Clusters::EcosystemInformation::Id: - emberAfEcosystemInformationClusterInitCallback(endpoint); - break; - case app::Clusters::ElectricalEnergyMeasurement::Id: - emberAfElectricalEnergyMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::ElectricalGridConditions::Id: - emberAfElectricalGridConditionsClusterInitCallback(endpoint); - break; - case app::Clusters::ElectricalPowerMeasurement::Id: - emberAfElectricalPowerMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::EnergyEvse::Id: - emberAfEnergyEvseClusterInitCallback(endpoint); - break; - case app::Clusters::EnergyEvseMode::Id: - emberAfEnergyEvseModeClusterInitCallback(endpoint); - break; - case app::Clusters::EnergyPreference::Id: - emberAfEnergyPreferenceClusterInitCallback(endpoint); - break; - case app::Clusters::EthernetNetworkDiagnostics::Id: - emberAfEthernetNetworkDiagnosticsClusterInitCallback(endpoint); - break; - case app::Clusters::FanControl::Id: - emberAfFanControlClusterInitCallback(endpoint); - break; - case app::Clusters::FaultInjection::Id: - emberAfFaultInjectionClusterInitCallback(endpoint); - break; - case app::Clusters::FixedLabel::Id: - emberAfFixedLabelClusterInitCallback(endpoint); - break; - case app::Clusters::FlowMeasurement::Id: - emberAfFlowMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::FormaldehydeConcentrationMeasurement::Id: - emberAfFormaldehydeConcentrationMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::GeneralCommissioning::Id: - emberAfGeneralCommissioningClusterInitCallback(endpoint); - break; - case app::Clusters::GeneralDiagnostics::Id: - emberAfGeneralDiagnosticsClusterInitCallback(endpoint); - break; - case app::Clusters::GroupKeyManagement::Id: - emberAfGroupKeyManagementClusterInitCallback(endpoint); - break; - case app::Clusters::Groups::Id: - emberAfGroupsClusterInitCallback(endpoint); - break; - case app::Clusters::HepaFilterMonitoring::Id: - emberAfHepaFilterMonitoringClusterInitCallback(endpoint); - break; - case app::Clusters::IcdManagement::Id: - emberAfIcdManagementClusterInitCallback(endpoint); - break; - case app::Clusters::Identify::Id: - emberAfIdentifyClusterInitCallback(endpoint); - break; - case app::Clusters::IlluminanceMeasurement::Id: - emberAfIlluminanceMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::JointFabricAdministrator::Id: - emberAfJointFabricAdministratorClusterInitCallback(endpoint); - break; - case app::Clusters::JointFabricDatastore::Id: - emberAfJointFabricDatastoreClusterInitCallback(endpoint); - break; - case app::Clusters::KeypadInput::Id: - emberAfKeypadInputClusterInitCallback(endpoint); - break; - case app::Clusters::LaundryDryerControls::Id: - emberAfLaundryDryerControlsClusterInitCallback(endpoint); - break; - case app::Clusters::LaundryWasherControls::Id: - emberAfLaundryWasherControlsClusterInitCallback(endpoint); - break; - case app::Clusters::LaundryWasherMode::Id: - emberAfLaundryWasherModeClusterInitCallback(endpoint); - break; - case app::Clusters::LevelControl::Id: - emberAfLevelControlClusterInitCallback(endpoint); - break; - case app::Clusters::LocalizationConfiguration::Id: - emberAfLocalizationConfigurationClusterInitCallback(endpoint); - break; - case app::Clusters::LowPower::Id: - emberAfLowPowerClusterInitCallback(endpoint); - break; - case app::Clusters::MediaInput::Id: - emberAfMediaInputClusterInitCallback(endpoint); - break; - case app::Clusters::MediaPlayback::Id: - emberAfMediaPlaybackClusterInitCallback(endpoint); - break; - case app::Clusters::Messages::Id: - emberAfMessagesClusterInitCallback(endpoint); - break; - case app::Clusters::MeterIdentification::Id: - emberAfMeterIdentificationClusterInitCallback(endpoint); - break; - case app::Clusters::MicrowaveOvenControl::Id: - emberAfMicrowaveOvenControlClusterInitCallback(endpoint); - break; - case app::Clusters::MicrowaveOvenMode::Id: - emberAfMicrowaveOvenModeClusterInitCallback(endpoint); - break; - case app::Clusters::ModeSelect::Id: - emberAfModeSelectClusterInitCallback(endpoint); - break; - case app::Clusters::NetworkCommissioning::Id: - emberAfNetworkCommissioningClusterInitCallback(endpoint); - break; - case app::Clusters::NitrogenDioxideConcentrationMeasurement::Id: - emberAfNitrogenDioxideConcentrationMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::OccupancySensing::Id: - emberAfOccupancySensingClusterInitCallback(endpoint); - break; - case app::Clusters::OnOff::Id: - emberAfOnOffClusterInitCallback(endpoint); - break; - case app::Clusters::OperationalCredentials::Id: - emberAfOperationalCredentialsClusterInitCallback(endpoint); - break; - case app::Clusters::OperationalState::Id: - emberAfOperationalStateClusterInitCallback(endpoint); - break; - case app::Clusters::OtaSoftwareUpdateProvider::Id: - emberAfOtaSoftwareUpdateProviderClusterInitCallback(endpoint); - break; - case app::Clusters::OtaSoftwareUpdateRequestor::Id: - emberAfOtaSoftwareUpdateRequestorClusterInitCallback(endpoint); - break; - case app::Clusters::OvenCavityOperationalState::Id: - emberAfOvenCavityOperationalStateClusterInitCallback(endpoint); - break; - case app::Clusters::OvenMode::Id: - emberAfOvenModeClusterInitCallback(endpoint); - break; - case app::Clusters::OzoneConcentrationMeasurement::Id: - emberAfOzoneConcentrationMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::Pm10ConcentrationMeasurement::Id: - emberAfPm10ConcentrationMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::Pm1ConcentrationMeasurement::Id: - emberAfPm1ConcentrationMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::Pm25ConcentrationMeasurement::Id: - emberAfPm25ConcentrationMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::PowerSource::Id: - emberAfPowerSourceClusterInitCallback(endpoint); - break; - case app::Clusters::PowerSourceConfiguration::Id: - emberAfPowerSourceConfigurationClusterInitCallback(endpoint); - break; - case app::Clusters::PowerTopology::Id: - emberAfPowerTopologyClusterInitCallback(endpoint); - break; - case app::Clusters::PressureMeasurement::Id: - emberAfPressureMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::ProxyConfiguration::Id: - emberAfProxyConfigurationClusterInitCallback(endpoint); - break; - case app::Clusters::ProxyDiscovery::Id: - emberAfProxyDiscoveryClusterInitCallback(endpoint); - break; - case app::Clusters::ProxyValid::Id: - emberAfProxyValidClusterInitCallback(endpoint); - break; - case app::Clusters::PulseWidthModulation::Id: - emberAfPulseWidthModulationClusterInitCallback(endpoint); - break; - case app::Clusters::PumpConfigurationAndControl::Id: - emberAfPumpConfigurationAndControlClusterInitCallback(endpoint); - break; - case app::Clusters::PushAvStreamTransport::Id: - emberAfPushAvStreamTransportClusterInitCallback(endpoint); - break; - case app::Clusters::RadonConcentrationMeasurement::Id: - emberAfRadonConcentrationMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::RefrigeratorAlarm::Id: - emberAfRefrigeratorAlarmClusterInitCallback(endpoint); - break; - case app::Clusters::RefrigeratorAndTemperatureControlledCabinetMode::Id: - emberAfRefrigeratorAndTemperatureControlledCabinetModeClusterInitCallback(endpoint); - break; - case app::Clusters::RelativeHumidityMeasurement::Id: - emberAfRelativeHumidityMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::RvcCleanMode::Id: - emberAfRvcCleanModeClusterInitCallback(endpoint); - break; - case app::Clusters::RvcOperationalState::Id: - emberAfRvcOperationalStateClusterInitCallback(endpoint); - break; - case app::Clusters::RvcRunMode::Id: - emberAfRvcRunModeClusterInitCallback(endpoint); - break; - case app::Clusters::SampleMei::Id: - emberAfSampleMeiClusterInitCallback(endpoint); - break; - case app::Clusters::ScenesManagement::Id: - emberAfScenesManagementClusterInitCallback(endpoint); - break; - case app::Clusters::ServiceArea::Id: - emberAfServiceAreaClusterInitCallback(endpoint); - break; - case app::Clusters::SmokeCoAlarm::Id: - emberAfSmokeCoAlarmClusterInitCallback(endpoint); - break; - case app::Clusters::SoftwareDiagnostics::Id: - emberAfSoftwareDiagnosticsClusterInitCallback(endpoint); - break; - case app::Clusters::SoilMeasurement::Id: - emberAfSoilMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::Switch::Id: - emberAfSwitchClusterInitCallback(endpoint); - break; - case app::Clusters::TargetNavigator::Id: - emberAfTargetNavigatorClusterInitCallback(endpoint); - break; - case app::Clusters::TemperatureControl::Id: - emberAfTemperatureControlClusterInitCallback(endpoint); - break; - case app::Clusters::TemperatureMeasurement::Id: - emberAfTemperatureMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::Thermostat::Id: - emberAfThermostatClusterInitCallback(endpoint); - break; - case app::Clusters::ThermostatUserInterfaceConfiguration::Id: - emberAfThermostatUserInterfaceConfigurationClusterInitCallback(endpoint); - break; - case app::Clusters::ThreadBorderRouterManagement::Id: - emberAfThreadBorderRouterManagementClusterInitCallback(endpoint); - break; - case app::Clusters::ThreadNetworkDiagnostics::Id: - emberAfThreadNetworkDiagnosticsClusterInitCallback(endpoint); - break; - case app::Clusters::ThreadNetworkDirectory::Id: - emberAfThreadNetworkDirectoryClusterInitCallback(endpoint); - break; - case app::Clusters::TimeFormatLocalization::Id: - emberAfTimeFormatLocalizationClusterInitCallback(endpoint); - break; - case app::Clusters::TimeSynchronization::Id: - emberAfTimeSynchronizationClusterInitCallback(endpoint); - break; - case app::Clusters::TlsCertificateManagement::Id: - emberAfTlsCertificateManagementClusterInitCallback(endpoint); - break; - case app::Clusters::TlsClientManagement::Id: - emberAfTlsClientManagementClusterInitCallback(endpoint); - break; - case app::Clusters::TotalVolatileOrganicCompoundsConcentrationMeasurement::Id: - emberAfTotalVolatileOrganicCompoundsConcentrationMeasurementClusterInitCallback(endpoint); - break; - case app::Clusters::UnitLocalization::Id: - emberAfUnitLocalizationClusterInitCallback(endpoint); - break; - case app::Clusters::UnitTesting::Id: - emberAfUnitTestingClusterInitCallback(endpoint); - break; - case app::Clusters::UserLabel::Id: - emberAfUserLabelClusterInitCallback(endpoint); - break; - case app::Clusters::ValveConfigurationAndControl::Id: - emberAfValveConfigurationAndControlClusterInitCallback(endpoint); - break; - case app::Clusters::WakeOnLan::Id: - emberAfWakeOnLanClusterInitCallback(endpoint); - break; - case app::Clusters::WaterHeaterManagement::Id: - emberAfWaterHeaterManagementClusterInitCallback(endpoint); - break; - case app::Clusters::WaterHeaterMode::Id: - emberAfWaterHeaterModeClusterInitCallback(endpoint); - break; - case app::Clusters::WebRTCTransportProvider::Id: - emberAfWebRTCTransportProviderClusterInitCallback(endpoint); - break; - case app::Clusters::WebRTCTransportRequestor::Id: - emberAfWebRTCTransportRequestorClusterInitCallback(endpoint); - break; - case app::Clusters::WiFiNetworkDiagnostics::Id: - emberAfWiFiNetworkDiagnosticsClusterInitCallback(endpoint); - break; - case app::Clusters::WiFiNetworkManagement::Id: - emberAfWiFiNetworkManagementClusterInitCallback(endpoint); - break; - case app::Clusters::WindowCovering::Id: - emberAfWindowCoveringClusterInitCallback(endpoint); - break; - case app::Clusters::ZoneManagement::Id: - emberAfZoneManagementClusterInitCallback(endpoint); - break; - default: - // Unrecognized cluster ID - break; - } -} diff --git a/components/esp_matter/zap_common/generate_zap_common_files.py b/components/esp_matter/zap_common/generate_zap_common_files.py index 439a00b0f..876e53f1c 100755 --- a/components/esp_matter/zap_common/generate_zap_common_files.py +++ b/components/esp_matter/zap_common/generate_zap_common_files.py @@ -113,63 +113,18 @@ def generate_plugin_application_callbacks_h(xml_files, output_dir): header_file.write('void Matter{}PluginServerInitCallback();\n'.format( format_cluster_name(get_cluster_name(cluster)))) - header_file.writelines( - ['\n', - '#include \n', - '\n', - '#define MATTER_PLUGINS_INIT esp_matter::cluster::plugin_init_callback_common();\n']) - - -def generate_callback_stub_cpp(xml_files, output_dir): - with open(os.path.join(output_dir, 'app/callback-stub.cpp'), 'w') as src_file: - src_file.writelines( - ['#include \n', - '\n', - 'using namespace chip;\n']) +def generate_cluster_callbacks_h(xml_files, output_dir): + with open(os.path.join(output_dir, 'app/ClusterCallbacks.h'), 'w') as header_file: + header_file.write('#pragma once\n\n') + header_file.write('#include \n\n') + header_file.write('using chip::EndpointId;\n\n') clusters = get_clusters_from_xml_files(xml_files) clusters.sort(key=get_formatted_cluster_name) for cluster in clusters: - src_file.write('void __attribute__((weak)) emberAf{}ClusterInitCallback(EndpointId endpoint)\n'.format( + header_file.write('void ESPMatter{}ClusterServerInitCallback(EndpointId endpoint);\n'.format( + format_cluster_name(get_cluster_name(cluster)))) + header_file.write('void ESPMatter{}ClusterServerShutdownCallback(EndpointId endpoint);\n\n'.format( format_cluster_name(get_cluster_name(cluster)))) - src_file.writelines( - ['{\n', - ' // To prevent warning\n', - ' (void) endpoint;\n' - '}\n']) - - -def generate_cluster_init_callback_cpp(xml_files, output_dir): - with open(os.path.join(output_dir, 'app/cluster-init-callback.cpp'), 'w') as src_file: - src_file.writelines( - ['#include \n', - '#include \n', - '#include \n', - '#include \n', - '\n', - 'using namespace chip;\n', - '\n', - '// Cluster Init Functions\n', - 'void emberAfClusterInitCallback(EndpointId endpoint, ClusterId clusterId)\n', - '{\n', - ' switch (clusterId)\n', - ' {\n']) - clusters = get_clusters_from_xml_files(xml_files) - clusters.sort(key=get_formatted_cluster_name) - for cluster in clusters: - formatted_cluster_name = format_cluster_name( - get_cluster_name(cluster)) - src_file.writelines( - [' case app::Clusters::{}::Id:\n'.format(formatted_cluster_name), - ' emberAf{}ClusterInitCallback(endpoint);\n'.format( - formatted_cluster_name), - ' break;\n']) - - src_file.writelines( - [' default:\n', - ' // Unrecognized cluster ID\n', - ' break;\n', - ' }\n', - '}\n']) def get_attribute_read_privilege(attribute): @@ -274,8 +229,6 @@ def get_privileges(clusters): return attribute_read_privileges, attribute_write_privileges, command_invoke_privileges, event_read_privileges - - def get_privileges_array(privileges, array_type, interaction_type, object_type): if array_type == 'cluster': array = '// Parallel array data (*cluster*, {}, privilege) for {} {}\n'.format( @@ -345,8 +298,7 @@ def main(): args = get_args() xml_files = glob.glob(os.path.join(args.xml_dir, '*.xml')) generate_plugin_application_callbacks_h(xml_files, args.output_dir) - generate_callback_stub_cpp(xml_files, args.output_dir) - generate_cluster_init_callback_cpp(xml_files, args.output_dir) + generate_cluster_callbacks_h(xml_files, args.output_dir) generate_access_h(xml_files, args.output_dir) diff --git a/components/esp_matter/zap_common/zap-generated/access.h b/components/esp_matter/zap_common/zap-generated/access.h index 20d66c17d..c75f6cfcd 100644 --- a/components/esp_matter/zap_common/zap-generated/access.h +++ b/components/esp_matter/zap_common/zap-generated/access.h @@ -75,6 +75,7 @@ 0x00000752, /* Cluster: Joint Fabric Datastore, Attribute: NodeACLList, Privilege: administer */ \ 0x00000752, /* Cluster: Joint Fabric Datastore, Attribute: NodeEndpointList, Privilege: administer */ \ 0x00000753, /* Cluster: Joint Fabric Administrator, Attribute: AdministratorFabricIndex, Privilege: administer */ \ + 0xFFF1FC05, /* Cluster: Unit Testing, Attribute: UnsupportedAttributeRequiringAdminPrivilege, Privilege: administer */ \ } // Parallel array data (cluster, *attribute*, privilege) for read attribute @@ -145,6 +146,7 @@ 0x0000000C, /* Cluster: Joint Fabric Datastore, Attribute: NodeACLList, Privilege: administer */ \ 0x0000000D, /* Cluster: Joint Fabric Datastore, Attribute: NodeEndpointList, Privilege: administer */ \ 0x00000000, /* Cluster: Joint Fabric Administrator, Attribute: AdministratorFabricIndex, Privilege: administer */ \ + 0x000000FE, /* Cluster: Unit Testing, Attribute: UnsupportedAttributeRequiringAdminPrivilege, Privilege: administer */ \ } // Parallel array data (cluster, attribute, *privilege*) for read attribute @@ -215,6 +217,7 @@ chip::Access::Privilege::kAdminister, /* Cluster: Joint Fabric Datastore, Attribute: NodeACLList, Privilege: administer */ \ chip::Access::Privilege::kAdminister, /* Cluster: Joint Fabric Datastore, Attribute: NodeEndpointList, Privilege: administer */ \ chip::Access::Privilege::kAdminister, /* Cluster: Joint Fabric Administrator, Attribute: AdministratorFabricIndex, Privilege: administer */ \ + chip::Access::Privilege::kAdminister, /* Cluster: Unit Testing, Attribute: UnsupportedAttributeRequiringAdminPrivilege, Privilege: administer */ \ } //////////////////////////////////////////////////////////////////////////////// @@ -293,17 +296,6 @@ 0x00000201, /* Cluster: Thermostat, Attribute: Schedules, Privilege: manage */ \ 0x00000204, /* Cluster: Thermostat User Interface Configuration, Attribute: KeypadLockout, Privilege: manage */ \ 0x00000204, /* Cluster: Thermostat User Interface Configuration, Attribute: ScheduleProgrammingVisibility, Privilege: manage */ \ - 0x00000300, /* Cluster: Color Control, Attribute: WhitePointX, Privilege: manage */ \ - 0x00000300, /* Cluster: Color Control, Attribute: WhitePointY, Privilege: manage */ \ - 0x00000300, /* Cluster: Color Control, Attribute: ColorPointRX, Privilege: manage */ \ - 0x00000300, /* Cluster: Color Control, Attribute: ColorPointRY, Privilege: manage */ \ - 0x00000300, /* Cluster: Color Control, Attribute: ColorPointRIntensity, Privilege: manage */ \ - 0x00000300, /* Cluster: Color Control, Attribute: ColorPointGX, Privilege: manage */ \ - 0x00000300, /* Cluster: Color Control, Attribute: ColorPointGY, Privilege: manage */ \ - 0x00000300, /* Cluster: Color Control, Attribute: ColorPointGIntensity, Privilege: manage */ \ - 0x00000300, /* Cluster: Color Control, Attribute: ColorPointBX, Privilege: manage */ \ - 0x00000300, /* Cluster: Color Control, Attribute: ColorPointBY, Privilege: manage */ \ - 0x00000300, /* Cluster: Color Control, Attribute: ColorPointBIntensity, Privilege: manage */ \ 0x00000300, /* Cluster: Color Control, Attribute: StartUpColorTemperatureMireds, Privilege: manage */ \ 0x00000301, /* Cluster: Ballast Configuration, Attribute: MinLevel, Privilege: manage */ \ 0x00000301, /* Cluster: Ballast Configuration, Attribute: MaxLevel, Privilege: manage */ \ @@ -342,6 +334,7 @@ 0x00000551, /* Cluster: Camera AV Stream Management, Attribute: LocalSnapshotRecordingEnabled, Privilege: manage */ \ 0x00000551, /* Cluster: Camera AV Stream Management, Attribute: StatusLightEnabled, Privilege: manage */ \ 0x00000551, /* Cluster: Camera AV Stream Management, Attribute: StatusLightBrightness, Privilege: manage */ \ + 0xFFF1FC05, /* Cluster: Unit Testing, Attribute: UnsupportedAttributeRequiringAdminPrivilege, Privilege: administer */ \ } // Parallel array data (cluster, *attribute*, privilege) for write attribute @@ -418,17 +411,6 @@ 0x00000051, /* Cluster: Thermostat, Attribute: Schedules, Privilege: manage */ \ 0x00000001, /* Cluster: Thermostat User Interface Configuration, Attribute: KeypadLockout, Privilege: manage */ \ 0x00000002, /* Cluster: Thermostat User Interface Configuration, Attribute: ScheduleProgrammingVisibility, Privilege: manage */ \ - 0x00000030, /* Cluster: Color Control, Attribute: WhitePointX, Privilege: manage */ \ - 0x00000031, /* Cluster: Color Control, Attribute: WhitePointY, Privilege: manage */ \ - 0x00000032, /* Cluster: Color Control, Attribute: ColorPointRX, Privilege: manage */ \ - 0x00000033, /* Cluster: Color Control, Attribute: ColorPointRY, Privilege: manage */ \ - 0x00000034, /* Cluster: Color Control, Attribute: ColorPointRIntensity, Privilege: manage */ \ - 0x00000036, /* Cluster: Color Control, Attribute: ColorPointGX, Privilege: manage */ \ - 0x00000037, /* Cluster: Color Control, Attribute: ColorPointGY, Privilege: manage */ \ - 0x00000038, /* Cluster: Color Control, Attribute: ColorPointGIntensity, Privilege: manage */ \ - 0x0000003A, /* Cluster: Color Control, Attribute: ColorPointBX, Privilege: manage */ \ - 0x0000003B, /* Cluster: Color Control, Attribute: ColorPointBY, Privilege: manage */ \ - 0x0000003C, /* Cluster: Color Control, Attribute: ColorPointBIntensity, Privilege: manage */ \ 0x00004010, /* Cluster: Color Control, Attribute: StartUpColorTemperatureMireds, Privilege: manage */ \ 0x00000010, /* Cluster: Ballast Configuration, Attribute: MinLevel, Privilege: manage */ \ 0x00000011, /* Cluster: Ballast Configuration, Attribute: MaxLevel, Privilege: manage */ \ @@ -467,6 +449,7 @@ 0x00000026, /* Cluster: Camera AV Stream Management, Attribute: LocalSnapshotRecordingEnabled, Privilege: manage */ \ 0x00000027, /* Cluster: Camera AV Stream Management, Attribute: StatusLightEnabled, Privilege: manage */ \ 0x00000028, /* Cluster: Camera AV Stream Management, Attribute: StatusLightBrightness, Privilege: manage */ \ + 0x000000FE, /* Cluster: Unit Testing, Attribute: UnsupportedAttributeRequiringAdminPrivilege, Privilege: administer */ \ } // Parallel array data (cluster, attribute, *privilege*) for write attribute @@ -543,17 +526,6 @@ chip::Access::Privilege::kManage, /* Cluster: Thermostat, Attribute: Schedules, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Thermostat User Interface Configuration, Attribute: KeypadLockout, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Thermostat User Interface Configuration, Attribute: ScheduleProgrammingVisibility, Privilege: manage */ \ - chip::Access::Privilege::kManage, /* Cluster: Color Control, Attribute: WhitePointX, Privilege: manage */ \ - chip::Access::Privilege::kManage, /* Cluster: Color Control, Attribute: WhitePointY, Privilege: manage */ \ - chip::Access::Privilege::kManage, /* Cluster: Color Control, Attribute: ColorPointRX, Privilege: manage */ \ - chip::Access::Privilege::kManage, /* Cluster: Color Control, Attribute: ColorPointRY, Privilege: manage */ \ - chip::Access::Privilege::kManage, /* Cluster: Color Control, Attribute: ColorPointRIntensity, Privilege: manage */ \ - chip::Access::Privilege::kManage, /* Cluster: Color Control, Attribute: ColorPointGX, Privilege: manage */ \ - chip::Access::Privilege::kManage, /* Cluster: Color Control, Attribute: ColorPointGY, Privilege: manage */ \ - chip::Access::Privilege::kManage, /* Cluster: Color Control, Attribute: ColorPointGIntensity, Privilege: manage */ \ - chip::Access::Privilege::kManage, /* Cluster: Color Control, Attribute: ColorPointBX, Privilege: manage */ \ - chip::Access::Privilege::kManage, /* Cluster: Color Control, Attribute: ColorPointBY, Privilege: manage */ \ - chip::Access::Privilege::kManage, /* Cluster: Color Control, Attribute: ColorPointBIntensity, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Color Control, Attribute: StartUpColorTemperatureMireds, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Ballast Configuration, Attribute: MinLevel, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Ballast Configuration, Attribute: MaxLevel, Privilege: manage */ \ @@ -592,6 +564,7 @@ chip::Access::Privilege::kManage, /* Cluster: Camera AV Stream Management, Attribute: LocalSnapshotRecordingEnabled, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Camera AV Stream Management, Attribute: StatusLightEnabled, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Camera AV Stream Management, Attribute: StatusLightBrightness, Privilege: manage */ \ + chip::Access::Privilege::kAdminister, /* Cluster: Unit Testing, Attribute: UnsupportedAttributeRequiringAdminPrivilege, Privilege: administer */ \ } //////////////////////////////////////////////////////////////////////////////// @@ -605,6 +578,7 @@ 0x00000004, /* Cluster: Groups, Command: RemoveAllGroups, Privilege: manage */ \ 0x00000004, /* Cluster: Groups, Command: AddGroupIfIdentifying, Privilege: manage */ \ 0x0000001F, /* Cluster: Access Control, Command: ReviewFabricRestrictions, Privilege: administer */ \ + 0x0000002A, /* Cluster: OTA Software Update Requestor, Command: AnnounceOTAProvider, Privilege: administer */ \ 0x00000030, /* Cluster: General Commissioning, Command: ArmFailSafe, Privilege: administer */ \ 0x00000030, /* Cluster: General Commissioning, Command: SetRegulatoryConfig, Privilege: administer */ \ 0x00000030, /* Cluster: General Commissioning, Command: CommissioningComplete, Privilege: administer */ \ @@ -673,6 +647,8 @@ 0x00000104, /* Cluster: Closure Control, Command: Calibrate, Privilege: manage */ \ 0x00000201, /* Cluster: Thermostat, Command: SetWeeklySchedule, Privilege: manage */ \ 0x00000201, /* Cluster: Thermostat, Command: ClearWeeklySchedule, Privilege: manage */ \ + 0x00000201, /* Cluster: Thermostat, Command: AddThermostatSuggestion, Privilege: manage */ \ + 0x00000201, /* Cluster: Thermostat, Command: RemoveThermostatSuggestion, Privilege: manage */ \ 0x00000201, /* Cluster: Thermostat, Command: AtomicRequest, Privilege: manage */ \ 0x00000451, /* Cluster: Wi-Fi Network Management, Command: NetworkPassphraseRequest, Privilege: manage */ \ 0x00000452, /* Cluster: Thread Border Router Management, Command: GetActiveDatasetRequest, Privilege: manage */ \ @@ -752,6 +728,7 @@ 0x00000004, /* Cluster: Groups, Command: RemoveAllGroups, Privilege: manage */ \ 0x00000005, /* Cluster: Groups, Command: AddGroupIfIdentifying, Privilege: manage */ \ 0x00000000, /* Cluster: Access Control, Command: ReviewFabricRestrictions, Privilege: administer */ \ + 0x00000000, /* Cluster: OTA Software Update Requestor, Command: AnnounceOTAProvider, Privilege: administer */ \ 0x00000000, /* Cluster: General Commissioning, Command: ArmFailSafe, Privilege: administer */ \ 0x00000002, /* Cluster: General Commissioning, Command: SetRegulatoryConfig, Privilege: administer */ \ 0x00000004, /* Cluster: General Commissioning, Command: CommissioningComplete, Privilege: administer */ \ @@ -820,6 +797,8 @@ 0x00000002, /* Cluster: Closure Control, Command: Calibrate, Privilege: manage */ \ 0x00000001, /* Cluster: Thermostat, Command: SetWeeklySchedule, Privilege: manage */ \ 0x00000003, /* Cluster: Thermostat, Command: ClearWeeklySchedule, Privilege: manage */ \ + 0x00000007, /* Cluster: Thermostat, Command: AddThermostatSuggestion, Privilege: manage */ \ + 0x00000008, /* Cluster: Thermostat, Command: RemoveThermostatSuggestion, Privilege: manage */ \ 0x000000FE, /* Cluster: Thermostat, Command: AtomicRequest, Privilege: manage */ \ 0x00000000, /* Cluster: Wi-Fi Network Management, Command: NetworkPassphraseRequest, Privilege: manage */ \ 0x00000000, /* Cluster: Thread Border Router Management, Command: GetActiveDatasetRequest, Privilege: manage */ \ @@ -899,6 +878,7 @@ chip::Access::Privilege::kManage, /* Cluster: Groups, Command: RemoveAllGroups, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Groups, Command: AddGroupIfIdentifying, Privilege: manage */ \ chip::Access::Privilege::kAdminister, /* Cluster: Access Control, Command: ReviewFabricRestrictions, Privilege: administer */ \ + chip::Access::Privilege::kAdminister, /* Cluster: OTA Software Update Requestor, Command: AnnounceOTAProvider, Privilege: administer */ \ chip::Access::Privilege::kAdminister, /* Cluster: General Commissioning, Command: ArmFailSafe, Privilege: administer */ \ chip::Access::Privilege::kAdminister, /* Cluster: General Commissioning, Command: SetRegulatoryConfig, Privilege: administer */ \ chip::Access::Privilege::kAdminister, /* Cluster: General Commissioning, Command: CommissioningComplete, Privilege: administer */ \ @@ -967,6 +947,8 @@ chip::Access::Privilege::kManage, /* Cluster: Closure Control, Command: Calibrate, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Thermostat, Command: SetWeeklySchedule, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Thermostat, Command: ClearWeeklySchedule, Privilege: manage */ \ + chip::Access::Privilege::kManage, /* Cluster: Thermostat, Command: AddThermostatSuggestion, Privilege: manage */ \ + chip::Access::Privilege::kManage, /* Cluster: Thermostat, Command: RemoveThermostatSuggestion, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Thermostat, Command: AtomicRequest, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Wi-Fi Network Management, Command: NetworkPassphraseRequest, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Thread Border Router Management, Command: GetActiveDatasetRequest, Privilege: manage */ \ diff --git a/components/esp_matter/zap_common/zap-generated/endpoint_config.h b/components/esp_matter/zap_common/zap-generated/endpoint_config.h index 2fbac3d40..0c91e0bca 100644 --- a/components/esp_matter/zap_common/zap-generated/endpoint_config.h +++ b/components/esp_matter/zap_common/zap-generated/endpoint_config.h @@ -23,57 +23,9 @@ #include #include -#define GENERATED_ATTRIBUTES \ - {} - -#define GENERATED_CLUSTERS \ - {} - -#define GENERATED_ENDPOINT_TYPES \ - {} - -#define ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT 0 - -// Largest attribute size is needed for various buffers -#define ATTRIBUTE_LARGEST CONFIG_ESP_MATTER_ATTRIBUTE_BUFFER_LARGEST - -static_assert(ATTRIBUTE_LARGEST <= CHIP_CONFIG_MAX_ATTRIBUTE_STORE_ELEMENT_SIZE, "ATTRIBUTE_LARGEST larger than expected"); - -// Total size of attribute storage -#define ATTRIBUTE_MAX_SIZE (0) - // Number of fixed endpoints #define FIXED_ENDPOINT_COUNT (0) #ifdef CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT #undef CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT #endif #define CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT CONFIG_ESP_MATTER_MAX_DYNAMIC_ENDPOINT_COUNT - -// Array of endpoints that are supported, the data inside -// the array is the endpoint number. -#define FIXED_ENDPOINT_ARRAY \ - {0} - -// Array of profile ids -#define FIXED_PROFILE_IDS \ - {0} - -// Array of device types -#define FIXED_DEVICE_TYPES \ - {0} - -// Array of device type offsets -#define FIXED_DEVICE_TYPE_OFFSETS \ - {0} - -// Array of device type lengths -#define FIXED_DEVICE_TYPE_LENGTHS \ - {0} - -// Array of endpoint types supported on each endpoint -#define FIXED_ENDPOINT_TYPES \ - {0} - -// Array of networks supported on each endpoint -#define FIXED_NETWORKS \ - {0} diff --git a/components/esp_matter/zap_common/zap-generated/gen_config.h b/components/esp_matter/zap_common/zap-generated/gen_config.h index e75747650..118d0288c 100644 --- a/components/esp_matter/zap_common/zap-generated/gen_config.h +++ b/components/esp_matter/zap_common/zap-generated/gen_config.h @@ -25,11 +25,6 @@ // User options for plugin Binding Table Library #define MATTER_BINDING_TABLE_SIZE CONFIG_ESP_MATTER_BINDING_TABLE_SIZE -/**** Network Section ****/ -#define EMBER_SUPPORTED_NETWORKS (1) - -#define EMBER_APS_UNICAST_MESSAGE_COUNT CONFIG_ESP_MATTER_UNICAST_MESSAGE_COUNT - /* Cluster macros for all */ #define ZCL_USING_ACCESS_CONTROL_CLUSTER_SERVER #define ZCL_USING_ACCOUNT_LOGIN_CLUSTER_SERVER diff --git a/components/esp_matter_bridge/esp_matter_bridge.cpp b/components/esp_matter_bridge/esp_matter_bridge.cpp index 78b38b8b4..4a4c46fbf 100644 --- a/components/esp_matter_bridge/esp_matter_bridge.cpp +++ b/components/esp_matter_bridge/esp_matter_bridge.cpp @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "esp_matter_endpoint.h" #include #include #include @@ -271,14 +272,12 @@ static bool parent_endpoint_is_valid(node_t *node, uint16_t parent_endpoint_id) ESP_LOGE(TAG, "Parent endpoint cannot be NULL"); return false; } - uint8_t device_type_count = 0; - uint32_t *device_type_ids_ptr = get_device_type_ids(parent_endpoint, &device_type_count); - if (device_type_ids_ptr == NULL || device_type_count == 0) { - ESP_LOGE(TAG, "Device type id array cannot be NULL"); - return false; - } + uint8_t device_type_count = get_device_type_count(parent_endpoint); for (uint8_t i = 0; i < device_type_count; ++i) { - if (device_type_ids_ptr[i] == esp_matter::endpoint::aggregator::get_device_type_id()) { + uint32_t dev_type_id; + uint8_t dev_type_ver; + if ((ESP_OK == get_device_type_at_index(parent_endpoint, i, dev_type_id, dev_type_ver)) && + (dev_type_id == endpoint::aggregator::get_device_type_id())) { return true; } } diff --git a/components/esp_matter_console/CMakeLists.txt b/components/esp_matter_console/CMakeLists.txt index 159f822df..929c60737 100644 --- a/components/esp_matter_console/CMakeLists.txt +++ b/components/esp_matter_console/CMakeLists.txt @@ -8,6 +8,11 @@ if ("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") list(APPEND priv_req esp_rcp_update) endif() +if (NOT CONFIG_ESP_MATTER_ENABLE_DATA_MODEL) + list(APPEND exclude_srcs_list "esp_matter_console_attribute.cpp") +endif() + idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS . + EXCLUDE_SRCS ${exclude_srcs_list} PRIV_REQUIRES ${priv_req}) diff --git a/components/esp_matter_console/esp_matter_console.h b/components/esp_matter_console/esp_matter_console.h index b513cc9cc..e0d76c36f 100644 --- a/components/esp_matter_console/esp_matter_console.h +++ b/components/esp_matter_console/esp_matter_console.h @@ -164,5 +164,14 @@ esp_err_t udc_register_commands(); */ esp_err_t factoryreset_register_commands(); +/** Add Attribute Commands + * + * Add the command for attribute value management + * + * @return ESP_OK on success + * @return error in case of failure. + */ +esp_err_t attribute_register_commands(); + } // namespace console } // namespace esp_matter diff --git a/components/esp_matter_console/esp_matter_console_attribute.cpp b/components/esp_matter_console/esp_matter_console_attribute.cpp new file mode 100644 index 000000000..ca228d857 --- /dev/null +++ b/components/esp_matter_console/esp_matter_console_attribute.cpp @@ -0,0 +1,247 @@ +#include +#include +#include +#include +#include +#include +#include + +#define TAG "attribute_console" + +namespace esp_matter { +namespace console { + +static esp_matter::console::engine attribute_console; + +static esp_err_t console_set_handler(int argc, char **argv) +{ + VerifyOrReturnError(argc >= 4, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "The arguments for this command is invalid")); + + uint16_t endpoint_id = strtoul((const char *)&argv[0][2], NULL, 16); + uint32_t cluster_id = strtoul((const char *)&argv[1][2], NULL, 16); + uint32_t attribute_id = strtoul((const char *)&argv[2][2], NULL, 16); + + attribute_t *attr = attribute::get(endpoint_id, cluster_id, attribute_id); + if (!attr) { + return ESP_ERR_INVALID_ARG; + } + esp_matter_attr_val_t val = esp_matter_invalid(NULL); + ESP_RETURN_ON_ERROR(attribute::get_val(attr, &val), TAG, "Failed to get current valure"); + switch (val.type) { + case ESP_MATTER_VAL_TYPE_NULLABLE_BOOLEAN: + if (strncmp(argv[3], "null", sizeof("null")) == 0) { + val = esp_matter_nullable_bool(nullable()); + } else { + bool value = atoi(argv[3]); + val = esp_matter_nullable_bool(value); + } + break; + case ESP_MATTER_VAL_TYPE_BOOLEAN: { + bool value = atoi(argv[3]); + val = esp_matter_bool(value); + break; + } + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT8: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8: + if (strncmp(argv[3], "null", sizeof("null")) == 0) { + val = esp_matter_nullable_uint8(nullable()); + } else { + uint8_t value = atoi(argv[3]); + val = esp_matter_nullable_uint8(value); + } + break; + case ESP_MATTER_VAL_TYPE_UINT8: + case ESP_MATTER_VAL_TYPE_ENUM8: + case ESP_MATTER_VAL_TYPE_BITMAP8: { + uint8_t value = atoi(argv[3]); + val = esp_matter_uint8(value); + break; + } + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT16: + case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16: + if (strncmp(argv[3], "null", sizeof("null")) == 0) { + val = esp_matter_nullable_uint16(nullable()); + } else { + uint16_t value = atoi(argv[3]); + val = esp_matter_nullable_uint16(value); + } + break; + case ESP_MATTER_VAL_TYPE_UINT16: + case ESP_MATTER_VAL_TYPE_ENUM16: + case ESP_MATTER_VAL_TYPE_BITMAP16: { + uint16_t value = atoi(argv[3]); + val = esp_matter_uint16(value); + break; + } + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT32: + case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32: + if (strncmp(argv[3], "null", sizeof("null")) == 0) { + val = esp_matter_nullable_uint32(nullable()); + } else { + uint32_t value = strtoull(argv[3], nullptr, 10); + val = esp_matter_nullable_uint32(value); + } + break; + case ESP_MATTER_VAL_TYPE_UINT32: + case ESP_MATTER_VAL_TYPE_BITMAP32: { + uint32_t value = strtoull(argv[3], nullptr, 10); + val = esp_matter_uint32(value); + break; + } + case ESP_MATTER_VAL_TYPE_NULLABLE_UINT64: + if (strncmp(argv[3], "null", sizeof("null")) == 0) { + val = esp_matter_nullable_uint64(nullable()); + } else { + uint64_t value = strtoull(argv[3], nullptr, 10); + val = esp_matter_nullable_uint64(value); + } + break; + case ESP_MATTER_VAL_TYPE_UINT64: { + uint64_t value = strtoull(argv[3], nullptr, 10); + val = esp_matter_uint64(value); + break; + } + case ESP_MATTER_VAL_TYPE_NULLABLE_INT8: + if (strncmp(argv[3], "null", sizeof("null")) == 0) { + val = esp_matter_nullable_int8(nullable()); + } else { + int8_t value = atoi(argv[3]); + val = esp_matter_nullable_int8(value); + } + break; + case ESP_MATTER_VAL_TYPE_INT8: { + int8_t value = atoi(argv[3]); + val = esp_matter_int8(value); + break; + } + case ESP_MATTER_VAL_TYPE_NULLABLE_INT16: + if (strncmp(argv[3], "null", sizeof("null")) == 0) { + val = esp_matter_nullable_int16(nullable()); + } else { + int16_t value = atoi(argv[3]); + val = esp_matter_nullable_int16(value); + } + break; + case ESP_MATTER_VAL_TYPE_INT16: { + int16_t value = atoi(argv[3]); + val = esp_matter_int16(value); + break; + } + case ESP_MATTER_VAL_TYPE_NULLABLE_INT32: + if (strncmp(argv[3], "null", sizeof("null")) == 0) { + val = esp_matter_nullable_int32(nullable()); + } else { + int32_t value = atoi(argv[3]); + val = esp_matter_nullable_int32(value); + } + break; + case ESP_MATTER_VAL_TYPE_INT32: { + int32_t value = atoi(argv[3]); + val = esp_matter_int32(value); + break; + } + case ESP_MATTER_VAL_TYPE_NULLABLE_INT64: + if (strncmp(argv[3], "null", sizeof("null")) == 0) { + val = esp_matter_nullable_int64(nullable()); + } else { + int64_t value = strtoll(argv[3], nullptr, 10); + val = esp_matter_nullable_int64(value); + } + break; + case ESP_MATTER_VAL_TYPE_INT64: { + int64_t value = strtoll(argv[3], nullptr, 10); + val = esp_matter_int64(value); + break; + } + case ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT: + if (strncmp(argv[3], "null", sizeof("null")) == 0) { + val = esp_matter_nullable_float(nullable()); + } else { + float value = (float)atof(argv[3]); + val = esp_matter_nullable_float(value); + } + break; + case ESP_MATTER_VAL_TYPE_FLOAT: { + float value = (float)atof(argv[3]); + val = esp_matter_float(value); + break; + } + case ESP_MATTER_VAL_TYPE_CHAR_STRING: { + char *value = argv[3]; + val = esp_matter_char_str(value, strlen(value)); + break; + } + case ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING: { + char *value = argv[3]; + val = esp_matter_long_char_str(value, strlen(value)); + break; + } + default: + ESP_LOGE(TAG, "Type not handled: %d", val.type); + return ESP_ERR_INVALID_ARG; + } + return attribute::update(endpoint_id, cluster_id, attribute_id, &val); +} + +static esp_err_t console_get_handler(int argc, char **argv) +{ + VerifyOrReturnError(argc >= 3, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "The arguments for this command is invalid")); + uint16_t endpoint_id = strtoul((const char *)&argv[0][2], NULL, 16); + uint32_t cluster_id = strtoul((const char *)&argv[1][2], NULL, 16); + uint32_t attribute_id = strtoul((const char *)&argv[2][2], NULL, 16); + + attribute_t *attr = attribute::get(endpoint_id, cluster_id, attribute_id); + if (!attr) { + return ESP_ERR_INVALID_ARG; + } + esp_matter_attr_val_t val = esp_matter_invalid(NULL); + ESP_RETURN_ON_ERROR(esp_matter::attribute::get_val(attr, &val), TAG, "Failed to get current valure"); + /* Here, the val_print function gets called on attribute read. */ + attribute::val_print(endpoint_id, cluster_id, attribute_id, &val, true); + return ESP_OK; +} + +static esp_err_t console_dispatch(int argc, char **argv) +{ + VerifyOrReturnError(argc > 0, ESP_OK, + attribute_console.for_each_command(esp_matter::console::print_description, NULL)); + return attribute_console.exec_command(argc, argv); +} + +esp_err_t attribute_register_commands() +{ + static bool init_done = false; + VerifyOrReturnError(!init_done, ESP_ERR_INVALID_STATE); + static const esp_matter::console::command_t command = { + .name = "attribute", + .description = "This can be used to simulate on-device control. ", + .handler = console_dispatch, + }; + + static const esp_matter::console::command_t attribute_commands[] = { + { + .name = "set", + .description = "Set an attribute value of a cluster on an endpoint. " + "Usage: matter esp attribute set . " + "Example: matter esp attribute set 0x0001 0x0006 0x0000 1.", + .handler = console_set_handler, + }, + { + .name = "get", + .description = "Get an attribute value of a cluster on an endpoint. " + "Usage: matter esp attribute get . " + "Example: matter esp attribute get 0x0001 0x0006 0x0000.", + .handler = console_get_handler, + }, + }; + attribute_console.register_commands(attribute_commands, + sizeof(attribute_commands) / sizeof(esp_matter::console::command_t)); + esp_matter::console::add_commands(&command, 1); + init_done = true; + return ESP_OK; +} + +} // namespace console +} // namespace esp_matter diff --git a/components/esp_matter_controller/data_model_provider/controller_data_model_provider.h b/components/esp_matter_controller/data_model_provider/controller_data_model_provider.h index 575f1fee0..acae1e5d3 100644 --- a/components/esp_matter_controller/data_model_provider/controller_data_model_provider.h +++ b/components/esp_matter_controller/data_model_provider/controller_data_model_provider.h @@ -27,6 +27,7 @@ #include #include #include +#include using chip::ClusterId; using chip::CommandId; @@ -107,6 +108,11 @@ public: return CHIP_NO_ERROR; } + CHIP_ERROR EventInfo(const ConcreteEventPath & path, EventEntry & eventInfo) override + { + return CHIP_NO_ERROR; + } + CHIP_ERROR Attributes(const ConcreteClusterPath &path, ReadOnlyBufferBuilder &builder) override { return CHIP_NO_ERROR; @@ -121,10 +127,6 @@ public: return CHIP_NO_ERROR; } - CHIP_ERROR EventInfo(const ConcreteEventPath & path, EventEntry & eventInfo) override - { - return CHIP_NO_ERROR; - } void Temporary_ReportAttributeChanged(const AttributePathParams &path) override {} private: diff --git a/connectedhomeip/connectedhomeip b/connectedhomeip/connectedhomeip index 320b9a6f6..bdc38cd77 160000 --- a/connectedhomeip/connectedhomeip +++ b/connectedhomeip/connectedhomeip @@ -1 +1 @@ -Subproject commit 320b9a6f6c49cc3877701bbdc1e631edf32b802b +Subproject commit bdc38cd772964c67b43060cc399a2fe531529c39 diff --git a/examples/.build-rules.yml b/examples/.build-rules.yml index 061720bb5..540b8e323 100644 --- a/examples/.build-rules.yml +++ b/examples/.build-rules.yml @@ -47,7 +47,7 @@ examples/bridge_apps/esp-now_bridge_light: examples/controller: enable: - - if: IDF_TARGET in ["esp32"] + - if: IDF_TARGET in ["esp32s3"] temporary: true reason: the other targets are not tested yet diff --git a/examples/all_device_types_app/main/app_driver.cpp b/examples/all_device_types_app/main/app_driver.cpp index 48dc06752..a2ac96a82 100644 --- a/examples/all_device_types_app/main/app_driver.cpp +++ b/examples/all_device_types_app/main/app_driver.cpp @@ -203,8 +203,8 @@ esp_err_t app_driver_attribute_update(app_driver_handle_t driver_handle, uint16_ if (attribute_id == FanControl::Attributes::FanMode::Id) { esp_matter_attr_val_t val_a = esp_matter_invalid(NULL); get_attribute(endpoint_id, FanControl::Id, Attributes::PercentSetting::Id, &val_a); - /* When FanMode attribute change , should check the persent setting value, if this value not match - FanMode, need write the persent setting value to corresponding value. Now we set it to the max + /* When FanMode attribute change , should check the present setting value, if this value not match + FanMode, need write the present setting value to corresponding value. Now we set it to the max value of the FanMode */ if (!check_if_mode_percent_match(val->val.u8, val_a.val.u8)) { switch (val->val.u8) { diff --git a/examples/bridge_apps/esp-now_bridge_light/main/app_driver.cpp b/examples/bridge_apps/esp-now_bridge_light/main/app_driver.cpp index c0918e6dc..7e4b4ea27 100644 --- a/examples/bridge_apps/esp-now_bridge_light/main/app_driver.cpp +++ b/examples/bridge_apps/esp-now_bridge_light/main/app_driver.cpp @@ -18,6 +18,7 @@ #include #include "app/CommandPathParams.h" #include +#include using namespace chip::app::Clusters; using namespace esp_matter; diff --git a/examples/common/blemesh_platform/platform/ESP32_custom/BUILD.gn b/examples/common/blemesh_platform/platform/ESP32_custom/BUILD.gn index e675ff781..aaf8b5126 100644 --- a/examples/common/blemesh_platform/platform/ESP32_custom/BUILD.gn +++ b/examples/common/blemesh_platform/platform/ESP32_custom/BUILD.gn @@ -125,7 +125,6 @@ static_library("ESP32_custom") { "PlatformManagerImpl.cpp", "PlatformManagerImpl.h", "SystemTimeSupport.cpp", - "SystemTimeSupport.h", ] deps = [ diff --git a/examples/common/blemesh_platform/platform/ESP32_custom/SystemTimeSupport.h b/examples/common/blemesh_platform/platform/ESP32_custom/SystemTimeSupport.h deleted file mode 120000 index b5bd16627..000000000 --- a/examples/common/blemesh_platform/platform/ESP32_custom/SystemTimeSupport.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/SystemTimeSupport.h \ No newline at end of file diff --git a/examples/common/external_platform/BUILD.gn b/examples/common/external_platform/BUILD.gn index ebcfde676..397399c14 100644 --- a/examples/common/external_platform/BUILD.gn +++ b/examples/common/external_platform/BUILD.gn @@ -120,7 +120,6 @@ static_library("ESP32_custom") { "PlatformManagerImpl.cpp", "PlatformManagerImpl.h", "SystemTimeSupport.cpp", - "SystemTimeSupport.h", ] deps = [ diff --git a/examples/common/utils/common_macros.h b/examples/common/utils/common_macros.h index 04497e304..237f2c4f6 100644 --- a/examples/common/utils/common_macros.h +++ b/examples/common/utils/common_macros.h @@ -19,6 +19,21 @@ #include #include +/** Remap attribute values + * + * This can be used to remap attribute values to different ranges. + * Example: To convert the brightness value (0-255) into brightness percentage (0-100) and vice-versa. + */ +#define REMAP_TO_RANGE(value, from, to) ((value * to) / from) + +/** Remap attribute values with inverse dependency + * + * This can be used to remap attribute values with inverse dependency to different ranges. + * Example: To convert the temperature mireds into temperature kelvin and vice-versa where the relation between them + * is: Mireds = 1,000,000/Kelvin. + */ +#define REMAP_TO_RANGE_INVERSE(value, factor) (factor / (value ? value : 1)) + #define ABORT_APP_ON_FAILURE(x, ...) do { \ if (!(unlikely(x))) { \ __VA_ARGS__; \ diff --git a/examples/light/main/app_driver.cpp b/examples/light/main/app_driver.cpp index 819477497..7ac765cd3 100644 --- a/examples/light/main/app_driver.cpp +++ b/examples/light/main/app_driver.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include diff --git a/examples/light/main/app_main.cpp b/examples/light/main/app_main.cpp index 6b10c42f3..e852be554 100644 --- a/examples/light/main/app_main.cpp +++ b/examples/light/main/app_main.cpp @@ -262,6 +262,7 @@ extern "C" void app_main() esp_matter::console::diagnostics_register_commands(); esp_matter::console::wifi_register_commands(); esp_matter::console::factoryreset_register_commands(); + esp_matter::console::attribute_register_commands(); #if CONFIG_OPENTHREAD_CLI esp_matter::console::otcli_register_commands(); #endif diff --git a/examples/light_network_prov/main/app_driver.cpp b/examples/light_network_prov/main/app_driver.cpp index 1cbc88303..60f129afb 100644 --- a/examples/light_network_prov/main/app_driver.cpp +++ b/examples/light_network_prov/main/app_driver.cpp @@ -15,6 +15,7 @@ #include "bsp/esp-bsp.h" #include +#include using namespace chip::app::Clusters; using namespace esp_matter; diff --git a/examples/light_network_prov/main/app_main.cpp b/examples/light_network_prov/main/app_main.cpp index 923c69184..f3b6b27b8 100644 --- a/examples/light_network_prov/main/app_main.cpp +++ b/examples/light_network_prov/main/app_main.cpp @@ -232,9 +232,8 @@ static esp_err_t bulk_write_cb(const esp_rmaker_device_t *device, const esp_rmak if (ctx) { ESP_LOGI(TAG, "Received write request via : %s", esp_rmaker_device_cb_src_to_str(ctx->src)); } - ESP_LOGI(TAG, "Light received %d params in write", count); app_driver_handle_t light_handle = (app_driver_handle_t)priv_data; - esp_matter_attr_val_t matter_val; + ESP_LOGI(TAG, "Light received %d params in write", count); for (int i = 0; i < count; i++) { const esp_rmaker_param_t *param = write_req[i].param; esp_rmaker_param_val_t val = write_req[i].val; diff --git a/examples/managed_component_light/main/app_driver.cpp b/examples/managed_component_light/main/app_driver.cpp index cdc96af1d..07ac082fe 100644 --- a/examples/managed_component_light/main/app_driver.cpp +++ b/examples/managed_component_light/main/app_driver.cpp @@ -14,6 +14,7 @@ #include "bsp/esp-bsp.h" #include +#include using namespace chip::app::Clusters; using namespace esp_matter; diff --git a/examples/zap_light/main/app_driver.cpp b/examples/zap_light/main/app_driver.cpp index 961a0f81a..c17997976 100644 --- a/examples/zap_light/main/app_driver.cpp +++ b/examples/zap_light/main/app_driver.cpp @@ -14,8 +14,14 @@ #include #include +#include #include +#include +#include +#include "app/data-model/Nullable.h" +#include "platform/PlatformManager.h" + using namespace chip::app::Clusters; using namespace esp_matter; @@ -24,70 +30,88 @@ extern uint16_t light_endpoint_id; extern app_driver_handle_t light_handle; /* Do any conversions/remapping for the actual value here */ -static esp_err_t app_driver_light_set_power(led_driver_handle_t handle, esp_matter_attr_val_t *val) +static esp_err_t app_driver_light_set_power(led_driver_handle_t handle, bool val) { - return led_driver_set_power(handle, val->val.b); + return led_driver_set_power(handle, val); } -static esp_err_t app_driver_light_set_brightness(led_driver_handle_t handle, esp_matter_attr_val_t *val) +static esp_err_t app_driver_light_set_brightness(led_driver_handle_t handle, uint8_t val) { - int value = REMAP_TO_RANGE(val->val.u8, MATTER_BRIGHTNESS, STANDARD_BRIGHTNESS); + int value = REMAP_TO_RANGE(val, MATTER_BRIGHTNESS, STANDARD_BRIGHTNESS); return led_driver_set_brightness(handle, value); } -static esp_err_t app_driver_light_set_hue(led_driver_handle_t handle, esp_matter_attr_val_t *val) +static esp_err_t app_driver_light_set_hue(led_driver_handle_t handle, uint8_t val) { - int value = REMAP_TO_RANGE(val->val.u8, MATTER_HUE, STANDARD_HUE); + int value = REMAP_TO_RANGE(val, MATTER_HUE, STANDARD_HUE); return led_driver_set_hue(handle, value); } -static esp_err_t app_driver_light_set_saturation(led_driver_handle_t handle, esp_matter_attr_val_t *val) +static esp_err_t app_driver_light_set_saturation(led_driver_handle_t handle, uint8_t val) { - int value = REMAP_TO_RANGE(val->val.u8, MATTER_SATURATION, STANDARD_SATURATION); + int value = REMAP_TO_RANGE(val, MATTER_SATURATION, STANDARD_SATURATION); return led_driver_set_saturation(handle, value); } -static esp_err_t app_driver_light_set_temperature(led_driver_handle_t handle, esp_matter_attr_val_t *val) +static esp_err_t app_driver_light_set_temperature(led_driver_handle_t handle, uint16_t val) { - uint32_t value = REMAP_TO_RANGE_INVERSE(val->val.u16, STANDARD_TEMPERATURE_FACTOR); + uint32_t value = REMAP_TO_RANGE_INVERSE(val, STANDARD_TEMPERATURE_FACTOR); return led_driver_set_temperature(handle, value); } static void app_driver_button_toggle_cb(void *arg, void *data) { ESP_LOGI(TAG, "Toggle button pressed"); - uint16_t endpoint_id = light_endpoint_id; - uint32_t cluster_id = OnOff::Id; - uint32_t attribute_id = OnOff::Attributes::OnOff::Id; - uint8_t value; - attribute::get_val_raw(endpoint_id, cluster_id, attribute_id, &value, sizeof(uint8_t)); - esp_matter_attr_val_t val = esp_matter_bool(value); - val.val.b = !val.val.b; - attribute::update(endpoint_id, cluster_id, attribute_id, &val); + chip::DeviceLayer::PlatformMgr().ScheduleWork([](intptr_t arg){ + bool value; + OnOff::Attributes::OnOff::Get(light_endpoint_id, &value); + value = !value; + OnOff::Attributes::OnOff::Set(light_endpoint_id, value); + }); } esp_err_t app_driver_attribute_update(app_driver_handle_t driver_handle, uint16_t endpoint_id, uint32_t cluster_id, - uint32_t attribute_id, esp_matter_attr_val_t *val) + uint32_t attribute_id, uint8_t type, uint8_t *val_raw, uint16_t val_raw_size) { esp_err_t err = ESP_OK; if (endpoint_id == light_endpoint_id) { led_driver_handle_t handle = (led_driver_handle_t)driver_handle; if (cluster_id == OnOff::Id) { if (attribute_id == OnOff::Attributes::OnOff::Id) { - err = app_driver_light_set_power(handle, val); + if (type == ZCL_BOOLEAN_ATTRIBUTE_TYPE && val_raw_size == sizeof(bool)) { + bool val; + memcpy(&val, val_raw, val_raw_size); + err = app_driver_light_set_power(handle, val); + } } } else if (cluster_id == LevelControl::Id) { if (attribute_id == LevelControl::Attributes::CurrentLevel::Id) { - err = app_driver_light_set_brightness(handle, val); + if (type == ZCL_INT8U_ATTRIBUTE_TYPE && val_raw_size == sizeof(uint8_t)) { + uint8_t val; + memcpy(&val, val_raw, val_raw_size); + err = app_driver_light_set_brightness(handle, val); + } } } else if (cluster_id == ColorControl::Id) { if (attribute_id == ColorControl::Attributes::CurrentHue::Id) { - err = app_driver_light_set_hue(handle, val); + if (type == ZCL_INT8U_ATTRIBUTE_TYPE && val_raw_size == sizeof(uint8_t)) { + uint8_t val; + memcpy(&val, val_raw, val_raw_size); + err = app_driver_light_set_hue(handle, val); + } } else if (attribute_id == ColorControl::Attributes::CurrentSaturation::Id) { - err = app_driver_light_set_saturation(handle, val); + if (type == ZCL_INT8U_ATTRIBUTE_TYPE && val_raw_size == sizeof(uint8_t)) { + uint8_t val; + memcpy(&val, val_raw, val_raw_size); + err = app_driver_light_set_saturation(handle, val); + } } else if (attribute_id == ColorControl::Attributes::ColorTemperatureMireds::Id) { - err = app_driver_light_set_temperature(handle, val); + if (type == ZCL_INT16U_ATTRIBUTE_TYPE && val_raw_size == sizeof(uint16_t)) { + uint16_t val; + memcpy(&val, val_raw, val_raw_size); + err = app_driver_light_set_temperature(handle, val); + } } } } @@ -103,48 +127,36 @@ esp_err_t app_driver_light_set_defaults(uint16_t endpoint_id) led_driver_handle_t handle = (led_driver_handle_t)light_handle; uint8_t value; uint16_t value_u16; - uint32_t cluster_id = 0; - uint32_t attribute_id = 0; - esp_matter_attr_val_t val = esp_matter_invalid(NULL); + chip::app::DataModel::Nullable nullable_value; /* Setting brightness */ - cluster_id = LevelControl::Id; - attribute_id = LevelControl::Attributes::CurrentLevel::Id; - attribute::get_val_raw(endpoint_id, cluster_id, attribute_id, &value, sizeof(uint8_t)); - val = esp_matter_uint8(value); - err |= app_driver_light_set_brightness(handle, &val); + LevelControl::Attributes::CurrentLevel::Get(endpoint_id, nullable_value); + if (!nullable_value.IsNull()) { + err |= app_driver_light_set_brightness(handle, nullable_value.Value()); + } /* Setting color */ - cluster_id = ColorControl::Id; - attribute_id = ColorControl::Attributes::CurrentHue::Id; - attribute::get_val_raw(endpoint_id, cluster_id, attribute_id, &value, sizeof(uint8_t)); - if (value == (uint8_t)ColorControl::ColorMode::kCurrentHueAndCurrentSaturation) { + ColorControl::ColorModeEnum mode; + ColorControl::Attributes::ColorMode::Get(endpoint_id, &mode); + if (mode == ColorControl::ColorModeEnum::kCurrentHueAndCurrentSaturation) { /* Setting hue */ - attribute_id = ColorControl::Attributes::CurrentHue::Id; - attribute::get_val_raw(endpoint_id, cluster_id, attribute_id, &value, sizeof(uint8_t)); - val = esp_matter_uint8(value); - err |= app_driver_light_set_hue(handle, &val); + ColorControl::Attributes::CurrentHue::Get(endpoint_id, &value); + err |= app_driver_light_set_hue(handle, value); /* Setting saturation */ - attribute_id = ColorControl::Attributes::CurrentSaturation::Id; - attribute::get_val_raw(endpoint_id, cluster_id, attribute_id, &value, sizeof(uint8_t)); - val = esp_matter_uint8(value); - err |= app_driver_light_set_saturation(handle, &val); + ColorControl::Attributes::CurrentSaturation::Get(endpoint_id, &value); + err |= app_driver_light_set_saturation(handle, value); } else if (value == (uint8_t)ColorControl::ColorMode::kColorTemperature) { /* Setting temperature */ - attribute_id = ColorControl::Attributes::ColorTemperatureMireds::Id; - attribute::get_val_raw(endpoint_id, cluster_id, attribute_id, (uint8_t *)&value_u16, sizeof(uint16_t)); - val = esp_matter_uint16(value_u16); - err |= app_driver_light_set_temperature(handle, &val); + ColorControl::Attributes::ColorTemperatureMireds::Get(endpoint_id, &value_u16); + err |= app_driver_light_set_temperature(handle, value_u16); } else { ESP_LOGE(TAG, "Color mode not supported"); } /* Setting power */ - cluster_id = OnOff::Id; - attribute_id = OnOff::Attributes::OnOff::Id; - attribute::get_val_raw(endpoint_id, cluster_id, attribute_id, &value, sizeof(uint8_t)); - val = esp_matter_bool(value); - err |= app_driver_light_set_power(handle, &val); + bool onoff; + OnOff::Attributes::OnOff::Get(endpoint_id, &onoff); + err |= app_driver_light_set_power(handle, onoff); return err; } diff --git a/examples/zap_light/main/app_main.cpp b/examples/zap_light/main/app_main.cpp index 79c266197..debc9de2e 100644 --- a/examples/zap_light/main/app_main.cpp +++ b/examples/zap_light/main/app_main.cpp @@ -14,15 +14,15 @@ #include #include -#include #include #include +#include +#include "platform/PlatformManager.h" #if CHIP_DEVICE_CONFIG_ENABLE_THREAD #include #endif using namespace esp_matter; -using namespace esp_matter::attribute; static const char *TAG = "app_main"; uint16_t light_endpoint_id = 0; @@ -67,18 +67,13 @@ static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg) // This callback is called for every attribute update. The callback implementation shall // handle the desired attributes and return an appropriate error code. If the attribute // is not of your interest, please do not return an error code and strictly return ESP_OK. -static esp_err_t app_attribute_update_cb(callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id, - uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data) + +chip::Protocols::InteractionModel::Status MatterPreAttributeChangeCallback( + const chip::app::ConcreteAttributePath &attributePath, uint8_t type, uint16_t size, uint8_t *value) { - esp_err_t err = ESP_OK; - - if (type == PRE_UPDATE) { - /* Driver update */ - app_driver_handle_t driver_handle = light_handle; - err = app_driver_attribute_update(driver_handle, endpoint_id, cluster_id, attribute_id, val); - } - - return err; + esp_err_t err = app_driver_attribute_update(light_handle, attributePath.mEndpointId, attributePath.mClusterId, + attributePath.mAttributeId, type, value, size); + return err == ESP_OK ? chip::Protocols::InteractionModel::Status::Success : chip::Protocols::InteractionModel::Status::Failure; } extern "C" void app_main() @@ -94,7 +89,6 @@ extern "C" void app_main() app_reset_button_register(button_handle); /* Initialize matter callback */ - attribute::set_callback(app_attribute_update_cb); light_endpoint_id = 1; /* This is from zap-generated/endpoint_config.h */ #if CHIP_DEVICE_CONFIG_ENABLE_THREAD @@ -111,11 +105,15 @@ extern "C" void app_main() err = esp_matter::start(app_event_cb); ABORT_APP_ON_FAILURE(err == ESP_OK, ESP_LOGE(TAG, "Failed to start Matter, err:%d", err)); + init_network_driver(); + esp_matter::identification::init(1, 0); esp_matter::identification::set_callback(nullptr); /* Starting driver with default values */ - app_driver_light_set_defaults(light_endpoint_id); + chip::DeviceLayer::PlatformMgr().ScheduleWork([](intptr_t arg){ + app_driver_light_set_defaults(light_endpoint_id); + }); #if CONFIG_ENABLE_CHIP_SHELL esp_matter::console::diagnostics_register_commands(); diff --git a/examples/zap_light/main/app_network_instance.cpp b/examples/zap_light/main/app_network_instance.cpp new file mode 100644 index 000000000..f8336c5ef --- /dev/null +++ b/examples/zap_light/main/app_network_instance.cpp @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include +#include +#include +#include + +using namespace chip; +using namespace chip::DeviceLayer; + +namespace { + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI && CHIP_DEVICE_CONFIG_WIFI_NETWORK_DRIVER +app::Clusters::NetworkCommissioning::Instance + sWiFiNetworkCommissioningInstance(CONFIG_WIFI_NETWORK_ENDPOINT_ID /* Endpoint Id */, + &(NetworkCommissioning::ESPWiFiDriver::GetInstance())); +#endif + +#if CHIP_DEVICE_CONFIG_ENABLE_ETHERNET && CHIP_DEVICE_CONFIG_ETHERNET_NETWORK_DRIVER +app::Clusters::NetworkCommissioning::Instance + sEthernetNetworkCommissioningInstance(CONFIG_ETHERNET_NETWORK_ENDPOINT_ID /* Endpoint Id */, + &(NetworkCommissioning::ESPEthernetDriver::GetInstance())); +#endif + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD && CONFIG_THREAD_NETWORK_COMMISSIONING_DRIVER +app::Clusters::NetworkCommissioning::InstanceAndDriver + sThreadNetworkDriver(CONFIG_THREAD_NETWORK_ENDPOINT_ID); +#endif + +#if defined(CONFIG_WIFI_NETWORK_ENDPOINT_ID) && defined(CONFIG_THREAD_NETWORK_ENDPOINT_ID) +static_assert(CONFIG_WIFI_NETWORK_ENDPOINT_ID != CONFIG_THREAD_NETWORK_ENDPOINT_ID, + "Wi-Fi network endpoint id and Thread network endpoint id should not be the same."); +#endif +#if defined(CONFIG_WIFI_NETWORK_ENDPOINT_ID) && defined(CONFIG_ETHERNET_NETWORK_ENDPOINT_ID) +static_assert(CONFIG_WIFI_NETWORK_ENDPOINT_ID != CONFIG_ETHERNET_NETWORK_ENDPOINT_ID, + "Wi-Fi network endpoint id and Ethernet network endpoint id should not be the same."); +#endif +#if defined(CONFIG_THREAD_NETWORK_ENDPOINT_ID) && defined(CONFIG_ETHERNET_NETWORK_ENDPOINT_ID) +static_assert(CONFIG_THREAD_NETWORK_ENDPOINT_ID != CONFIG_ETHERNET_NETWORK_ENDPOINT_ID, + "Thread network endpoint id and Ethernet network endpoint id should not be the same."); +#endif +} // namespace + +void init_network_driver() +{ +#if CHIP_DEVICE_CONFIG_WIFI_NETWORK_DRIVER + sWiFiNetworkCommissioningInstance.Init(); +#endif // CHIP_DEVICE_CONFIG_WIFI_NETWORK_DRIVER +#if CHIP_DEVICE_CONFIG_ETHERNET_NETWORK_DRIVER + sEthernetNetworkCommissioningInstance.Init(); +#endif // CHIP_DEVICE_CONFIG_ETHERNET_NETWORK_DRIVER +#ifdef CONFIG_THREAD_NETWORK_COMMISSIONING_DRIVER + sThreadNetworkDriver.Init(); +#endif // CONFIG_THREAD_NETWORK_COMMISSIONING_DRIVER +} diff --git a/examples/zap_light/main/app_priv.h b/examples/zap_light/main/app_priv.h index 11106ee68..92e73218b 100644 --- a/examples/zap_light/main/app_priv.h +++ b/examples/zap_light/main/app_priv.h @@ -55,13 +55,15 @@ app_driver_handle_t app_driver_button_init(); * @param[in] endpoint_id Endpoint ID of the attribute. * @param[in] cluster_id Cluster ID of the attribute. * @param[in] attribute_id Attribute ID of the attribute. - * @param[in] val Pointer to `esp_matter_attr_val_t`. Use appropriate elements as per the value type. + * @param[in] type Attribute value type. + * @param[in] val_raw Attribute value raw buffer. + * @param[in] val_raw_size Attribute value raw buffer size. * * @return ESP_OK on success. * @return error in case of failure. */ esp_err_t app_driver_attribute_update(app_driver_handle_t driver_handle, uint16_t endpoint_id, uint32_t cluster_id, - uint32_t attribute_id, esp_matter_attr_val_t *val); + uint32_t attribute_id, uint8_t type, uint8_t *val_raw, uint16_t val_raw_size); /** Set defaults for light driver * @@ -76,6 +78,8 @@ esp_err_t app_driver_attribute_update(app_driver_handle_t driver_handle, uint16_ */ esp_err_t app_driver_light_set_defaults(uint16_t endpoint_id); +void init_network_driver(); + #if CHIP_DEVICE_CONFIG_ENABLE_THREAD #define ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG() \ { \