Skip to content

Commit

Permalink
Add data version storage to endpoints. (#14471)
Browse files Browse the repository at this point in the history
* Add data version storage to endpoints.

For fixed endpoints we codegen the storage.  For dynamic endpoints
consumers are responsible for providing some.

* Address review comments.
  • Loading branch information
bzbarsky-apple authored and pull[bot] committed Oct 16, 2023
1 parent 3d4b72c commit cad43a1
Show file tree
Hide file tree
Showing 32 changed files with 247 additions and 48 deletions.
20 changes: 13 additions & 7 deletions examples/bridge-app/esp32/main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ DECLARE_DYNAMIC_CLUSTER(ZCL_ON_OFF_CLUSTER_ID, onOffAttrs), DECLARE_DYNAMIC_CLUS
// Declare Bridged Light endpoint
DECLARE_DYNAMIC_ENDPOINT(bridgedLightEndpoint, bridgedLightClusters);

DataVersion gLight1DataVersions[ArraySize(bridgedLightClusters)];
DataVersion gLight2DataVersions[ArraySize(bridgedLightClusters)];
DataVersion gLight3DataVersions[ArraySize(bridgedLightClusters)];
DataVersion gLight4DataVersions[ArraySize(bridgedLightClusters)];

/* REVISION definitions:
*/

Expand All @@ -113,7 +118,8 @@ DECLARE_DYNAMIC_ENDPOINT(bridgedLightEndpoint, bridgedLightClusters);
#define ZCL_FIXED_LABEL_CLUSTER_REVISION (1u)
#define ZCL_ON_OFF_CLUSTER_REVISION (4u)

CHIP_ERROR AddDeviceEndpoint(Device * dev, EmberAfEndpointType * ep, uint16_t deviceType)
CHIP_ERROR AddDeviceEndpoint(Device * dev, EmberAfEndpointType * ep, uint16_t deviceType,
const Span<DataVersion> & dataVersionStorage)
{
uint8_t index = 0;
while (index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT)
Expand All @@ -122,7 +128,7 @@ CHIP_ERROR AddDeviceEndpoint(Device * dev, EmberAfEndpointType * ep, uint16_t de
{
gDevices[index] = dev;
EmberAfStatus ret;
ret = emberAfSetDynamicEndpoint(index, gCurrentEndpointId, ep, deviceType, DEVICE_VERSION_DEFAULT);
ret = emberAfSetDynamicEndpoint(index, gCurrentEndpointId, ep, deviceType, DEVICE_VERSION_DEFAULT, dataVersionStorage);
if (ret == EMBER_ZCL_STATUS_SUCCESS)
{
ChipLogProgress(DeviceLayer, "Added device %s to dynamic endpoint %d (index=%d)", dev->GetName(),
Expand Down Expand Up @@ -360,18 +366,18 @@ static void InitServer(intptr_t context)
emberAfEndpointEnableDisable(emberAfEndpointFromIndex(static_cast<uint16_t>(emberAfFixedEndpointCount() - 1)), false);

// Add lights 1..3 --> will be mapped to ZCL endpoints 2, 3, 4
AddDeviceEndpoint(&gLight1, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT);
AddDeviceEndpoint(&gLight2, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT);
AddDeviceEndpoint(&gLight3, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT);
AddDeviceEndpoint(&gLight1, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT, Span<DataVersion>(gLight1DataVersions));
AddDeviceEndpoint(&gLight2, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT, Span<DataVersion>(gLight2DataVersions));
AddDeviceEndpoint(&gLight3, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT, Span<DataVersion>(gLight3DataVersions));

// Remove Light 2 -- Lights 1 & 3 will remain mapped to endpoints 2 & 4
RemoveDeviceEndpoint(&gLight2);

// Add Light 4 -- > will be mapped to ZCL endpoint 5
AddDeviceEndpoint(&gLight4, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT);
AddDeviceEndpoint(&gLight4, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT, Span<DataVersion>(gLight4DataVersions));

// Re-add Light 2 -- > will be mapped to ZCL endpoint 6
AddDeviceEndpoint(&gLight2, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT);
AddDeviceEndpoint(&gLight2, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT, Span<DataVersion>(gLight2DataVersions));
}

extern "C" void app_main()
Expand Down
27 changes: 18 additions & 9 deletions examples/bridge-app/linux/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ DECLARE_DYNAMIC_CLUSTER(ZCL_ON_OFF_CLUSTER_ID, onOffAttrs), DECLARE_DYNAMIC_CLUS

// Declare Bridged Light endpoint
DECLARE_DYNAMIC_ENDPOINT(bridgedLightEndpoint, bridgedLightClusters);
DataVersion gLight1DataVersions[ArraySize(bridgedLightClusters)];
DataVersion gLight2DataVersions[ArraySize(bridgedLightClusters)];
DataVersion gLight3DataVersions[ArraySize(bridgedLightClusters)];
DataVersion gLight4DataVersions[ArraySize(bridgedLightClusters)];

// ---------------------------------------------------------------------------
//
Expand Down Expand Up @@ -169,6 +173,8 @@ DECLARE_DYNAMIC_CLUSTER(ZCL_SWITCH_CLUSTER_ID, switchAttrs),

// Declare Bridged Switch endpoint
DECLARE_DYNAMIC_ENDPOINT(bridgedSwitchEndpoint, bridgedSwitchClusters);
DataVersion gSwitch1DataVersions[ArraySize(bridgedSwitchClusters)];
DataVersion gSwitch2DataVersions[ArraySize(bridgedSwitchClusters)];

// REVISION DEFINITIONS:
// =================================================================================
Expand All @@ -181,7 +187,7 @@ DECLARE_DYNAMIC_ENDPOINT(bridgedSwitchEndpoint, bridgedSwitchClusters);

// ---------------------------------------------------------------------------

int AddDeviceEndpoint(Device * dev, EmberAfEndpointType * ep, uint16_t deviceType)
int AddDeviceEndpoint(Device * dev, EmberAfEndpointType * ep, uint16_t deviceType, const Span<DataVersion> & dataVersionStorage)
{
uint8_t index = 0;
while (index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT)
Expand All @@ -192,7 +198,8 @@ int AddDeviceEndpoint(Device * dev, EmberAfEndpointType * ep, uint16_t deviceTyp
EmberAfStatus ret;
while (1)
{
ret = emberAfSetDynamicEndpoint(index, gCurrentEndpointId, ep, deviceType, DEVICE_VERSION_DEFAULT);
ret = emberAfSetDynamicEndpoint(index, gCurrentEndpointId, ep, deviceType, DEVICE_VERSION_DEFAULT,
dataVersionStorage);
if (ret == EMBER_ZCL_STATUS_SUCCESS)
{
ChipLogProgress(DeviceLayer, "Added device %s to dynamic endpoint %d (index=%d)", dev->GetName(),
Expand Down Expand Up @@ -648,22 +655,24 @@ int main(int argc, char * argv[])
emberAfEndpointEnableDisable(emberAfEndpointFromIndex(static_cast<uint16_t>(emberAfFixedEndpointCount() - 1)), false);

// Add lights 1..3 --> will be mapped to ZCL endpoints 2, 3, 4
AddDeviceEndpoint(&Light1, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT);
AddDeviceEndpoint(&Light2, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT);
AddDeviceEndpoint(&Light3, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT);
AddDeviceEndpoint(&Light1, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT, Span<DataVersion>(gLight1DataVersions));
AddDeviceEndpoint(&Light2, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT, Span<DataVersion>(gLight2DataVersions));
AddDeviceEndpoint(&Light3, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT, Span<DataVersion>(gLight3DataVersions));

// Remove Light 2 -- Lights 1 & 3 will remain mapped to endpoints 2 & 4
RemoveDeviceEndpoint(&Light2);

// Add Light 4 -- > will be mapped to ZCL endpoint 5
AddDeviceEndpoint(&Light4, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT);
AddDeviceEndpoint(&Light4, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT, Span<DataVersion>(gLight4DataVersions));

// Re-add Light 2 -- > will be mapped to ZCL endpoint 6
AddDeviceEndpoint(&Light2, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT);
AddDeviceEndpoint(&Light2, &bridgedLightEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT, Span<DataVersion>(gLight2DataVersions));

// Add switch 1..2 --> will be mapped to ZCL endpoints 7,8
AddDeviceEndpoint(&Switch1, &bridgedSwitchEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT_SWITCH);
AddDeviceEndpoint(&Switch2, &bridgedSwitchEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT_SWITCH);
AddDeviceEndpoint(&Switch1, &bridgedSwitchEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT_SWITCH,
Span<DataVersion>(gSwitch1DataVersions));
AddDeviceEndpoint(&Switch2, &bridgedSwitchEndpoint, DEVICE_TYPE_LO_ON_OFF_LIGHT_SWITCH,
Span<DataVersion>(gSwitch2DataVersions));

// Run CHIP

Expand Down
13 changes: 11 additions & 2 deletions examples/tv-app/linux/AppImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ DECLARE_DYNAMIC_CLUSTER(ZCL_DESCRIPTOR_CLUSTER_ID, descriptorAttrs),
// Declare Content App endpoint
DECLARE_DYNAMIC_ENDPOINT(contentAppEndpoint, contentAppClusters);

namespace {

DataVersion gDataVersions[APP_LIBRARY_SIZE][ArraySize(contentAppClusters)];

} // anonymous namespace

ContentAppFactoryImpl::ContentAppFactoryImpl() {}

uint16_t ContentAppFactoryImpl::GetPlatformCatalogVendorId()
Expand Down Expand Up @@ -184,12 +190,15 @@ ContentApp * ContentAppFactoryImpl::LoadContentApp(CatalogVendorApp vendorApp)
ChipLogProgress(DeviceLayer, "ContentAppFactoryImpl: LoadContentAppByAppId catalogVendorId=%d applicationId=%s ",
vendorApp.catalogVendorId, vendorApp.applicationId);

for (auto & app : mContentApps)
for (size_t i = 0; i < ArraySize(mContentApps); ++i)
{
auto & app = mContentApps[i];

ChipLogProgress(DeviceLayer, " Looking next=%s ", app.GetApplicationBasicDelegate()->GetCatalogVendorApp()->applicationId);
if (app.GetApplicationBasicDelegate()->GetCatalogVendorApp()->Matches(vendorApp))
{
ContentAppPlatform::GetInstance().AddContentApp(&app, &contentAppEndpoint, DEVICE_TYPE_CONTENT_APP);
ContentAppPlatform::GetInstance().AddContentApp(&app, &contentAppEndpoint, DEVICE_TYPE_CONTENT_APP,
Span<DataVersion>(gDataVersions[i]));
return &app;
}
}
Expand Down
6 changes: 4 additions & 2 deletions src/app/app-platform/ContentAppPlatform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ EmberAfStatus emberAfExternalAttributeWriteCallback(EndpointId endpoint, Cluster
namespace chip {
namespace AppPlatform {

EndpointId ContentAppPlatform::AddContentApp(ContentApp * app, EmberAfEndpointType * ep, uint16_t deviceType)
EndpointId ContentAppPlatform::AddContentApp(ContentApp * app, EmberAfEndpointType * ep, uint16_t deviceType,
const Span<DataVersion> & dataVersionStorage)
{
CatalogVendorApp vendorApp = app->GetApplicationBasicDelegate()->GetCatalogVendorApp();

Expand All @@ -111,7 +112,8 @@ EndpointId ContentAppPlatform::AddContentApp(ContentApp * app, EmberAfEndpointTy
EmberAfStatus ret;
while (1)
{
ret = emberAfSetDynamicEndpoint(index, mCurrentEndpointId, ep, deviceType, DEVICE_VERSION_DEFAULT);
ret = emberAfSetDynamicEndpoint(index, mCurrentEndpointId, ep, deviceType, DEVICE_VERSION_DEFAULT,
dataVersionStorage);
if (ret == EMBER_ZCL_STATUS_SUCCESS)
{
ChipLogProgress(DeviceLayer, "Added ContentApp %s to dynamic endpoint %d (index=%d)", vendorApp.applicationId,
Expand Down
7 changes: 6 additions & 1 deletion src/app/app-platform/ContentAppPlatform.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <app/app-platform/ContentApp.h>
#include <app/util/attribute-storage.h>
#include <functional>
#include <lib/support/Span.h>
#include <platform/CHIPDeviceLayer.h>
#include <stdbool.h>
#include <stdint.h>
Expand Down Expand Up @@ -72,7 +73,11 @@ class DLL_EXPORT ContentAppPlatform
// add apps to the platform.
// This will assign the app to an endpoint (if it is not already added) and make it accessible via Matter
// returns the global endpoint for this app, or 0 if an error occurred
EndpointId AddContentApp(ContentApp * app, EmberAfEndpointType * ep, uint16_t deviceType);
//
// dataVersionStorage.size() needs to be at least as big as the number of
// server clusters in the EmberAfEndpointType passed in.
EndpointId AddContentApp(ContentApp * app, EmberAfEndpointType * ep, uint16_t deviceType,
const Span<DataVersion> & dataVersionStorage);

// remove app from the platform.
// returns the endpoint id where the app was, or 0 if app was not loaded
Expand Down
5 changes: 5 additions & 0 deletions src/app/util/af-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,11 @@ typedef struct
* Endpoint type for this endpoint.
*/
const EmberAfEndpointType * endpointType;
/**
* Pointer to the DataVersion storage for the server clusters on this
* endpoint
*/
chip::DataVersion * dataVersions;
/**
* Network index for this endpoint.
*/
Expand Down
10 changes: 10 additions & 0 deletions src/app/util/af.h
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,16 @@ int emberAfMain(MAIN_FUNCTION_PARAMETERS);
*/
EmberAfStatus emberAfClusterSpecificCommandParse(EmberAfClusterCommand * cmd);

/**
* Returns the pointer to the data version storage for the given endpoint and
* cluster. Can return null in the following cases:
*
* 1) There is no such endpoint.
* 2) There is no such server cluster on the given endpoint.
* 3) No storage for a data version was provided for the endpoint.
*/
chip::DataVersion * emberAfDataVersionStorage(chip::EndpointId endpointId, chip::ClusterId clusterId);

namespace chip {
namespace app {

Expand Down
93 changes: 84 additions & 9 deletions src/app/util/attribute-storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ GENERATED_FUNCTION_ARRAYS
constexpr const EmberAfAttributeMetadata generatedAttributes[] = GENERATED_ATTRIBUTES;
constexpr const EmberAfCluster generatedClusters[] = GENERATED_CLUSTERS;
constexpr const EmberAfEndpointType generatedEmberAfEndpointTypes[] = GENERATED_ENDPOINT_TYPES;
// Not const, because these need to mutate.
DataVersion fixedEndpointDataVersions[ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT];

#if !defined(EMBER_SCRIPTED_TEST)
#define endpointNumber(x) fixedEndpoints[x]
Expand Down Expand Up @@ -131,15 +133,34 @@ void emberAfEndpointConfigure(void)
uint8_t fixedNetworks[] = FIXED_NETWORKS;
#endif

emberEndpointCount = FIXED_ENDPOINT_COUNT;
#if ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT > 0
// Initialize our data version storage. If
// ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT == 0, gcc complains about a memset
// with size equal to number of elements without multiplication by element
// size, because the sizeof() is also 0 in that case...
if (Crypto::DRBG_get_bytes(reinterpret_cast<uint8_t *>(fixedEndpointDataVersions), sizeof(fixedEndpointDataVersions)) !=
CHIP_NO_ERROR)
{
// Now what? At least 0-init it.
memset(fixedEndpointDataVersions, 0, sizeof(fixedEndpointDataVersions));
}
#endif // ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT > 0

emberEndpointCount = FIXED_ENDPOINT_COUNT;
DataVersion * currentDataVersions = fixedEndpointDataVersions;
for (ep = 0; ep < FIXED_ENDPOINT_COUNT; ep++)
{
emAfEndpoints[ep].endpoint = endpointNumber(ep);
emAfEndpoints[ep].deviceId = endpointDeviceId(ep);
emAfEndpoints[ep].deviceVersion = endpointDeviceVersion(ep);
emAfEndpoints[ep].endpointType = endpointTypeMacro(ep);
emAfEndpoints[ep].dataVersions = currentDataVersions;
emAfEndpoints[ep].networkIndex = endpointNetworkIndex(ep);
emAfEndpoints[ep].bitmask = EMBER_AF_ENDPOINT_ENABLED;

// Increment currentDataVersions by 1 (slot) for every server cluster
// this endpoint has.
currentDataVersions += emberAfClusterCountByIndex(ep, /* server = */ true);
}

#if CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT
Expand Down Expand Up @@ -176,7 +197,7 @@ uint16_t emberAfGetDynamicIndexFromEndpoint(EndpointId id)
}

EmberAfStatus emberAfSetDynamicEndpoint(uint16_t index, EndpointId id, EmberAfEndpointType * ep, uint16_t deviceId,
uint8_t deviceVersion)
uint8_t deviceVersion, const Span<DataVersion> & dataVersionStorage)
{
auto realIndex = index + FIXED_ENDPOINT_COUNT;

Expand All @@ -189,6 +210,12 @@ EmberAfStatus emberAfSetDynamicEndpoint(uint16_t index, EndpointId id, EmberAfEn
return EMBER_ZCL_STATUS_CONSTRAINT_ERROR;
}

auto serverClusterCount = emberAfClusterCountForEndpointType(ep, /* server = */ true);
if (dataVersionStorage.size() < serverClusterCount)
{
return EMBER_ZCL_STATUS_INSUFFICIENT_SPACE;
}

index = static_cast<uint16_t>(realIndex);
for (uint16_t i = FIXED_ENDPOINT_COUNT; i < MAX_ENDPOINT_COUNT; i++)
{
Expand All @@ -202,12 +229,24 @@ EmberAfStatus emberAfSetDynamicEndpoint(uint16_t index, EndpointId id, EmberAfEn
emAfEndpoints[index].deviceId = deviceId;
emAfEndpoints[index].deviceVersion = deviceVersion;
emAfEndpoints[index].endpointType = ep;
emAfEndpoints[index].dataVersions = dataVersionStorage.data();
emAfEndpoints[index].networkIndex = 0;
// Start the endpoint off as disabled.
emAfEndpoints[index].bitmask = EMBER_AF_ENDPOINT_DISABLED;

emberAfSetDynamicEndpointCount(MAX_ENDPOINT_COUNT - FIXED_ENDPOINT_COUNT);

// Initialize the data versions.
size_t dataSize = sizeof(DataVersion) * serverClusterCount;
if (dataSize != 0)
{
if (Crypto::DRBG_get_bytes(reinterpret_cast<uint8_t *>(dataVersionStorage.data()), dataSize) != CHIP_NO_ERROR)
{
// Now what? At least 0-init it.
memset(dataVersionStorage.data(), 0, dataSize);
}
}

// Now enable the endpoint.
emberAfEndpointEnableDisable(id, true);
emberAfSetDeviceEnabled(id, true);
Expand Down Expand Up @@ -971,22 +1010,31 @@ EndpointId emberAfEndpointFromIndex(uint16_t index)
uint8_t emberAfClusterCount(EndpointId endpoint, bool server)
{
uint16_t index = emberAfIndexFromEndpoint(endpoint);
uint8_t i, c = 0;
EmberAfDefinedEndpoint * de;
const EmberAfCluster * cluster;

if (index == 0xFFFF)
{
return 0;
}
de = &(emAfEndpoints[index]);

return emberAfClusterCountByIndex(index, server);
}

uint8_t emberAfClusterCountByIndex(uint16_t endpointIndex, bool server)
{
const EmberAfDefinedEndpoint * de = &(emAfEndpoints[endpointIndex]);
if (de->endpointType == NULL)
{
return 0;
}
for (i = 0; i < de->endpointType->clusterCount; i++)

return emberAfClusterCountForEndpointType(de->endpointType, server);
}

uint8_t emberAfClusterCountForEndpointType(const EmberAfEndpointType * type, bool server)
{
uint8_t c = 0;
for (uint8_t i = 0; i < type->clusterCount; i++)
{
cluster = &(de->endpointType->cluster[i]);
auto * cluster = &(type->cluster[i]);
if (server && emberAfClusterIsServer(cluster))
{
c++;
Expand Down Expand Up @@ -1381,3 +1429,30 @@ Optional<AttributeId> emberAfGetServerAttributeIdByIndex(EndpointId endpoint, Cl
}
return Optional<AttributeId>(clusterObj->attributes[attributeIndex].attributeId);
}

DataVersion * emberAfDataVersionStorage(chip::EndpointId endpointId, chip::ClusterId clusterId)
{
uint16_t index = emberAfIndexFromEndpoint(endpointId);
if (index == 0xFFFF)
{
// Unknown endpoint.
return nullptr;
}
const EmberAfDefinedEndpoint & ep = emAfEndpoints[index];
if (!ep.dataVersions)
{
// No storage provided.
return nullptr;
}

// This does a second walk over endpoints to find the right one, but
// probably worth it to avoid duplicating code.
auto clusterIndex = emberAfClusterIndex(endpointId, clusterId, CLUSTER_MASK_SERVER);
if (clusterIndex == 0xFF)
{
// No such cluster on this endpoint.
return nullptr;
}

return ep.dataVersions + clusterIndex;
}
Loading

0 comments on commit cad43a1

Please sign in to comment.