Skip to content

Commit

Permalink
[IM] Implement supported CommandList (#14299)
Browse files Browse the repository at this point in the history
* Add (Client|Server)GeneratedCommandList

* [GlobalAttributes] Add support to Server|ClientGeneratedCommands

* Run Codegen

* Update controller-clusters.zap

* Update endpoint-config template

* Run Codegen

* Update

* Add Tests

* Run Codegen

* Apply suggestions from code review

Co-authored-by: Boris Zbarsky <[email protected]>

* Fix merge

* Address Comments & Fix test

* Run Codegen

* Run Codegen

Co-authored-by: Boris Zbarsky <[email protected]>
  • Loading branch information
erjiaqing and bzbarsky-apple authored Feb 2, 2022
1 parent 46ab4be commit 15ef474
Show file tree
Hide file tree
Showing 54 changed files with 82,383 additions and 13,816 deletions.
13 changes: 13 additions & 0 deletions src/app/tests/suites/TestCluster.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3741,3 +3741,16 @@ tests:
# TODO: We don't have a way to represent cluster-specific status
# here yet.
error: FAILURE

- label: "read ClientGeneratedCommandList attribute"
command: "readAttribute"
attribute: "ClientGeneratedCommandList"
response:
value:
[0, 1, 2, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21]

- label: "read ServerGeneratedCommandList attribute"
command: "readAttribute"
attribute: "ServerGeneratedCommandList"
response:
value: [0, 1, 4, 5, 6, 9, 10, 11]
12 changes: 12 additions & 0 deletions src/app/util/af-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,18 @@ typedef struct
* if this cluster has no functions.
*/
const EmberAfGenericClusterFunction * functions;

/**
* A list of client generated commands. A client generated command
* is a client to server command. Can be nullptr or terminated by 0xFFFF_FFFF.
*/
const chip::CommandId * clientGeneratedCommandList;

/**
* A list of server generated commands. A server generated command
* is a response to client command request. Can be nullptr or terminated by 0xFFFF_FFFF.
*/
const chip::CommandId * serverGeneratedCommandList;
} EmberAfCluster;

