Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / app / zap-templates / templates / app / helper.js
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *
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
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 // Import helpers from zap core
19 const zapPath      = '../../../../../third_party/zap/repo/src-electron/';
20 const queryImpexp  = require(zapPath + 'db/query-impexp.js')
21 const templateUtil = require(zapPath + 'generator/template-util.js')
22 const zclHelper    = require(zapPath + 'generator/helper-zcl.js')
23 const zclQuery     = require(zapPath + 'db/query-zcl.js')
24 const cHelper      = require(zapPath + 'generator/helper-c.js')
25
26 const StringHelper    = require('../../common/StringHelper.js');
27 const ChipTypesHelper = require('../../common/ChipTypesHelper.js');
28
29 /**
30  * Check if the cluster (name) has any enabled manufacturer commands. This works only inside
31  * cluster block helpers.
32  *
33  * @param {*} name : Cluster name
34  * @param {*} side : Cluster side
35  * @param {*} options
36  * @returns True if cluster has enabled commands otherwise false
37  */
38 function user_cluster_has_enabled_manufacturer_command(name, side, options)
39 {
40   return queryImpexp.exportendPointTypeIds(this.global.db, this.global.sessionId)
41       .then((endpointTypes) => zclQuery.exportClustersAndEndpointDetailsFromEndpointTypes(this.global.db, endpointTypes))
42       .then((endpointsAndClusters) => zclQuery.exportCommandDetailsFromAllEndpointTypesAndClusters(
43                 this.global.db, endpointsAndClusters))
44       .then((endpointCommands) => {
45         return !!endpointCommands.find(cmd => cmd.mfgCode && zclHelper.isStrEqual(name, cmd.clusterName)
46                 && zclHelper.isCommandAvailable(side, cmd.incoming, cmd.outgoing, cmd.commandSource, cmd.name));
47       })
48 }
49
50 function asValueIfNotPresent(type, isArray)
51 {
52   if (StringHelper.isString(type) || isArray) {
53     return 'NULL';
54   }
55
56   function fn(pkgId)
57   {
58     const options = { 'hash' : {} };
59     return zclHelper.asUnderlyingZclType.call(this, type, options).then(zclType => {
60       switch (zclType) {
61       case 'uint8_t':
62         return 'UINT8_MAX';
63       case 'uint16_t':
64         return 'UINT16_MAX';
65       case 'uint32_t':
66         return 'UINT32_MAX';
67       default:
68         error = 'Unhandled underlying type ' + zclType + ' for original type ' + type;
69         throw error;
70       }
71     })
72   }
73
74   const promise = templateUtil.ensureZclPackageId(this).then(fn.bind(this)).catch(err => console.log(err));
75   return templateUtil.templatePromise(this.global, promise)
76 }
77
78 // TODO Expose the readTypeLength as an additional member field of {{asUnderlyingZclType}} instead
79 //      of having to call this method separately.
80 function asReadTypeLength(type)
81 {
82   const db = this.global.db;
83
84   if (StringHelper.isShortString(type)) {
85     return '1u';
86   }
87
88   if (StringHelper.isLongString(type)) {
89     return '2u';
90   }
91
92   function fn(pkgId)
93   {
94     const defaultResolver = zclQuery.selectAtomicType(db, pkgId, type);
95
96     const enumResolver = zclHelper.isEnum(db, type, pkgId).then(result => {
97       return result == 'unknown' ? null : zclQuery.selectEnumByName(db, type, pkgId).then(rec => {
98         return zclQuery.selectAtomicType(db, pkgId, rec.type);
99       });
100     });
101
102     const bitmapResolver = zclHelper.isBitmap(db, type, pkgId).then(result => {
103       return result == 'unknown' ? null : zclQuery.selectBitmapByName(db, pkgId, type).then(rec => {
104         return zclQuery.selectAtomicType(db, pkgId, rec.type);
105       });
106     });
107
108     const typeResolver = Promise.all([ defaultResolver, enumResolver, bitmapResolver ]);
109     return typeResolver.then(types => (types.find(type => type)).size);
110   }
111
112   const promise = templateUtil.ensureZclPackageId(this).then(fn.bind(this)).catch(err => console.log(err));
113   return templateUtil.templatePromise(this.global, promise)
114 }
115
116 // TODO Expose the readType as an additional member field of {{asUnderlyingZclType}} instead
117 //      of having to call this method separately.
118 function asReadType(type)
119 {
120   if (StringHelper.isShortString(type)) {
121     return 'String';
122   }
123
124   if (StringHelper.isLongString(type)) {
125     return 'LongString';
126   }
127
128   function fn(pkgId)
129   {
130     const options = { 'hash' : {} };
131     return zclHelper.asUnderlyingZclType.call(this, type, options).then(zclType => {
132       const basicType = ChipTypesHelper.asBasicType(zclType);
133       switch (basicType) {
134       case 'int8_t':
135       case 'uint8_t':
136         return 'Int8u';
137       case 'int16_t':
138       case 'uint16_t':
139         return 'Int16u';
140       case 'int24_t':
141       case 'uint24_t':
142         return 'Int24u';
143       case 'int32_t':
144       case 'uint32_t':
145         return 'Int32u';
146       case 'int64_t':
147       case 'uint64_t':
148         return 'Int64u';
149       default:
150         error = 'Unhandled underlying type ' + zclType + ' for original type ' + type;
151         throw error;
152       }
153     })
154   }
155
156   const promise = templateUtil.ensureZclPackageId(this).then(fn.bind(this)).catch(err => console.log(err));
157   return templateUtil.templatePromise(this.global, promise)
158 }
159
160 /**
161  * Returns CHIP specific type for ZCL framework
162  * This function is flawed since it relies on the
163  * type label for CHIP type conversion. CHIP specific XML should have the
164  * correct type directly embedded inside.
165  *
166  * @param {*} label : The xml label of the type.
167  * @param {*} type : The xml type to be converted
168  */
169 function asChipUnderlyingType(label, type)
170 {
171
172   if (zclHelper.isStrEqual(label, "endpoint")) {
173     return 'chip::EndpointId';
174   } else if (zclHelper.isStrEqual(label, "endpointId")) {
175     return 'chip::EndpointId';
176   } else if (zclHelper.isStrEqual(type, "CLUSTER_ID")) {
177     return 'chip::ClusterId';
178   } else if (zclHelper.isStrEqual(type, "ATTRIBUTE_ID")) {
179     return 'chip::AttributeId';
180   } else if (zclHelper.isStrEqual(label, "groupId")) {
181     return 'chip::GroupId';
182   } else if (zclHelper.isStrEqual(label, "commandId")) {
183     return 'chip::CommandId';
184   } else {
185     const options = { 'hash' : {} };
186     return zclHelper.asUnderlyingZclType.call(this, type, options);
187   }
188 }
189
190 //  Endpoint-config specific helpers
191 // these helpers are a Hot fix for the "GENERATED_FUNCTIONS" problem
192 // They should be removed or replace once issue #4369 is resolved
193 // These helpers only works within the endpoint_config iterator
194
195 // List of all cluster with generated functions
196 var endpointClusterWithInit = [ 'Identify', 'Groups', 'Scenes', 'On/off', 'Level Control', 'Color Control', 'IAS Zone' ];
197 var endpointClusterWithAttributeChanged = [ 'Identify', 'Door Lock' ];
198 var endpointClusterWithPreAttribute     = [ 'IAS Zone' ];
199 var endpointClusterWithMessageSent      = [ 'IAS Zone' ];
200
201 /**
202  * extract the cluster name from the enpoint cluster comment
203  * @param {*} comments
204  */
205 function extract_cluster_name(comments)
206 {
207   let secondPart = comments.split(": ").pop();
208   return secondPart.split(" (")[0];
209 }
210
211 /**
212  * Populate the GENERATED_FUNCTIONS field
213  */
214 function chip_endpoint_generated_functions()
215 {
216   let alreadySetCluster = [];
217   let ret               = '\\\n';
218   this.clusterList.forEach((c) => {
219     let clusterName  = extract_cluster_name(c.comment);
220     let functionList = '';
221     if (alreadySetCluster.includes(clusterName)) {
222       // Only one array of Generated functions per cluster across all endpoints
223       return
224     }
225     if (c.comment.includes('server')) {
226       let hasFunctionArray = false
227       if (endpointClusterWithInit.includes(clusterName))
228       {
229         hasFunctionArray = true
230         functionList     = functionList.concat(
231             `  (EmberAfGenericClusterFunction) emberAf${cHelper.asCamelCased(clusterName, false)}ClusterServerInitCallback,\\\n`)
232       }
233
234       if (endpointClusterWithAttributeChanged.includes(clusterName)) {
235         functionList     = functionList.concat(`  (EmberAfGenericClusterFunction) emberAf${
236             cHelper.asCamelCased(clusterName, false)}ClusterServerAttributeChangedCallback,\\\n`)
237         hasFunctionArray = true
238       }
239
240       if (endpointClusterWithMessageSent.includes(clusterName)) {
241         functionList     = functionList.concat(`  (EmberAfGenericClusterFunction) emberAf${
242             cHelper.asCamelCased(clusterName, false)}ClusterServerMessageSentCallback,\\\n`)
243         hasFunctionArray = true
244       }
245
246       if (endpointClusterWithPreAttribute.includes(clusterName)) {
247         functionList     = functionList.concat(`  (EmberAfGenericClusterFunction) emberAf${
248             cHelper.asCamelCased(clusterName, false)}ClusterServerPreAttributeChangedCallback,\\\n`)
249         hasFunctionArray = true
250       }
251
252       if (hasFunctionArray) {
253         ret = ret.concat(
254             `const EmberAfGenericClusterFunction chipFuncArray${cHelper.asCamelCased(clusterName, false)}Server[] = {\\\n`)
255         ret = ret.concat(functionList)
256         ret = ret.concat(`};\\\n`)
257         alreadySetCluster.push(clusterName)
258       }
259     }
260   })
261   return ret.concat('\n');
262 }
263
264 /**
265  * Return endpoint config GENERATED_CLUSTER MACRO
266  * To be used as a replacement of endpoint_cluster_list since this one
267  * includes the GENERATED_FUNCTIONS array
268  */
269 function chip_endpoint_cluster_list()
270 {
271   let ret = '{ \\\n';
272   this.clusterList.forEach((c) => {
273     let mask          = '';
274     let functionArray = c.functions;
275     let clusterName   = extract_cluster_name(c.comment);
276
277     if (c.comment.includes('server')) {
278       let hasFunctionArray = false;
279       if (endpointClusterWithInit.includes(clusterName)) {
280         c.mask.push('INIT_FUNCTION')
281         hasFunctionArray = true
282       }
283
284       if (endpointClusterWithAttributeChanged.includes(clusterName)) {
285         c.mask.push('ATTRIBUTE_CHANGED_FUNCTION')
286         hasFunctionArray = true
287       }
288
289       if (endpointClusterWithPreAttribute.includes(clusterName)) {
290         c.mask.push('PRE_ATTRIBUTE_CHANGED_FUNCTION')
291         hasFunctionArray = true
292       }
293
294       if (endpointClusterWithMessageSent.includes(clusterName)) {
295         c.mask.push('MESSAGE_SENT_FUNCTION')
296         hasFunctionArray = true
297       }
298
299       if (hasFunctionArray) {
300         functionArray = 'chipFuncArray' + cHelper.asCamelCased(clusterName, false) + 'Server'
301       }
302     }
303
304     if (c.mask.length == 0) {
305       mask = '0'
306     } else {
307       mask = c.mask.map((m) => `ZAP_CLUSTER_MASK(${m.toUpperCase()})`).join(' | ')
308     }
309     ret = ret.concat(`  { ${c.clusterId}, ZAP_ATTRIBUTE_INDEX(${c.attributeIndex}), ${c.attributeCount}, ${c.attributeSize}, ${
310         mask}, ${functionArray} }, /* ${c.comment} */ \\\n`)
311   })
312   return ret.concat('}\n');
313 }
314
315 //  End of Endpoint-config specific helpers
316
317 function asPrintFormat(type)
318 {
319   if (StringHelper.isString(type)) {
320     return '%s';
321   }
322
323   function fn(pkgId)
324   {
325     const options = { 'hash' : {} };
326     return zclHelper.asUnderlyingZclType.call(this, type, options).then(zclType => {
327       const basicType = ChipTypesHelper.asBasicType(zclType);
328       switch (basicType) {
329       case 'int8_t':
330         return '%" PRId8 "';
331       case 'uint8_t':
332         return '%" PRIu8 "';
333       case 'int16_t':
334         return '%" PRId16 "';
335       case 'uint16_t':
336         return '%" PRIu16 "';
337       case 'int24_t':
338         return '%" PRId32 "';
339       case 'uint24_t':
340         return '%" PRIu32 "';
341       case 'int32_t':
342         return '%" PRId32 "';
343       case 'uint32_t':
344         return '%" PRIu32 "';
345       case 'int64_t':
346         return '%" PRId64 "';
347       case 'uint64_t':
348         return '%" PRIu64 "';
349       default:
350         return '%p';
351       }
352     })
353   }
354
355   const promise = templateUtil.ensureZclPackageId(this).then(fn.bind(this)).catch(err => console.log(err));
356   return templateUtil.templatePromise(this.global, promise)
357 }
358
359 function isFirstElement(index)
360 {
361   return index == 0;
362 }
363
364 function isStrEndsWith(str, substr)
365 {
366   return str.endsWith(substr);
367 }
368
369 //
370 // Module exports
371 //
372 exports.asPrintFormat                                 = asPrintFormat;
373 exports.asReadType                                    = asReadType;
374 exports.asReadTypeLength                              = asReadTypeLength;
375 exports.asValueIfNotPresent                           = asValueIfNotPresent;
376 exports.asChipUnderlyingType                          = asChipUnderlyingType;
377 exports.isFirstElement                                = isFirstElement;
378 exports.user_cluster_has_enabled_manufacturer_command = user_cluster_has_enabled_manufacturer_command;
379 exports.chip_endpoint_generated_functions             = chip_endpoint_generated_functions
380 exports.chip_endpoint_cluster_list                    = chip_endpoint_cluster_list
381 exports.isSigned                                      = ChipTypesHelper.isSigned;
382 exports.isStrEndsWith                                 = isStrEndsWith;