Skip to content

Commit

Permalink
Adding to all_user_cluster_attributes_irrespective_of_manufacturing_s…
Browse files Browse the repository at this point in the history
…pecification helper to replace chip_server_cluster_attributes

- chip_server_cluster_attributes is returning server attributes which are not actually enabled because the server side cluster is disabled.
- The reason chip_server_cluster_attributes is picking the server side attributes which are not enabled is because those are enabled in the .zap file(Which is the case for saving user selections and ease of use). However the helper is not actually checking if the cluster is enabled as well.
- all_user_cluster_attributes_irrespective_of_manufacturing_specification is solving this issue correctly and actually only showing attributes which are truly enabled.

- Extending endpointTypeAttributeExtended such that there is a common place for an attribute map
- Updating endpointTypeAttributeExtended with everything that attributeExportMapping had such that it can act as a common place for all other temporary maps that have been created across our code. Also sorting endpointTypeAttributeExtended for easier readability and avoiding duplicate keys

- Updating zcl_attributes_server block helper such that it can behave like chip_server_cluster_attributes.
- Updating attribute map such that it can be used more widely

- Adding additional helpers to remove the stateful helpers
- Adding as_underlying_language_specific_zcl_type to return language specific data types for zcl data types
- Adding removeKey option for removing certain columns which are not needed in a block helper such as all_user_cluster_attributes_irrespective_of_manufatucuring_specification
- Adding if_unsupported_attribute_type and if_attribute_complex to check for unsupported and complex zcl data types

- Deprecating old stateful helpers with new stateless helpers
Github: ZAP#898
  • Loading branch information
brdandu committed Mar 9, 2023
1 parent 8acc6a8 commit 1bd167f
Show file tree
Hide file tree
Showing 6 changed files with 507 additions and 77 deletions.
77 changes: 54 additions & 23 deletions src-electron/db/db-mapping.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

const dbApi = require('./db-api.js')
const dbEnums = require('../../src-shared/db-enum.js')
const bin = require('../util/bin')

