Skip to content

Commit

Permalink
Update the ZAP template to encode/decode commands (project-chip#3935)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
vivien-apple authored Dec 4, 2020
1 parent fd26ea2 commit 252b094
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 42 deletions.
4 changes: 4 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -232,5 +232,9 @@ TabWidth: 8
UseTab: Never
---
Language: JavaScript
BasedOnStyle: WebKit
AlignConsecutiveAssignments: true
AllowShortFunctionsOnASingleLine: None
IndentWidth: 2
ColumnLimit: 132
...
6 changes: 1 addition & 5 deletions src/app/zap-templates/af-structs.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,12 @@ typedef struct _{{asType label}} {
{{ident}}chip::EndpointId {{asSymbol label}};
{{else if (isStrEqual label "endpointId")}}
{{ident}}chip::EndpointId {{asSymbol label}};
{{else if (isStrEqual type "CLUSTER_ID")}}
{{ident}}chip::ClusterId {{asSymbol label}};
{{else if (isStrEqual type "ATTRIBUTE_ID")}}
{{ident}}chip::AttributeId {{asSymbol label}};
{{else if (isStrEqual label "groupId")}}
{{ident}}chip::GroupId {{asSymbol label}};
{{else if (isStrEqual label "commandId")}}
{{ident}}chip::CommandId {{asSymbol label}};
{{else}}
{{ident}}{{asUnderlyingType type}} {{asSymbol label}};
{{ident}}{{asUnderlyingZclType type}} {{asSymbol label}};
{{/if}}
{{/zcl_struct_items}}
} {{asUnderlyingType label}};
Expand Down
2 changes: 1 addition & 1 deletion src/app/zap-templates/attribute-size.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
// ZCL attribute sizes
{{#zcl_atomics}}
{{#if size}}
{{ident}}ZCL_{{asDelimitedMacro name}}_ATTRIBUTE_TYPE, {{size}}, \
{{ident}}ZCL_{{asDelimitedMacro name}}_ATTRIBUTE_TYPE, {{size}},
{{/if}}
{{/zcl_atomics}}
41 changes: 33 additions & 8 deletions src/app/zap-templates/call-command-handler-src.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,43 @@ EmberAfStatus emberAf{{asCamelCased name false}}Cluster{{asCamelCased side false
{{#if (isCommandAvailable parent.side incoming outgoing commandSource name)}}
case ZCL_{{asDelimitedMacro name}}_COMMAND_ID: {
{{#if (zcl_command_arguments_count this.id)}}
uint32_t argOffset = 0;
uint32_t payloadOffset = cmd->payloadStartIndex;
{{#zcl_command_arguments}}
{{asUnderlyingType type}} * {{asSymbol label}} = ({{asUnderlyingType type}} *)(cmd->buffer + argOffset);
{{#unless (isLastElement index count)}}
argOffset+= sizeof({{asUnderlyingType type}});
{{/unless}}
{{asUnderlyingZclType type}} {{asSymbol label}};
{{/zcl_command_arguments}}

{{#zcl_command_arguments}}
{{#if presentIf}}
if ({{presentIf}})
{
{{/if}}
{{#if isArray}}
{{asSymbol label}} = cmd->buffer + payloadOffset;
{{else}}
if (cmd->bufLen < payloadOffset + {{asReadTypeLength type}})
{
return EMBER_ZCL_STATUS_MALFORMED_COMMAND;
}
{{asSymbol label}} = emberAfGet{{asReadType type}}(cmd->buffer, payloadOffset, cmd->bufLen);
{{#unless (isLastElement index count)}}
{{#if (isString type)}}
payloadOffset += emberAf{{asReadType type}}Length({{asSymbol label}}) + {{asReadTypeLength type}};
{{else}}
payloadOffset += {{asReadTypeLength type}};
{{/if}}
{{/unless}}
{{/if}}
{{#if presentIf}}
}
else
{
{{asSymbol label}} = {{asValueIfNotPresent type}};
}
{{/if}}
{{/zcl_command_arguments}}

wasHandled = emberAf{{asCamelCased parent.name false}}Cluster{{asCamelCased name false}}Callback({{#zcl_command_arguments}} *{{asSymbol label}}{{#unless (isLastElement index count)}}, {{/unless}}{{/zcl_command_arguments}});
{{else}}
wasHandled = emberAf{{asCamelCased parent.name false}}Cluster{{asCamelCased name false}}Callback();
{{/if}}
wasHandled = emberAf{{asCamelCased parent.name false}}Cluster{{asCamelCased name false}}Callback({{#zcl_command_arguments}}{{asSymbol label}}{{#unless (isLastElement index count)}}, {{/unless}}{{/zcl_command_arguments}});
break;
}
{{/if}}
Expand Down
7 changes: 1 addition & 6 deletions src/app/zap-templates/callback.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,7 @@ void emberAf{{asCamelCased name false}}Cluster{{asCamelCased side false}}TickCal
{{/if}}
*/

{{#if (zcl_command_arguments_count this.id)}}
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}});
{{else}}
bool emberAf{{asCamelCased parent.name false}}Cluster{{asCamelCased name false}}Callback();
{{/if}}

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}});

{{/if}}
{{/if}}
Expand Down
1 change: 1 addition & 0 deletions src/app/zap-templates/chip-templates.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "CHIP templates",
"version": "chip-v1",
"helpers": ["helper-chip.js"],
"override": "override.js",
"templates": [
{
"path": "af-structs.zapt",
Expand Down
158 changes: 137 additions & 21 deletions src/app/zap-templates/helper-chip.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,20 @@
* @module Templating API: toplevel utility helpers
*/

// Import Zcl helper from zap core
const helperZcl = require('../../../third_party/zap/repo/src-electron/generator/helper-zcl.js')

/**
* Dummy helper that add a string to the templates showing
* if the strings matches. Use to demonstrate the use
* of ZAP helper within the chip-helper environment
*
* @param {*} str1 : First string to compare
* @param {*} str2 : Second string to comapre
*/
function example_helper(str1, str2) {
if (helperZcl.isStrEqual(str1, str2)) {
return 'The two strings are identical'
} else {
return 'The two strings are different'
}
}
// Import helpers from zap core
const zapPath = '../../../third_party/zap/repo/src-electron/';
const cHelper = require(zapPath + 'generator/helper-c.js')
const zclHelper = require(zapPath + 'generator/helper-zcl.js')
const zclQuery = require(zapPath + 'db/query-zcl.js')
const templateUtil = require(zapPath + 'generator/template-util.js')

/**
* Produces the top-of-the-file header for a C file.
*
* @returns The header content
*/
function chip_header() {
function chip_header()
{
return `
/*
*
Expand All @@ -65,10 +54,137 @@ function chip_header() {
*/`;
}

const stringShortTypes = [ 'CHAR_STRING', 'OCTET_STRING' ];
const stringLongTypes = [ 'LONG_CHAR_STRING', 'LONG_OCTET_STRING' ];

function isShortString(type)
{
return stringShortTypes.includes(type);
}

function isLongString(type)
{
return stringLongTypes.includes(type);
}

function isString(type)
{
return isShortString(type) || isLongString(type);
}

function asValueIfNotPresent(type, isArray)
{
if (isString(type) || isArray) {
return 'NULL';
}

function resolve(packageId)
{
const options = { 'hash' : {} };
return cHelper.asUnderlyingZclType.call(this, type, options).then(zclType => {
switch (zclType) {
case 'uint8_t':
return 'UINT8_MAX';
case 'uint16_t':
return 'UINT16_MAX';
case 'uint32_t':
return 'UINT32_MAX';
default:
error = 'Unhandled underlying type ' + zclType + ' for original type ' + type;
throw error;
}
})
}

const promise = templateUtil.ensureZclPackageId(this).then(resolve.bind(this)).catch(err => console.log(err));
return templateUtil.templatePromise(this.global, promise)
}

// TODO Expose the readTypeLength as an additional member field of {{asUnderlyingZclType}} instead
// of having to call this method separately.
function asReadTypeLength(type)
{
if (isShortString(type)) {
return '1u';
}

if (isLongString(type)) {
return '2u';
}

function resolve(packageId)
{
const db = this.global.db;

const defaultResolver = zclQuery.selectAtomicType(db, packageId, type);

const enumResolver = zclHelper.isEnum(db, type, packageId).then(result => {
return result == 'unknown' ? null : zclQuery.selectEnumByName(db, type, packageId).then(rec => {
return zclQuery.selectAtomicType(db, packageId, rec.type);
});
});

const bitmapResolver = zclHelper.isBitmap(db, type, packageId).then(result => {
return result == 'unknown' ? null : zclQuery.selectBitmapByName(db, packageId, type).then(rec => {
return zclQuery.selectAtomicType(db, packageId, rec.type);
});
});

const typeResolver = Promise.all([ defaultResolver, enumResolver, bitmapResolver ]);
return typeResolver.then(types => (types.find(type => type)).size);
}

const promise = templateUtil.ensureZclPackageId(this).then(resolve.bind(this)).catch(err => console.log(err));
return templateUtil.templatePromise(this.global, promise)
}

// TODO Expose the readType as an additional member field of {{asUnderlyingZclType}} instead
// of having to call this method separately.
function asReadType(type)
{
if (isShortString(type)) {
return 'String';
}

if (isLongString(type)) {
return 'LongString';
}

function resolve(packageId)
{
const options = { 'hash' : {} };
return zclHelper.asUnderlyingZclType.call(this, type, options).then(zclType => {
switch (zclType) {
case 'int8_t':
case 'uint8_t':
return 'Int8u';
case 'int16_t':
case 'uint16_t':
return 'Int16u';
case 'int24_t':
case 'uint24_t':
return 'Int24u';
case 'int32_t':
case 'uint32_t':
return 'Int32u';
default:
error = 'Unhandled underlying type ' + zclType + ' for original type ' + type;
throw error;
}
})
}

const promise = templateUtil.ensureZclPackageId(this).then(resolve.bind(this)).catch(err => console.log(err));
return templateUtil.templatePromise(this.global, promise)
}

// WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
//
// Note: these exports are public API. Templates that might have been created in the past and are
// available in the wild might depend on these names.
// If you rename the functions, you need to still maintain old exports list.
exports.chip_header = chip_header;
exports.example_helper = example_helper;
exports.chip_header = chip_header;
exports.isString = isString;
exports.asReadType = asReadType;
exports.asReadTypeLength = asReadTypeLength;
exports.asValueIfNotPresent = asValueIfNotPresent;
30 changes: 30 additions & 0 deletions src/app/zap-templates/override.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
*
* Copyright (c) 2020 Project CHIP Authors
*
* 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.
*/

function atomicType(arg)
{
switch (arg.name) {
case 'attribute_id':
return 'chip::AttributeId';
case 'cluster_id':
return 'chip::ClusterId';
default:
throw 'not overriding';
}
}

exports.atomicType = atomicType
2 changes: 1 addition & 1 deletion third_party/zap/repo
Submodule repo updated 58 files
+12 −0 apack.info
+12 −0 apack.info.dist
+5 −3 docs/custom-zcl.md
+12 −0 docs/sdk-integration.md
+860 −857 docs/zap-schema.svg
+ docs/zap_splash.xcf
+1 −2 package-lock.json
+9 −5 package.json
+4 −1 quasar.conf.js
+43 −15 src-electron/db/db-api.js
+26 −1 src-electron/db/db-mapping.js
+19 −9 src-electron/db/query-config.js
+143 −0 src-electron/db/query-package.js
+120 −50 src-electron/db/query-zcl.js
+3 −1 src-electron/db/zap-schema.sql
+201 −36 src-electron/generator/generation-engine.js
+17 −3 src-electron/generator/helper-c.js
+16 −9 src-electron/generator/helper-endpointconfig.js
+168 −0 src-electron/generator/helper-sdkextension.js
+52 −0 src-electron/generator/helper-session.js
+191 −18 src-electron/generator/helper-zcl.js
+2 −0 src-electron/generator/overridable.js
+1 −0 src-electron/generator/template-engine.js
+104 −0 src-electron/generator/template-util.js
+65 −0 src-electron/main-process/about.js
+47 −37 src-electron/main-process/electron-main.js
+32 −50 src-electron/main-process/menu.js
+23 −18 src-electron/main-process/preference.js
+8 −11 src-electron/main-process/startup.js
+3 −7 src-electron/main-process/ui.js
+4 −6 src-electron/rest/generation.js
+4 −6 src-electron/rest/user-data.js
+71 −33 src-electron/server/ws-server.js
+1 −0 src-electron/util/env.js
+14 −0 src-electron/util/string.js
+11 −1 src-electron/util/types.js
+47 −3 src-electron/util/util.js
+1 −0 src-electron/zcl/zcl-loader-dotdot.js
+10 −3 src-electron/zcl/zcl-loader-silabs.js
+1 −6 src-electron/zcl/zcl-loader.js
+1 −2 src-script/zap-generate.js
+17 −0 src-shared/db-enum.js
+24 −9 src/App.vue
+ src/assets/zap_splash.png
+5 −1 src/boot/ws.js
+25 −0 src/pages/About.vue
+4 −0 src/router/routes.js
+1 −1 test/endpoint-config.test.js
+35 −1 test/gen-template/zigbee/gen-templates.json
+22 −0 test/gen-template/zigbee/sdk-extension.zapt
+6 −11 test/gen-template/zigbee/zap-config.zapt
+42 −2 test/genengine.test.js
+72 −11 test/generation.test.js
+179 −0 test/helpers.test.js
+76 −1 test/query.test.js
+6 −0 test/string.test.js
+25 −2 test/zcl-loader-consecutive.test.js
+8 −0 test/zcl-loader.test.js

0 comments on commit 252b094

Please sign in to comment.