diff --git a/src/app/util/attribute-storage.cpp b/src/app/util/attribute-storage.cpp index be5252f4d11cd9..5f3dc13381ab49 100644 --- a/src/app/util/attribute-storage.cpp +++ b/src/app/util/attribute-storage.cpp @@ -236,6 +236,40 @@ uint16_t emberAfGetDynamicIndexFromEndpoint(EndpointId id) return kEmberInvalidEndpointIndex; } +const EmberAfCluster * getClusterTypeDefinition(EndpointId endpointId, ClusterId clusterId, EmberAfClusterMask mask) +{ + uint16_t index = emberAfIndexFromEndpointIncludingDisabledEndpoints(endpointId); + if (index != kEmberInvalidEndpointIndex) + { + return emberAfFindClusterInType(emAfEndpoints[index].endpointType, clusterId, mask, nullptr); + } + // not found + return nullptr; +} + +EmberAfStatus setupDynamicEndpointDeclaration(EmberAfEndpointType & endpointType, EndpointId templateEndpointId, + const Span & templateClusterIds) +{ + // allocate cluster list + endpointType.clusterCount = static_cast(templateClusterIds.size()); + endpointType.cluster = new EmberAfCluster[endpointType.clusterCount]; + endpointType.endpointSize = 0; + // get the actual cluster pointers and sum up memory size + for (size_t i = 0; i < templateClusterIds.size(); i++) + { + auto cluster = getClusterTypeDefinition(templateEndpointId, templateClusterIds.data()[i], 0); + VerifyOrDieWithMsg(cluster, Support, "cluster 0x%04x template in endpoint %d does not exist", templateClusterIds.data()[i], + templateEndpointId); + // for now, we need to copy the cluster definition, unfortunately. + // TODO: make endpointType use a pointer to a list of EmberAfCluster* instead, so we can re-use cluster definitions + // instead of duplicating them here once for every instance. + memcpy((void *) &endpointType.cluster[i], cluster, sizeof(EmberAfCluster)); + // sum up the needed storage + endpointType.endpointSize += cluster->clusterSize; + } + return EMBER_ZCL_STATUS_SUCCESS; +} + EmberAfStatus emberAfSetDynamicEndpoint(uint16_t index, EndpointId id, const EmberAfEndpointType * ep, const chip::Span & dataVersionStorage, chip::Span deviceTypeList, EndpointId parentEndpointId, @@ -289,6 +323,17 @@ EmberAfStatus emberAfSetDynamicEndpoint(uint16_t index, EndpointId id, const Emb } } + if (dynamicAttributeStorage != nullptr && ep->endpointSize > 0) + { + // Flag the endpoint as enabled here, because otherwise loading attributes cannot work + emAfEndpoints[index].bitmask = EMBER_AF_ENDPOINT_ENABLED; + // Load attributes from NVstorage or set defaults + emAfLoadAttributeDefaults(id, false); + // set disabled again, so enabling below will detect a transition + emAfEndpoints[index].bitmask = EMBER_AF_ENDPOINT_DISABLED; + } + // + // Now enable the endpoint. emberAfEndpointEnableDisable(id, true); @@ -631,8 +676,9 @@ EmberAfStatus emAfReadOrWriteAttribute(EmberAfAttributeSearchRecord * attRecord, (am->mask & ATTRIBUTE_MASK_SINGLETON ? singletonAttributeLocation(am) : (hasDynamicAttributeStorage ? emAfEndpoints[ep].dynamicAttributeStorage - : attributeData) + attributeStorageOffset); - ; + : attributeData) + + attributeStorageOffset); + uint8_t *src, *dst; if (write) diff --git a/src/app/util/attribute-storage.h b/src/app/util/attribute-storage.h index 227d85782d3d2b..325a76c82fda6a 100644 --- a/src/app/util/attribute-storage.h +++ b/src/app/util/attribute-storage.h @@ -17,7 +17,7 @@ #pragma once -//#include PLATFORM_HEADER +// #include PLATFORM_HEADER #include #include #include @@ -209,6 +209,18 @@ chip::Span emberAfDeviceTypeListFromEndpoint(chip::Endp // CHIP_ERROR emberAfSetDeviceTypeList(chip::EndpointId endpoint, chip::Span deviceTypeList); +// setup a dynamic endpoint's EmberAfEndpointType from a list of template clusters. +// +// This is a alternative to declare dynamic endpoint metadata using DECLARE_DYNAMIC_* macros. +// +// As clusters to be used in dynamic endpoint setup need to be defined in ZAP anyway +// (usually on a special endpoint which remains always disabled), the cluster's +// metadata including all attributes already exists and can be re-used this way, +// without error prone manual duplicating with DECLARE_DYNAMIC_* + +EmberAfStatus setupDynamicEndpointDeclaration(EmberAfEndpointType & endpointType, chip::EndpointId templateEndpointId, + const chip::Span & templateClusterIds); + // Register a dynamic endpoint. This involves registering descriptors that describe // the composition of the endpoint (encapsulated in the 'ep' argument) as well as providing // storage for data versions.