diff --git a/examples/chip-tool/templates/commands.zapt b/examples/chip-tool/templates/commands.zapt index e4a1ef7dcb3559..a0ec4aff7db1b0 100644 --- a/examples/chip-tool/templates/commands.zapt +++ b/examples/chip-tool/templates/commands.zapt @@ -281,12 +281,12 @@ private: {{#if isList}} chip::Callback::Callback<{{asCamelCased parent.name false}}{{asCamelCased name false}}ListAttributeCallback> * onSuccessCallback = new chip::Callback::Callback<{{asCamelCased parent.name false}}{{asCamelCased name false}}ListAttributeCallback>(On{{asCamelCased parent.name false}}{{asCamelCased name false}}ListAttributeResponse, this); {{else}} - chip::Callback::Callback<{{asCallbackAttributeType atomicTypeId}}AttributeCallback> * onSuccessCallback = new chip::Callback::Callback<{{asCallbackAttributeType atomicTypeId}}AttributeCallback>(On{{asCallbackAttributeType atomicTypeId}}AttributeResponse, this); + chip::Callback::Callback<{{chipCallback.name}}AttributeCallback> * onSuccessCallback = new chip::Callback::Callback<{{chipCallback.name}}AttributeCallback>(On{{chipCallback.name}}AttributeResponse, this); {{/if}} chip::Callback::Callback * onFailureCallback = new chip::Callback::Callback(OnDefaultFailureResponse, this); }; -{{#if (isWritableAttribute)}} +{{#if isWritableAttribute}} class Write{{asCamelCased parent.name false}}{{asCamelCased name false}}: public ModelCommand { public: @@ -327,7 +327,7 @@ private: }; {{/if}} -{{#if (isReportableAttribute)}} +{{#if isReportableAttribute}} class Report{{asCamelCased parent.name false}}{{asCamelCased name false}}: public ModelCommand { public: @@ -368,7 +368,7 @@ public: private: chip::Callback::Callback * onSuccessCallback = new chip::Callback::Callback(OnDefaultSuccessResponse, this); chip::Callback::Callback * onFailureCallback = new chip::Callback::Callback(OnDefaultFailureResponse, this); - chip::Callback::Callback<{{asCallbackAttributeType atomicTypeId}}AttributeCallback> * onReportCallback = new chip::Callback::Callback<{{asCallbackAttributeType atomicTypeId}}AttributeCallback>(On{{asCallbackAttributeType atomicTypeId}}AttributeResponse, this); + chip::Callback::Callback<{{chipCallback.name}}AttributeCallback> * onReportCallback = new chip::Callback::Callback<{{chipCallback.name}}AttributeCallback>(On{{chipCallback.name}}AttributeResponse, this); uint16_t mMinInterval; uint16_t mMaxInterval; {{#if isAnalog}} @@ -395,10 +395,10 @@ void registerCluster{{asCamelCased name false}}(Commands & commands) make_unique(), {{#chip_server_cluster_attributes}} make_unique(), - {{#if (isWritableAttribute)}} + {{#if isWritableAttribute}} make_unique(), {{/if}} - {{#if (isReportableAttribute)}} + {{#if isReportableAttribute}} make_unique(), {{/if}} {{/chip_server_cluster_attributes}} diff --git a/examples/chip-tool/templates/reporting-commands.zapt b/examples/chip-tool/templates/reporting-commands.zapt index b77c9c139c2762..0c827b2a7699c8 100644 --- a/examples/chip-tool/templates/reporting-commands.zapt +++ b/examples/chip-tool/templates/reporting-commands.zapt @@ -18,7 +18,7 @@ public: { {{#chip_clusters}} {{#chip_server_cluster_attributes}} -{{#if (isReportableAttribute)}} +{{#if isReportableAttribute}} delete onReport{{asCamelCased parent.name false}}{{asCamelCased name false}}Callback; {{/if}} {{/chip_server_cluster_attributes}} @@ -30,7 +30,7 @@ public: chip::app::CHIPDeviceCallbacksMgr & callbacksMgr = chip::app::CHIPDeviceCallbacksMgr::GetInstance(); {{#chip_clusters}} {{#chip_server_cluster_attributes}} -{{#if (isReportableAttribute)}} +{{#if isReportableAttribute}} callbacksMgr.AddReportCallback(chip::kTestDeviceNodeId, endpointId, {{asHex parent.code 4}}, {{asHex code 4}}, onReport{{asCamelCased parent.name false}}{{asCamelCased name false}}Callback->Cancel()); {{/if}} {{/chip_server_cluster_attributes}} @@ -75,8 +75,8 @@ public: private: {{#chip_clusters}} {{#chip_server_cluster_attributes}} -{{#if (isReportableAttribute)}} - chip::Callback::Callback<{{asCallbackAttributeType atomicTypeId}}AttributeCallback> * onReport{{asCamelCased parent.name false}}{{asCamelCased name false}}Callback = new chip::Callback::Callback<{{asCallbackAttributeType atomicTypeId}}AttributeCallback>(On{{asCallbackAttributeType atomicTypeId}}AttributeResponse, this); +{{#if isReportableAttribute}} + chip::Callback::Callback<{{chipCallback.name}}AttributeCallback> * onReport{{asCamelCased parent.name false}}{{asCamelCased name false}}Callback = new chip::Callback::Callback<{{chipCallback.name}}AttributeCallback>(On{{chipCallback.name}}AttributeResponse, this); {{/if}} {{/chip_server_cluster_attributes}} {{/chip_clusters}} diff --git a/src/app/zap-templates/common/ClustersHelper.js b/src/app/zap-templates/common/ClustersHelper.js index c90b3a8a649f36..6d99f6b7e62ea1 100644 --- a/src/app/zap-templates/common/ClustersHelper.js +++ b/src/app/zap-templates/common/ClustersHelper.js @@ -26,6 +26,7 @@ const zclQuery = require(zapPath + 'db/query-zcl.js') const { Deferred } = require('./Deferred.js'); const ListHelper = require('./ListHelper.js'); const StringHelper = require('./StringHelper.js'); +const StructHelper = require('./StructHelper.js'); const ChipTypesHelper = require('./ChipTypesHelper.js'); // @@ -118,6 +119,14 @@ function loadAttributes(packageId) //.then(attributes => Promise.all(attributes.map(attribute => types.typeSizeAttribute(db, packageId, attribute)) } +function loadGlobalAttributes(packageId) +{ + const { db, sessionId } = this.global; + return zclQuery.selectAllAttributes(db, packageId) + .then(attributes => attributes.filter(attribute => attribute.clusterRef == null)) + .then(attributes => attributes.map(attribute => attribute.code)); +} + // // Load step 2 // @@ -166,6 +175,37 @@ function asPutCastType(zclType) } } +function asChipCallback(item) +{ + if (StringHelper.isString(item.type)) { + return { name : 'String', type : 'const chip::ByteSpan' }; + } + + if (ListHelper.isList(item.type)) { + return { name : 'List', type : null }; + } + + if (item.type == 'boolean') { + return { name : 'Boolean', type : 'bool' }; + } + + const basicType = ChipTypesHelper.asBasicType(item.chipType); + switch (basicType) { + case 'int8_t': + case 'int16_t': + case 'int32_t': + case 'int64_t': + return { name : 'Int' + basicType.replace(/[^0-9]/g, '') + 's', type : basicType }; + case 'uint8_t': + case 'uint16_t': + case 'uint32_t': + case 'uint64_t': + return { name : 'Int' + basicType.replace(/[^0-9]/g, '') + 'u', type : basicType }; + default: + return { name : 'Unsupported', type : null }; + } +} + function getAtomic(atomics, type) { return atomics.find(atomic => atomic.name == type.toLowerCase()); @@ -321,7 +361,8 @@ function enhancedCommands(commands, types) }); commands.forEach(command => { - command.isResponse = command.name.includes('Response'); + command.isResponse = command.name.includes('Response'); + command.isManufacturerSpecificCommand = !!this.mfgCode; }); commands.forEach(command => { @@ -392,14 +433,25 @@ function enhancedCommands(commands, types) return commands; } -function enhancedAttributes(attributes, types) +function enhancedAttributes(attributes, globalAttributes, types) { attributes.forEach(attribute => { enhancedItem(attribute, types); + attribute.isGlobalAttribute = globalAttributes.includes(attribute.code); + attribute.isWritableAttribute = attribute.isWritable === 1; + attribute.isReportableAttribute = attribute.includedReportable === 1; + attribute.chipCallback = asChipCallback(attribute); }); attributes.forEach(attribute => { - const argument = { isList : attribute.isList, name : attribute.name, chipType : attribute.chipType, type : attribute.type }; + const argument = { + name : attribute.name, + type : attribute.type, + size : attribute.size, + isList : attribute.isList, + chipType : attribute.chipType, + chipCallback : attribute.chipCallback + }; attribute.arguments = [ argument ]; attribute.response = { arguments : [ argument ] }; }); @@ -434,12 +486,13 @@ Clusters.init = function(context, packageId) { loadClusters.call(context), loadCommands.call(context, packageId), loadAttributes.call(context, packageId), + loadGlobalAttributes.call(context, packageId), ]; - return Promise.all(promises).then(([types, clusters, commands, attributes]) => { + return Promise.all(promises).then(([types, clusters, commands, attributes, globalAttributes]) => { this._clusters = clusters; this._commands = enhancedCommands(commands, types); - this._attributes = enhancedAttributes(attributes, types); + this._attributes = enhancedAttributes(attributes, globalAttributes, types); return this.ready.resolve(); }); @@ -461,78 +514,123 @@ function asPromise(promise) return templateUtil.ensureZclPackageId(this).then(fn).catch(err => console.log(err)); } +// +// Helpers: Get all clusters/commands/responses/attributes. +// +const kResponseFilter = (isResponse, item) => isResponse == item.isResponse; + Clusters.getClusters = function() { return this.ready.then(() => this._clusters); } -Clusters.getCommands = function(name, side) +Clusters.getCommands = function() { - const filter = command => command.clusterName.toLowerCase() == name.toLowerCase() && command.clusterSide == side && command.isResponse == false; - return this.ready.then(() => this._commands.filter(filter)); + return this.ready.then(() => this._commands.filter(kResponseFilter.bind(null, false))); } -Clusters.getResponses = function(name, side) +Clusters.getResponses = function() { - const filter = command => command.clusterName.toLowerCase() == name.toLowerCase() && command.clusterSide == side && command.isResponse == true; - return this.ready.then(() => this._commands.filter(filter)); + return this.ready.then(() => this._commands.filter(kResponseFilter.bind(null, true))); } -Clusters.getAttributes = function(name, side) +Clusters.getAttributes = function() +{ + return this.ready.then(() => this._attributes); +} + +// +// Helpers: Get by Cluster Name +// +const kNameFilter = (name, item) => name.toLowerCase() == (item.clusterName || item.name).toLowerCase(); + +Clusters.getCommandsByClusterName = function(name) +{ + return this.getCommands().then(items => items.filter(kNameFilter.bind(null, name))); +} + +Clusters.getResponsesByClusterName = function(name) +{ + return this.getResponses().then(items => items.filter(kNameFilter.bind(null, name))); +} + +Clusters.getAttributesByClusterName = function(name) { return this.ready.then(() => { - const code = this._clusters.find(cluster => cluster.name.toLowerCase() == name.toLowerCase()).id; - const filter = attribute => attribute.clusterId == code && attribute.side == side; - return this._attributes.filter(filter); + const clusterId = this._clusters.find(kNameFilter.bind(null, name)).id; + const filter = attribute => attribute.clusterId == clusterId; + return this.getAttributes().then(items => items.filter(filter)); }); } +// +// Helpers: Get by Cluster Side +// +const kSideFilter = (side, item) => side == (item.clusterSide || item.side); + +Clusters.getCommandsByClusterSide = function(side) +{ + return this.getCommands().then(items => items.filter(kSideFilter.bind(null, side))); +} + +Clusters.getResponsesByClusterSide = function(side) +{ + return this.getResponses().then(items => items.filter(kSideFilter.bind(null, side))); +} + +Clusters.getAttributesByClusterSide = function(side) +{ + return this.getAttributes().then(items => items.filter(kSideFilter.bind(null, side))); +} + // // Helpers: Client // +const kClientSideFilter = kSideFilter.bind(null, 'client'); + Clusters.getClientClusters = function() { - const filter = cluster => cluster.side == 'client'; - return this.ready.then(() => this._clusters.filter(filter)); + return this.getClusters().then(items => items.filter(kClientSideFilter)); } Clusters.getClientCommands = function(name) { - return this.getCommands(name, 'client'); + return this.getCommandsByClusterName(name).then(items => items.filter(kClientSideFilter)); } Clusters.getClientResponses = function(name) { - return this.getResponses(name, 'client'); + return this.getResponsesByClusterName(name).then(items => items.filter(kClientSideFilter)); } Clusters.getClientAttributes = function(name) { - return this.getAttributes(name, 'client'); + return this.getAttributesByClusterName(name).then(items => items.filter(kClientSideFilter)); } // // Helpers: Server // +const kServerSideFilter = kSideFilter.bind(null, 'server'); + Clusters.getServerClusters = function() { - const filter = cluster => cluster.side == 'server'; - return this.ready.then(() => this._clusters.filter(filter)); + return this.getClusters().then(items => items.filter(kServerSideFilter)); } Clusters.getServerCommands = function(name) { - return this.getCommands(name, 'server'); + return this.getCommandsByClusterName(name).then(items => items.filter(kServerSideFilter)); } Clusters.getServerResponses = function(name) { - return this.getResponses(name, 'server'); + return this.getResponsesByClusterName(name).then(items => items.filter(kServerSideFilter)); } Clusters.getServerAttributes = function(name) { - return this.getAttributes(name, 'server'); + return this.getAttributesByClusterName(name).then(items => items.filter(kServerSideFilter)); } // diff --git a/src/app/zap-templates/templates/app/CHIPClusters-src.zapt b/src/app/zap-templates/templates/app/CHIPClusters-src.zapt index ca6a615b775a5e..a629da0aa2a0b0 100644 --- a/src/app/zap-templates/templates/app/CHIPClusters-src.zapt +++ b/src/app/zap-templates/templates/app/CHIPClusters-src.zapt @@ -84,12 +84,12 @@ CHIP_ERROR {{asCamelCased parent.name false}}Cluster::ReadAttribute{{asCamelCase {{#if isList}} {{asCamelCased parent.name false}}Cluster{{asCamelCased name false}}ListAttributeFilter {{else}} - BasicAttributeFilter<{{asCallbackAttributeType atomicTypeId}}AttributeCallback> + BasicAttributeFilter<{{chipCallback.name}}AttributeCallback> {{/if}} ); } -{{#if (isWritableAttribute)}} +{{#if isWritableAttribute}} CHIP_ERROR {{asCamelCased parent.name false}}Cluster::WriteAttribute{{asCamelCased name false}}(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback, {{chipType}} value) { uint8_t seqNum = mDevice->GetNextSequenceNumber(); @@ -98,7 +98,7 @@ CHIP_ERROR {{asCamelCased parent.name false}}Cluster::WriteAttribute{{asCamelCas } {{/if}} -{{#if (isReportableAttribute)}} +{{#if isReportableAttribute}} CHIP_ERROR {{asCamelCased parent.name false}}Cluster::ConfigureAttribute{{asCamelCased name false}}(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback, uint16_t minInterval, uint16_t maxInterval{{#if isAnalog}}, {{chipType}} change{{/if}}) { uint8_t seqNum = mDevice->GetNextSequenceNumber(); diff --git a/src/app/zap-templates/templates/app/CHIPClusters.zapt b/src/app/zap-templates/templates/app/CHIPClusters.zapt index 7ca45fb7df4ccb..283d3228f7311f 100644 --- a/src/app/zap-templates/templates/app/CHIPClusters.zapt +++ b/src/app/zap-templates/templates/app/CHIPClusters.zapt @@ -35,12 +35,12 @@ public: CHIP_ERROR ReadAttribute{{asCamelCased name false}}(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback); {{/chip_server_cluster_attributes}} {{#chip_server_cluster_attributes}} - {{#if (isWritableAttribute)}} + {{#if isWritableAttribute}} CHIP_ERROR WriteAttribute{{asCamelCased name false}}(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback, {{chipType}} value); {{/if}} {{/chip_server_cluster_attributes}} {{#chip_server_cluster_attributes}} - {{#if (isReportableAttribute)}} + {{#if isReportableAttribute}} CHIP_ERROR ConfigureAttribute{{asCamelCased name false}}(Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback, uint16_t minInterval, uint16_t maxInterval{{#if isAnalog}}, {{chipType}} change{{/if}}); CHIP_ERROR ReportAttribute{{asCamelCased name false}}(Callback::Cancelable * onReportCallback); {{/if}} diff --git a/src/app/zap-templates/templates/app/attribute-size-src.zapt b/src/app/zap-templates/templates/app/attribute-size-src.zapt index a0e91c8c7150b5..b1896cf8b8cd82 100644 --- a/src/app/zap-templates/templates/app/attribute-size-src.zapt +++ b/src/app/zap-templates/templates/app/attribute-size-src.zapt @@ -61,7 +61,7 @@ uint16_t emberAfCopyList(ClusterId clusterId, EmberAfAttributeMetadata * am, boo switch (clusterId) { {{#chip_server_clusters}} - {{#if (chip_has_list_attributes)}} + {{#if (chip_server_has_list_attributes)}} case {{asHex code 4}}: // {{name}} Cluster { uint16_t entryOffset = kSizeLengthInBytes; @@ -152,7 +152,7 @@ uint16_t emberAfAttributeValueListSize(ClusterId clusterId, AttributeId attribut switch (clusterId) { {{#chip_server_clusters}} -{{#if (chip_has_list_attributes)}} +{{#if (chip_server_has_list_attributes)}} case {{asHex code 4}}: // {{name}} Cluster switch (attributeId) { diff --git a/src/app/zap-templates/templates/app/chip-zcl-zpro-codec-api.zapt b/src/app/zap-templates/templates/app/chip-zcl-zpro-codec-api.zapt index eca05aa8d43100..a525c3e12db644 100644 --- a/src/app/zap-templates/templates/app/chip-zcl-zpro-codec-api.zapt +++ b/src/app/zap-templates/templates/app/chip-zcl-zpro-codec-api.zapt @@ -27,7 +27,7 @@ chip::System::PacketBufferHandle encode{{asCamelCased name false}}ClusterDiscove */ chip::System::PacketBufferHandle encode{{asCamelCased parent.name false}}ClusterRead{{asCamelCased name false}}Attribute(uint8_t seqNum, chip::EndpointId destinationEndpoint); -{{#if (isWritableAttribute)}} +{{#if isWritableAttribute}} /** * @brief * Encode a {{parent.name}} server write command for the {{name}} attribute into buffer including the APS frame @@ -35,7 +35,7 @@ chip::System::PacketBufferHandle encode{{asCamelCased parent.name false}}Cluster chip::System::PacketBufferHandle encode{{asCamelCased parent.name false}}ClusterWrite{{asCamelCased name false}}Attribute(uint8_t seqNum, chip::EndpointId destinationEndpoint, {{chipType}} {{asCamelCased name}}); {{/if}} -{{#if (isReportableAttribute)}} +{{#if isReportableAttribute}} /** * @brief * Encode a {{parent.name}} server configure report command for the {{name}} attribute into buffer including the APS frame diff --git a/src/app/zap-templates/templates/app/encoder-src.zapt b/src/app/zap-templates/templates/app/encoder-src.zapt index 2ad82d98d1c066..8de5c319ae8776 100644 --- a/src/app/zap-templates/templates/app/encoder-src.zapt +++ b/src/app/zap-templates/templates/app/encoder-src.zapt @@ -80,11 +80,11 @@ PacketBufferHandle encode{{asUpperCamelCase parent.name}}ClusterRead{{asUpperCam buf.Put8(kFrameControlGlobalCommand) .Put8(seqNum) .Put32(Globals::Commands::Ids::ReadAttributes) - .Put32({{#if (isGlobalAttribute)}}Globals{{else}}{{asUpperCamelCase parent.name}}{{/if}}::Attributes::Ids::{{asUpperCamelCase name}}); + .Put32({{#if isGlobalAttribute}}Globals{{else}}{{asUpperCamelCase parent.name}}{{/if}}::Attributes::Ids::{{asUpperCamelCase name}}); COMMAND_FOOTER(); } -{{#if (isWritableAttribute)}} +{{#if isWritableAttribute}} PacketBufferHandle encode{{asUpperCamelCase parent.name}}ClusterWrite{{asUpperCamelCase name}}Attribute(uint8_t seqNum, EndpointId destinationEndpoint, {{chipType}} {{asLowerCamelCase name}}) { COMMAND_HEADER("Write{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}", {{asUpperCamelCase parent.name}}::Id); @@ -100,7 +100,7 @@ PacketBufferHandle encode{{asUpperCamelCase parent.name}}ClusterWrite{{asUpperCa buf.Put8(kFrameControlGlobalCommand) .Put8(seqNum) .Put32(Globals::Commands::Ids::WriteAttributes) - .Put32({{#if (isGlobalAttribute)}}Globals{{else}}{{asUpperCamelCase parent.name}}{{/if}}::Attributes::Ids::{{asUpperCamelCase name}}) + .Put32({{#if isGlobalAttribute}}Globals{{else}}{{asUpperCamelCase parent.name}}{{/if}}::Attributes::Ids::{{asUpperCamelCase name}}) .Put8({{atomicTypeId}}) {{#if (isString type)}} .Put{{#if (isLongString type)}}16{{/if}}(static_cast<{{#if (isShortString type)}}uint8_t{{else}}uint16_t{{/if}}>({{asLowerCamelCase name}}StrLen)) @@ -113,7 +113,7 @@ PacketBufferHandle encode{{asUpperCamelCase parent.name}}ClusterWrite{{asUpperCa } {{/if}} -{{#if (isReportableAttribute)}} +{{#if isReportableAttribute}} PacketBufferHandle encode{{asUpperCamelCase parent.name}}ClusterConfigure{{asUpperCamelCase name}}Attribute(uint8_t seqNum, EndpointId destinationEndpoint, uint16_t minInterval, uint16_t maxInterval{{#if isAnalog}}, {{chipType}} change{{/if}}) { COMMAND_HEADER("Report{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}", {{asUpperCamelCase parent.name}}::Id); @@ -121,7 +121,7 @@ PacketBufferHandle encode{{asUpperCamelCase parent.name}}ClusterConfigure{{asUpp .Put8(seqNum) .Put32(Globals::Commands::Ids::ConfigureReporting) .Put8(EMBER_ZCL_REPORTING_DIRECTION_REPORTED) - .Put32({{#if (isGlobalAttribute)}}Globals{{else}}{{asUpperCamelCase parent.name}}{{/if}}::Attributes::Ids::{{asUpperCamelCase name}}) + .Put32({{#if isGlobalAttribute}}Globals{{else}}{{asUpperCamelCase parent.name}}{{/if}}::Attributes::Ids::{{asUpperCamelCase name}}) .Put8({{atomicTypeId}}) .Put16(minInterval) .Put16(maxInterval); diff --git a/src/app/zap-templates/templates/app/helper.js b/src/app/zap-templates/templates/app/helper.js index e008c09f709263..990f6abbd6c04d 100644 --- a/src/app/zap-templates/templates/app/helper.js +++ b/src/app/zap-templates/templates/app/helper.js @@ -21,10 +21,18 @@ const templateUtil = require(zapPath + 'generator/template-util.js') const zclHelper = require(zapPath + 'generator/helper-zcl.js') const zclQuery = require(zapPath + 'db/query-zcl.js') const cHelper = require(zapPath + 'generator/helper-c.js') +const string = require(zapPath + 'util/string.js') const StringHelper = require('../../common/StringHelper.js'); const ChipTypesHelper = require('../../common/ChipTypesHelper.js'); +// This list of attributes is taken from section '11.2. Global Attributes' of the +// Data Model specification. +const kGlobalAttributes = [ + 0xfffc, // ClusterRevision + 0xfffd, // FeatureMap +]; + // TODO Expose the readTypeLength as an additional member field of {{asUnderlyingZclType}} instead // of having to call this method separately. function asReadTypeLength(type) @@ -292,6 +300,23 @@ function asTypeLiteralSuffix(type) } } +function hasSpecificAttributes(options) +{ + return this.count > kGlobalAttributes.length; +} + +function asLowerCamelCase(label) +{ + let str = string.toCamelCase(label, true); + return str.replace(/[\.:]/g, ''); +} + +function asUpperCamelCase(label) +{ + let str = string.toCamelCase(label, false); + return str.replace(/[\.:]/g, ''); +} + // // Module exports // @@ -301,3 +326,6 @@ exports.asReadTypeLength = asReadTypeLength; exports.chip_endpoint_generated_functions = chip_endpoint_generated_functions exports.chip_endpoint_cluster_list = chip_endpoint_cluster_list exports.asTypeLiteralSuffix = asTypeLiteralSuffix; +exports.asLowerCamelCase = asLowerCamelCase; +exports.asUpperCamelCase = asUpperCamelCase; +exports.hasSpecificAttributes = hasSpecificAttributes; diff --git a/src/app/zap-templates/templates/chip/helper.js b/src/app/zap-templates/templates/chip/helper.js index 5d51033846bc83..b9c343dfaba44e 100644 --- a/src/app/zap-templates/templates/chip/helper.js +++ b/src/app/zap-templates/templates/chip/helper.js @@ -19,14 +19,11 @@ const zapPath = '../../../../../third_party/zap/repo/src-electron/'; const templateUtil = require(zapPath + 'generator/template-util.js') const zclHelper = require(zapPath + 'generator/helper-zcl.js') -const string = require(zapPath + 'util/string.js') const { Clusters, asBlocks, asPromise } = require('../../common/ClustersHelper.js'); const StringHelper = require('../../common/StringHelper.js'); const ChipTypesHelper = require('../../common/ChipTypesHelper.js'); -const kGlobalAttributes = [ 0xfffc, 0xfffd ]; - function throwErrorIfUndefined(item, errorMsg, conditions) { conditions.forEach(condition => { @@ -136,6 +133,34 @@ function chip_has_clusters(options) return asPromise.call(this, Clusters.getClusters().then(clusters => !!clusters.length)); } +/** + * Creates block iterator over the server global responses + * + * @param {*} options + */ +function chip_server_global_responses(options) +{ + const sorter = (a, b) => a.chipCallback.name.localeCompare(b.chipCallback.name, 'en', { numeric : true }); + + const reducer = (unique, item) => { + const { type, size, isList, chipCallback, chipType } = item.response.arguments[0]; + + // List-typed elements have a dedicated callback + if (isList) { + return unique; + } + + if (unique.find(item => item.chipCallback.name == chipCallback.name)) { + return unique; + } + + return [...unique, { chipCallback, chipType, size } ]; + }; + + const filter = attributes => attributes.reduce(reducer, []).sort(sorter); + return asBlocks.call(this, Clusters.getAttributesByClusterSide('server').then(filter), options); +} + /** * Creates block iterator over the server side cluster command * for a given cluster. @@ -204,22 +229,6 @@ function chip_server_cluster_response_arguments(options) return asBlocks.call(this, promise, options); } -/** - * Returns if a given cluster has any attributes of type List[T] - * - * This function is meant to be used inside a {{#chip_server_clusters}} - * block. It will throw otherwise. - * - * @param {*} options - */ -function chip_has_list_attributes(options) -{ - const { clusterName, clusterSide } = checkIsInsideClusterBlock(this, 'chip_has_list_attributes'); - - const filter = attribute => attribute.isList; - return asPromise.call(this, Clusters.getAttributes(clusterName, clusterSide).then(attributes => attributes.find(filter))); -} - /** * Returns if a given server cluster has any attributes of type List[T] * @@ -267,162 +276,12 @@ function chip_server_cluster_attributes(options) return asBlocks.call(this, Clusters.getServerAttributes(clusterName), options); } -/** - * Returns whether a given attribute is global. - * - * This function is meant to be used inside a {{#chip_server_cluster_attributes}} block. - * It will throw otherwise. - * - * @param {*} options - */ -function isGlobalAttribute(options) -{ - checkIsInsideAttributeBlock(this, 'isGlobalAttribute'); - return kGlobalAttributes.includes(this.code); -} - -/** - * Returns if a given attribute is writable. - * - * This function is meant to be used inside a {{#chip_server_cluster_attributes}} block. - * It will throw otherwise. - * - * @param {*} options - */ -function isWritableAttribute(options) -{ - checkIsInsideAttributeBlock(this, 'isWritableAttribute'); - return this.isWritable == 1; -} - -/** - * Returns if a given attribute is reportable. - * - * This function is meant to be used inside a {{#chip_server_cluster_attributes}} block. - * It will throw otherwise. - * - * @param {*} options - */ -function isReportableAttribute(options) -{ - checkIsInsideAttributeBlock(this, 'isReportableAttribute'); - return this.includedReportable == 1; -} - -/** - * Returns if a given command is manufacturer specific - * - * This function is meant to be used inside a {{#chip_server_cluster_commands}} block. - * It will throw otherwise. - * - * @param {*} options - */ -function isManufacturerSpecificCommand() -{ - checkIsInsideCommandBlock(this, 'isManufacturerSpecificCommand'); - return !!this.mfgCode; -} - -function asCallbackAttributeType(attributeType) -{ - switch (parseInt(attributeType)) { - case 0x00: // nodata / No data - case 0x0A: // data24 / 24-bit data - case 0x0C: // data40 / 40-bit data - case 0x0D: // data48 / 48-bit data - case 0x0E: // data56 / 56-bit data - case 0x1A: // map24 / 24-bit bitmap - case 0x1C: // map40 / 40-bit bitmap - case 0x1D: // map48 / 48-bit bitmap - case 0x1E: // map56 / 56-bit bitmap - case 0x22: // uint24 / Unsigned 24-bit integer - case 0x24: // uint40 / Unsigned 40-bit integer - case 0x25: // uint48 / Unsigned 48-bit integer - case 0x26: // uint56 / Unsigned 56-bit integer - case 0x2A: // int24 / Signed 24-bit integer - case 0x2C: // int40 / Signed 40-bit integer - case 0x2D: // int48 / Signed 48-bit integer - case 0x2E: // int56 / Signed 56-bit integer - case 0x38: // semi / Semi-precision - case 0x39: // single / Single precision - case 0x3A: // double / Double precision - case 0x49: // struct / Structure - case 0x50: // set / Set - case 0x51: // bag / Bag - case 0xE0: // ToD / Time of day - case 0xEA: // bacOID / BACnet OID - case 0xF1: // key128 / 128-bit security key - case 0xFF: // unk / Unknown - return 'Unsupported'; - case 0x41: // octstr / Octet string - case 0x42: // string / Character string - case 0x43: // octstr16 / Long octet string - case 0x44: // string16 / Long character string - return 'String'; - case 0x48: // array / Array - return 'List'; - case 0x08: // data8 / 8-bit data - case 0x18: // map8 / 8-bit bitmap - case 0x20: // uint8 / Unsigned 8-bit integer - case 0x30: // enum8 / 8-bit enumeration - return 'Int8u'; - case 0x09: // data16 / 16-bit data - case 0x19: // map16 / 16-bit bitmap - case 0x21: // uint16 / Unsigned 16-bit integer - case 0x31: // enum16 / 16-bit enumeration - case 0xE8: // clusterId / Cluster ID - case 0xE9: // attribId / Attribute ID - return 'Int16u'; - case 0x0B: // data32 / 32-bit data - case 0x1B: // map32 / 32-bit bitmap - case 0x23: // uint32 / Unsigned 32-bit integer - case 0xE1: // date / Date - case 0xE2: // UTC / UTCTime - return 'Int32u'; - case 0x0F: // data64 / 64-bit data - case 0x1F: // map64 / 64-bit bitmap - case 0x27: // uint64 / Unsigned 64-bit integer - case 0xF0: // EUI64 / IEEE address - return 'Int64u'; - case 0x10: // bool / Boolean - return 'Boolean'; - case 0x28: // int8 / Signed 8-bit integer - return 'Int8s'; - case 0x29: // int16 / Signed 16-bit integer - return 'Int16s'; - case 0x2B: // int32 / Signed 32-bit integer - return 'Int32s'; - case 0x2F: // int64 / Signed 64-bit integer - return 'Int64s'; - default: - error = 'Unhandled attribute type ' + attributeType; - throw error; - } -} - function chip_attribute_list_entryTypes(options) { checkIsInsideAttributeBlock(this, 'chip_attribute_list_entry_types'); return templateUtil.collectBlocks(this.items, options, this); } -function asLowerCamelCase(label) -{ - let str = string.toCamelCase(label, true); - return str.replace(/[\.:]/g, ''); -} - -function asUpperCamelCase(label) -{ - let str = string.toCamelCase(label, false); - return str.replace(/[\.:]/g, ''); -} - -function hasSpecificAttributes(options) -{ - return this.count > kGlobalAttributes.length; -} - // // Module exports // @@ -434,19 +293,9 @@ exports.chip_server_clusters = chip_server_clusters; exports.chip_has_server_clusters = chip_has_server_clusters; exports.chip_server_cluster_commands = chip_server_cluster_commands; exports.chip_server_cluster_command_arguments = chip_server_cluster_command_arguments +exports.chip_server_global_responses = chip_server_global_responses; exports.chip_server_cluster_responses = chip_server_cluster_responses; exports.chip_server_cluster_response_arguments = chip_server_cluster_response_arguments exports.chip_attribute_list_entryTypes = chip_attribute_list_entryTypes; -exports.asBasicType = ChipTypesHelper.asBasicType; exports.chip_server_cluster_attributes = chip_server_cluster_attributes; -exports.chip_has_list_attributes = chip_has_list_attributes; exports.chip_server_has_list_attributes = chip_server_has_list_attributes; -exports.chip_client_has_list_attributes = chip_client_has_list_attributes; -exports.isGlobalAttribute = isGlobalAttribute; -exports.isWritableAttribute = isWritableAttribute; -exports.isReportableAttribute = isReportableAttribute; -exports.isManufacturerSpecificCommand = isManufacturerSpecificCommand; -exports.asCallbackAttributeType = asCallbackAttributeType; -exports.asLowerCamelCase = asLowerCamelCase; -exports.asUpperCamelCase = asUpperCamelCase; -exports.hasSpecificAttributes = hasSpecificAttributes; diff --git a/src/controller/python/templates/python-CHIPClusters-cpp.zapt b/src/controller/python/templates/python-CHIPClusters-cpp.zapt index 40c9341285e2e0..087ed6697d07ba 100644 --- a/src/controller/python/templates/python-CHIPClusters-cpp.zapt +++ b/src/controller/python/templates/python-CHIPClusters-cpp.zapt @@ -133,11 +133,11 @@ CHIP_ERROR chip_ime_ReadAttribute_{{asCamelCased parent.name false}}_{{asCamelCa {{#if isList}} return cluster.ReadAttribute{{asCamelCased name false}}(g{{asCamelCased parent.name false}}{{asCamelCased name false}}ListAttributeCallback.Cancel(), gDefaultFailureCallback.Cancel()); {{else}} - return cluster.ReadAttribute{{asCamelCased name false}}(g{{asCallbackAttributeType atomicTypeId}}AttributeCallback.Cancel(), gDefaultFailureCallback.Cancel()); + return cluster.ReadAttribute{{asCamelCased name false}}(g{{chipCallback.name}}AttributeCallback.Cancel(), gDefaultFailureCallback.Cancel()); {{/if}} } -{{#if (isReportableAttribute)}} +{{#if isReportableAttribute}} CHIP_ERROR chip_ime_ConfigureAttribute_{{asCamelCased parent.name false}}_{{asCamelCased name false}}(chip::Controller::Device * device, chip::EndpointId ZCLendpointId, uint16_t minInterval, uint16_t maxInterval{{#if isAnalog}}, {{chipType}} change{{/if}}) { VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT); @@ -147,12 +147,12 @@ CHIP_ERROR chip_ime_ConfigureAttribute_{{asCamelCased parent.name false}}_{{asCa chip::Callback::Callback<{{asCamelCased parent.name false}}{{asCamelCased name false}}ListAttributeCallback> * onSuccessCallback = new chip::Callback::Callback<{{asCamelCased parent.name false}}{{asCamelCased name false}}ListAttributeCallback>(On{{asCamelCased parent.name false}}{{asCamelCased name false}}ListAttributeResponse, nullptr); return cluster.ConfigureAttribute{{asCamelCased name false}}(onSuccessCallback->Cancel(), gDefaultFailureCallback.Cancel(), minInterval, maxInterval{{#if isAnalog}}, change{{/if}}); {{else}} - return cluster.ConfigureAttribute{{asCamelCased name false}}(g{{asCallbackAttributeType atomicTypeId}}AttributeCallback.Cancel(), gDefaultFailureCallback.Cancel(), minInterval, maxInterval{{#if isAnalog}}, change{{/if}}); + return cluster.ConfigureAttribute{{asCamelCased name false}}(g{{chipCallback.name}}AttributeCallback.Cancel(), gDefaultFailureCallback.Cancel(), minInterval, maxInterval{{#if isAnalog}}, change{{/if}}); {{/if}} } {{/if}} -{{#if (isWritableAttribute)}} +{{#if isWritableAttribute}} CHIP_ERROR chip_ime_WriteAttribute_{{asCamelCased parent.name false}}_{{asCamelCased name false}}(chip::Controller::Device * device, chip::EndpointId ZCLendpointId, chip::GroupId, {{#if (isString type)}} uint8_t * value, size_t len{{else}}{{chipType}} value{{/if}}) { VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT); diff --git a/src/controller/python/templates/python-CHIPClusters-py.zapt b/src/controller/python/templates/python-CHIPClusters-py.zapt index 6387bff53e1761..56ee7cda23fab0 100644 --- a/src/controller/python/templates/python-CHIPClusters-py.zapt +++ b/src/controller/python/templates/python-CHIPClusters-py.zapt @@ -42,10 +42,10 @@ class ChipClusters: "{{asCamelCased name false}}": { "attributeId": {{asHex code 4}}, "type": "{{#if (isCharString type)}}str{{else}}{{asPythonType chipType}}{{/if}}", - {{#if (isReportableAttribute)}} + {{#if isReportableAttribute}} "reportable": True, {{/if}} - {{#if (isWritableAttribute)}} + {{#if isWritableAttribute}} "writable": True, {{/if}} }, @@ -106,11 +106,11 @@ class ChipClusters: {{#chip_server_cluster_attributes}} def Cluster{{asCamelCased parent.name false}}_ReadAttribute{{asCamelCased name false}}(self, device: ctypes.c_void_p, ZCLendpoint: int, ZCLgroupid: int): return self._chipLib.chip_ime_ReadAttribute_{{asCamelCased parent.name false}}_{{asCamelCased name false}}(device, ZCLendpoint, ZCLgroupid) -{{#if (isReportableAttribute)}} +{{#if isReportableAttribute}} def Cluster{{asCamelCased parent.name false}}_ConfigureAttribute{{asCamelCased name false}}(self, device: ctypes.c_void_p, ZCLendpoint: int, minInterval: int, maxInterval: int, change: int): return self._chipLib.chip_ime_ConfigureAttribute_{{asCamelCased parent.name false}}_{{asCamelCased name false}}(device, ZCLendpoint, minInterval, maxInterval, change) {{/if}} -{{#if (isWritableAttribute)}} +{{#if isWritableAttribute}} def Cluster{{asCamelCased parent.name false}}_WriteAttribute{{asCamelCased name false}}(self, device: ctypes.c_void_p, ZCLendpoint: int, ZCLgroupid: int, value: {{ asPythonType chipType }}): {{#if (isCharString type)}} value = value.encode("utf-8") + b'\x00' @@ -140,12 +140,12 @@ class ChipClusters: # Cluster {{asCamelCased parent.name false}} ReadAttribute {{asCamelCased name false}} self._chipLib.chip_ime_ReadAttribute_{{asCamelCased parent.name false}}_{{asCamelCased name false}}.argtypes = [ctypes.c_void_p, ctypes.c_uint8, ctypes.c_uint16] self._chipLib.chip_ime_ReadAttribute_{{asCamelCased parent.name false}}_{{asCamelCased name false}}.restype = ctypes.c_uint32 -{{#if (isReportableAttribute)}} +{{#if isReportableAttribute}} # Cluster {{asCamelCased parent.name false}} ConfigureAttribute {{asCamelCased name false}} self._chipLib.chip_ime_ConfigureAttribute_{{asCamelCased parent.name false}}_{{asCamelCased name false}}.argtypes = [ctypes.c_void_p, ctypes.c_uint8, ctypes.c_uint16, ctypes.c_uint16{{#if isAnalog}}, ctypes.{{asPythonCType chipType}}{{/if}}] self._chipLib.chip_ime_ConfigureAttribute_{{asCamelCased parent.name false}}_{{asCamelCased name false}}.restype = ctypes.c_uint32 {{/if}} -{{#if (isWritableAttribute)}} +{{#if isWritableAttribute}} # Cluster {{asCamelCased parent.name false}} WriteAttribute {{asCamelCased name false}} self._chipLib.chip_ime_WriteAttribute_{{asCamelCased parent.name false}}_{{asCamelCased name false}}.argtypes = [ctypes.c_void_p, ctypes.c_uint8, ctypes.c_uint16, {{#if (isString type)}}ctypes.c_char_p, ctypes.c_uint32{{else}}ctypes.{{asPythonCType chipType}}{{/if}}] self._chipLib.chip_ime_WriteAttribute_{{asCamelCased parent.name false}}_{{asCamelCased name false}}.restype = ctypes.c_uint32 diff --git a/src/darwin/Framework/CHIP/templates/CHIPClustersObjc-src.zapt b/src/darwin/Framework/CHIP/templates/CHIPClustersObjc-src.zapt index 7ed35327b674fe..935c3a78688845 100644 --- a/src/darwin/Framework/CHIP/templates/CHIPClustersObjc-src.zapt +++ b/src/darwin/Framework/CHIP/templates/CHIPClustersObjc-src.zapt @@ -625,7 +625,7 @@ private: {{#if isList}} CHIP{{asCamelCased parent.name false}}{{asCamelCased name false}}AttributeCallbackBridge * onSuccess = new CHIP{{asCamelCased parent.name false}}{{asCamelCased name false}}AttributeCallbackBridge(responseHandler, [self callbackQueue]); {{else}} - CHIP{{asCallbackAttributeType atomicTypeId}}AttributeCallbackBridge * onSuccess = new CHIP{{asCallbackAttributeType atomicTypeId}}AttributeCallbackBridge(responseHandler, [self callbackQueue]{{#if (isString type)}},{{#if (isOctetString type)}}true{{else}}false{{/if}}{{/if}}); + CHIP{{chipCallback.name}}AttributeCallbackBridge * onSuccess = new CHIP{{chipCallback.name}}AttributeCallbackBridge(responseHandler, [self callbackQueue]{{#if (isString type)}},{{#if (isOctetString type)}}true{{else}}false{{/if}}{{/if}}); {{/if}} if (!onSuccess) { responseHandler([CHIPError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE], nil); @@ -651,7 +651,7 @@ private: } } -{{#if (isWritableAttribute)}} +{{#if isWritableAttribute}} - (void)writeAttribute{{asCamelCased name false}}WithValue:({{asObjectiveCBasicType type}})value responseHandler:(ResponseHandler)responseHandler { CHIPDefaultSuccessCallbackBridge * onSuccess = new CHIPDefaultSuccessCallbackBridge(responseHandler, [self callbackQueue]); @@ -687,7 +687,7 @@ private: } {{/if}} -{{#if (isReportableAttribute)}} +{{#if isReportableAttribute}} - (void) configureAttribute{{asCamelCased name false}}WithMinInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval{{#if isAnalog}} change:({{chipType}})change{{/if}} responseHandler:(ResponseHandler)responseHandler { CHIPDefaultSuccessCallbackBridge * onSuccess = new CHIPDefaultSuccessCallbackBridge(responseHandler, [self callbackQueue]); @@ -718,7 +718,7 @@ private: - (void) reportAttribute{{asCamelCased name false}}WithResponseHandler:(ResponseHandler)reportHandler { - CHIP{{asCallbackAttributeType atomicTypeId}}AttributeCallbackBridge * onReport = new CHIP{{asCallbackAttributeType atomicTypeId}}AttributeCallbackBridge(reportHandler, [self callbackQueue]{{#if (isString type)}},{{#if (isOctetString type)}}true{{else}}false{{/if}}{{/if}}, true); + CHIP{{chipCallback.name}}AttributeCallbackBridge * onReport = new CHIP{{chipCallback.name}}AttributeCallbackBridge(reportHandler, [self callbackQueue]{{#if (isString type)}},{{#if (isOctetString type)}}true{{else}}false{{/if}}{{/if}}, true); if (!onReport) { reportHandler([CHIPError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE], nil); return; diff --git a/src/darwin/Framework/CHIP/templates/CHIPClustersObjc.zapt b/src/darwin/Framework/CHIP/templates/CHIPClustersObjc.zapt index 4326865455c56d..0bc56613149d51 100644 --- a/src/darwin/Framework/CHIP/templates/CHIPClustersObjc.zapt +++ b/src/darwin/Framework/CHIP/templates/CHIPClustersObjc.zapt @@ -43,10 +43,10 @@ NS_ASSUME_NONNULL_BEGIN {{#chip_server_cluster_attributes}} - (void)readAttribute{{asCamelCased name false}}WithResponseHandler:(ResponseHandler)responseHandler; -{{#if (isWritableAttribute)}} +{{#if isWritableAttribute}} - (void)writeAttribute{{asCamelCased name false}}WithValue:({{asObjectiveCBasicType type}})value responseHandler:(ResponseHandler)responseHandler; {{/if}} -{{#if (isReportableAttribute)}} +{{#if isReportableAttribute}} - (void) configureAttribute{{asCamelCased name false}}WithMinInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval{{#if isAnalog}} change:({{chipType}})change{{/if}} responseHandler:(ResponseHandler)responseHandler; - (void) reportAttribute{{asCamelCased name false}}WithResponseHandler:(ResponseHandler)responseHandler; {{/if}} diff --git a/src/darwin/Framework/CHIP/templates/clusters-tests.zapt b/src/darwin/Framework/CHIP/templates/clusters-tests.zapt index 52f07439242f08..66c98b9df68d7f 100644 --- a/src/darwin/Framework/CHIP/templates/clusters-tests.zapt +++ b/src/darwin/Framework/CHIP/templates/clusters-tests.zapt @@ -161,7 +161,7 @@ CHIPDevice * GetPairedDevice(uint64_t deviceId) [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; } -{{#if (isWritableAttribute)}} +{{#if isWritableAttribute}} - (void)testSendCluster{{asCamelCased parent.name false}}WriteAttribute{{asCamelCased name false}}WithValue { XCTestExpectation * expectation = [self expectationWithDescription:@"{{asCamelCased parent.name false}}WriteAttribute{{asCamelCased name false}}WithValue"];