Skip to content

Commit

Permalink
Add event subscription and any cluster commands to chip-tool-darwin (#…
Browse files Browse the repository at this point in the history
…18050)

* Update chip-tool-darwin to have any clusters and add Event Subs

* Generated code
  • Loading branch information
krypton36 authored and pull[bot] committed Feb 6, 2024
1 parent e914ce1 commit 228b885
Show file tree
Hide file tree
Showing 8 changed files with 9,623 additions and 20,531 deletions.
3 changes: 3 additions & 0 deletions examples/chip-tool-darwin/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ config("config") {
executable("chip-tool-darwin") {
sources = [
"${chip_root}/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp",
"commands/clusters/ClusterCommandBridge.h",
"commands/clusters/ModelCommandBridge.mm",
"commands/clusters/ReportCommandBridge.h",
"commands/clusters/WriteAttributeCommandBridge.h",
"commands/common/CHIPCommandBridge.mm",
"commands/common/CHIPCommandStorageDelegate.mm",
"commands/common/CHIPToolKeypair.mm",
Expand Down
133 changes: 133 additions & 0 deletions examples/chip-tool-darwin/commands/clusters/ClusterCommandBridge.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* Copyright (c) 2022 Project CHIP Authors
* All rights reserved.
*
* 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.
*
*/

#pragma once

#import <CHIP/CHIP.h>
#import <CHIP/CHIPDevice_Internal.h>
#include <lib/support/UnitTestUtils.h>

#include "ModelCommandBridge.h"

class ClusterCommand : public ModelCommand {
public:
ClusterCommand()
: ModelCommand("command-by-id")
{
AddArgument("cluster-id", 0, UINT32_MAX, &mClusterId);
AddArgument("command-id", 0, UINT32_MAX, &mCommandId);
AddArgument("payload", &mPayload);
AddArgument("timedInteractionTimeoutMs", 0, UINT16_MAX, &mTimedInteractionTimeoutMs);
AddArgument("repeat-count", 1, UINT16_MAX, &mRepeatCount);
AddArgument("repeat-delay-ms", 0, UINT16_MAX, &mRepeatDelayInMs);
ModelCommand::AddArguments();
}

ClusterCommand(chip::ClusterId clusterId)
: ModelCommand("command-by-id")
, mClusterId(clusterId)
{
AddArgument("command-id", 0, UINT32_MAX, &mCommandId);
AddArgument("payload", &mPayload);
AddArgument("timedInteractionTimeoutMs", 0, UINT16_MAX, &mTimedInteractionTimeoutMs);
AddArgument("repeat-count", 1, UINT16_MAX, &mRepeatCount);
AddArgument("repeat-delay-ms", 0, UINT16_MAX, &mRepeatDelayInMs);
ModelCommand::AddArguments();
}

ClusterCommand(const char * _Nonnull commandName)
: ModelCommand(commandName)
{
AddArgument("timedInteractionTimeoutMs", 0, UINT16_MAX, &mTimedInteractionTimeoutMs);
AddArgument("repeat-count", 1, UINT16_MAX, &mRepeatCount);
AddArgument("repeat-delay-ms", 0, UINT16_MAX, &mRepeatDelayInMs);
}

~ClusterCommand() {}

CHIP_ERROR SendCommand(CHIPDevice * _Nonnull device, chip::EndpointId endpointId) override
{
chip::TLV::TLVWriter writer;
chip::TLV::TLVReader reader;

mData = static_cast<uint8_t *>(chip::Platform::MemoryCalloc(sizeof(uint8_t), mDataMaxLen));
VerifyOrReturnError(mData != nullptr, CHIP_ERROR_NO_MEMORY);

writer.Init(mData, mDataMaxLen);

ReturnErrorOnFailure(mPayload.Encode(writer, chip::TLV::AnonymousTag()));
reader.Init(mData, writer.GetLengthWritten());
ReturnErrorOnFailure(reader.Next());

id commandFields = NSObjectFromCHIPTLV(&reader);
if (commandFields == nil) {
return CHIP_ERROR_INTERNAL;
}
return ClusterCommand::SendCommand(device, endpointId, mClusterId, mCommandId, commandFields);
}

CHIP_ERROR SendCommand(CHIPDevice * _Nonnull device, chip::EndpointId endpointId, chip::ClusterId clusterId,
chip::CommandId commandId, id _Nonnull commandFields)
{
uint16_t repeatCount = mRepeatCount.ValueOr(1);
uint16_t __block responsesNeeded = repeatCount;
dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL);

while (repeatCount--) {
[device invokeCommandWithEndpointId:[NSNumber numberWithUnsignedShort:endpointId]
clusterId:[NSNumber numberWithUnsignedInteger:clusterId]
commandId:[NSNumber numberWithUnsignedInteger:commandId]
commandFields:commandFields
timedInvokeTimeout:mTimedInteractionTimeoutMs.HasValue()
? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()]
: nil
clientQueue:callbackQueue
completion:^(
NSArray<NSDictionary<NSString *, id> *> * _Nullable values, NSError * _Nullable error) {
CHIP_ERROR err = [CHIPError errorToCHIPErrorCode:error];
responsesNeeded--;
if (err != CHIP_NO_ERROR) {
mError = err;
ChipLogProgress(chipTool, "Error: %s", chip::ErrorStr(err));
}
if (responsesNeeded == 0) {
SetCommandExitStatus(mError);
}
}];

if (mRepeatDelayInMs.HasValue()) {
chip::test_utils::SleepMillis(mRepeatDelayInMs.Value());
}
}
return CHIP_NO_ERROR;
}

protected:
chip::Optional<uint16_t> mTimedInteractionTimeoutMs;
chip::Optional<uint16_t> mRepeatCount;
chip::Optional<uint16_t> mRepeatDelayInMs;
CHIP_ERROR mError = CHIP_NO_ERROR;

private:
chip::ClusterId mClusterId;
chip::CommandId mCommandId;

CustomArgument mPayload;
static constexpr uint32_t mDataMaxLen = 4096;
uint8_t * _Nullable mData = nullptr;
};
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class ModelCommand : public CHIPCommandBridge
CHIP_ERROR RunCommand() override;
chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(10); }

