Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IM] Implement supported CommandList #14299

Merged
merged 19 commits into from
Feb 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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