Skip to content

Commit

Permalink
Generate Darwin framework glue for all known data model things. (#18220)
Browse files Browse the repository at this point in the history
The Darwin codegen was only generating things for
clusters/commands/attributes enabled in controller-clusters.zap.  We
should generate for everything instead.
  • Loading branch information
bzbarsky-apple authored and pull[bot] committed Jan 19, 2024
1 parent b478bf8 commit 8431780
Show file tree
Hide file tree
Showing 15 changed files with 66,661 additions and 36,407 deletions.
152 changes: 122 additions & 30 deletions src/app/zap-templates/common/ClustersHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,26 @@ async function loadEndpoints()
return result;
}

async function loadAllClusters(packageId)
{
const { db, sessionId } = this.global;

let allClusters = await zclQuery.selectAllClusters(db, packageId);
// To match what loadClusters does, sort by cluster name (not cluster code).
allClusters.sort((a, b) => {
if (a.name < b.name) {
return -1;
}
if (a.name == b.name) {
return 0;
}
return 1;
});
let serverClusters = allClusters.map(cluster => ({...cluster, side : 'server', enabled : true }));
let clientClusters = allClusters.map(cluster => ({...cluster, side : 'client', enabled : true }));
return serverClusters.concat(clientClusters);
}

async function loadClusters()
{
const { db, sessionId } = this.global;
Expand Down Expand Up @@ -147,17 +167,70 @@ function loadCommandArguments(command, packageId)
});
}

async function loadAllCommands(packageId)
{
const { db, sessionId } = this.global;
let cmds = await queryCommand.selectAllCommandsWithClusterInfo(db, [ packageId ]);
// For each command, include it twice: once as outgoing for its source, once
// as incoming for its destination.
let outgoing = cmds.map(cmd => ({...cmd, incoming : false, outgoing : true, clusterSide : cmd.source }));
let incoming = cmds.map(
cmd => ({...cmd, incoming : true, outgoing : false, clusterSide : (cmd.source == 'server' ? 'client' : 'server') }));
let commands = Promise.resolve(outgoing.concat(incoming));
return loadCommandsCommon.call(this, packageId, commands);
}

function loadCommands(packageId)
{
const { db, sessionId } = this.global;
return queryEndpointType.selectEndpointTypeIds(db, sessionId)
.then(endpointTypes => queryEndpointType.selectClustersAndEndpointDetailsFromEndpointTypes(db, endpointTypes))
.then(endpointTypesAndClusters => queryCommand.selectCommandDetailsFromAllEndpointTypesAndClusters(
db, endpointTypesAndClusters, true))
.then(commands => Promise.all(commands.map(command => loadCommandResponse.call(this, command, packageId))))
let cmds = queryEndpointType.selectEndpointTypeIds(db, sessionId)
.then(endpointTypes => queryEndpointType.selectClustersAndEndpointDetailsFromEndpointTypes(db, endpointTypes))
.then(endpointTypesAndClusters => queryCommand.selectCommandDetailsFromAllEndpointTypesAndClusters(
db, endpointTypesAndClusters, true));

return loadCommandsCommon.call(this, packageId, cmds);
}

// commandsPromise is a promise for an array of commands.
function loadCommandsCommon(packageId, commandsPromise)
{
return commandsPromise.then(commands => Promise.all(commands.map(command => loadCommandResponse.call(this, command, packageId))))
.then(commands => Promise.all(commands.map(command => loadCommandArguments.call(this, command, packageId))));
}

async function loadAllAttributes(packageId)
{
// The 'server' side is enforced here, because the list of attributes is used to generate client global
// commands to retrieve server side attributes.
const { db, sessionId } = this.global;
let attrs = await zclQuery.selectAllAttributesBySide(db, 'server', [ packageId ]);
const globalAttrs = attrs.filter(attr => attr.clusterRef == null);
// Exclude global attributes for now, since we will add them ourselves for
// all clusters.
attrs = attrs.filter(attr => attr.clusterRef != null);
// selectAllAttributesBySide sets clusterRef, not clusterId, so manually
// set the latter here.
attrs.forEach(attr => attr.clusterId = attr.clusterRef);

const clusters = await zclQuery.selectAllClusters(db, packageId);
for (let cluster of clusters) {
for (let globalAttr of globalAttrs) {
attrs.push({...globalAttr, clusterId : cluster.id });
}
}
// selectAllAttributesBySide includes optionality information, which we
// don't want here, because the types of the attributes are not in fact
// optionals for our purposes.
attrs.forEach(attr => delete attr.isOptional);
// Treat all attributes that could be reportable as reportable.
attrs.forEach(attr => {
if (attr.isReportable) {
attr.includedReportable = true;
}
});
return attrs.sort((a, b) => a.code - b.code);
}

