diff --git a/src-electron/db/query-cluster.js b/src-electron/db/query-cluster.js index fcca9c6980..2d34fedd47 100644 --- a/src-electron/db/query-cluster.js +++ b/src-electron/db/query-cluster.js @@ -23,6 +23,22 @@ const dbApi = require('./db-api.js') const dbMapping = require('./db-mapping.js') +/** + * Returns a cluster name from the cluster ref + * + * @param db + * @param clusterRef + * @returns Cluster name + */ +async function selectClusterName(db, clusterRef) { + let clusterName = await dbApi.dbAll( + db, + 'SELECT NAME FROM CLUSTER WHERE CLUSTER_ID = ?', + [clusterRef] + ) + return clusterName[0].NAME +} + /** * All cluster details along with their attribute details per endpoint. * @param db @@ -280,6 +296,7 @@ async function selectTokenAttributeClustersForEndpoint( return rows.map(dbMapping.map.cluster) } +exports.selectClusterName = selectClusterName exports.selectClusterDetailsFromEnabledClusters = selectClusterDetailsFromEnabledClusters exports.selectAllUserClustersWithTokenAttributes = diff --git a/src-electron/db/query-config.js b/src-electron/db/query-config.js index 63b213b556..6861882f39 100644 --- a/src-electron/db/query-config.js +++ b/src-electron/db/query-config.js @@ -25,6 +25,7 @@ const dbMapping = require('./db-mapping.js') const queryPackage = require('./query-package.js') const dbEnum = require('../../src-shared/db-enum.js') const queryZcl = require('./query-zcl.js') +const queryUpgrade = require('../upgrade/upgrade.js') const queryDeviceType = require('./query-device-type') const queryCommand = require('./query-command.js') const restApi = require('../../src-shared/rest-api.js') @@ -211,15 +212,17 @@ async function insertOrUpdateAttributeState( attributeId, clusterRef ) - if ( - staticAttribute.storagePolicy == - dbEnum.storagePolicy.attributeAccessInterface - ) { - staticAttribute.storagePolicy = dbEnum.storageOption.external - } else { - staticAttribute.storagePolicy = dbEnum.storageOption.ram - } - + let forcedExternal = await queryUpgrade.getForcedExternalStorage( + db, + attributeId + ) + let storageOption = await queryUpgrade.computeStorageNewConfig( + db, + clusterRef, + staticAttribute.storagePolicy, + forcedExternal, + staticAttribute.name + ) if (staticAttribute == null) { throw new Error(`COULD NOT LOCATE ATTRIBUTE: ${attributeId} `) } @@ -253,7 +256,7 @@ INTO ENDPOINT_TYPE_ATTRIBUTE ( cluster.endpointTypeClusterId, attributeId, staticAttribute.defaultValue ? staticAttribute.defaultValue : '', - staticAttribute.storagePolicy, + storageOption, clusterRef, reportMinInterval, reportMaxInterval, diff --git a/src-electron/db/query-impexp.js b/src-electron/db/query-impexp.js index 14422fc2aa..b6344460a7 100644 --- a/src-electron/db/query-impexp.js +++ b/src-electron/db/query-impexp.js @@ -23,7 +23,7 @@ const dbApi = require('./db-api') const dbEnums = require('../../src-shared/db-enum') const dbMapping = require('./db-mapping.js') - +const queryUpgrade = require('../upgrade/upgrade.js') /** * Imports a single endpoint * @param {} db @@ -619,6 +619,7 @@ ORDER BY * @param {*} endpointTypeId * @param {*} endpointClusterId may be null if global attribute * @param {*} attribute + * @param {*} cluster * @returns Promise of an attribute insertion. */ async function importAttributeForEndpointType( @@ -626,13 +627,15 @@ async function importAttributeForEndpointType( packageIds, endpointTypeId, endpointClusterId, - attribute + attribute, + cluster ) { let selectAttributeQuery = ` SELECT A.ATTRIBUTE_ID, A.REPORTING_POLICY, - A.STORAGE_POLICY + A.STORAGE_POLICY, + A.NAME FROM ATTRIBUTE AS A INNER JOIN @@ -657,14 +660,18 @@ WHERE let attributeId let reportingPolicy let storagePolicy + let forcedExternal + let attributeName if (atRow.length == 0) { attributeId = null reportingPolicy = null storagePolicy = null + attributeName = null } else { attributeId = atRow[0].ATTRIBUTE_ID reportingPolicy = atRow[0].REPORTING_POLICY storagePolicy = atRow[0].STORAGE_POLICY + attributeName = atRow[0].NAME } // If the spec has meanwhile changed the policies to mandatory or prohibited, @@ -674,7 +681,19 @@ WHERE } else if (reportingPolicy == dbEnums.reportingPolicy.prohibited) { attribute.reportable = false } - + if (attributeId) { + forcedExternal = await queryUpgrade.getForcedExternalStorage( + db, + attributeId + ) + storagePolicy = await queryUpgrade.computeStorageImport( + db, + cluster.name, + storagePolicy, + forcedExternal, + attributeName + ) + } if (storagePolicy == dbEnums.storagePolicy.attributeAccessInterface) { attribute.storageOption = dbEnums.storageOption.external } diff --git a/src-electron/db/query-package.js b/src-electron/db/query-package.js index 4b8a558b68..4ad8faca05 100644 --- a/src-electron/db/query-package.js +++ b/src-electron/db/query-package.js @@ -186,6 +186,22 @@ async function getPackageByPackageId(db, packageId) { .then(dbMapping.map.package) } +/** + * Returns a package ref from the attribute ID + * + * @param db + * @param attributeId + * @returns package ref + */ +async function getPackageRefByAttributeId(db, attributeId) { + let package_ref = await dbApi.dbAll( + db, + 'SELECT PACKAGE_REF FROM ATTRIBUTE WHERE ATTRIBUTE_ID = ?', + [attributeId] + ) + return package_ref[0].PACKAGE_REF +} + /** * Resolves with a CRC or null for a given path. * @@ -979,6 +995,7 @@ async function insertSessionKeyValuesFromPackageDefaults(db, sessionId) { } // exports +exports.getPackageRefByAttributeId = getPackageRefByAttributeId exports.getPackageByPathAndParent = getPackageByPathAndParent exports.getPackageByPackageId = getPackageByPackageId exports.getPackagesByType = getPackagesByType diff --git a/src-electron/importexport/import-json.js b/src-electron/importexport/import-json.js index 90ea70bc09..f4e5f4904e 100644 --- a/src-electron/importexport/import-json.js +++ b/src-electron/importexport/import-json.js @@ -336,7 +336,8 @@ async function importEndpointTypes( allZclPackageIds, endpointId, endpointClusterId, - attribute + attribute, + cluster ) ) }) diff --git a/src-electron/upgrade/upgrade.js b/src-electron/upgrade/upgrade.js new file mode 100644 index 0000000000..7a4e8f3a68 --- /dev/null +++ b/src-electron/upgrade/upgrade.js @@ -0,0 +1,121 @@ +/** + * + * Copyright (c) 2020 Silicon Labs + * + * 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. + */ + +const dbApi = require('../db/db-api.js') +const queryPackage = require('../db/query-package.js') +const queryCluster = require('../db/query-cluster.js') +const dbEnum = require('../../src-shared/db-enum.js') +const fs = require('fs') +const fsp = fs.promises + +/** + * This file implements upgrade rules which are used to upgrade .zap files and xml files + * to be in sync with the spec + */ + +/** + * Returns an array of objects containing global attributes that should be forced external. + * + * @export + * @param {*} db + * @param {*} attributeId + * @returns An array of objects + */ + +async function getForcedExternalStorage(db, attributeId) { + let pkgs = await queryPackage.getPackageRefByAttributeId(db, attributeId) + let zcl = await queryPackage.getPackageByPackageId(db, pkgs) + zcl = zcl.path + let obj = await fsp.readFile(zcl) + let data = JSON.parse(obj) + let byName = data?.attributeAccessInterfaceAttributes + let lists = data?.listsUseAttributeAccessInterface + let forcedExternal = { byName, lists } + return forcedExternal +} + +/** + * Returns a flag stating which type of storage option the attribute is categorized to be. + * + * @export + * @param {*} db + * @param {*} clusterName + * @param {*} clusterRef + * @param {*} storagePolicy + * @param {*} forcedExternal + * @param {*} attributeId + * @returns Storage Option + */ + +async function computeStorageNewConfig( + db, + clusterRef, + storagePolicy, + forcedExternal, + attributeName +) { + let storageOption + let clusterName + clusterName = await queryCluster.selectClusterName(db, clusterRef) + if (storagePolicy == dbEnum.storagePolicy.attributeAccessInterface) { + storageOption = dbEnum.storageOption.external + } else if (storagePolicy == dbEnum.storagePolicy.any) { + storageOption = dbEnum.storageOption.ram + } else { + throw 'check storage policy' + } + if ( + forcedExternal.byName && + forcedExternal.byName[clusterName] && + forcedExternal.byName[clusterName].includes(attributeName) + ) { + storageOption = dbEnum.storageOption.external + } + return storageOption +} + +/** + * Returns a flag stating which type of storage option the attribute is categorized to be. + * + * @export + * @param {*} db + * @param {*} clusterName + * @param {*} forcedExternal + * @param {*} attributeId + * @returns Storage Policy + */ + +async function computeStorageImport( + db, + clusterName, + storagePolicy, + forcedExternal, + attributeName +) { + if ( + forcedExternal.byName && + forcedExternal.byName[clusterName] && + forcedExternal.byName[clusterName].includes(attributeName) + ) { + storagePolicy = dbEnum.storagePolicy.attributeAccessInterface + } + return storagePolicy +} + +exports.getForcedExternalStorage = getForcedExternalStorage +exports.computeStorageImport = computeStorageImport +exports.computeStorageNewConfig = computeStorageNewConfig diff --git a/src-electron/zcl/zcl-loader-silabs.js b/src-electron/zcl/zcl-loader-silabs.js index 1db35958db..a9f2a591a9 100644 --- a/src-electron/zcl/zcl-loader-silabs.js +++ b/src-electron/zcl/zcl-loader-silabs.js @@ -560,7 +560,6 @@ function prepareCluster(cluster, context, isExtension = false) { if (context.listsUseAttributeAccessInterface && attribute.$.entryType) { storagePolicy = dbEnum.storagePolicy.attributeAccessInterface } else if ( - context.listsUseAttributeAccessInterface && context.attributeAccessInterfaceAttributes && context.attributeAccessInterfaceAttributes[cluster.name] && context.attributeAccessInterfaceAttributes[cluster.name].includes(name) diff --git a/test/gen-matter-4.test.js b/test/gen-matter-4.test.js index 86687a57a5..66bf746e21 100644 --- a/test/gen-matter-4.test.js +++ b/test/gen-matter-4.test.js @@ -114,7 +114,7 @@ test( },\\`) expect(ept).toContain(`#define GENERATED_ENDPOINT_TYPES { \\ - { ZAP_CLUSTER_INDEX(0), 29, 377 }, \\ + { ZAP_CLUSTER_INDEX(0), 29, 367 }, \\ { ZAP_CLUSTER_INDEX(29), 46, 3516 }, \\ { ZAP_CLUSTER_INDEX(75), 5, 105 }, \\ { ZAP_CLUSTER_INDEX(80), 1, 0 }, \\ @@ -150,7 +150,7 @@ test( expect(ept).toContain('#define GENERATED_CLUSTER_COUNT 81') expect(ept).toContain('#define ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT 79') expect(ept).toContain('#define ATTRIBUTE_SINGLETONS_SIZE (37)') - expect(ept).toContain('#define ATTRIBUTE_MAX_SIZE (3998)') + expect(ept).toContain('#define ATTRIBUTE_MAX_SIZE (3988)') expect(ept).toContain('#define FIXED_ENDPOINT_COUNT (4)') expect(ept).toContain( '#define FIXED_ENDPOINT_ARRAY { 0x0000, 0x0001, 0x0002, 0xFFFE }' diff --git a/test/tokens.test.js b/test/tokens.test.js index 8d869a0846..617471ae1d 100644 --- a/test/tokens.test.js +++ b/test/tokens.test.js @@ -40,7 +40,7 @@ beforeAll(async () => { env.zapVersion() ) await zclLoader.loadZcl(db, env.builtinSilabsZclMetafile()) -}, testUtil.timeout.medium()) +}, testUtil.timeout.long()) afterAll(() => dbApi.closeDatabase(db), testUtil.timeout.short()) @@ -58,7 +58,7 @@ test( expect(context.packageId).not.toBeNull() templateContext = context }, - testUtil.timeout.medium() + testUtil.timeout.long() ) test( @@ -68,7 +68,7 @@ test( templateContext.sessionId = importResult.sessionId expect(importResult.sessionId).not.toBeNull() }, - testUtil.timeout.medium() + testUtil.timeout.long() ) test(