/**
Expand Down
1 change: 1 addition & 0 deletions src/app/util/af.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
#include <app/util/debug-printing.h>
#include <app/util/ember-print.h>

#include <lib/core/DataModelTypes.h>
#include <lib/support/Iterators.h>
#include <lib/support/SafeInt.h>

Expand Down
1 change: 1 addition & 0 deletions src/app/util/attribute-storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ constexpr const EmberAfAttributeMinMaxValue minMaxDefaults[] = GENERATED_MIN_MAX
GENERATED_FUNCTION_ARRAYS
#endif

constexpr const chip::CommandId generatedCommands[] = GENERATED_COMMANDS;
constexpr const EmberAfAttributeMetadata generatedAttributes[] = GENERATED_ATTRIBUTES;
constexpr const EmberAfCluster generatedClusters[] = GENERATED_CLUSTERS;
constexpr const EmberAfEndpointType generatedEmberAfEndpointTypes[] = GENERATED_ENDPOINT_TYPES;
Expand Down
77 changes: 52 additions & 25 deletions src/app/util/ember-compatibility-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,39 +315,62 @@ class MandatoryGlobalAttributeReader : public AttributeAccessInterface
const EmberAfCluster * mCluster;
};

class AttributeListReader : public MandatoryGlobalAttributeReader
class GlobalAttributeReader : public MandatoryGlobalAttributeReader
{
public:
AttributeListReader(const EmberAfCluster * aCluster) : MandatoryGlobalAttributeReader(aCluster) {}
GlobalAttributeReader(const EmberAfCluster * aCluster) : MandatoryGlobalAttributeReader(aCluster) {}

CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
};

CHIP_ERROR AttributeListReader::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
CHIP_ERROR GlobalAttributeReader::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
{
// The id of AttributeList is not in the attribute metadata.
using namespace Clusters::Globals::Attributes;
// The id of the attributes below is not in the attribute metadata.
// TODO: This does not play nicely with wildcard reads. Need to fix ZAP to
// put it in the metadata, or fix wildcard expansion to add it.
return aEncoder.EncodeList([this](const auto & encoder) {
constexpr AttributeId ourId = Clusters::Globals::Attributes::AttributeList::Id;
const size_t count = mCluster->attributeCount;
bool addedOurId = false;
for (size_t i = 0; i < count; ++i)
{
AttributeId id = mCluster->attributes[i].attributeId;
if (!addedOurId && id > ourId)
switch (aPath.mAttributeId)
{
case AttributeList::Id:
return aEncoder.EncodeList([this](const auto & encoder) {
constexpr AttributeId ourId = Clusters::Globals::Attributes::AttributeList::Id;
const size_t count = mCluster->attributeCount;
bool addedOurId = false;
for (size_t i = 0; i < count; ++i)
{
AttributeId id = mCluster->attributes[i].attributeId;
if (!addedOurId && id > ourId)
{
ReturnErrorOnFailure(encoder.Encode(ourId));
addedOurId = true;
}
ReturnErrorOnFailure(encoder.Encode(id));
}
if (!addedOurId)
{
ReturnErrorOnFailure(encoder.Encode(ourId));
addedOurId = true;
}
ReturnErrorOnFailure(encoder.Encode(id));
}
if (!addedOurId)
{
ReturnErrorOnFailure(encoder.Encode(ourId));
}
return CHIP_NO_ERROR;
});
case ClientGeneratedCommandList::Id:
return aEncoder.EncodeList([this](const auto & encoder) {
for (const CommandId * cmd = mCluster->clientGeneratedCommandList; cmd != nullptr && *cmd != kInvalidCommandId; cmd++)
{
ReturnErrorOnFailure(encoder.Encode(*cmd));
}
return CHIP_NO_ERROR;
});
case ServerGeneratedCommandList::Id:
return aEncoder.EncodeList([this](const auto & encoder) {
for (const CommandId * cmd = mCluster->serverGeneratedCommandList; cmd != nullptr && *cmd != kInvalidCommandId; cmd++)
{
ReturnErrorOnFailure(encoder.Encode(*cmd));
}
return CHIP_NO_ERROR;
});
default:
return CHIP_NO_ERROR;
});
}
}

// Helper function for trying to read an attribute value via an
Expand Down Expand Up @@ -397,12 +420,16 @@ CHIP_ERROR ReadSingleClusterData(const SubjectDescriptor & aSubjectDescriptor, b
const EmberAfCluster * attributeCluster = nullptr;
const EmberAfAttributeMetadata * attributeMetadata = nullptr;

if (aPath.mAttributeId == Clusters::Globals::Attributes::AttributeList::Id)
switch (aPath.mAttributeId)
{
case Clusters::Globals::Attributes::AttributeList::Id:
FALLTHROUGH;
case Clusters::Globals::Attributes::ClientGeneratedCommandList::Id:
FALLTHROUGH;
case Clusters::Globals::Attributes::ServerGeneratedCommandList::Id:
attributeCluster = emberAfFindCluster(aPath.mEndpointId, aPath.mClusterId, CLUSTER_MASK_SERVER);
}
else
{
break;
default:
attributeMetadata =
emberAfLocateAttributeMetadata(aPath.mEndpointId, aPath.mClusterId, aPath.mAttributeId, CLUSTER_MASK_SERVER);
}
Expand Down Expand Up @@ -442,7 +469,7 @@ CHIP_ERROR ReadSingleClusterData(const SubjectDescriptor & aSubjectDescriptor, b
{
// Special handling for mandatory global attributes: these are always for attribute list, using a special
// reader (which can be lightweight constructed even from nullptr).
AttributeListReader reader(attributeCluster);
GlobalAttributeReader reader(attributeCluster);
AttributeAccessInterface * attributeOverride =
(attributeCluster != nullptr) ? &reader : findAttributeAccessOverride(aPath.mEndpointId, aPath.mClusterId);
if (attributeOverride)
Expand Down
10 changes: 10 additions & 0 deletions src/app/zap-templates/templates/app/endpoint_config.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,22 @@
// This is an array of EmberAfCluster structures.
#define ZAP_ATTRIBUTE_INDEX(index) (&generatedAttributes[index])

#define ZAP_GENERATED_COMMANDS_INDEX(index) ((chip::CommandId *) (&generatedCommands[index]))

// Cluster function static arrays
#define GENERATED_FUNCTION_ARRAYS {{chip_endpoint_generated_functions}}

// clang-format off
#define GENERATED_COMMANDS {{chip_endpoint_generated_commands_list}}
// clang-format on

#define ZAP_CLUSTER_MASK(mask) CLUSTER_MASK_ ## mask
#define GENERATED_CLUSTER_COUNT {{endpoint_cluster_count}}


// clang-format off
#define GENERATED_CLUSTERS {{chip_endpoint_cluster_list}}
// clang-format on

#define ZAP_CLUSTER_INDEX(index) (&generatedClusters[index])

Expand Down
107 changes: 85 additions & 22 deletions src/app/zap-templates/templates/app/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ zclHelper['isEvent'] = function(db, event_name, packageId) {
// This list of attributes is taken from section '11.2. Global Attributes' of the
// Data Model specification.
const kGlobalAttributes = [
0xfff8, // ServerGeneratedCommandList
0xfff9, // ClientGeneratedCommandList
0xfffb, // AttributeList
0xfffc, // ClusterRevision
0xfffd, // FeatureMap
Expand Down Expand Up @@ -178,14 +180,46 @@ function chip_endpoint_generated_functions()
return ret.concat('\n');
}

function chip_endpoint_generated_commands_list()
{
let ret = '{ \\\n';
this.clusterList.forEach((c) => {
let clientGeneratedCommands = [];
let serverGeneratedCommands = [];

c.commands.forEach((cmd) => {
if (cmd.mask.includes('incoming_server')) {
clientGeneratedCommands.push(`${cmd.commandId} /* ${cmd.name} */`);
}
if (cmd.mask.includes('incoming_client')) {
serverGeneratedCommands.push(`${cmd.commandId} /* ${cmd.name} */`);
}
});

if (clientGeneratedCommands.length > 0 || serverGeneratedCommands.length > 0) {
ret = ret.concat(` /* ${c.comment} */\\\n`);
}
if (clientGeneratedCommands.length > 0) {
clientGeneratedCommands.push('chip::kInvalidCommandId /* end of list */')
ret = ret.concat(` /* client_generated */ \\\n ${clientGeneratedCommands.join(', \\\n ')}, \\\n`);
}
if (serverGeneratedCommands.length > 0) {
serverGeneratedCommands.push('chip::kInvalidCommandId /* end of list */')
ret = ret.concat(` /* server_generated */ \\\n ${serverGeneratedCommands.join(', \\\n ')}, \\\n`);
}
})
return ret.concat('}\n');
}

/**
* Return endpoint config GENERATED_CLUSTER MACRO
* To be used as a replacement of endpoint_cluster_list since this one
* includes the GENERATED_FUNCTIONS array
*/
function chip_endpoint_cluster_list()
{
let ret = '{ \\\n';
let ret = '{ \\\n';
let totalCommands = 0;
this.clusterList.forEach((c) => {
let mask = '';
let functionArray = c.functions;
Expand Down Expand Up @@ -223,8 +257,36 @@ function chip_endpoint_cluster_list()
} else {
mask = c.mask.map((m) => `ZAP_CLUSTER_MASK(${m.toUpperCase()})`).join(' | ')
}
ret = ret.concat(` { ${c.clusterId}, ZAP_ATTRIBUTE_INDEX(${c.attributeIndex}), ${c.attributeCount}, ${c.attributeSize}, ${
mask}, ${functionArray} }, /* ${c.comment} */ \\\n`)

let clientGeneratedCommands = c.commands.reduce(((acc, cmd) => (acc + (cmd.mask.includes('incoming_server') ? 1 : 0))), 0);
let serverGeneratedCommands = c.commands.reduce(((acc, cmd) => (acc + (cmd.mask.includes('incoming_client') ? 1 : 0))), 0);

let clientGeneratedCommandsListVal = "nullptr";
let serverGeneratedCommandsListVal = "nullptr";

if (clientGeneratedCommands > 0) {
clientGeneratedCommands++; // Leaves space for the terminator
clientGeneratedCommandsListVal = `ZAP_GENERATED_COMMANDS_INDEX( ${totalCommands} )`;
}

if (serverGeneratedCommands > 0) {
serverGeneratedCommands++; // Leaves space for the terminator
serverGeneratedCommandsListVal = `ZAP_GENERATED_COMMANDS_INDEX( ${totalCommands + clientGeneratedCommands} )`;
}

ret = ret.concat(` { \\
/* ${c.comment} */ \\
.clusterId = ${c.clusterId}, \\
.attributes = ZAP_ATTRIBUTE_INDEX(${c.attributeIndex}), \\
.attributeCount = ${c.attributeCount}, \\
.clusterSize = ${c.attributeSize}, \\
.mask = ${mask}, \\
.functions = ${functionArray}, \\
.clientGeneratedCommandList = ${clientGeneratedCommandsListVal} ,\\
.serverGeneratedCommandList = ${serverGeneratedCommandsListVal} ,\\
},\\\n`)

totalCommands = totalCommands + clientGeneratedCommands + serverGeneratedCommands;
})
return ret.concat('}\n');
}
Expand Down Expand Up @@ -764,22 +826,23 @@ async function zcl_events_fields_by_event_name(name, options)
//
// Module exports
//
exports.asPrintFormat = asPrintFormat;
exports.asReadType = asReadType;
exports.chip_endpoint_generated_functions = chip_endpoint_generated_functions
exports.chip_endpoint_cluster_list = chip_endpoint_cluster_list
exports.chip_endpoint_data_version_count = chip_endpoint_data_version_count;
exports.asTypedLiteral = asTypedLiteral;
exports.asLowerCamelCase = asLowerCamelCase;
exports.asUpperCamelCase = asUpperCamelCase;
exports.hasProperty = hasProperty;
exports.hasSpecificAttributes = hasSpecificAttributes;
exports.asMEI = asMEI;
exports.zapTypeToEncodableClusterObjectType = zapTypeToEncodableClusterObjectType;
exports.zapTypeToDecodableClusterObjectType = zapTypeToDecodableClusterObjectType;
exports.zapTypeToPythonClusterObjectType = zapTypeToPythonClusterObjectType;
exports.getResponseCommandName = getResponseCommandName;
exports.isWeaklyTypedEnum = isWeaklyTypedEnum;
exports.getPythonFieldDefault = getPythonFieldDefault;
exports.incrementDepth = incrementDepth;
exports.zcl_events_fields_by_event_name = zcl_events_fields_by_event_name;
exports.asPrintFormat = asPrintFormat;
exports.asReadType = asReadType;
exports.chip_endpoint_generated_functions = chip_endpoint_generated_functions
exports.chip_endpoint_cluster_list = chip_endpoint_cluster_list
exports.chip_endpoint_data_version_count = chip_endpoint_data_version_count;
exports.chip_endpoint_generated_commands_list = chip_endpoint_generated_commands_list
exports.asTypedLiteral = asTypedLiteral;
exports.asLowerCamelCase = asLowerCamelCase;
exports.asUpperCamelCase = asUpperCamelCase;
exports.hasProperty = hasProperty;
exports.hasSpecificAttributes = hasSpecificAttributes;
exports.asMEI = asMEI;
exports.zapTypeToEncodableClusterObjectType = zapTypeToEncodableClusterObjectType;
exports.zapTypeToDecodableClusterObjectType = zapTypeToDecodableClusterObjectType;
exports.zapTypeToPythonClusterObjectType = zapTypeToPythonClusterObjectType;
exports.getResponseCommandName = getResponseCommandName;
exports.isWeaklyTypedEnum = isWeaklyTypedEnum;
exports.getPythonFieldDefault = getPythonFieldDefault;
exports.incrementDepth = incrementDepth;
exports.zcl_events_fields_by_event_name = zcl_events_fields_by_event_name;
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ limitations under the License.
<attribute side="client" code="0xFFFC" define="FEATURE_MAP_CLIENT" type="bitmap32" default="0" optional="true">FeatureMap</attribute>
<attribute side="server" code="0xFFFC" define="FEATURE_MAP_SERVER" type="bitmap32" default="0" optional="true">FeatureMap</attribute>
<attribute side="server" code="0xFFFB" define="ATTRIBUTE_LIST_SERVER" type="array" entryType="attrib_id">AttributeList</attribute>
<attribute side="server" code="0xFFF9" define="CLIENT_GENERATED_COMMAND_LIST" type="array" entryType="command_id">ClientGeneratedCommandList</attribute>
<attribute side="server" code="0xFFF8" define="SERVER_GENERATED_COMMAND_LIST" type="array" entryType="command_id">ServerGeneratedCommandList</attribute>

</global>
</configurator>
Loading

0 comments on commit 15ef474

Please sign in to comment.