更新
更旧
/**
*
* 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 cHelper = require('./helper-c.js')
const templateUtil = require('./template-util')

Timotej Ecimovic
已提交
const queryEndpoint = require('../db/query-endpoint.js')
const queryEndpointType = require('../db/query-endpoint-type.js')

Timotej Ecimovic
已提交
const types = require('../util/types.js')
const dbEnum = require('../../src-shared/db-enum.js')
/**
* Returns number of endpoint types.
*
* @param {*} options
* @returns number of endpoint types
*/
function endpoint_type_count(options) {
/**
* Returns number of endpoints.
*
* @param {*} options
* @returns number of endpoints
*/

Timotej Ecimovic
已提交
function endpoint_count(options) {
return this.endpoints.length
}
/**
* Prints out all the macros that the endpoint config
* configuration depends on. These macros are created
* by ZAP, because the use of these macros is also
* created by ZAP.
*
* @returns Macros that need to be created
*/
function endpoint_config_macros(options) {
let longDef = options.hash.longDefaults
let minMaxDef = options.hash.minMaxDefaults
if (longDef == null) longDef = 'def_long_defaults'
if (minMaxDef == null) minMaxDef = 'def_minmax_defaults'
return `
#define ZAP_TYPE(type) ZCL_ ## type ## _ATTRIBUTE_TYPE
#define ZAP_LONG_DEFAULTS_INDEX(index) {(uint8_t*)(&${longDef}[index])}
#define ZAP_MIN_MAX_DEFAULTS_INDEX(index) {(uint8_t*)(&${minMaxDef}[index])}
#define ZAP_EMPTY_DEFAULT() {(uint8_t*) 0}
#define ZAP_SIMPLE_DEFAULT(x) {(uint8_t *) x}
`
}
/**
* Creates array of endpointId fields on endpoints
*
* @param {*} options
* @returns C array including the { } brackets
*/
function endpoint_fixed_endpoint_array(options) {
this.endpoints.forEach((ep) => {
epIds.push('0x' + bin.int16ToHex(ep.endpointId))
})
return '{ ' + epIds.join(', ') + ' }'
}
/**
* Creates array of profileId fields on endpoints
*
* @param {*} options
* @returns C array including the { } brackets
*/
function endpoint_fixed_profile_id_array(options) {
profileIds.push('0x' + bin.int16ToHex(parseInt(ep.profileId)))
})
return '{ ' + profileIds.join(', ') + ' }'
}
/**
* Creates array of networkId fields on endpoints
*
* @param {*} options
* @returns C array including the { } brackets
*/
function endpoint_fixed_network_array(options) {
return '{ ' + this.endpoints.map((ep) => ep.networkId).join(', ') + ' }'
/**
* Each element of an array contains an index into the
* endpoint type array, for the appropriate endpoint.
*
* @param {*} options
* @returns C array of indexes, one for each endpoint.
*/
function endpoint_fixed_endpoint_type_array(options) {
for (const ep of this.endpoints) {
let epType = ep.endpointTypeRef
let index = -1
for (let j = 0; j < this.endpointTypes.length; j++) {
if (epType == this.endpointTypes[j].id) {
index = j
}
}
indexes.push(index)
}
return '{ ' + indexes.join(', ') + ' }'
}
if (codeIndexPairs.length == 0) {
ret = ret.concat(' { 0x00, 0x00 } \\\n')
} else {
codeIndexPairs.forEach((c) => {
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
})
}
return ret.concat('}\n')
}
/**
* Generates array of { index , mfgCode } pairs, matching
* the indexes in attribute table.
*
* @param {*} options
* @returns manufacturer code array
*/
function endpoint_attribute_manufacturer_codes(options) {
return createMfgCodes(this.attributeMfgCodes)
}
function endpoint_attribute_manufacturer_code_count(options) {
return this.attributeMfgCodes.length
}
function endpoint_command_manufacturer_codes(options) {
return createMfgCodes(this.commandMfgCodes)
}
function endpoint_command_manufacturer_code_count(options) {
return this.commandMfgCodes.length
}
function endpoint_cluster_manufacturer_codes(options) {
return createMfgCodes(this.clusterMfgCodes)
}
function endpoint_cluster_manufacturer_code_count(options) {
return this.clusterMfgCodes.length
}
function endpoint_largest_attribute_size(options) {
}
function endpoint_singletons_size(options) {
return this.singletonsSize
}
function endpoint_total_storage_size(options) {
return this.totalAttributeSize
}
function endpoint_command_count(options) {
return this.commandList.length
}
this.endpointList.forEach((ep) => {
ret = ret.concat(
` { ZAP_CLUSTER_INDEX(${ep.clusterIndex}), ${ep.clusterCount}, ${ep.attributeSize} }, \\\n`
)
})
return ret.concat('}\n')
}
function endpoint_cluster_count(options) {
return this.clusterList.length
}
function endpoint_cluster_list(options) {
this.clusterList.forEach((c) => {
if (c.mask.length == 0) {
mask = '0'
} else {
mask = c.mask
.map((m) => `ZAP_CLUSTER_MASK(${m.toUpperCase()})`)
.join(' | ')
}
ret = ret.concat(
` { ${c.clusterId}, ZAP_ATTRIBUTE_INDEX(${c.attributeIndex}), ${c.attributeCount}, ${c.attributeSize}, ${mask}, ${c.functions} }, /* ${c.comment} */ \\\n`
)
})
return ret.concat('}\n')
}
function endpoint_command_list(options) {
let comment = null
this.commandList.forEach((cmd) => {
if (cmd.comment != comment) {
ret += `\\\n /* ${cmd.comment} */ \\\n`
comment = cmd.comment
}
if (cmd.mask.length == 0) {
mask = '0'
} else {
mask = cmd.mask
.map((m) => `ZAP_COMMAND_MASK(${m.toUpperCase()})`)
.join(' | ')
}
ret += ` { ${cmd.clusterId}, ${cmd.commandId}, ${mask} }, /* ${cmd.name} */ \\\n`
ret += '}\n'
return ret
function endpoint_attribute_count(options) {
return this.attributeList.length
}
function endpoint_attribute_list(options) {
let order = options.hash.order
if (order == null || order.length == 0) {
// This is the default value if none is specified
order = 'default,id,size,type,mask'
}
let comment = null
let littleEndian = true
let pointerSize = 4
if (options.hash.endian == 'big') {
littleEndian = false
if (typeof options.hash.pointer != 'undefined') {
pointerSize = options.hash.pointer
}
}
this.attributeList.forEach((at) => {
if (at.comment != comment) {
ret += `\\\n /* ${at.comment} */ \\\n`
comment = at.comment
}
if (at.mask.length == 0) {
mask = '0'
} else {
mask = at.mask
.map((m) => `ZAP_ATTRIBUTE_MASK(${m.toUpperCase()})`)
.join(' | ')
}

Timotej Ecimovic
已提交
let finalDefaultValue

Timotej Ecimovic
已提交
finalDefaultValue = `ZAP_EMPTY_DEFAULT()`
} else if (at.isMacro) {
finalDefaultValue = at.defaultValue
} else {
let defaultValue = at.defaultValue
if (!littleEndian) {
defaultValue = Number(defaultValue)
.toString(16)
.padStart(6, '0x0000')
.padEnd(2 + 2 * pointerSize, '0')
}
finalDefaultValue = `ZAP_SIMPLE_DEFAULT(${defaultValue})`
let orderTokens = order.split(',').map((x) => (x ? x.trim() : ''))
let items = []
orderTokens.forEach((tok) => {
switch (tok) {
case 'default':
items.push(finalDefaultValue)
break
case 'id':
items.push(at.id)
break
case 'size':
items.push(at.size)
break
case 'type':
items.push(at.type)
break
case 'mask':
items.push(mask)
break
}
})
ret += ` { ${items.join(', ')} }, /* ${at.name} */ \\\n`
ret += '}\n'
return ret
function endpoint_fixed_device_type_array(options) {
let ret = '{'
let wroteItem = false
for (let i = 0; i < this.deviceList.length; i++) {
if (this.deviceList[i] != null && this.deviceList[i].deviceId != null) {
if (wroteItem) {
ret += ','
}
ret +=
'{' +
'0x' +
bin.int16ToHex(this.deviceList[i].deviceId) +
',' +
this.deviceList[i].deviceVersion.toString() +
'}'
wroteItem = true
}
}
ret += '}'
return ret
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
function endpoint_fixed_device_type_array_offsets(options) {
let ret = '{ '
let curOffset = 0
for (let i = 0; i < this.deviceList.length; i++) {
if (i != 0) {
ret += ','
}
ret += curOffset.toString()
if (this.deviceList[i] != null && this.deviceList[i].deviceId != null) {
curOffset += 1
}
}
ret += '}'
return ret
}
function endpoint_fixed_device_type_array_lengths(options) {
let ret = '{ '
for (let i = 0; i < this.deviceList.length; i++) {
if (i != 0) {
ret += ','
}
if (this.deviceList[i] != null && this.deviceList[i].deviceId != null) {
ret += '1'
} else {
ret += '0'
}
}
ret += '}'
return ret
function endpoint_attribute_min_max_count(options) {
return this.minMaxList.length
}
function endpoint_attribute_min_max_list(options) {
let comment = null
let order = options.hash.order
if (order == null || order.length == 0) {
order = 'def,min,max'
}
this.minMaxList.forEach((mm, index) => {
throw new Error(
`Can't have min/max for attributes larger than 2 bytes like '${mm.name}'`
)
if (mm.comment != comment) {
ret += `\\\n /* ${mm.comment} */ \\\n`
comment = mm.comment
}
let def = parseInt(mm.default)
let min = parseInt(mm.min)
let max = parseInt(mm.max)
if (isNaN(def)) def = 0
if (isNaN(min)) min = 0
if (isNaN(max)) max = 0xffff
let defS =
(def >= 0 ? '' : '-') + '0x' + Math.abs(def).toString(16).toUpperCase()
let minS =
(min >= 0 ? '' : '-') + '0x' + Math.abs(min).toString(16).toUpperCase()
let maxS =
(max >= 0 ? '' : '-') + '0x' + Math.abs(max).toString(16).toUpperCase()
let defMinMaxItems = []
order
.split(',')
.map((x) => (x ? x.trim() : ''))
.forEach((tok) => {
switch (tok) {
case 'def':
defMinMaxItems.push(`(uint16_t)${defS}`)
break
case 'min':
defMinMaxItems.push(`(uint16_t)${minS}`)
break
case 'max':
defMinMaxItems.push(`(uint16_t)${maxS}`)
break
}
})
ret += ` { ${defMinMaxItems.join(', ')} }${
index == this.minMaxList.length - 1 ? '' : ','
} /* ${mm.name} */ \\\n`
ret += '}\n'
return ret
/**
* This helper supports an "order" CSV string, such as:
* "direction,endpoint,clusterId,attributeId,mask,mfgCode,minmax"
* The string above is a default value, and it determines in what order are the fields generated.
*
* @param {*} options
*/

Timotej Ecimovic
已提交
function endpoint_reporting_config_defaults(options) {
let order = options.hash.order
if (order == null || order.length == 0) {
// This is the default value if none is specified
order = 'direction,endpoint,clusterId,attributeId,mask,mfgCode,minmax'
}
let minmaxorder = options.hash.minmaxorder
if (minmaxorder == null || minmaxorder.length == 0) {
minmaxorder = 'min,max,change'
}
let comment = null

Timotej Ecimovic
已提交
this.reportList.forEach((r) => {
if (r.comment != comment) {
ret += `\\\n /* ${r.comment} */ \\\n`
comment = r.comment
}
let minmaxItems = []
let minmaxToks = minmaxorder.split(',').map((x) => (x ? x.trim() : ''))
minmaxToks.forEach((tok) => {
switch (tok) {
case 'min':
minmaxItems.push(r.minOrSource)
break
case 'max':
minmaxItems.push(r.maxOrEndpoint)
break
case 'change':
minmaxItems.push(r.reportableChangeOrTimeout)
break
}
})
let minmax = minmaxItems.join(', ')
if (r.mask.length == 0) {
mask = '0'
} else {
mask = r.mask
.map((m) => `ZAP_CLUSTER_MASK(${m.toUpperCase()})`)
.join(' | ')
}
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
let orderTokens = order.split(',').map((x) => (x ? x.trim() : ''))
let items = []
orderTokens.forEach((tok) => {
switch (tok) {
case 'direction':
items.push(`ZAP_REPORT_DIRECTION(${r.direction})`)
break
case 'endpoint':
items.push(r.endpoint)
break
case 'clusterId':
items.push(r.clusterId)
break
case 'attributeId':
items.push(r.attributeId)
break
case 'mask':
items.push(mask)
break
case 'mfgCode':
items.push(r.mfgCode)
break
case 'minmax':
items.push(`{{ ${minmax} }}`)
break
}
})
let singleRow = ` { ${items.join(', ')} }, /* ${r.name} */ \\\n`
ret += singleRow

Timotej Ecimovic
已提交
})
ret += '}\n'
return ret

Timotej Ecimovic
已提交
}
function endpoint_reporting_config_default_count(options) {
return this.reportList.length
}
function endpoint_attribute_long_defaults_count(options) {
return this.longDefaultsList.length
}
function endpoint_attribute_long_defaults(options) {
let comment = null
if (options.hash.endian == 'big') {
littleEndian = false
}

Timotej Ecimovic
已提交
this.longDefaultsList.forEach((ld) => {
let value = ld.value
if (littleEndian && !types.isString(ld.type)) {
// ld.value is in big-endian order. For types for which endianness
// matters, we need to reverse it.
let valArr = value.split(/\s*,\s*/).filter((s) => s.length != 0)
valArr.reverse()
value = valArr.join(', ') + ', '
if (ld.comment != comment) {
ret += `\\\n /* ${ld.comment}, ${

Timotej Ecimovic
已提交
littleEndian ? 'little-endian' : 'big-endian'
} */\\\n\\\n`
comment = ld.comment
}
ret += ` /* ${ld.index} - ${ld.name}, */\\\n ${value}\\\n\\\n`
ret += '}\n'
return ret
function asMEI(manufacturerCode, code) {
// Left-shift (and for that matter bitwise or) produces a _signed_ 32-bit
// number, which will probably be negative. Force it to unsigned 32-bit using
// >>> 0.
return '0x' + bin.int32ToHex(((manufacturerCode << 16) | code) >>> 0)
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
// The representation of null depends on the type, so we can't use a single
// macro that's defined elsewhere for "null value".
function determineAttributeDefaultValue(
specifiedDefault,
type,
typeSize,
isNullable
) {
if (specifiedDefault !== null || !isNullable) {
return specifiedDefault
}
if (types.isString(type)) {
// Handled elsewhere.
return null
}
if (types.isSignedInteger(type)) {
return '0x80' + '00'.repeat(typeSize - 1)
}
if (types.isFloat(type)) {
// Not supported yet.
throw new Error(
"Don't know how to output a null default value for a float type"
)
}
// Assume everything else is an unsigned integer.
return '0x' + 'FF'.repeat(typeSize)
}
/**
* Attribute collection works like this:
* 1.) Go over all the clusters that exist.
* 2.) If client is included on at least one endpoint add client atts.
* 3.) If server is included on at least one endpoint add server atts.
*/
async function collectAttributes(endpointTypes, options) {
let commandMfgCodes = [] // Array of { index, mfgCode } objects
let clusterMfgCodes = [] // Array of { index, mfgCode } objects
let attributeMfgCodes = [] // Array of { index, mfgCode } objects
let attributeList = []
let commandList = []
let endpointList = [] // Array of { clusterIndex, clusterCount, attributeSize }
let clusterList = [] // Array of { clusterId, attributeIndex, attributeCount, attributeSize, eventIndex, eventCount, mask, functions, comment }
let longDefaults = [] // Array of strings representing bytes
let longDefaultsIndex = 0
let minMaxIndex = 0
let largestAttribute = 0
let singletonsSize = 0
let totalAttributeSize = 0
let clusterAttributeSize = 0
let endpointAttributeSize = 0
let clusterIndex = 0
let deviceList = [] // Array of { deviceId, deviceVersion }
let minMaxList = [] // Array of { default, min, max }
let reportList = [] // Array of { direction, endpoint, clusterId, attributeId, mask, mfgCode, minOrSource, maxOrEndpoint, reportableChangeOrTimeout }
let longDefaultsList = [] // Array of { value, size. comment }
let spaceForDefaultValue =
options.spaceForDefaultValue !== undefined
? options.spaceForDefaultValue
: 2
clusterCount: ept.clusters.length,
deviceId: ept.deviceIdentifier,
deviceVersion: ept.endpointVersion,
deviceList.push(device)
// Go over all the clusters in the endpoint and add them to the list.
ept.clusters.forEach((c) => {
clusterId: asMEI(c.manufacturerCode, c.code),
clusterName: c.name,
clusterSide: c.side,
attributeIndex: attributeIndex,
attributeCount: c.attributes.length,
eventIndex: eventIndex,
eventCount: c.events.length,
functions: 'NULL',
comment: `Endpoint: ${ept.endpointId}, Cluster: ${c.name} (${c.side})`,
clusterIndex++
attributeIndex += c.attributes.length
eventIndex += c.events.length
// Go over all the attributes in the endpoint and add them to the list.
c.attributes.forEach((a) => {
// typeSize is the size of a buffer needed to hold the attribute, if
// that's known.
let typeSize = a.typeSize
// defaultSize is the size of the attribute in the readonly defaults
// store.
let defaultSize = typeSize
let attributeDefaultValue = determineAttributeDefaultValue(
a.defaultValue,
a.type,
typeSize,
a.isNullable
)
// Various types store the length of the actual content in bytes.
// For those, we can size the default storage to be just big enough for
// the actual default value.
if (types.isOneBytePrefixedString(a.type)) {
defaultSize =
(attributeDefaultValue ? attributeDefaultValue.length : 0) + 1
} else if (types.isTwoBytePrefixedString(a.type)) {
defaultSize =
(attributeDefaultValue ? attributeDefaultValue.length : 0) + 2
// storageSize is the size of the attribute in the read/write attribute
// store.
let storageSize = typeSize
// External attributes should not take up space in the default store or
// the read/write store.
if (a.storage == dbEnum.storageOption.external) {
// Some external attributes do not have a usable typeSize
// (e.g. structs or lists of structs); the value of typeSize in those
// cases is an error string. Use 0 in those cases.
if (typeof typeSize == 'string') {
typeSize = 0
}
// List-typed attributes don't have a useful typeSize no matter what.
// typeSizeAttribute will return values here based on various XML bits
// and ZAP file default values, but all of those have nothing to do
// with the actual attribute.
if (a.typeInfo.atomicType == 'array') {
typeSize = 0
}
attributeDefaultValue = undefined
let defaultValueIsMacro = false
// Zero-length strings can just use ZAP_EMPTY_DEFAULT() as the default
// and don't need long defaults. Similar for external strings.
// Apart from that, there are a few string cases that _could_ fit into our
// default value as the size is determined by spaceForDefaultValue. Some
// example strings that would fit if spaceForDefaultValue were 2 bytes are:
// a 1-char-long short string, or a null string. But figuring out how
// to produce a uint8_t* for those as a literal value is a pain, so just
// force all non-external strings with a nonempty default value to use
// long defaults.
defaultSize > spaceForDefaultValue ||
(types.isString(a.type) &&
attributeDefaultValue !== undefined &&
attributeDefaultValue !== '')
// We will need to generate the GENERATED_DEFAULTS
longDefaults.push(a)
let def
if (
types.isString(a.type) &&
attributeDefaultValue === null &&
a.isNullable
) {
// We don't want to make longTypeDefaultValue know about our null
// string representation.
if (types.isOneBytePrefixedString(a.type)) {
def = ['0xFF']
} else if (types.isTwoBytePrefixedString(a.type)) {
def = ['0xFF', '0xFF']
} else {
throw new Error(`Unknown string type: ${type}`)
}
} else {
def = types.longTypeDefaultValue(
defaultSize,
a.type,
attributeDefaultValue
)
}
size: defaultSize,
index: longDefaultsIndex,
name: a.name,
comment: cluster.comment,
}
attributeDefaultValue = `ZAP_LONG_DEFAULTS_INDEX(${longDefaultsIndex})`

Timotej Ecimovic
已提交
defaultValueIsMacro = true
longDefaultsList.push(longDef)
longDefaultsIndex += defaultSize

Timotej Ecimovic
已提交
}
let mask = []
if ((a.min != null || a.max != null) && a.isWritable) {
mask.push('min_max')
default: attributeDefaultValue,
name: a.name,
comment: cluster.comment,
}
attributeDefaultValue = `ZAP_MIN_MAX_DEFAULTS_INDEX(${minMaxIndex})`

Timotej Ecimovic
已提交
defaultValueIsMacro = true
minMaxList.push(minMax)
if (a.includedReportable) {
direction: 'REPORTED', // or 'RECEIVED'
endpoint: '0x' + bin.int16ToHex(ept.endpointId),
clusterId: asMEI(c.manufacturerCode, c.code),
attributeId: asMEI(a.manufacturerCode, a.code),
mfgCode:
a.manufacturerCode == null
? '0x0000'
: '0x' + bin.int16ToHex(a.manufacturerCode),
minOrSource: a.minInterval,
maxOrEndpoint: a.maxInterval,
reportableChangeOrTimeout: a.reportableChange,
name: a.name,
comment: cluster.comment,
}
reportList.push(rpt)

Timotej Ecimovic
已提交
}
if (typeSize > largestAttribute) {
largestAttribute = typeSize
}
if (a.isSingleton) {
singletonsSize += storageSize
}
clusterAttributeSize += storageSize
totalAttributeSize += storageSize

Timotej Ecimovic
已提交
if (a.side == dbEnum.side.client) {
mask.push('client')
}

Timotej Ecimovic
已提交
if (a.storage == dbEnum.storageOption.nvm) {
mask.push('TOKENIZE')
} else if (a.storage == dbEnum.storageOption.external) {

Timotej Ecimovic
已提交
mask.push('EXTERNAL_STORAGE')
} else if (a.storage == dbEnum.storageOption.ram) {
// Nothing to do
} else {
if (!options.allowUnknownStorageOption)
throw new Error(
`Unknown storage type "${a.storage}" for attribute "${
a.name
}" of cluster "${c.name}" on endpoint ${
ept.endpointId
}. Valid values are: ${[
dbEnum.storageOption.nvm,
dbEnum.storageOption.external,
dbEnum.storageOption.ram,
]
.map((s) => `"${s}"`)
.join(', ')}`
)

Timotej Ecimovic
已提交
}
if (a.isSingleton) mask.push('singleton')
if (a.isNullable) mask.push('nullable')
if (a.mustUseTimedWrite) mask.push('must_use_timed_write')
let zap_type = 'UNKNOWN ATTRIBUTE TYPE'
if (a.typeInfo.atomicType) {
zap_type = a.typeInfo.atomicType
} else if (a.typeInfo.type == dbEnum.zclType.struct) {
zap_type = 'STRUCT'
} else if (a.typeInfo.type == dbEnum.zclType.enum && a.typeInfo.size) {
zap_type = 'ENUM' + a.typeInfo.size * 8
} else if (
a.typeInfo.type == dbEnum.zclType.bitmap &&
a.typeInfo.size
) {
zap_type = 'BITMAP' + a.typeInfo.size * 8
id: asMEI(a.manufacturerCode, a.code), // attribute code
type: `ZAP_TYPE(${cHelper.asDelimitedMacro(zap_type)})`, // type
size: typeSize, // size
mask: mask, // array of special properties
defaultValue: attributeDefaultValue, // default value, pointer to default value, or pointer to min/max/value triplet.

Timotej Ecimovic
已提交
isMacro: defaultValueIsMacro,
name: a.name,
comment: cluster.comment,
}
attributeList.push(attr)
if (a.manufacturerCode) {
let att = {
index: attributeList.indexOf(attr),
mfgCode: a.manufacturerCode,
}
attributeMfgCodes.push(att)
}
})
// Go over the commands
c.commands.forEach((cmd) => {
// ZAP files can have nonsense incoming/outgoing values,
// unfortunately, claiming that client-sourced commands are
// incoming for a client-side cluster. Make sure that we only
// set the flags that actually make sense based on the command
// and cluster instance we are looking at.
if (
cmd.source == dbEnum.source.client &&
c.side == dbEnum.side.server &&
) {
mask.push('incoming_server')
}
if (
cmd.source == dbEnum.source.client &&
c.side == dbEnum.side.client &&
) {
mask.push('outgoing_client')
}
if (
cmd.source == dbEnum.source.server &&
c.side == dbEnum.side.server &&
) {
mask.push('outgoing_server')
}
if (
cmd.source == dbEnum.source.server &&
c.side == dbEnum.side.client &&
) {
mask.push('incoming_client')
clusterId: asMEI(c.manufacturerCode, c.code),
commandId: asMEI(cmd.manufacturerCode, cmd.code),
name: cmd.name,
comment: cluster.comment,
responseName: cmd.responseName,
responseId:
cmd.responseRef !== null
? asMEI(cmd.responseManufacturerCode, cmd.responseCode)
: null,
}

Timotej Ecimovic
已提交
commandList.push(command)
if (cmd.manufacturerCode) {
let mfgCmd = {
index: commandList.length - 1,
mfgCode: cmd.manufacturerCode,
}
commandMfgCodes.push(mfgCmd)
}
})
// Go over the events
c.events.sort(zclUtil.eventComparator)
c.events.forEach((ev) => {
let event = {
eventId: asMEI(ev.manufacturerCode, ev.code),
name: ev.name,
comment: cluster.comment,
}
eventList.push(event)
})
endpointAttributeSize += clusterAttributeSize
cluster.attributeSize = clusterAttributeSize
clusterList.push(cluster)
if (c.manufacturerCode) {
let clt = {
index: clusterList.length - 1,
mfgCode: c.manufacturerCode,
}
clusterMfgCodes.push(clt)
}
endpoint.attributeSize = endpointAttributeSize
endpointList.push(endpoint)
endpointList: endpointList,
clusterList: clusterList,

Timotej Ecimovic
已提交
attributeList: attributeList,
commandList: commandList,