function loadAttributes(packageId)
{
// The 'server' side is enforced here, because the list of attributes is used to generate client global
Expand All @@ -176,24 +249,37 @@ function loadAttributes(packageId)
//.then(attributes => Promise.all(attributes.map(attribute => types.typeSizeAttribute(db, packageId, attribute))
}

function loadEvents(packageId)
async function loadAllEvents(packageId)
{
const { db, sessionId } = this.global;
let clusters = await zclQuery.selectAllClusters(db, packageId);
return loadEventsCommon.call(this, packageId, clusters);
}

async function loadEvents(packageId)
{
const { db, sessionId } = this.global;
let clusters = await queryEndpointType.selectEndpointTypeIds(db, sessionId)
.then(endpointTypes => Promise.all(
endpointTypes.map(({ endpointTypeId }) => queryEndpoint.selectEndpointClusters(db, endpointTypeId))))
.then(clusters => clusters.flat(3));
return loadEventsCommon.call(this, packageId, clusters);
}

// clusters is an array of clusters (not a promise).
function loadEventsCommon(packageId, clusters)
{
const { db, sessionId } = this.global;
return queryEvent.selectAllEvents(db, packageId)
.then(events => { return queryEndpointType.selectEndpointTypeIds(db, sessionId)
.then(endpointTypes => Promise.all(
endpointTypes.map(({ endpointTypeId }) => queryEndpoint.selectEndpointClusters(db, endpointTypeId))))
.then(clusters => clusters.flat(3))
.then(clusters => {
events.forEach(event => {
const cluster = clusters.find(cluster => cluster.code == event.clusterCode && cluster.side == 'client');
if (cluster) {
event.clusterId = cluster.clusterId;
event.clusterName = cluster.name;
}
});
return events.filter(event => clusters.find(cluster => cluster.code == event.clusterCode));
}) })
return queryEvent.selectAllEvents(db, packageId).then(events => {
events.forEach(event => {
const cluster = clusters.find(cluster => cluster.code == event.clusterCode);
if (cluster) {
event.clusterId = cluster.clusterId;
event.clusterName = cluster.name;
}
});
return events.filter(event => clusters.find(cluster => cluster.code == event.clusterCode));
});
}

function loadGlobalAttributes(packageId)
Expand Down Expand Up @@ -473,8 +559,8 @@ function enhancedAttributes(attributes, globalAttributes, types)
attributes.forEach(attribute => {
enhancedItem(attribute, types);
attribute.isGlobalAttribute = globalAttributes.includes(attribute.code);
attribute.isWritableAttribute = attribute.isWritable === 1;
attribute.isReportableAttribute = attribute.includedReportable === 1;
attribute.isWritableAttribute = !!attribute.isWritable;
attribute.isReportableAttribute = !!attribute.includedReportable;
attribute.chipCallback = asChipCallback(attribute);
attribute.isComplex = attribute.isList || attribute.isStruct || attribute.isArray;
});
Expand Down Expand Up @@ -602,7 +688,11 @@ Clusters._computeUsedStructureNames = async function(structs) {
this._used_structure_names = new Set(this._cluster_structures.usedStructures.keys())
}