virtual CHIP_ERROR SendCommand(CHIPDevice * _Nullable device, chip::EndpointId endPointId) = 0;
virtual CHIP_ERROR SendCommand(CHIPDevice * _Nonnull device, chip::EndpointId endPointId) = 0;

private:
chip::NodeId mNodeId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
CHIP_ERROR err = CHIP_NO_ERROR;
if (error) {
err = [CHIPError errorToCHIPErrorCode:error];
} else if (device == nil) {
err = CHIP_ERROR_INTERNAL;
} else {
err = SendCommand(device, mEndPointId);
}
Expand Down
231 changes: 231 additions & 0 deletions examples/chip-tool-darwin/commands/clusters/ReportCommandBridge.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
/*
* Copyright (c) 2022 Project CHIP Authors
* All rights reserved.
*
* 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.
*
*/

#pragma once

#include "ModelCommandBridge.h"

class ReadAttribute : public ModelCommand {
public:
ReadAttribute()
: ModelCommand("read-by-id")
{
AddArgument("cluster-id", 0, UINT32_MAX, &mClusterId);
AddArgument("attribute-id", 0, UINT32_MAX, &mAttributeId);
AddArgument("fabric-filtered", 0, 1, &mFabricFiltered);
ModelCommand::AddArguments();
}

ReadAttribute(chip::ClusterId clusterId)
: ModelCommand("read-by-id")
, mClusterId(clusterId)
{
AddArgument("attribute-id", 0, UINT32_MAX, &mAttributeId);
AddArgument("fabric-filtered", 0, 1, &mFabricFiltered);
ModelCommand::AddArguments();
}

ReadAttribute(const char * _Nonnull attributeName)
: ModelCommand("read")
{
AddArgument("attr-name", attributeName);
AddArgument("fabric-filtered", 0, 1, &mFabricFiltered);
ModelCommand::AddArguments();
}

~ReadAttribute() {}

CHIP_ERROR SendCommand(CHIPDevice * _Nonnull device, chip::EndpointId endpointId) override
{
dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL);
CHIPReadParams * params = [[CHIPReadParams alloc] init];
params.fabricFiltered = mFabricFiltered.HasValue() ? [NSNumber numberWithBool:mFabricFiltered.Value()] : nil;
[device
readAttributeWithEndpointId:[NSNumber numberWithUnsignedShort:endpointId]
clusterId:[NSNumber numberWithUnsignedInteger:mClusterId]
attributeId:[NSNumber numberWithUnsignedInteger:mAttributeId]
params:params
clientQueue:callbackQueue
completion:^(NSArray<NSDictionary<NSString *, id> *> * _Nullable values, NSError * _Nullable error) {
CHIP_ERROR err = [CHIPError errorToCHIPErrorCode:error];
if (values) {
for (id item in values) {
NSLog(@"Response Item: %@", [item description]);
}
}
if (err != CHIP_NO_ERROR) {
ChipLogError(chipTool, "Error: %s", chip::ErrorStr(err));
}
SetCommandExitStatus(err);
}];
return CHIP_NO_ERROR;
}

protected:
chip::Optional<bool> mFabricFiltered;

private:
chip::ClusterId mClusterId;
chip::AttributeId mAttributeId;
};

