From 12859308062a05b2465d41ee669c1f5424470b40 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas Date: Fri, 25 Oct 2024 20:45:05 +0200 Subject: [PATCH] [darwin-framework-tool] Add an optional -use-mtr-device argument to read-by-id and write-by-id commands (#36243) * [darwin-framework-tool][use-mtr-device] Add an option to send command using an MTRDevice instead of a MTRBaseDevice * [darwin-framework-tool][use-mtr-device] Add an implementation for reading attributes via an MTRDevice * [darwin-framework-tool][use-mtr-device] Add an implementation for writing attributes via an MTRDevice --- .../commands/clusters/ClusterCommandBridge.h | 2 + .../commands/clusters/ModelCommandBridge.h | 4 ++ .../commands/clusters/ModelCommandBridge.mm | 14 ++++-- .../commands/clusters/ReportCommandBridge.h | 43 +++++++++++++++++- .../clusters/WriteAttributeCommandBridge.h | 44 ++++++++++++++++++- .../commands/common/CHIPCommandBridge.h | 4 ++ .../commands/common/CHIPCommandBridge.mm | 11 +++++ 7 files changed, 115 insertions(+), 7 deletions(-) diff --git a/examples/darwin-framework-tool/commands/clusters/ClusterCommandBridge.h b/examples/darwin-framework-tool/commands/clusters/ClusterCommandBridge.h index 50b9cfed5d912b..c94d666de5fa6f 100644 --- a/examples/darwin-framework-tool/commands/clusters/ClusterCommandBridge.h +++ b/examples/darwin-framework-tool/commands/clusters/ClusterCommandBridge.h @@ -45,6 +45,8 @@ class ClusterCommand : public ModelCommand { ~ClusterCommand() {} + using ModelCommand::SendCommand; + CHIP_ERROR SendCommand(MTRBaseDevice * _Nonnull device, chip::EndpointId endpointId) override { id commandFields; diff --git a/examples/darwin-framework-tool/commands/clusters/ModelCommandBridge.h b/examples/darwin-framework-tool/commands/clusters/ModelCommandBridge.h index 8e5bb8f9842210..6f29bf165dcce5 100644 --- a/examples/darwin-framework-tool/commands/clusters/ModelCommandBridge.h +++ b/examples/darwin-framework-tool/commands/clusters/ModelCommandBridge.h @@ -52,6 +52,10 @@ class ModelCommand : public CHIPCommandBridge } virtual CHIP_ERROR SendCommand(MTRBaseDevice * _Nonnull device, chip::EndpointId endPointId) = 0; + virtual CHIP_ERROR SendCommand(MTRDevice * _Nonnull device, chip::EndpointId endPointId) { return CHIP_ERROR_NOT_IMPLEMENTED; } + +protected: + chip::Optional mUseMTRDevice; private: chip::NodeId mNodeId; diff --git a/examples/darwin-framework-tool/commands/clusters/ModelCommandBridge.mm b/examples/darwin-framework-tool/commands/clusters/ModelCommandBridge.mm index 47a29f80c3a4e5..c430364f53b96d 100644 --- a/examples/darwin-framework-tool/commands/clusters/ModelCommandBridge.mm +++ b/examples/darwin-framework-tool/commands/clusters/ModelCommandBridge.mm @@ -26,10 +26,18 @@ CHIP_ERROR ModelCommand::RunCommand() { ChipLogProgress(chipTool, "Sending command to node 0x" ChipLogFormatX64, ChipLogValueX64(mNodeId)); - auto * device = BaseDeviceWithNodeId(mNodeId); - VerifyOrReturnError(device != nil, CHIP_ERROR_INCORRECT_STATE); - CHIP_ERROR err = SendCommand(device, mEndPointId); + CHIP_ERROR err = CHIP_NO_ERROR; + + if (mUseMTRDevice.ValueOr(false)) { + auto * device = DeviceWithNodeId(mNodeId); + VerifyOrReturnError(device != nil, CHIP_ERROR_INCORRECT_STATE); + err = SendCommand(device, mEndPointId); + } else { + auto * device = BaseDeviceWithNodeId(mNodeId); + VerifyOrReturnError(device != nil, CHIP_ERROR_INCORRECT_STATE); + err = SendCommand(device, mEndPointId); + } if (err != CHIP_NO_ERROR) { ChipLogError(chipTool, "Error: %s", chip::ErrorStr(err)); diff --git a/examples/darwin-framework-tool/commands/clusters/ReportCommandBridge.h b/examples/darwin-framework-tool/commands/clusters/ReportCommandBridge.h index 1a2612b7e3b13d..cd8125e3b12273 100644 --- a/examples/darwin-framework-tool/commands/clusters/ReportCommandBridge.h +++ b/examples/darwin-framework-tool/commands/clusters/ReportCommandBridge.h @@ -28,7 +28,7 @@ class ReadAttribute : public ModelCommand { AddArgument("cluster-id", 0, UINT32_MAX, &mClusterId); AddArgument("attribute-id", 0, UINT32_MAX, &mAttributeId); AddArgument("fabric-filtered", 0, 1, &mFabricFiltered); - ModelCommand::AddArguments(); + AddCommonByIdArguments(); } ReadAttribute(chip::ClusterId clusterId) @@ -37,7 +37,7 @@ class ReadAttribute : public ModelCommand { { AddArgument("attribute-id", 0, UINT32_MAX, &mAttributeId); AddArgument("fabric-filtered", 0, 1, &mFabricFiltered); - ModelCommand::AddArguments(); + AddCommonByIdArguments(); } ReadAttribute(const char * _Nonnull attributeName) @@ -83,7 +83,46 @@ class ReadAttribute : public ModelCommand { return CHIP_NO_ERROR; } + CHIP_ERROR SendCommand(MTRDevice * _Nonnull device, chip::EndpointId endpointId) override + { + MTRReadParams * params = [[MTRReadParams alloc] init]; + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + + __auto_type * endpoint = @(endpointId); + __auto_type * cluster = @(mClusterId); + __auto_type * attribute = @(mAttributeId); + __auto_type values = [device readAttributeWithEndpointID:endpoint + clusterID:cluster + attributeID:attribute + params:params]; + + NSError * error = nil; + if (nil == values) { + __auto_type * userInfo = @ { @"reason" : @"No value available." }; + error = [NSError errorWithDomain:@"Error" code:0 userInfo:userInfo]; + LogNSError("Error reading attribute", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(endpoint, cluster, attribute, error); + } else { + for (id item in values) { + NSLog(@"Response Item: %@", [item description]); + } + RemoteDataModelLogger::LogAttributeAsJSON(endpoint, cluster, attribute, values); + } + + SetCommandExitStatus(error); + return CHIP_NO_ERROR; + } + protected: + void AddCommonByIdArguments() + { + AddArgument("use-mtr-device", 0, 1, &mUseMTRDevice, + "Use MTRDevice instead of MTRBaseDevice to send this command. Default is false."); + ModelCommand::AddArguments(); + } + chip::Optional mFabricFiltered; private: diff --git a/examples/darwin-framework-tool/commands/clusters/WriteAttributeCommandBridge.h b/examples/darwin-framework-tool/commands/clusters/WriteAttributeCommandBridge.h index f274ea21aa654b..0a779740b9dc05 100644 --- a/examples/darwin-framework-tool/commands/clusters/WriteAttributeCommandBridge.h +++ b/examples/darwin-framework-tool/commands/clusters/WriteAttributeCommandBridge.h @@ -25,6 +25,8 @@ #import "MTRError_Utils.h" #import +constexpr uint32_t kDefaultExpectedValueInterval = 60000; + class WriteAttribute : public ModelCommand { public: WriteAttribute() @@ -33,7 +35,7 @@ class WriteAttribute : public ModelCommand { AddArgument("cluster-id", 0, UINT32_MAX, &mClusterId); AddArgument("attribute-id", 0, UINT32_MAX, &mAttributeId); AddArgument("attribute-value", &mAttributeValue); - AddArguments(); + AddCommonByIdArguments(); } WriteAttribute(chip::ClusterId clusterId) @@ -42,7 +44,7 @@ class WriteAttribute : public ModelCommand { { AddArgument("attribute-id", 0, UINT32_MAX, &mAttributeId); AddArgument("attribute-value", &mAttributeValue); - AddArguments(); + AddCommonByIdArguments(); } ~WriteAttribute() {} @@ -54,6 +56,13 @@ class WriteAttribute : public ModelCommand { return WriteAttribute::SendCommand(device, endpointId, mClusterId, mAttributeId, value); } + CHIP_ERROR SendCommand(MTRDevice * _Nonnull device, chip::EndpointId endpointId) override + { + id value; + ReturnErrorOnFailure(GetValue(&value)); + return WriteAttribute::SendCommand(device, endpointId, mClusterId, mAttributeId, value); + } + CHIP_ERROR SendCommand(MTRBaseDevice * _Nonnull device, chip::EndpointId endpointId, chip::ClusterId clusterId, chip::AttributeId attributeId, id _Nonnull value) { @@ -87,6 +96,28 @@ class WriteAttribute : public ModelCommand { return CHIP_NO_ERROR; } + CHIP_ERROR SendCommand(MTRDevice * _Nonnull device, chip::EndpointId endpointId, chip::ClusterId clusterId, + chip::AttributeId attributeId, id _Nonnull value) + { + __auto_type * endpoint = @(endpointId); + __auto_type * cluster = @(mClusterId); + __auto_type * attribute = @(mAttributeId); + __auto_type * expectedValueInterval = @(mExpectedValueInterval.ValueOr(kDefaultExpectedValueInterval)); + __auto_type * timedWriteTimeout = mTimedInteractionTimeoutMs.HasValue() + ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] + : nil; + + [device writeAttributeWithEndpointID:endpoint + clusterID:cluster + attributeID:attribute + value:value + expectedValueInterval:expectedValueInterval + timedWriteTimeout:timedWriteTimeout]; + + SetCommandExitStatus(CHIP_NO_ERROR); + return CHIP_NO_ERROR; + } + protected: WriteAttribute(const char * _Nonnull attributeName) : ModelCommand("write") @@ -95,6 +126,14 @@ class WriteAttribute : public ModelCommand { // Subclasses are responsible for calling AddArguments. } + void AddCommonByIdArguments() + { + AddArgument("use-mtr-device", 0, 1, &mUseMTRDevice, + "Use MTRDevice instead of MTRBaseDevice to send this command. Default is false."); + AddArgument("expectedValueInterval", 0, UINT32_MAX, &mExpectedValueInterval, "When the write is issued using an MTRDevice (via –use-mtr-device), specify the maximum interval (in milliseconds) during which reads of the attribute will return the expected value. The default is 60000 milliseconds (60 seconds)."); + AddArguments(); + } + void AddArguments() { AddArgument("timedInteractionTimeoutMs", 0, UINT16_MAX, &mTimedInteractionTimeoutMs, @@ -104,6 +143,7 @@ class WriteAttribute : public ModelCommand { } chip::Optional mTimedInteractionTimeoutMs; + chip::Optional mExpectedValueInterval; chip::Optional mDataVersion; private: diff --git a/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h b/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h index f58251bff48dd0..3466972f1f6f25 100644 --- a/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h +++ b/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h @@ -97,6 +97,10 @@ class CHIPCommandBridge : public Command { // Will utilize an existing PASE connection if the device is being commissioned. MTRBaseDevice * BaseDeviceWithNodeId(chip::NodeId nodeId); + // Returns the MTRDevice for the specified node ID. + // Will utilize an existing PASE connection if the device is being commissioned. + MTRDevice * DeviceWithNodeId(chip::NodeId nodeId); + // Will log the given string and given error (as progress if success, error // if failure). void LogNSError(const char * logString, NSError * error); diff --git a/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.mm b/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.mm index 724a9a20c3a571..85ce8d8935bec0 100644 --- a/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.mm +++ b/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.mm @@ -285,6 +285,17 @@ ?: [MTRBaseDevice deviceWithNodeID:@(nodeId) controller:controller]; } +MTRDevice * CHIPCommandBridge::DeviceWithNodeId(chip::NodeId nodeId) +{ + __auto_type * controller = CurrentCommissioner(); + VerifyOrReturnValue(nil != controller, nil); + + __auto_type * device = [MTRDevice deviceWithNodeID:@(nodeId) controller:controller]; + VerifyOrReturnValue(nil != device, nil); + + return device; +} + void CHIPCommandBridge::StopCommissioners() { for (auto & pair : mControllers) {