3 * Copyright (c) 2020-2021 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 queryConfig = require(zapPath + 'db/query-config.js')
21 const queryImpexp = require(zapPath + 'db/query-impexp.js')
22 const templateUtil = require(zapPath + 'generator/template-util.js')
23 const zclHelper = require(zapPath + 'generator/helper-zcl.js')
24 const zclQuery = require(zapPath + 'db/query-zcl.js')
26 const StringHelper = require('../../common/StringHelper.js');
27 const ChipTypesHelper = require('../../common/ChipTypesHelper.js');
30 * This method converts a ZCL type to the length expected for the
31 * BufferWriter.Put method.
33 * Not all types are supported at the moment, so if there is any unsupported type
34 * that we are trying to convert, it will throw an error.
36 function asPutLength(zclType)
38 const type = ChipTypesHelper.asBasicType(zclType);
48 return type.replace(/[^0-9]/g, '');
50 throw error = 'asPutLength: Unhandled type: ' + zclType;
54 function asPutCastType(zclType)
56 const type = ChipTypesHelper.asBasicType(zclType);
69 throw error = 'asPutCastType: Unhandled type: ' + zclType;
74 * Creates block iterator over the enabled server side clusters
78 function chip_server_clusters(options)
80 const db = this.global.db;
82 return queryImpexp.exportendPointTypeIds(db, this.global.sessionId)
83 .then(endpointTypes => { return zclQuery.exportAllClustersDetailsFromEndpointTypes(db, endpointTypes) })
84 .then(clusters => clusters.filter(cluster => cluster.enabled == 1 && cluster.side == 'server'))
85 .then(clusters => templateUtil.collectBlocks(clusters, options, this))
88 function chip_clusters(options)
90 const db = this.global.db;
92 return queryImpexp.exportendPointTypeIds(db, this.global.sessionId)
93 .then(endpointTypes => { return zclQuery.exportAllClustersDetailsFromEndpointTypes(db, endpointTypes) })
94 .then(clusters => clusters.filter(cluster => cluster.enabled == 1))
95 .then(clusters => templateUtil.collectBlocks(clusters, options, this))
99 * Creates block iterator over the server side cluster command
100 * for a given cluster.
102 * This function is meant to be used inside a {{#chip_server_clusters}}
103 * block. It will throws otherwise.
107 function chip_server_cluster_commands(options)
109 // Retrieve the clusterName and the clusterSide. If any if not available, an error will be thrown.
110 const clusterName = this.name;
111 const clusterSide = this.side;
112 if (clusterName == undefined || clusterSide == undefined) {
113 const error = 'chip_server_cluster_commands: Could not find relevant parent cluster.';
118 function filterCommand(cmd)
120 return cmd.clusterName == clusterName && cmd.clusterSide == 'client' && cmd.name.includes('Response') == false;
123 const db = this.global.db;
124 return queryImpexp.exportendPointTypeIds(db, this.global.sessionId)
125 .then(endpointTypes => zclQuery.exportClustersAndEndpointDetailsFromEndpointTypes(db, endpointTypes))
126 .then(endpointsAndClusters => zclQuery.exportCommandDetailsFromAllEndpointTypesAndClusters(db, endpointsAndClusters))
127 .then(endpointCommands => endpointCommands.filter(filterCommand))
128 .then(endpointCommands => templateUtil.collectBlocks(endpointCommands, options, this))
132 * Creates block iterator over the server side cluster command arguments
133 * for a given command.
135 * This function is meant to be used inside a {{#chip_server_cluster_commands}}
136 * block. It will throws otherwise.
140 function chip_server_cluster_command_arguments(options)
142 const db = this.global.db;
144 function collectItem(arg, pkgId)
146 return zclHelper.isStruct(db, arg.type, pkgId).then(result => {
147 if (result == 'unknown') {
151 return zclQuery.selectStructByName(db, arg.type, pkgId).then(rec => {
152 return zclQuery.selectAllStructItemsById(db, rec.id).then(items => items.map(item => {
153 item.name = item.label;
160 function collectItems(args, pkgId)
162 return Promise.all(args.map(arg => collectItem.call(this, arg, pkgId))).then(items => items.flat()).then(items => {
163 return Promise.all(items.map(item => {
164 if (StringHelper.isString(item.type)) {
165 item.chipType = 'chip::ByteSpan';
169 return zclHelper.asUnderlyingZclType.call(this, item.type, options).then(zclType => {
170 // Enhanced the command argument with 'chipType', 'chipTypePutLength', 'chipTypePutCastType' for conveniences.
171 item.chipType = zclType;
172 item.chipTypePutLength = asPutLength(zclType);
173 item.chipTypePutCastType = asPutCastType(zclType);
182 return zclQuery.selectCommandArgumentsByCommandId(db, this.id, pkgId)
183 .then(args => collectItems.call(this, args, pkgId))
184 .then(items => templateUtil.collectBlocks(items, options, this));
187 const promise = templateUtil.ensureZclPackageId(this).then(fn.bind(this)).catch(err => console.log(err));
188 return templateUtil.templatePromise(this.global, promise)
192 * Returns if a given command argument chip type is signed.
194 * This function is meant to be used inside a {{#chip_*}} block.
195 * It will throws otherwise.
199 function isSignedType()
201 const type = this.chipType;
203 const error = 'isSignedType: Could not find chipType';
220 * Returns if a given command argument chip type is discrete.
222 * This function is meant to be used inside a {{#chip_*}} block.
223 * It will throws otherwise.
227 function isDiscreteType()
229 const type = this.chipType;
231 const error = 'isDiscreteType: Could not find chipType';
236 return this.discrete;
239 function getAttributes(pkgId, options)
241 const db = this.global.db;
242 return queryConfig.getAllSessionAttributes(db, this.global.sessionId).then(atts => {
243 return Promise.all(atts.map(att => zclQuery.selectAtomicByName(db, att.type, pkgId).then(atomic => {
244 // Enhanced the attribute with 'atomidId', 'discrete', chipType properties for convenience.
245 att.atomicTypeId = atomic.atomicId;
246 att.discrete = atomic.discrete;
248 if (StringHelper.isString(att.type)) {
249 // Enhanced the command argument with 'chipType' for conveniences.
250 att.chipType = 'chip::ByteSpan';
254 return zclHelper.asUnderlyingZclType.call(this, att.type, options).then(zclType => {
255 att.chipType = zclType;
263 * Creates block iterator over the server side cluster attributes
264 * for a given cluster.
266 * This function is meant to be used inside a {{#chip_server_clusters}}
267 * block. It will throws otherwise.
271 function chip_server_cluster_attributes(options)
273 // Retrieve the clusterCode and the clusterSide. If any if not available, an error will be thrown.
274 const clusterCode = this.code;
275 const clusterSide = this.side;
276 if (clusterCode == undefined || clusterSide == undefined) {
277 const error = 'chip_server_cluster_attributes: Could not find relevant parent cluster.';
284 return getAttributes.call(this, pkgId, options).then(atts => {
285 atts = atts.filter(att => att.clusterCode == clusterCode && att.side == 'server');
286 atts.forEach(att => {
287 const sameAttributes = atts.filter(att2 => att.name == att2.name);
288 let isWritable = !!sameAttributes.find(att2 => att2.writable);
289 let isReportable = !!sameAttributes.find(att2 => att2.reportable.included);
290 if (isWritable || isReportable) {
291 if (!StringHelper.isString(att.type)) {
292 att.chipTypePutLength = asPutLength(att.chipType);
293 att.chipTypePutCastType = asPutCastType(att.chipType);
295 att.writable = isWritable;
296 att.reportable.included = isReportable;
299 atts = atts.filter((att, index) => atts.findIndex(att2 => att.name == att2.name) == index);
300 return templateUtil.collectBlocks(atts, options, this);
304 const promise = templateUtil.ensureZclPackageId(this).then(fn.bind(this)).catch(err => console.log(err));
305 return templateUtil.templatePromise(this.global, promise);
309 * Returns if a given attribute is writable.
311 * This function is meant to be used inside a {{#chip_server_cluster_attributes}} block.
312 * It will throws otherwise.
316 function isWritableAttribute(options)
318 if (this.attributeCode == undefined) {
319 const error = 'isWritableAttribute: missing attribute code.';
324 return this.writable == 1;
328 * Returns if a given attribute is reportable.
330 * This function is meant to be used inside a {{#chip_server_cluster_attributes}} block.
331 * It will throws otherwise.
335 function isReportableAttribute(options)
337 if (this.attributeCode == undefined) {
338 const error = 'isReportableAttribute: missing attribute code.';
343 return this.reportable.included == 1;
347 * Returns if a given command is manufacturer specific
349 * This function is meant to be used inside a {{#chip_server_cluster_commands}} block.
350 * It will throws otherwise.
354 function isManufacturerSpecificCommand()
356 if (this.commandSource == undefined) {
357 const error = 'isManufacturerSpecificCommand: Not inside a ({#chip_server_cluster_commands}} block.';
362 return !!this.mfgCode;
365 function asPythonType(zclType)
367 const type = ChipTypesHelper.asBasicType(zclType);
381 case 'chip::ByteSpan':
386 function asPythonCType(zclType)
388 const type = ChipTypesHelper.asBasicType(zclType);
398 return 'c_' + type.replace('_t', '');
405 function hasSpecificResponse(commandName)
407 // Retrieve the clusterName and the clusterSide. If any if not available, an error will be thrown.
408 const clusterName = this.parent.name;
409 const clusterSide = this.parent.side;
410 if (clusterName == undefined || clusterSide == undefined) {
411 const error = 'chip_server_cluster_commands: Could not find relevant parent cluster.';
416 function filterCommand(cmd)
418 return cmd.clusterName == clusterName && cmd.name == (commandName + "Response");
423 const db = this.global.db;
424 return queryImpexp.exportendPointTypeIds(db, this.global.sessionId)
425 .then(endpointTypes => zclQuery.exportClustersAndEndpointDetailsFromEndpointTypes(db, endpointTypes))
426 .then(endpointsAndClusters => zclQuery.exportCommandDetailsFromAllEndpointTypesAndClusters(db, endpointsAndClusters))
427 .then(endpointCommands => endpointCommands.filter(filterCommand).length)
430 const promise = templateUtil.ensureZclPackageId(this).then(fn.bind(this)).catch(err => console.log(err));
431 return templateUtil.templatePromise(this.global, promise);
434 function asCallbackAttributeType(attributeType)
436 switch (parseInt(attributeType)) {
437 case 0x00: // nodata / No data
438 case 0x0A: // data24 / 24-bit data
439 case 0x0C: // data40 / 40-bit data
440 case 0x0D: // data48 / 48-bit data
441 case 0x0E: // data56 / 56-bit data
442 case 0x1A: // map24 / 24-bit bitmap
443 case 0x1C: // map40 / 40-bit bitmap
444 case 0x1D: // map48 / 48-bit bitmap
445 case 0x1E: // map56 / 56-bit bitmap
446 case 0x22: // uint24 / Unsigned 24-bit integer
447 case 0x24: // uint40 / Unsigned 40-bit integer
448 case 0x25: // uint48 / Unsigned 48-bit integer
449 case 0x26: // uint56 / Unsigned 56-bit integer
450 case 0x2A: // int24 / Signed 24-bit integer
451 case 0x2C: // int40 / Signed 40-bit integer
452 case 0x2D: // int48 / Signed 48-bit integer
453 case 0x2E: // int56 / Signed 56-bit integer
454 case 0x38: // semi / Semi-precision
455 case 0x39: // single / Single precision
456 case 0x3A: // double / Double precision
457 case 0x48: // array / Array
458 case 0x49: // struct / Structure
459 case 0x50: // set / Set
460 case 0x51: // bag / Bag
461 case 0xE0: // ToD / Time of day
462 case 0xEA: // bacOID / BACnet OID
463 case 0xF1: // key128 / 128-bit security key
464 case 0xFF: // unk / Unknown
465 return 'Unsupported';
466 case 0x41: // octstr / Octet string
467 case 0x42: // string / Character string
468 case 0x43: // octstr16 / Long octet string
469 case 0x44: // string16 / Long character string
471 case 0x08: // data8 / 8-bit data
472 case 0x18: // map8 / 8-bit bitmap
473 case 0x20: // uint8 / Unsigned 8-bit integer
474 case 0x30: // enum8 / 8-bit enumeration
476 case 0x09: // data16 / 16-bit data
477 case 0x19: // map16 / 16-bit bitmap
478 case 0x21: // uint16 / Unsigned 16-bit integer
479 case 0x31: // enum16 / 16-bit enumeration
480 case 0xE8: // clusterId / Cluster ID
481 case 0xE9: // attribId / Attribute ID
483 case 0x0B: // data32 / 32-bit data
484 case 0x1B: // map32 / 32-bit bitmap
485 case 0x23: // uint32 / Unsigned 32-bit integer
486 case 0xE1: // date / Date
487 case 0xE2: // UTC / UTCTime
489 case 0x0F: // data64 / 64-bit data
490 case 0x1F: // map64 / 64-bit bitmap
491 case 0x27: // uint64 / Unsigned 64-bit integer
492 case 0xF0: // EUI64 / IEEE address
494 case 0x10: // bool / Boolean
496 case 0x28: // int8 / Signed 8-bit integer
498 case 0x29: // int16 / Signed 16-bit integer
500 case 0x2B: // int32 / Signed 32-bit integer
502 case 0x2F: // int64 / Signed 64-bit integer
505 error = 'Unhandled attribute type ' + attributeType;
510 function asObjectiveCBasicType(type)
512 if (StringHelper.isOctetString(type)) {
514 } else if (StringHelper.isCharString(type)) {
517 return ChipTypesHelper.asBasicType(this.chipType);
521 function asObjectiveCNumberType(label, type)
525 const options = { 'hash' : {} };
526 return zclHelper.asUnderlyingZclType.call(this, type, options).then(zclType => {
529 return 'UnsignedChar';
531 return 'UnsignedShort';
533 return 'UnsignedLong';
535 return 'UnsignedLongLong';
545 error = label + ': Unhandled underlying type ' + zclType + ' for original type ' + type;
551 const promise = templateUtil.ensureZclPackageId(this).then(fn.bind(this)).catch(err => console.log(err));
552 return templateUtil.templatePromise(this.global, promise)
555 function isStrEndsWith(str, substr)
557 return str.endsWith(substr);
563 exports.chip_clusters = chip_clusters;
564 exports.chip_server_clusters = chip_server_clusters;
565 exports.chip_server_cluster_commands = chip_server_cluster_commands;
566 exports.chip_server_cluster_command_arguments = chip_server_cluster_command_arguments
567 exports.asBasicType = ChipTypesHelper.asBasicType;
568 exports.asObjectiveCBasicType = asObjectiveCBasicType;
569 exports.asObjectiveCNumberType = asObjectiveCNumberType;
570 exports.isSignedType = isSignedType;
571 exports.isDiscreteType = isDiscreteType;
572 exports.chip_server_cluster_attributes = chip_server_cluster_attributes;
573 exports.isWritableAttribute = isWritableAttribute;
574 exports.isReportableAttribute = isReportableAttribute;
575 exports.isManufacturerSpecificCommand = isManufacturerSpecificCommand;
576 exports.asPythonType = asPythonType;
577 exports.asPythonCType = asPythonCType;
578 exports.asCallbackAttributeType = asCallbackAttributeType;
579 exports.hasSpecificResponse = hasSpecificResponse;
580 exports.isStrEndsWith = isStrEndsWith;