class SubscribeAttribute : public ModelCommand {
public:
SubscribeAttribute()
: ModelCommand("subscribe-by-id")
{
AddArgument("cluster-id", 0, UINT32_MAX, &mClusterId);
AddArgument("attribute-id", 0, UINT32_MAX, &mAttributeId);
AddArgument("min-interval", 0, UINT16_MAX, &mMinInterval);
AddArgument("max-interval", 0, UINT16_MAX, &mMaxInterval);
AddArgument("fabric-filtered", 0, 1, &mFabricFiltered);
AddArgument("keepSubscriptions", 0, 1, &mKeepSubscriptions);
AddArgument("wait", 0, 1, &mWait);
ModelCommand::AddArguments();
}

SubscribeAttribute(chip::ClusterId clusterId)
: ModelCommand("subscribe-by-id")
, mClusterId(clusterId)
{
AddArgument("attribute-id", 0, UINT32_MAX, &mAttributeId);
AddArgument("min-interval", 0, UINT16_MAX, &mMinInterval);
AddArgument("max-interval", 0, UINT16_MAX, &mMaxInterval);
AddArgument("fabric-filtered", 0, 1, &mFabricFiltered);
AddArgument("keepSubscriptions", 0, 1, &mKeepSubscriptions);
AddArgument("wait", 0, 1, &mWait);
ModelCommand::AddArguments();
}

SubscribeAttribute(const char * _Nonnull attributeName)
: ModelCommand("subscribe")
{
AddArgument("attr-name", attributeName);
AddArgument("min-interval", 0, UINT16_MAX, &mMinInterval);
AddArgument("max-interval", 0, UINT16_MAX, &mMaxInterval);
AddArgument("fabric-filtered", 0, 1, &mFabricFiltered);
AddArgument("keepSubscriptions", 0, 1, &mKeepSubscriptions);
AddArgument("wait", 0, 1, &mWait);
ModelCommand::AddArguments();
}

~SubscribeAttribute() {}

CHIP_ERROR SendCommand(CHIPDevice * _Nonnull device, chip::EndpointId endpointId) override
{
dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL);
CHIPSubscribeParams * params = [[CHIPSubscribeParams alloc] init];
params.keepPreviousSubscriptions
= mKeepSubscriptions.HasValue() ? [NSNumber numberWithBool:mKeepSubscriptions.Value()] : nil;
[device subscribeAttributeWithEndpointId:[NSNumber numberWithUnsignedShort:endpointId]
clusterId:[NSNumber numberWithUnsignedInteger:mClusterId]
attributeId:[NSNumber numberWithUnsignedInteger:mAttributeId]
minInterval:[NSNumber numberWithUnsignedInteger:mMinInterval]
maxInterval:[NSNumber numberWithUnsignedInteger:mMaxInterval]
params:params
clientQueue:callbackQueue
reportHandler:^(
NSArray<NSDictionary<NSString *, id> *> * _Nullable values, NSError * _Nullable error) {
if (values) {
for (id item in values) {
NSLog(@"Response Item: %@", [item description]);
}
}
if (error || !mWait) {
SetCommandExitStatus([CHIPError errorToCHIPErrorCode:error]);
}
}
subscriptionEstablished:nil];

return CHIP_NO_ERROR;
}

protected:
chip::Optional<bool> mKeepSubscriptions;
chip::Optional<bool> mFabricFiltered;
uint16_t mMinInterval;
uint16_t mMaxInterval;
bool mWait;

private:
chip::ClusterId mClusterId;
chip::AttributeId mAttributeId;
};

class SubscribeEvent : public ModelCommand {
public:
SubscribeEvent()
: ModelCommand("subscribe-all-events")
{
AddArgument("min-interval", 0, UINT16_MAX, &mMinInterval);
AddArgument("max-interval", 0, UINT16_MAX, &mMaxInterval);
AddArgument("keepSubscriptions", 0, 1, &mKeepSubscriptions);
AddArgument("wait", 0, 1, &mWait);
ModelCommand::AddArguments();
}

~SubscribeEvent() {}

CHIP_ERROR SendCommand(CHIPDevice * _Nonnull device, chip::EndpointId endpointId) override
{
dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL);

CHIPSubscribeParams * params = [[CHIPSubscribeParams alloc] init];
params.keepPreviousSubscriptions
= mKeepSubscriptions.HasValue() ? [NSNumber numberWithBool:mKeepSubscriptions.Value()] : nil;
[device subscribeWithQueue:callbackQueue
minInterval:mMinInterval
maxInterval:mMaxInterval
params:params
cacheContainer:nil
attributeReportHandler:^(NSArray * value) {
if (!mWait) {
SetCommandExitStatus(CHIP_NO_ERROR);
}
}
eventReportHandler:^(NSArray * value) {
for (id item in value) {
NSLog(@"Response Item: %@", [item description]);
}
if (!mWait) {
SetCommandExitStatus(CHIP_NO_ERROR);
}
}
errorHandler:^(NSError * error) {
if (error && !mWait) {
SetCommandExitStatus([CHIPError errorToCHIPErrorCode:error]);
}
}
subscriptionEstablished:^() {
}];

return CHIP_NO_ERROR;
}

chip::System::Clock::Timeout GetWaitDuration() const override
{
return chip::System::Clock::Seconds16(mWait ? UINT16_MAX : 10);
}

protected:
chip::Optional<bool> mKeepSubscriptions;
chip::Optional<chip::EventNumber> mEventNumber;
uint16_t mMinInterval;
uint16_t mMaxInterval;
bool mWait;
};
Loading

0 comments on commit 228b885

Please sign in to comment.