3 * Copyright (c) 2020 Project CHIP Authors
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 // Import helpers from zap core
19 const zapPath = '../../../../../third_party/zap/repo/src-electron/';
20 const queryImpexp = require(zapPath + 'db/query-impexp.js')
21 const templateUtil = require(zapPath + 'generator/template-util.js')
22 const zclHelper = require(zapPath + 'generator/helper-zcl.js')
23 const zclQuery = require(zapPath + 'db/query-zcl.js')
24 const cHelper = require(zapPath + 'generator/helper-c.js')
26 const StringHelper = require('../../common/StringHelper.js');
27 const ChipTypesHelper = require('../../common/ChipTypesHelper.js');
30 * Check if the cluster (name) has any enabled manufacturer commands. This works only inside
31 * cluster block helpers.
33 * @param {*} name : Cluster name
34 * @param {*} side : Cluster side
36 * @returns True if cluster has enabled commands otherwise false
38 function user_cluster_has_enabled_manufacturer_command(name, side, options)
40 return queryImpexp.exportendPointTypeIds(this.global.db, this.global.sessionId)
41 .then((endpointTypes) => zclQuery.exportClustersAndEndpointDetailsFromEndpointTypes(this.global.db, endpointTypes))
42 .then((endpointsAndClusters) => zclQuery.exportCommandDetailsFromAllEndpointTypesAndClusters(
43 this.global.db, endpointsAndClusters))
44 .then((endpointCommands) => {
45 return !!endpointCommands.find(cmd => cmd.mfgCode && zclHelper.isStrEqual(name, cmd.clusterName)
46 && zclHelper.isCommandAvailable(side, cmd.incoming, cmd.outgoing, cmd.commandSource, cmd.name));
50 function asValueIfNotPresent(type, isArray)
52 if (StringHelper.isString(type) || isArray) {
58 const options = { 'hash' : {} };
59 return zclHelper.asUnderlyingZclType.call(this, type, options).then(zclType => {
68 error = 'Unhandled underlying type ' + zclType + ' for original type ' + type;
74 const promise = templateUtil.ensureZclPackageId(this).then(fn.bind(this)).catch(err => console.log(err));
75 return templateUtil.templatePromise(this.global, promise)
78 // TODO Expose the readTypeLength as an additional member field of {{asUnderlyingZclType}} instead
79 // of having to call this method separately.
80 function asReadTypeLength(type)
82 const db = this.global.db;
84 if (StringHelper.isShortString(type)) {
88 if (StringHelper.isLongString(type)) {
94 const defaultResolver = zclQuery.selectAtomicType(db, pkgId, type);
96 const enumResolver = zclHelper.isEnum(db, type, pkgId).then(result => {
97 return result == 'unknown' ? null : zclQuery.selectEnumByName(db, type, pkgId).then(rec => {
98 return zclQuery.selectAtomicType(db, pkgId, rec.type);
102 const bitmapResolver = zclHelper.isBitmap(db, type, pkgId).then(result => {
103 return result == 'unknown' ? null : zclQuery.selectBitmapByName(db, pkgId, type).then(rec => {
104 return zclQuery.selectAtomicType(db, pkgId, rec.type);
108 const typeResolver = Promise.all([ defaultResolver, enumResolver, bitmapResolver ]);
109 return typeResolver.then(types => (types.find(type => type)).size);
112 const promise = templateUtil.ensureZclPackageId(this).then(fn.bind(this)).catch(err => console.log(err));
113 return templateUtil.templatePromise(this.global, promise)
116 // TODO Expose the readType as an additional member field of {{asUnderlyingZclType}} instead
117 // of having to call this method separately.
118 function asReadType(type)
120 if (StringHelper.isShortString(type)) {
124 if (StringHelper.isLongString(type)) {
130 const options = { 'hash' : {} };
131 return zclHelper.asUnderlyingZclType.call(this, type, options).then(zclType => {
132 const basicType = ChipTypesHelper.asBasicType(zclType);
150 error = 'Unhandled underlying type ' + zclType + ' for original type ' + type;
156 const promise = templateUtil.ensureZclPackageId(this).then(fn.bind(this)).catch(err => console.log(err));
157 return templateUtil.templatePromise(this.global, promise)
161 * Returns CHIP specific type for ZCL framework
162 * This function is flawed since it relies on the
163 * type label for CHIP type conversion. CHIP specific XML should have the
164 * correct type directly embedded inside.
166 * @param {*} label : The xml label of the type.
167 * @param {*} type : The xml type to be converted
169 function asChipUnderlyingType(label, type)
172 if (zclHelper.isStrEqual(label, "endpoint")) {
173 return 'chip::EndpointId';
174 } else if (zclHelper.isStrEqual(label, "endpointId")) {
175 return 'chip::EndpointId';
176 } else if (zclHelper.isStrEqual(type, "CLUSTER_ID")) {
177 return 'chip::ClusterId';
178 } else if (zclHelper.isStrEqual(type, "ATTRIBUTE_ID")) {
179 return 'chip::AttributeId';
180 } else if (zclHelper.isStrEqual(label, "groupId")) {
181 return 'chip::GroupId';
182 } else if (zclHelper.isStrEqual(label, "commandId")) {
183 return 'chip::CommandId';
185 const options = { 'hash' : {} };
186 return zclHelper.asUnderlyingZclType.call(this, type, options);
190 // Endpoint-config specific helpers
191 // these helpers are a Hot fix for the "GENERATED_FUNCTIONS" problem
192 // They should be removed or replace once issue #4369 is resolved
193 // These helpers only works within the endpoint_config iterator
195 // List of all cluster with generated functions
196 var endpointClusterWithInit = [ 'Identify', 'Groups', 'Scenes', 'On/off', 'Level Control', 'Color Control', 'IAS Zone' ];
197 var endpointClusterWithAttributeChanged = [ 'Identify', 'Door Lock' ];
198 var endpointClusterWithPreAttribute = [ 'IAS Zone' ];
199 var endpointClusterWithMessageSent = [ 'IAS Zone' ];
202 * extract the cluster name from the enpoint cluster comment
203 * @param {*} comments
205 function extract_cluster_name(comments)
207 let secondPart = comments.split(": ").pop();
208 return secondPart.split(" (")[0];
212 * Populate the GENERATED_FUNCTIONS field
214 function chip_endpoint_generated_functions()
216 let alreadySetCluster = [];
218 this.clusterList.forEach((c) => {
219 let clusterName = extract_cluster_name(c.comment);
220 let functionList = '';
221 if (alreadySetCluster.includes(clusterName)) {
222 // Only one array of Generated functions per cluster across all endpoints
225 if (c.comment.includes('server')) {
226 let hasFunctionArray = false
227 if (endpointClusterWithInit.includes(clusterName))
229 hasFunctionArray = true
230 functionList = functionList.concat(
231 ` (EmberAfGenericClusterFunction) emberAf${cHelper.asCamelCased(clusterName, false)}ClusterServerInitCallback,\\\n`)
234 if (endpointClusterWithAttributeChanged.includes(clusterName)) {
235 functionList = functionList.concat(` (EmberAfGenericClusterFunction) emberAf${
236 cHelper.asCamelCased(clusterName, false)}ClusterServerAttributeChangedCallback,\\\n`)
237 hasFunctionArray = true
240 if (endpointClusterWithMessageSent.includes(clusterName)) {
241 functionList = functionList.concat(` (EmberAfGenericClusterFunction) emberAf${
242 cHelper.asCamelCased(clusterName, false)}ClusterServerMessageSentCallback,\\\n`)
243 hasFunctionArray = true
246 if (endpointClusterWithPreAttribute.includes(clusterName)) {
247 functionList = functionList.concat(` (EmberAfGenericClusterFunction) emberAf${
248 cHelper.asCamelCased(clusterName, false)}ClusterServerPreAttributeChangedCallback,\\\n`)
249 hasFunctionArray = true
252 if (hasFunctionArray) {
254 `const EmberAfGenericClusterFunction chipFuncArray${cHelper.asCamelCased(clusterName, false)}Server[] = {\\\n`)
255 ret = ret.concat(functionList)
256 ret = ret.concat(`};\\\n`)
257 alreadySetCluster.push(clusterName)
261 return ret.concat('\n');
265 * Return endpoint config GENERATED_CLUSTER MACRO
266 * To be used as a replacement of endpoint_cluster_list since this one
267 * includes the GENERATED_FUNCTIONS array
269 function chip_endpoint_cluster_list()
272 this.clusterList.forEach((c) => {
274 let functionArray = c.functions;
275 let clusterName = extract_cluster_name(c.comment);
277 if (c.comment.includes('server')) {
278 let hasFunctionArray = false;
279 if (endpointClusterWithInit.includes(clusterName)) {
280 c.mask.push('INIT_FUNCTION')
281 hasFunctionArray = true
284 if (endpointClusterWithAttributeChanged.includes(clusterName)) {
285 c.mask.push('ATTRIBUTE_CHANGED_FUNCTION')
286 hasFunctionArray = true
289 if (endpointClusterWithPreAttribute.includes(clusterName)) {
290 c.mask.push('PRE_ATTRIBUTE_CHANGED_FUNCTION')
291 hasFunctionArray = true
294 if (endpointClusterWithMessageSent.includes(clusterName)) {
295 c.mask.push('MESSAGE_SENT_FUNCTION')
296 hasFunctionArray = true
299 if (hasFunctionArray) {
300 functionArray = 'chipFuncArray' + cHelper.asCamelCased(clusterName, false) + 'Server'
304 if (c.mask.length == 0) {
307 mask = c.mask.map((m) => `ZAP_CLUSTER_MASK(${m.toUpperCase()})`).join(' | ')
309 ret = ret.concat(` { ${c.clusterId}, ZAP_ATTRIBUTE_INDEX(${c.attributeIndex}), ${c.attributeCount}, ${c.attributeSize}, ${
310 mask}, ${functionArray} }, /* ${c.comment} */ \\\n`)
312 return ret.concat('}\n');
315 // End of Endpoint-config specific helpers
317 function asPrintFormat(type)
319 if (StringHelper.isString(type)) {
325 const options = { 'hash' : {} };
326 return zclHelper.asUnderlyingZclType.call(this, type, options).then(zclType => {
327 const basicType = ChipTypesHelper.asBasicType(zclType);
334 return '%" PRId16 "';
336 return '%" PRIu16 "';
338 return '%" PRId32 "';
340 return '%" PRIu32 "';
342 return '%" PRId32 "';
344 return '%" PRIu32 "';
346 return '%" PRId64 "';
348 return '%" PRIu64 "';
355 const promise = templateUtil.ensureZclPackageId(this).then(fn.bind(this)).catch(err => console.log(err));
356 return templateUtil.templatePromise(this.global, promise)
359 function isFirstElement(index)
364 function isStrEndsWith(str, substr)
366 return str.endsWith(substr);
372 exports.asPrintFormat = asPrintFormat;
373 exports.asReadType = asReadType;
374 exports.asReadTypeLength = asReadTypeLength;
375 exports.asValueIfNotPresent = asValueIfNotPresent;
376 exports.asChipUnderlyingType = asChipUnderlyingType;
377 exports.isFirstElement = isFirstElement;
378 exports.user_cluster_has_enabled_manufacturer_command = user_cluster_has_enabled_manufacturer_command;
379 exports.chip_endpoint_generated_functions = chip_endpoint_generated_functions
380 exports.chip_endpoint_cluster_list = chip_endpoint_cluster_list
381 exports.isSigned = ChipTypesHelper.isSigned;
382 exports.isStrEndsWith = isStrEndsWith;