Skip to content

Commit

Permalink
[attribute storage] allow setting up dynamic endpoints from templates
Browse files Browse the repository at this point in the history
Instead of re-creating dynamic endpoint's cluster declarations
using the DECLARE_DYNAMIC_xxx macros, the new
`setupDynamicEndpointDeclaration()` function allows setting
up a dynamic endpoint by using clusters defined in another
endpoint as templates. Usually that is a disabled endpoint created
in ZAP with all possibly dynamically used clusters assigned.

In combination with dynamic endpoint attribute storage, this
greatly simplifies implementing dynamic endpoints and allows
configuring them using the ZAP tool to ensure specs conformance,
much the same way as with statically defined endpoints.
  • Loading branch information
plan44 committed Jul 28, 2023
1 parent 751380d commit 2e48bd5
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 3 deletions.
50 changes: 48 additions & 2 deletions src/app/util/attribute-storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const ClusterId> & templateClusterIds)
{
// allocate cluster list
endpointType.clusterCount = static_cast<uint8_t>(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<chip::DataVersion> & dataVersionStorage,
chip::Span<const EmberAfDeviceType> deviceTypeList, EndpointId parentEndpointId,
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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)
Expand Down
14 changes: 13 additions & 1 deletion src/app/util/attribute-storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

#pragma once

//#include PLATFORM_HEADER
// #include PLATFORM_HEADER
#include <app/AttributeAccessInterface.h>
#include <app/ConcreteAttributePath.h>
#include <app/util/af.h>
Expand Down Expand Up @@ -209,6 +209,18 @@ chip::Span<const EmberAfDeviceType> emberAfDeviceTypeListFromEndpoint(chip::Endp
//
CHIP_ERROR emberAfSetDeviceTypeList(chip::EndpointId endpoint, chip::Span<const EmberAfDeviceType> 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<const chip::ClusterId> & 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.
Expand Down

0 comments on commit 2e48bd5

Please sign in to comment.