exports.map = {
package: (x) => {
Expand Down Expand Up @@ -93,7 +94,7 @@ exports.map = {
manufacturerCode: x.MANUFACTURER_CODE,
name: x.NAME,
label: x.NAME,
type: x.TYPE,
type: x.TYPE != 'array' ? x.TYPE : x.ARRAY_TYPE,
side: x.SIDE,
define: x.DEFINE,
min: x.MIN,
Expand All @@ -105,15 +106,20 @@ exports.map = {
reportableChange: x.REPORTABLE_CHANGE,
reportableChangeLength: x.REPORTABLE_CHANGE_LENGTH,
isWritable: dbApi.fromDbBool(x.IS_WRITABLE),
isWritableAttribute: dbApi.fromDbBool(x.IS_WRITABLE),
isNullable: dbApi.fromDbBool(x.IS_NULLABLE),
defaultValue: x.DEFAULT_VALUE,
isOptional: dbApi.fromDbBool(x.IS_OPTIONAL),
isReportable:
x.REPORTING_POLICY == dbEnums.reportingPolicy.mandatory ||
x.REPORTING_POLICY == dbEnums.reportingPolicy.suggested,
isReportableAttribute:
x.REPORTING_POLICY == dbEnums.reportingPolicy.mandatory ||
x.REPORTING_POLICY == dbEnums.reportingPolicy.suggested,
reportingPolicy: x.REPORTING_POLICY,
isSceneRequired: dbApi.fromDbBool(x.IS_SCENE_REQUIRED),
entryType: x.ARRAY_TYPE,
isArray: x.ARRAY_TYPE ? 1 : 0,
mustUseTimedWrite: dbApi.fromDbBool(x.MUST_USE_TIMED_WRITE),
}
},
Expand Down Expand Up @@ -475,36 +481,61 @@ exports.map = {
endpointTypeAttributeExtended: (x) => {
if (x == null) return undefined
return {
endpointTypeRef: x.ENDPOINT_TYPE_REF,
clusterRef: x.CLUSTER_REF,
arrayType: x.ARRAY_TYPE,
attributeRef: x.ATTRIBUTE_REF,
included: dbApi.fromDbBool(x.INCLUDED),
storageOption: x.STORAGE_OPTION,
singleton: dbApi.fromDbBool(x.SINGLETON),
bounded: dbApi.fromDbBool(x.BOUNDED),
defaultValue: x.DEFAULT_VALUE,
includedReportable: dbApi.fromDbBool(x.INCLUDED_REPORTABLE),
minInterval: x.MIN_INTERVAL,
maxInterval: x.MAX_INTERVAL,
reportableChange: x.REPORTABLE_CHANGE,
name: x.NAME, // Attribute Name
code: x.CODE, // Attribute Code
side: x.SIDE, // Attribute Side
define: x.DEFINE, // Attribute define
type: x.TYPE, // Attribute type
mfgCode: x.MANUFACTURER_CODE
? x.MANUFACTURER_CODE
: x.CLUSTER_MANUFACTURER_CODE, // Attribute manufacturer code
clusterDefine: x.CLUSTER_DEFINE,
clusterMfgCode: x.CLUSTER_MANUFACTURER_CODE,
clusterName: x.CLUSTER_NAME,
clusterDefine: x.CLUSTER_DEFINE,
isSingleton: dbApi.fromDbBool(x.SINGLETON), // Endpoint type attribute is singleton or not
clusterRef: x.CLUSTER_REF,
clusterSide: x.SIDE,
code: x.CODE, // Attribute Code
defaultValue: x.DEFAULT_VALUE,
define: x.DEFINE, // Attribute define
endpointId: x.ENDPOINT_IDENTIFIER, // Endpoint type attribute's endpoint Id
endpointTypeRef: x.ENDPOINT_TYPE_REF,
entryType: x.ARRAY_TYPE,
hexCode: '0x' + bin.int16ToHex(x['CODE']), // Attribute code in hex
id: x.ATTRIBUTE_ID, // Attribute id
included: dbApi.fromDbBool(x.INCLUDED),
includedReportable: dbApi.fromDbBool(x.INCLUDED_REPORTABLE), // Is attribute reportable
isArray: x.IS_ARRAY, // Is attribute of type array
isBound: dbApi.fromDbBool(x.BOUNDED), // Is endpoint type attribute bounded
isClusterEnabled: x.ENABLED,
isGlobalAttribute: x.IS_GLOBAL_ATTRIBUTE, // Is attribute global
isIncluded: dbApi.fromDbBool(x.INCLUDED), // Is endpoint type attribute included
isManufacturingSpecific: dbApi.toDbBool(
x.MANUFACTURER_CODE | x.CLUSTER_MANUFACTURER_CODE
), // Is Attribute mfg specific or not
endpointId: x.ENDPOINT_IDENTIFIER, // Endpoint type attribute's endpoint Id
tokenId: x.TOKEN_ID, // Endpoint type attribute's token id
isNullable: dbApi.fromDbBool(x.IS_NULLABLE), // Is attribute nullable
isOptionalAttribute: dbApi.fromDbBool(x.IS_OPTIONAL),
isReportableAttribute: dbApi.fromDbBool(x.INCLUDED_REPORTABLE), // Is attribute reportable
isSceneRequired: dbApi.fromDbBool(x.IS_SCENE_REQUIRED),
isSingleton: dbApi.fromDbBool(x.SINGLETON), // Endpoint type attribute is singleton or not
isWritable: dbApi.fromDbBool(x.IS_WRITABLE), // Is attribute writable
isWritableAttribute: dbApi.fromDbBool(x.IS_WRITABLE), // Is attribute writable
manufacturerCode: x.MANUFACTURER_CODE
? x.MANUFACTURER_CODE
: x.CLUSTER_MANUFACTURER_CODE, // Attribute manufacturer code
max: x.MAX, // Attribute max value
maxInterval: x.MAX_INTERVAL,
maxLength: x.MAX_LENGTH, // Attribute max length
mfgCode: x.MANUFACTURER_CODE
? x.MANUFACTURER_CODE
: x.CLUSTER_MANUFACTURER_CODE, // Attribute manufacturer code
min: x.MIN, // Attribute min value
minInterval: x.MIN_INTERVAL,
minLength: x.MIN_LENGTH, // Attribute min length
mustUseTimedWrite: dbApi.fromDbBool(x.MUST_USE_TIMED_WRITE),
name: x.NAME, // Attribute Name
reportableChange: x.REPORTABLE_CHANGE,
side: x.SIDE, // Attribute Side
singleton: dbApi.fromDbBool(x.SINGLETON),
smallestEndpointIdentifier: x.SMALLEST_ENDPOINT_IDENTIFIER, // Smallest endpoint Id in which the attribute is present
storage: x.STORAGE_OPTION,
storageOption: x.STORAGE_OPTION,
tokenId: x.TOKEN_ID, // Endpoint type attribute's token id
type: x.TYPE, // Attribute type
}
},

Expand Down
86 changes: 61 additions & 25 deletions src-electron/db/query-attribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,6 @@
const dbApi = require('./db-api.js')
const dbMapping = require('./db-mapping.js')

function attributeExportMapping(x) {
return {
id: x.ATTRIBUTE_ID,
name: x.NAME,
code: x.CODE,
side: x.SIDE,
type: x.TYPE,
define: x.DEFINE,
mfgCode: x.MANUFACTURER_CODE,
clusterSide: x.SIDE,
clusterName: x.CLUSTER_NAME,
isClusterEnabled: x.ENABLED,
}
}

/**
* Promises to select all endpoint type attributes filtered by EndpointTypeRef and ClusterRef.
*
Expand Down Expand Up @@ -146,13 +131,19 @@ async function duplicateEndpointTypeAttribute(
* @param {*} db
* @param {*} endpointTypeId
* @param {*} packageIds
* @param {*} side
* @returns Promise that resolves with the attribute data.
*/
async function selectAllAttributeDetailsFromEnabledClusters(
db,
endpointsAndClusters,
packageIds
packageIds,
side = null
) {
let sideFilter = ''
if (side) {
sideFilter = ` AND ATTRIBUTE.SIDE = '${side}' `
}
let endpointTypeClusterRef = endpointsAndClusters
.map((ep) => ep.endpointTypeClusterRef)
.toString()
Expand All @@ -165,26 +156,71 @@ async function selectAllAttributeDetailsFromEnabledClusters(
ATTRIBUTE.NAME,
ATTRIBUTE.CODE,
ATTRIBUTE.SIDE,
ATTRIBUTE.TYPE,
CASE
WHEN
ATTRIBUTE.ARRAY_TYPE IS NULL
THEN
ATTRIBUTE.TYPE
ELSE
ATTRIBUTE.ARRAY_TYPE
END AS TYPE,
ATTRIBUTE.DEFINE,
ATTRIBUTE.MANUFACTURER_CODE,
ENDPOINT_TYPE_CLUSTER.SIDE,
CLUSTER.NAME AS CLUSTER_NAME,
ENDPOINT_TYPE_CLUSTER.ENABLED
ENDPOINT_TYPE_CLUSTER.ENABLED,
CASE
WHEN
ATTRIBUTE.ARRAY_TYPE IS NOT NULL
THEN
1
ELSE
0
END AS IS_ARRAY,
ATTRIBUTE.IS_WRITABLE,
ATTRIBUTE.IS_NULLABLE,
ATTRIBUTE.MAX_LENGTH,
ATTRIBUTE.MIN_LENGTH,
ATTRIBUTE.MIN,
ATTRIBUTE.MAX,
ATTRIBUTE.ARRAY_TYPE,
ATTRIBUTE.MUST_USE_TIMED_WRITE,
ATTRIBUTE.IS_SCENE_REQUIRED,
ATTRIBUTE.IS_OPTIONAL,
CASE
WHEN
ATTRIBUTE.CLUSTER_REF IS NULL
THEN
1
ELSE
0
END AS IS_GLOBAL_ATTRIBUTE,
ENDPOINT_TYPE_ATTRIBUTE.INCLUDED_REPORTABLE,
ENDPOINT_TYPE_ATTRIBUTE.STORAGE_OPTION,
ENDPOINT_TYPE_ATTRIBUTE.SINGLETON,
ENDPOINT_TYPE_ATTRIBUTE.BOUNDED,
ENDPOINT_TYPE_ATTRIBUTE.INCLUDED,
ENDPOINT_TYPE_ATTRIBUTE.DEFAULT_VALUE,
ENDPOINT_TYPE_ATTRIBUTE.MIN_INTERVAL,
ENDPOINT_TYPE_ATTRIBUTE.MAX_INTERVAL,
ENDPOINT_TYPE_ATTRIBUTE.REPORTABLE_CHANGE
FROM ATTRIBUTE
INNER JOIN ENDPOINT_TYPE_ATTRIBUTE
ON ATTRIBUTE.ATTRIBUTE_ID = ENDPOINT_TYPE_ATTRIBUTE.ATTRIBUTE_REF
INNER JOIN CLUSTER
ON ATTRIBUTE.CLUSTER_REF = CLUSTER.CLUSTER_ID
INNER JOIN ENDPOINT_TYPE_CLUSTER
ON CLUSTER.CLUSTER_ID = ENDPOINT_TYPE_CLUSTER.CLUSTER_REF
ON ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID
INNER JOIN CLUSTER
ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID
WHERE ENDPOINT_TYPE_CLUSTER.CLUSTER_REF IN (${endpointTypeClusterRef})
AND ENDPOINT_TYPE_ATTRIBUTE.INCLUDED = 1
AND ATTRIBUTE.PACKAGE_REF IN (${dbApi.toInClause(packageIds)})
GROUP BY ATTRIBUTE.NAME
AND ENDPOINT_TYPE_CLUSTER.ENABLED = 1
AND ATTRIBUTE.PACKAGE_REF IN (${dbApi.toInClause(packageIds)})
${sideFilter}
GROUP BY CLUSTER.MANUFACTURER_CODE, CLUSTER.CODE, ATTRIBUTE.MANUFACTURER_CODE, ATTRIBUTE.CODE, ATTRIBUTE.SIDE
ORDER BY ATTRIBUTE.CODE
`
)
.then((rows) => rows.map(attributeExportMapping))
.then((rows) => rows.map(dbMapping.map.endpointTypeAttributeExtended))
}

/**
Expand Down Expand Up @@ -247,7 +283,7 @@ async function selectAttributeDetailsFromAllEndpointTypesAndClustersUtil(
GROUP BY ATTRIBUTE.NAME
`
)
.then((rows) => rows.map(attributeExportMapping))
.then((rows) => rows.map(dbMapping.map.endpointTypeAttributeExtended))
}

/**
Expand Down
74 changes: 74 additions & 0 deletions src-electron/generator/helper-attribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

const queryAttribute = require('../db/query-attribute')
const templateUtil = require('./template-util')
const queryZcl = require('../db/query-zcl')

async function featureBits(options) {
if ('featureBits' in this) {
Expand Down Expand Up @@ -65,6 +66,77 @@ async function attributeDefault(options) {
return templateUtil.templatePromise(this.global, p)
}

/**
* If helper that checks if an attribute is not supported.
* An attribute is not supported when it is a struct. However it is supported
* if it is an array of structs.
* @param {*} type
* @param {*} isArray
* @param {*} options
* @returns Promise of content
*/
async function if_unsupported_attribute_type(type, isArray, options) {
let struct = null
if (isArray) {
return options.inverse(this)
} else {
let packageIds = await templateUtil.ensureZclPackageIds(this)
if (type && typeof type == 'string') {
struct = await queryZcl.selectStructByName(
this.global.db,
type,
packageIds
)
} else if (type) {
struct = await queryZcl.selectStructById(this.global.db, type)
} else {
console.log('Attribute type not defined for ' + this.name)
}
if (struct) {
return options.fn(this)
} else {
return options.inverse(this)
}
}
}

/**
* If helper that checks if an attribute is complex or not.
* An attribute is complex if it is either nullable, optional, array type or
* struct.
* This helper should be used within an attribute block helper.
*
* example:
* {{#if_attribute_complex type}}
* type is complex
* {{else}}
* type is not complex
* {{/if_attribute_complex}}
* @param {*} type
* @param {*} options
* @returns Promise of content
*/
async function if_attribute_complex(type, options) {
let struct = null
if (this.isNullable || this.isOptional || this.isArray) {
return options.fn(this)
} else {
let packageIds = await templateUtil.ensureZclPackageIds(this)
if (type && typeof type == 'string') {
struct = await queryZcl.selectStructByName(
this.global.db,
type,
packageIds
)
}
if (struct) {
return options.fn(this)
} else {
return options.inverse(this)
}
}
}

// WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
//
// Note: these exports are public API. Templates that might have been created in the past and are
Expand All @@ -73,3 +145,5 @@ async function attributeDefault(options) {

exports.global_attribute_default = attributeDefault
exports.feature_bits = featureBits
exports.if_unsupported_attribute_type = if_unsupported_attribute_type
exports.if_attribute_complex = if_attribute_complex
Loading

0 comments on commit 1bd167f

Please sign in to comment.