Clusters.init = async function(context) {
/**
* If includeAll is true, all events/commands/attributes will be included, not
* just the ones enabled in the ZAP configuration.
*/
Clusters.init = async function(context, includeAll) {
if (this.ready.running)
{
return this.ready;
Expand All @@ -621,11 +711,13 @@ Clusters.init = async function(context) {
const promises = [
Promise.all(loadTypes),
loadEndpoints.call(context),
loadClusters.call(context),
loadCommands.call(context, packageId),
loadAttributes.call(context, packageId),
// For now just always use loadClusters, because we have a bunch of things
// defined in our XML that are not actually part of Matter.
(includeAll ? loadClusters : loadClusters).call(context, packageId),
(includeAll ? loadAllCommands : loadCommands).call(context, packageId),
(includeAll ? loadAllAttributes : loadAttributes).call(context, packageId),
loadGlobalAttributes.call(context, packageId),
loadEvents.call(context, packageId),
(includeAll ? loadAllEvents : loadEvents).call(context, packageId),
];

let [types, endpoints, clusters, commands, attributes, globalAttributes, events] = await Promise.all(promises);
Expand Down Expand Up @@ -654,13 +746,13 @@ function asBlocks(promise, options)
return promise.then(data => templateUtil.collectBlocks(data, options, this))
}

function ensureClusters(context)
function ensureClusters(context, includeAll = false)
{
// Kick off Clusters initialization. This is async, but that's fine: all the
// getters on Clusters wait on that initialziation to complete.
ensureState(context, "Don't have a context");

Clusters.init(context);
Clusters.init(context, includeAll);
return Clusters;
}

Expand Down
6 changes: 3 additions & 3 deletions src/app/zap-templates/templates/chip/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ function getResponses(methodName)
*/
function chip_server_clusters(options)
{
return asBlocks.call(this, ensureClusters(this).getServerClusters(), options);
return asBlocks.call(this, ensureClusters(this, options.hash.includeAll).getServerClusters(), options);
}

/**
Expand All @@ -123,7 +123,7 @@ function chip_has_server_clusters(options)
*/
function chip_client_clusters(options)
{
return asBlocks.call(this, ensureClusters(this).getClientClusters(), options);
return asBlocks.call(this, ensureClusters(this, options.hash.includeAll).getClientClusters(), options);
}

/**
Expand All @@ -142,7 +142,7 @@ function chip_has_client_clusters(options)
*/
function chip_clusters(options)
{
return asBlocks.call(this, ensureClusters(this).getClusters(), options);
return asBlocks.call(this, ensureClusters(this, options.hash.includeAll).getClusters(), options);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#import <Foundation/Foundation.h>

#import "CHIPError_Internal.h"
#import "zap-generated/CHIPClientCallbacks.h"
#import "zap-generated/CHIPClustersObjc.h"

#include <app/data-model/NullObject.h>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ id CHIPDecodeAttributeValue(const ConcreteAttributePath & aPath, TLV::TLVReader
{
switch (aPath.mClusterId)
{
{{#chip_client_clusters}}
{{#chip_client_clusters includeAll=true}}
case Clusters::{{asUpperCamelCase name}}::Id: {
using namespace Clusters::{{asUpperCamelCase name}};
switch (aPath.mAttributeId)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{{> header}}

{{#if (chip_has_client_clusters)}}
#import "CHIPCallbackBridge_internal.h"
#import "CHIPStructsObjc.h"
#import "CHIPCommandPayloadsObjc.h"
Expand Down Expand Up @@ -38,7 +37,7 @@
{{#>CHIPCallbackBridge type="vendor_id" isNullable=false ns="chip"}}VendorIdAttributeCallback{{/CHIPCallbackBridge}}
{{#>CHIPCallbackBridge type="vendor_id" isNullable=true ns="chip"}}NullableVendorIdAttributeCallback{{/CHIPCallbackBridge}}

{{#chip_client_clusters}}
{{#chip_client_clusters includeAll=true}}
{{#chip_server_cluster_attributes}}
{{#if isArray}}
{{#>CHIPCallbackBridge ns=parent.name }}{{asUpperCamelCase ../../name}}{{asUpperCamelCase ../name}}ListAttributeCallback{{/CHIPCallbackBridge}}
Expand All @@ -53,7 +52,7 @@
{{/chip_server_cluster_attributes}}
{{/chip_client_clusters}}

{{#chip_client_clusters}}
{{#chip_client_clusters includeAll=true}}
{{#chip_cluster_responses}}
{{#>CHIPCallbackBridge partial-type="Command" }}{{asUpperCamelCase ../../name}}Cluster{{asUpperCamelCase ../name}}Callback{{/CHIPCallbackBridge}}
{{/chip_cluster_responses}}
Expand All @@ -65,5 +64,3 @@
{{#>CHIPCallbackBridge type=(asType label) isNullable=true ns=parent.name}}Nullable{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}AttributeCallback{{/CHIPCallbackBridge}}
{{/zcl_enums}}
{{/zcl_clusters}}

{{/if}}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{{> header}}

{{#if (chip_has_client_clusters)}}
#import <Foundation/Foundation.h>
#import "CHIPCallbackBridgeBase_internal.h"

#include <app/data-model/DecodableList.h>
#include <app/util/im-client-callbacks.h>
#include <app-common/zap-generated/cluster-objects.h>

typedef void (*CommandSuccessCallback)(void *, const chip::app::DataModel::NullObjectType &);
Expand All @@ -14,7 +14,7 @@ typedef void (*CHIPDefaultSuccessCallbackType)(void *);
typedef void (*VendorIdAttributeCallback)(void *, chip::VendorId);
typedef void (*NullableVendorIdAttributeCallback)(void *, const chip::app::DataModel::Nullable<chip::VendorId> &);

{{#chip_client_clusters}}
{{#chip_client_clusters includeAll=true}}
{{#chip_cluster_responses}}
typedef void (*CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}CallbackType)(void *, const chip::app::Clusters::{{asUpperCamelCase parent.name}}::Commands::{{asUpperCamelCase name}}::DecodableType &);
{{/chip_cluster_responses}}
Expand All @@ -27,16 +27,18 @@ typedef void (*Nullable{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase
{{/zcl_enums}}
{{/zcl_clusters}}

{{#chip_client_clusters}}
{{#chip_client_clusters includeAll=true}}
{{#chip_server_cluster_attributes}}
{{#unless isArray}}
{{#if isArray}}
typedef void (*{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}ListAttributeCallback)(void * context, {{zapTypeToDecodableClusterObjectType type ns=parent.name isArgument=true}} data);
{{else}}
{{#if_is_struct type}}
typedef void (*{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}StructAttributeCallback)(void *, {{zapTypeToDecodableClusterObjectType type ns=parent.name isArgument=true forceNotOptional=true}});
{{/if_is_struct}}
{{#if_is_bitmap type}}
typedef void (*{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback)(void *, {{zapTypeToDecodableClusterObjectType type ns=parent.name isArgument=true forceNotOptional=true}});
{{/if_is_bitmap}}
{{/unless}}
{{/if}}
{{/chip_server_cluster_attributes}}
{{/chip_client_clusters}}

Expand Down Expand Up @@ -71,7 +73,7 @@ typedef void (*{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}Attribut
{{#>CHIPCallbackBridge header="1" type="vendor_id" isNullable=false ns="chip"}}VendorIdAttributeCallback{{/CHIPCallbackBridge}}
{{#>CHIPCallbackBridge header="1" type="vendor_id" isNullable=true ns="chip"}}NullableVendorIdAttributeCallback{{/CHIPCallbackBridge}}

{{#chip_client_clusters}}
{{#chip_client_clusters includeAll=true}}
{{#chip_server_cluster_attributes}}
{{#if isArray}}
{{#>CHIPCallbackBridge header="1" ns=parent.name }}{{asUpperCamelCase ../../name}}{{asUpperCamelCase ../name}}ListAttributeCallback{{/CHIPCallbackBridge}}
Expand All @@ -86,7 +88,7 @@ typedef void (*{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}Attribut
{{/chip_server_cluster_attributes}}
{{/chip_client_clusters}}

{{#chip_client_clusters}}
{{#chip_client_clusters includeAll=true}}
{{#chip_cluster_responses}}
{{#>CHIPCallbackBridge header="1" partial-type="Command" }}{{asUpperCamelCase ../../name}}Cluster{{asUpperCamelCase ../name}}Callback{{/CHIPCallbackBridge}}
{{/chip_cluster_responses}}
Expand All @@ -98,5 +100,3 @@ typedef void (*{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}Attribut
{{#>CHIPCallbackBridge header="1" type=(asType label) isNullable=true ns=parent.name}}Nullable{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}AttributeCallback{{/CHIPCallbackBridge}}
{{/zcl_enums}}
{{/zcl_clusters}}

{{/if}}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{{> header}}

{{#if (chip_has_client_clusters)}}
#import <Foundation/Foundation.h>

#import "CHIPAttributeCacheContainer_Internal.h"
Expand All @@ -19,7 +18,7 @@ using chip::Callback::Callback;
using chip::Callback::Cancelable;
using namespace chip::app::Clusters;
// NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks): Linter is unable to locate the delete on these objects.
{{#chip_client_clusters}}
{{#chip_client_clusters includeAll=true}}
@implementation CHIP{{asUpperCamelCase name}}

- (chip::Controller::ClusterBase *)getCluster
Expand Down Expand Up @@ -206,4 +205,3 @@ subscriptionEstablished:(SubscriptionEstablishedHandler _Nullable)subscriptionEs

{{/chip_client_clusters}}
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
{{/if}}
4 changes: 1 addition & 3 deletions src/darwin/Framework/CHIP/templates/CHIPClustersObjc.zapt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{{> header}}

{{#if (chip_has_client_clusters)}}
#ifndef CHIP_CLUSTERS_H
#define CHIP_CLUSTERS_H

Expand All @@ -17,7 +16,7 @@ typedef void (^SubscriptionEstablishedHandler)(void);

NS_ASSUME_NONNULL_BEGIN

{{#chip_client_clusters}}
{{#chip_client_clusters includeAll=true}}


/**
Expand Down Expand Up @@ -84,4 +83,3 @@ typedef NS_OPTIONS({{asUnderlyingZclType type}}, {{objCEnumName ../name label}})
NS_ASSUME_NONNULL_END

#endif /* CHIP_CLUSTERS_H */
{{/if}}
Loading

0 comments on commit 8431780

Please sign in to comment.