blob: 6c46b496f4127be7b89956b56abb550f327d9061 [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Import helpers from zap core
const zapPath = '../../../../../third_party/zap/repo/src-electron/';
const queryConfig = require(zapPath + 'db/query-config.js')
const queryImpexp = require(zapPath + 'db/query-impexp.js')
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 StringHelper = require('../../common/StringHelper.js');
const ChipTypesHelper = require('../../common/ChipTypesHelper.js');
/**
* This method converts a ZCL type to the length expected for the
* BufBound.Put method.
* TODO
* Not all types are supported at the moment, so if there is any unsupported type
* that we are trying to convert, it will throw an error.
*/
function asPutLength(zclType)
{
const type = ChipTypesHelper.asBasicType(zclType);
switch (type) {
case 'int8_t':
case 'int16_t':
case 'int32_t':
case 'int64_t':
case 'uint8_t':
case 'uint16_t':
case 'uint32_t':
case 'uint64_t':
return type.replace(/[^0-9]/g, '');
default:
throw error = 'Unhandled type: ' + zclType;
}
}
function asPutCastType(zclType)
{
const type = ChipTypesHelper.asBasicType(zclType);
switch (type) {
case 'int8_t':
case 'int16_t':
case 'int32_t':
case 'int64_t':
return 'u' + type;
case 'uint8_t':
case 'uint16_t':
case 'uint32_t':
case 'uint64_t':
return type;
default:
throw error = 'Unhandled type: ' + zclType;
}
}
/**
* Creates block iterator over the enabled server side clusters
*
* @param {*} options
*/
function chip_server_clusters(options)
{
const db = this.global.db;
return queryImpexp.exportendPointTypeIds(db, this.global.sessionId)
.then(endpointTypes => { return zclQuery.exportAllClustersDetailsFromEndpointTypes(db, endpointTypes) })
.then(clusters => clusters.filter(cluster => cluster.enabled == 1 && cluster.side == 'server'))
.then(clusters => templateUtil.collectBlocks(clusters, options, this))
}
/**
* Creates block iterator over the server side cluster command
* for a given cluster.
*
* This function is meant to be used inside a {{#chip_server_clusters}}
* block. It will throws otherwise.
*
* @param {*} options
*/
function chip_server_cluster_commands(options)
{
// Retrieve the clusterName and the clusterSide. If any if not available, an error will be thrown.
const clusterName = this.name;
const clusterSide = this.side;
if (clusterName == undefined || clusterSide == undefined) {
const error = 'chip_server_cluster_commands: Could not find relevant parent cluster.';
console.log(error);
throw error;
}
function filterCommand(cmd)
{
return cmd.clusterName == clusterName && cmd.clusterSide == 'client' && cmd.name.includes('Response') == false;
}
const db = this.global.db;
return queryImpexp.exportendPointTypeIds(db, this.global.sessionId)
.then(endpointTypes => zclQuery.exportClustersAndEndpointDetailsFromEndpointTypes(db, endpointTypes))
.then(endpointsAndClusters => zclQuery.exportCommandDetailsFromAllEndpointTypesAndClusters(db, endpointsAndClusters))
.then(endpointCommands => endpointCommands.filter(filterCommand))
.then(endpointCommands => templateUtil.collectBlocks(endpointCommands, options, this))
}
/**
* Creates block iterator over the server side cluster command arguments
* for a given command.
*
* This function is meant to be used inside a {{#chip_server_cluster_commands}}
* block. It will throws otherwise.
*
* @param {*} options
*/
function chip_server_cluster_command_arguments(options)
{
const db = this.global.db;
function collectItem(arg, pkgId)
{
return zclHelper.isStruct(db, arg.type, pkgId).then(result => {
if (result == 'unknown') {
return arg;
}
return zclQuery.selectStructByName(db, arg.type, pkgId).then(rec => {
return zclQuery.selectAllStructItemsById(db, rec.id).then(items => items.map(item => {
item.name = item.label;
return item;
}));
})
})
}
function collectItems(args, pkgId)
{
return Promise.all(args.map(arg => collectItem.call(this, arg, pkgId))).then(items => items.flat()).then(items => {
return Promise.all(items.map(item => {
if (StringHelper.isString(item.type)) {
// Enhanced the command argument with 'chipType' for conveniences.
item.chipType = 'char *';
return item;
}
return zclHelper.asUnderlyingZclType.call(this, item.type, options).then(zclType => {
// Enhanced the command argument with 'chipType', 'chipTypePutLength', 'chipTypePutCastType' for conveniences.
item.chipType = zclType;
item.chipTypePutLength = asPutLength(zclType);
item.chipTypePutCastType = asPutCastType(zclType);
return item;
})
}));
});
}
function fn(pkgId)
{
return zclQuery.selectCommandArgumentsByCommandId(db, this.id, pkgId)
.then(args => collectItems.call(this, args, pkgId))
.then(items => templateUtil.collectBlocks(items, options, this));
}
const promise = templateUtil.ensureZclPackageId(this).then(fn.bind(this)).catch(err => console.log(err));
return templateUtil.templatePromise(this.global, promise)
}
/**
* Returns if a given command argument chip type is signed.
*
* This function is meant to be used inside a {{#chip_*}} block.
* It will throws otherwise.
*
* @param {*} options
*/
function isSignedType()
{
const type = this.chipType;
if (!type) {
const error = 'isSignedType: Could not find chipType';
console.log(error);
throw error;
}
switch (type) {
case 'int8_t':
case 'int16_t':
case 'int32_t':
case 'int64_t':
return true;
default:
return false;
}
}
/**
* Returns if a given command argument chip type is discrete.
*
* This function is meant to be used inside a {{#chip_*}} block.
* It will throws otherwise.
*
* @param {*} options
*/
function isDiscreteType()
{
const type = this.chipType;
if (!type) {
const error = 'isDiscreteType: Could not find chipType';
console.log(error);
throw error;
}
return this.discrete;
}
function getAttributes(pkgId, options)
{
const db = this.global.db;
return queryConfig.getAllSessionAttributes(db, this.global.sessionId).then(atts => {
return Promise.all(atts.map(att => zclQuery.selectAtomicByName(db, att.type, pkgId).then(atomic => {
// Enhanced the attribute with 'atomidId', 'discrete', chipType properties for convenience.
att.atomicTypeId = atomic.atomicId;
att.discrete = atomic.discrete;
return zclHelper.asUnderlyingZclType.call(this, att.type, options).then(zclType => {
att.chipType = zclType;
return att;
});
})));
})
}
/**
* Creates block iterator over the server side cluster attributes
* for a given cluster.
*
* This function is meant to be used inside a {{#chip_server_clusters}}
* block. It will throws otherwise.
*
* @param {*} options
*/
function chip_server_cluster_attributes(options)
{
// Retrieve the clusterCode and the clusterSide. If any if not available, an error will be thrown.
const clusterCode = this.code;
const clusterSide = this.side;
if (clusterCode == undefined || clusterSide == undefined) {
const error = 'chip_server_cluster_attributes: Could not find relevant parent cluster.';
console.log(error);
throw error;
}
function fn(pkgId)
{
return getAttributes.call(this, pkgId, options).then(atts => {
atts = atts.filter(att => att.clusterCode == clusterCode && att.side == clusterSide);
atts.forEach(att => {
const sameAttributes = atts.filter(att2 => att.name == att2.name);
let isWritable = !!sameAttributes.find(att2 => att2.writable);
let isReportable = !!sameAttributes.find(att2 => att2.reportable.included);
if (isWritable || isReportable) {
att.chipTypePutLength = asPutLength(att.chipType);
att.chipTypePutCastType = asPutCastType(att.chipType);
att.writable = isWritable;
att.reportable.included = isReportable;
}
})
atts = atts.filter((att, index) => atts.findIndex(att2 => att.name == att2.name) == index);
return templateUtil.collectBlocks(atts, options, this);
})
}
const promise = templateUtil.ensureZclPackageId(this).then(fn.bind(this)).catch(err => console.log(err));
return templateUtil.templatePromise(this.global, promise);
}
/**
* Returns if a given attribute is writable.
*
* This function is meant to be used inside a {{#chip_server_cluster_attributes}} block.
* It will throws otherwise.
*
* @param {*} options
*/
function isWritableAttribute(options)
{
if (this.attributeCode == undefined) {
const error = 'isWritableAttribute: missing attribute code.';
console.log(error);
throw error;
}
return this.writable == 1;
}
/**
* Returns if a given attribute is reportable.
*
* This function is meant to be used inside a {{#chip_server_cluster_attributes}} block.
* It will throws otherwise.
*
* @param {*} options
*/
function isReportableAttribute(options)
{
if (this.attributeCode == undefined) {
const error = 'isReportableAttribute: missing attribute code.';
console.log(error);
throw error;
}
return this.reportable.included == 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 throws otherwise.
*
* @param {*} options
*/
function isManufacturerSpecificCommand()
{
if (this.commandSource == undefined) {
const error = 'isManufacturerSpecificCommand: Not inside a ({#chip_server_cluster_commands}} block.';
console.log(error);
throw error;
}
return !!this.mfgCode;
}
//
// Module exports
//
exports.chip_server_clusters = chip_server_clusters;
exports.chip_server_cluster_commands = chip_server_cluster_commands;
exports.chip_server_cluster_command_arguments = chip_server_cluster_command_arguments
exports.asBasicType = ChipTypesHelper.asBasicType;
exports.isSignedType = isSignedType;
exports.isDiscreteType = isDiscreteType;
exports.chip_server_cluster_attributes = chip_server_cluster_attributes;
exports.isWritableAttribute = isWritableAttribute;
exports.isReportableAttribute = isReportableAttribute;
exports.isManufacturerSpecificCommand = isManufacturerSpecificCommand;