Skip to content

Commit 252b094

Browse files
authored
Update the ZAP template to encode/decode commands (#3935)
There are a few issues with the current template. 1. {{isArray}} is not taken into account. It results into a mismatch between the signatures of some clusters methods 2. Instead of using raw types, such as 'uint8_t', 'uint16_t', the current template uses 'enum'. It creates 2 types of issues: * The current template generates code that rely on sizeof(type) to move the pointer for the payload buffer. It does not work well with 'enum'. * The signatures of methods are using raw types. So it ask for a change in all the cluster signatures. 3. The buffer start pointer is mispositioned: It uses 0 instead of cmd->payloadStartIndex 4. String are using 'uint8_t *', which is OK but the pointer to the payload buffer is not moved to take into account the additional bytes with the size of the string
1 parent fd26ea2 commit 252b094

9 files changed

+209
-42
lines changed

.clang-format

+4
Original file line numberDiff line numberDiff line change
@@ -232,5 +232,9 @@ TabWidth: 8
232232
UseTab: Never
233233
---
234234
Language: JavaScript
235+
BasedOnStyle: WebKit
236+
AlignConsecutiveAssignments: true
237+
AllowShortFunctionsOnASingleLine: None
238+
IndentWidth: 2
235239
ColumnLimit: 132
236240
...

src/app/zap-templates/af-structs.zapt

+1-5
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,12 @@ typedef struct _{{asType label}} {
1616
{{ident}}chip::EndpointId {{asSymbol label}};
1717
{{else if (isStrEqual label "endpointId")}}
1818
{{ident}}chip::EndpointId {{asSymbol label}};
19-
{{else if (isStrEqual type "CLUSTER_ID")}}
20-
{{ident}}chip::ClusterId {{asSymbol label}};
21-
{{else if (isStrEqual type "ATTRIBUTE_ID")}}
22-
{{ident}}chip::AttributeId {{asSymbol label}};
2319
{{else if (isStrEqual label "groupId")}}
2420
{{ident}}chip::GroupId {{asSymbol label}};
2521
{{else if (isStrEqual label "commandId")}}
2622
{{ident}}chip::CommandId {{asSymbol label}};
2723
{{else}}
28-
{{ident}}{{asUnderlyingType type}} {{asSymbol label}};
24+
{{ident}}{{asUnderlyingZclType type}} {{asSymbol label}};
2925
{{/if}}
3026
{{/zcl_struct_items}}
3127
} {{asUnderlyingType label}};

src/app/zap-templates/attribute-size.zapt

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66
// ZCL attribute sizes
77
{{#zcl_atomics}}
88
{{#if size}}
9-
{{ident}}ZCL_{{asDelimitedMacro name}}_ATTRIBUTE_TYPE, {{size}}, \
9+
{{ident}}ZCL_{{asDelimitedMacro name}}_ATTRIBUTE_TYPE, {{size}},
1010
{{/if}}
1111
{{/zcl_atomics}}

src/app/zap-templates/call-command-handler-src.zapt

+33-8
Original file line numberDiff line numberDiff line change
@@ -100,18 +100,43 @@ EmberAfStatus emberAf{{asCamelCased name false}}Cluster{{asCamelCased side false
100100
{{#if (isCommandAvailable parent.side incoming outgoing commandSource name)}}
101101
case ZCL_{{asDelimitedMacro name}}_COMMAND_ID: {
102102
{{#if (zcl_command_arguments_count this.id)}}
103-
uint32_t argOffset = 0;
103+
uint32_t payloadOffset = cmd->payloadStartIndex;
104104
{{#zcl_command_arguments}}
105-
{{asUnderlyingType type}} * {{asSymbol label}} = ({{asUnderlyingType type}} *)(cmd->buffer + argOffset);
106-
{{#unless (isLastElement index count)}}
107-
argOffset+= sizeof({{asUnderlyingType type}});
108-
{{/unless}}
105+
{{asUnderlyingZclType type}} {{asSymbol label}};
106+
{{/zcl_command_arguments}}
107+
108+
{{#zcl_command_arguments}}
109+
{{#if presentIf}}
110+
if ({{presentIf}})
111+
{
112+
{{/if}}
113+
{{#if isArray}}
114+
{{asSymbol label}} = cmd->buffer + payloadOffset;
115+
{{else}}
116+
if (cmd->bufLen < payloadOffset + {{asReadTypeLength type}})
117+
{
118+
return EMBER_ZCL_STATUS_MALFORMED_COMMAND;
119+
}
120+
{{asSymbol label}} = emberAfGet{{asReadType type}}(cmd->buffer, payloadOffset, cmd->bufLen);
121+
{{#unless (isLastElement index count)}}
122+
{{#if (isString type)}}
123+
payloadOffset += emberAf{{asReadType type}}Length({{asSymbol label}}) + {{asReadTypeLength type}};
124+
{{else}}
125+
payloadOffset += {{asReadTypeLength type}};
126+
{{/if}}
127+
{{/unless}}
128+
{{/if}}
129+
{{#if presentIf}}
130+
}
131+
else
132+
{
133+
{{asSymbol label}} = {{asValueIfNotPresent type}};
134+
}
135+
{{/if}}
109136
{{/zcl_command_arguments}}
110137

111-
wasHandled = emberAf{{asCamelCased parent.name false}}Cluster{{asCamelCased name false}}Callback({{#zcl_command_arguments}} *{{asSymbol label}}{{#unless (isLastElement index count)}}, {{/unless}}{{/zcl_command_arguments}});
112-
{{else}}
113-
wasHandled = emberAf{{asCamelCased parent.name false}}Cluster{{asCamelCased name false}}Callback();
114138
{{/if}}
139+
wasHandled = emberAf{{asCamelCased parent.name false}}Cluster{{asCamelCased name false}}Callback({{#zcl_command_arguments}}{{asSymbol label}}{{#unless (isLastElement index count)}}, {{/unless}}{{/zcl_command_arguments}});
115140
break;
116141
}
117142
{{/if}}

src/app/zap-templates/callback.zapt

+1-6
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,7 @@ void emberAf{{asCamelCased name false}}Cluster{{asCamelCased side false}}TickCal
117117
{{/if}}
118118
*/
119119

120-
{{#if (zcl_command_arguments_count this.id)}}
121-
bool emberAf{{asCamelCased parent.name false}}Cluster{{asCamelCased name false}}Callback({{#zcl_command_arguments}} {{asUnderlyingType type}} {{asSymbol label}}{{#unless (isLastElement index count)}}, {{/unless}}{{/zcl_command_arguments}});
122-
{{else}}
123-
bool emberAf{{asCamelCased parent.name false}}Cluster{{asCamelCased name false}}Callback();
124-
{{/if}}
125-
120+
bool emberAf{{asCamelCased parent.name false}}Cluster{{asCamelCased name false}}Callback({{#zcl_command_arguments}}{{asUnderlyingZclType type}} {{asSymbol label}}{{#unless (isLastElement index count)}}, {{/unless}}{{/zcl_command_arguments}});
126121

127122
{{/if}}
128123
{{/if}}

src/app/zap-templates/chip-templates.json

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"name": "CHIP templates",
33
"version": "chip-v1",
44
"helpers": ["helper-chip.js"],
5+
"override": "override.js",
56
"templates": [
67
{
78
"path": "af-structs.zapt",

src/app/zap-templates/helper-chip.js

+137-21
Original file line numberDiff line numberDiff line change
@@ -21,31 +21,20 @@
2121
* @module Templating API: toplevel utility helpers
2222
*/
2323

24-
// Import Zcl helper from zap core
25-
const helperZcl = require('../../../third_party/zap/repo/src-electron/generator/helper-zcl.js')
26-
27-
/**
28-
* Dummy helper that add a string to the templates showing
29-
* if the strings matches. Use to demonstrate the use
30-
* of ZAP helper within the chip-helper environment
31-
*
32-
* @param {*} str1 : First string to compare
33-
* @param {*} str2 : Second string to comapre
34-
*/
35-
function example_helper(str1, str2) {
36-
if (helperZcl.isStrEqual(str1, str2)) {
37-
return 'The two strings are identical'
38-
} else {
39-
return 'The two strings are different'
40-
}
41-
}
24+
// Import helpers from zap core
25+
const zapPath = '../../../third_party/zap/repo/src-electron/';
26+
const cHelper = require(zapPath + 'generator/helper-c.js')
27+
const zclHelper = require(zapPath + 'generator/helper-zcl.js')
28+
const zclQuery = require(zapPath + 'db/query-zcl.js')
29+
const templateUtil = require(zapPath + 'generator/template-util.js')
4230

4331
/**
4432
* Produces the top-of-the-file header for a C file.
4533
*
4634
* @returns The header content
4735
*/
48-
function chip_header() {
36+
function chip_header()
37+
{
4938
return `
5039
/*
5140
*
@@ -65,10 +54,137 @@ function chip_header() {
6554
*/`;
6655
}
6756

57+
const stringShortTypes = [ 'CHAR_STRING', 'OCTET_STRING' ];
58+
const stringLongTypes = [ 'LONG_CHAR_STRING', 'LONG_OCTET_STRING' ];
59+
60+
function isShortString(type)
61+
{
62+
return stringShortTypes.includes(type);
63+
}
64+
65+
function isLongString(type)
66+
{
67+
return stringLongTypes.includes(type);
68+
}
69+
70+
function isString(type)
71+
{
72+
return isShortString(type) || isLongString(type);
73+
}
74+
75+
function asValueIfNotPresent(type, isArray)
76+
{
77+
if (isString(type) || isArray) {
78+
return 'NULL';
79+
}
80+
81+
function resolve(packageId)
82+
{
83+
const options = { 'hash' : {} };
84+
return cHelper.asUnderlyingZclType.call(this, type, options).then(zclType => {
85+
switch (zclType) {
86+
case 'uint8_t':
87+
return 'UINT8_MAX';
88+
case 'uint16_t':
89+
return 'UINT16_MAX';
90+
case 'uint32_t':
91+
return 'UINT32_MAX';
92+
default:
93+
error = 'Unhandled underlying type ' + zclType + ' for original type ' + type;
94+
throw error;
95+
}
96+
})
97+
}
98+
99+
const promise = templateUtil.ensureZclPackageId(this).then(resolve.bind(this)).catch(err => console.log(err));
100+
return templateUtil.templatePromise(this.global, promise)
101+
}
102+
103+
// TODO Expose the readTypeLength as an additional member field of {{asUnderlyingZclType}} instead
104+
// of having to call this method separately.
105+
function asReadTypeLength(type)
106+
{
107+
if (isShortString(type)) {
108+
return '1u';
109+
}
110+
111+
if (isLongString(type)) {
112+
return '2u';
113+
}
114+
115+
function resolve(packageId)
116+
{
117+
const db = this.global.db;
118+
119+
const defaultResolver = zclQuery.selectAtomicType(db, packageId, type);
120+
121+
const enumResolver = zclHelper.isEnum(db, type, packageId).then(result => {
122+
return result == 'unknown' ? null : zclQuery.selectEnumByName(db, type, packageId).then(rec => {
123+
return zclQuery.selectAtomicType(db, packageId, rec.type);
124+
});
125+
});
126+
127+
const bitmapResolver = zclHelper.isBitmap(db, type, packageId).then(result => {
128+
return result == 'unknown' ? null : zclQuery.selectBitmapByName(db, packageId, type).then(rec => {
129+
return zclQuery.selectAtomicType(db, packageId, rec.type);
130+
});
131+
});
132+
133+
const typeResolver = Promise.all([ defaultResolver, enumResolver, bitmapResolver ]);
134+
return typeResolver.then(types => (types.find(type => type)).size);
135+
}
136+
137+
const promise = templateUtil.ensureZclPackageId(this).then(resolve.bind(this)).catch(err => console.log(err));
138+
return templateUtil.templatePromise(this.global, promise)
139+
}
140+
141+
// TODO Expose the readType as an additional member field of {{asUnderlyingZclType}} instead
142+
// of having to call this method separately.
143+
function asReadType(type)
144+
{
145+
if (isShortString(type)) {
146+
return 'String';
147+
}
148+
149+
if (isLongString(type)) {
150+
return 'LongString';
151+
}
152+
153+
function resolve(packageId)
154+
{
155+
const options = { 'hash' : {} };
156+
return zclHelper.asUnderlyingZclType.call(this, type, options).then(zclType => {
157+
switch (zclType) {
158+
case 'int8_t':
159+
case 'uint8_t':
160+
return 'Int8u';
161+
case 'int16_t':
162+
case 'uint16_t':
163+
return 'Int16u';
164+
case 'int24_t':
165+
case 'uint24_t':
166+
return 'Int24u';
167+
case 'int32_t':
168+
case 'uint32_t':
169+
return 'Int32u';
170+
default:
171+
error = 'Unhandled underlying type ' + zclType + ' for original type ' + type;
172+
throw error;
173+
}
174+
})
175+
}
176+
177+
const promise = templateUtil.ensureZclPackageId(this).then(resolve.bind(this)).catch(err => console.log(err));
178+
return templateUtil.templatePromise(this.global, promise)
179+
}
180+
68181
// WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
69182
//
70183
// Note: these exports are public API. Templates that might have been created in the past and are
71184
// available in the wild might depend on these names.
72185
// If you rename the functions, you need to still maintain old exports list.
73-
exports.chip_header = chip_header;
74-
exports.example_helper = example_helper;
186+
exports.chip_header = chip_header;
187+
exports.isString = isString;
188+
exports.asReadType = asReadType;
189+
exports.asReadTypeLength = asReadTypeLength;
190+
exports.asValueIfNotPresent = asValueIfNotPresent;

src/app/zap-templates/override.js

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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+
function atomicType(arg)
19+
{
20+
switch (arg.name) {
21+
case 'attribute_id':
22+
return 'chip::AttributeId';
23+
case 'cluster_id':
24+
return 'chip::ClusterId';
25+
default:
26+
throw 'not overriding';
27+
}
28+
}
29+
30+
exports.atomicType = atomicType

third_party/zap/repo

Submodule repo updated 58 files

0 commit comments

Comments
 (0)