Skip to content

Commit

Permalink
Merge branch 'master' into add_command_id_checks
Browse files Browse the repository at this point in the history
  • Loading branch information
soares-sergio authored Oct 11, 2024
2 parents e64bb91 + 7287041 commit 18941dc
Show file tree
Hide file tree
Showing 47 changed files with 15,234 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class Converter():
def __init__(self, specifications):
self.__specs = specifications
self.__converters = [
DarwinAnyFormatConverter(),
StructFieldsNameConverter(),
FloatConverter(),
OctetStringConverter()
Expand Down Expand Up @@ -252,6 +253,43 @@ def maybe_convert(self, typename: str, value):
return value


class DarwinAnyFormatConverter(BaseConverter):
"""
Darwin payloads format for *ById commands is different from the base
format used for other commands.
"""

def run(self, specs, value, cluster_name: str, typename: str, array: bool):
if isinstance(value, list) and len(value) >= 1 and isinstance(value[0], dict) and value[0].get('data') is not None:
value = [self.__convert(item_value) for item_value in value]
return value

def __convert(self, value):
if not isinstance(value, dict):
return value

data = value.get('data')
if not isinstance(data, dict):
return value

value = data.get('value')
if not isinstance(value, list):
return value

value_type = data.get('type')

if value_type == 'Structure':
struct = {}
for field in value:
context_tag = field.get('contextTag')
struct[str(context_tag)] = self.__convert(field)
value = struct
elif value_type == 'Array':
value = [self.__convert(item_value) for item_value in value]

return value


class FloatConverter(BaseConverter):
"""
Jsoncpp stores floats as double.
Expand Down Expand Up @@ -348,7 +386,7 @@ def run(self, specs, value, cluster_name: str, typename: str, array: bool):
del value[key_name]

elif isinstance(value, list) and array:
value = [self.run(specs, v, cluster_name, typename, False)
value = [self.run(specs, v, cluster_name, typename, isinstance(v, list))
for v in value]

return value
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,16 @@ def __get_alias(self, cluster_name: str, command_name: str = None, argument_name
if aliases is None or aliases.get(argument_name) is None:
return None

return aliases.get(argument_name)
value = aliases.get(argument_name)

if cluster_name == '*' and self.__is_darwin_framework_tool:
if argument_name == 'AttributeId':
return 'attribute-id'
elif argument_name == 'ClusterId':
return 'cluster-id'
elif argument_name == 'Value':
return 'attribute-value'
return value

def _supports_endpoint(self, request):
return self._has_support(request, 'has_endpoint')
Expand Down
5 changes: 5 additions & 0 deletions examples/darwin-framework-tool/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ executable("darwin-framework-tool") {
"commands/discover/Commands.h",
"commands/discover/DiscoverCommissionablesCommand.h",
"commands/discover/DiscoverCommissionablesCommand.mm",
"commands/memory/Commands.h",
"commands/memory/DumpMemoryGraphCommand.h",
"commands/memory/DumpMemoryGraphCommand.mm",
"commands/memory/LeaksTool.h",
"commands/memory/LeaksTool.mm",
"commands/pairing/Commands.h",
"commands/pairing/DeviceControllerDelegateBridge.mm",
"commands/pairing/GetCommissionerNodeIdCommand.h",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,13 @@ class ClusterCommand : public ModelCommand {
uint16_t __block responsesNeeded = repeatCount;
dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);

__auto_type * endpoint = @(endpointId);
__auto_type * cluster = @(clusterId);
__auto_type * command = @(commandId);
while (repeatCount--) {
[device invokeCommandWithEndpointID:[NSNumber numberWithUnsignedShort:endpointId]
clusterID:[NSNumber numberWithUnsignedInteger:clusterId]
commandID:[NSNumber numberWithUnsignedInteger:commandId]
[device invokeCommandWithEndpointID:endpoint
clusterID:cluster
commandID:command
commandFields:commandFields
timedInvokeTimeout:mTimedInteractionTimeoutMs.HasValue()
? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()]
Expand All @@ -88,6 +91,9 @@ class ClusterCommand : public ModelCommand {
if (error != nil) {
mError = error;
LogNSError("Error", error);
RemoteDataModelLogger::LogCommandErrorAsJSON(endpoint, cluster, command, error);
} else {
RemoteDataModelLogger::LogCommandAsJSON(endpoint, cluster, command, values);
}
if (responsesNeeded == 0) {
SetCommandExitStatus(mError);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,26 @@ class ReadAttribute : public ModelCommand {
if (mFabricFiltered.HasValue()) {
params.filterByFabric = mFabricFiltered.Value();
}

__auto_type * endpoint = @(endpointId);
__auto_type * cluster = @(mClusterId);
__auto_type * attribute = @(mAttributeId);
[device
readAttributesWithEndpointID:[NSNumber numberWithUnsignedShort:endpointId]
clusterID:[NSNumber numberWithUnsignedInteger:mClusterId]
attributeID:[NSNumber numberWithUnsignedInteger:mAttributeId]
readAttributesWithEndpointID:endpoint
clusterID:cluster
attributeID:attribute
params:params
queue:callbackQueue
completion:^(NSArray<NSDictionary<NSString *, id> *> * _Nullable values, NSError * _Nullable error) {
if (error != nil) {
LogNSError("Error reading attribute", error);
RemoteDataModelLogger::LogAttributeErrorAsJSON(endpoint, cluster, attribute, error);
}
if (values) {
for (id item in values) {
NSLog(@"Response Item: %@", [item description]);
}
RemoteDataModelLogger::LogAttributeAsJSON(endpoint, cluster, attribute, values);
}
SetCommandExitStatus(error);
}];
Expand Down Expand Up @@ -137,16 +143,23 @@ class SubscribeAttribute : public ModelCommand {
params.resubscribeAutomatically = mAutoResubscribe.Value();
}

[device subscribeToAttributesWithEndpointID:[NSNumber numberWithUnsignedShort:endpointId]
clusterID:[NSNumber numberWithUnsignedInteger:mClusterId]
attributeID:[NSNumber numberWithUnsignedInteger:mAttributeId]
__auto_type * endpoint = @(endpointId);
__auto_type * cluster = @(mClusterId);
__auto_type * attribute = @(mAttributeId);
[device subscribeToAttributesWithEndpointID:endpoint
clusterID:cluster
attributeID:attribute
params:params
queue:callbackQueue
reportHandler:^(NSArray<NSDictionary<NSString *, id> *> * _Nullable values, NSError * _Nullable error) {
if (error != nil) {
RemoteDataModelLogger::LogAttributeErrorAsJSON(endpoint, cluster, attribute, error);
}
if (values) {
for (id item in values) {
NSLog(@"Response Item: %@", [item description]);
}
RemoteDataModelLogger::LogAttributeAsJSON(endpoint, cluster, attribute, values);
}
SetCommandExitStatus(error);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,13 @@ class WriteAttribute : public ModelCommand {
{
dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);

__auto_type * endpoint = @(endpointId);
__auto_type * cluster = @(mClusterId);
__auto_type * attribute = @(mAttributeId);
[device
writeAttributeWithEndpointID:[NSNumber numberWithUnsignedShort:endpointId]
clusterID:[NSNumber numberWithUnsignedInteger:clusterId]
attributeID:[NSNumber numberWithUnsignedInteger:attributeId]
writeAttributeWithEndpointID:endpoint
clusterID:cluster
attributeID:attribute
value:value
timedWriteTimeout:mTimedInteractionTimeoutMs.HasValue()
? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()]
Expand All @@ -86,11 +89,13 @@ class WriteAttribute : public ModelCommand {
completion:^(NSArray<NSDictionary<NSString *, id> *> * _Nullable values, NSError * _Nullable error) {
if (error != nil) {
LogNSError("Error writing attribute", error);
RemoteDataModelLogger::LogAttributeErrorAsJSON(endpoint, cluster, attribute, error);
}
if (values) {
for (id item in values) {
NSLog(@"Response Item: %@", [item description]);
}
RemoteDataModelLogger::LogAttributeAsJSON(endpoint, cluster, attribute, values);
}
SetCommandExitStatus(error);
}];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

#include <string>

constexpr char kAttributePathKey[] = "attributePath";
constexpr char kCommandPathKey[] = "commandPath";
constexpr char kClusterIdKey[] = "clusterId";
constexpr char kEndpointIdKey[] = "endpointId";
constexpr char kAttributeIdKey[] = "attributeId";
Expand Down Expand Up @@ -142,8 +144,45 @@ CHIP_ERROR LogAttributeAsJSON(NSNumber * endpointId, NSNumber * clusterId, NSNum

Json::Value jsonValue;
VerifyOrDie(CHIP_NO_ERROR == AsJsonValue(result, jsonValue));
value[kValueKey] = jsonValue;

// When using the *-by-id commands, the return format is always encapsulated
// within an array. If the attribute itself is an empty array, the result will
// appear as follows:
//
//[
// {
// attributePath = "<MTRAttributePath endpoint 0 cluster 0x41 (65, UserLabel) 0x0 (0, LabelList)>";
// data = {
// type = Array;
// value = (
// );
// };
// }
//]
bool hasData = false;
if (jsonValue.isArray() && !jsonValue.empty()) {
for (Json::ArrayIndex i = 0; i < jsonValue.size(); i++) {
if (jsonValue[i].isObject()) {
if (jsonValue[i].isMember(kAttributePathKey)) {
jsonValue[i].removeMember(kAttributePathKey);
}

if (!jsonValue[i].empty()) {
hasData = true;
}
} else {
hasData = true;
}
}
} else {
hasData = true;
}

if (!hasData) {
return CHIP_NO_ERROR;
}

value[kValueKey] = jsonValue;
auto valueStr = JsonToString(value);
return gDelegate->LogJSON(valueStr.c_str());
}
Expand All @@ -159,8 +198,31 @@ CHIP_ERROR LogCommandAsJSON(NSNumber * endpointId, NSNumber * clusterId, NSNumbe

Json::Value jsonValue;
VerifyOrDie(CHIP_NO_ERROR == AsJsonValue(result, jsonValue));
value[kValueKey] = jsonValue;

bool hasData = false;
if (jsonValue.isArray()) {
for (Json::ArrayIndex i = 0; i < jsonValue.size(); i++) {
if (jsonValue[i].isObject()) {
if (jsonValue[i].isMember(kCommandPathKey)) {
jsonValue[i].removeMember(kCommandPathKey);
}

if (!jsonValue[i].empty()) {
hasData = true;
}
} else {
hasData = true;
}
}
} else {
hasData = true;
}

if (!hasData) {
return CHIP_NO_ERROR;
}

value[kValueKey] = jsonValue;
auto valueStr = JsonToString(value);
return gDelegate->LogJSON(valueStr.c_str());
}
Expand Down
32 changes: 32 additions & 0 deletions examples/darwin-framework-tool/commands/memory/Commands.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2024 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 "commands/common/Commands.h"
#include "commands/memory/DumpMemoryGraphCommand.h"

void registerCommandsMemory(Commands & commands)
{
const char * clusterName = "memory";
commands_list clusterCommands = {
make_unique<DumpMemoryGraphCommand>(),
};

commands.RegisterCommandSet(clusterName, clusterCommands, "Commands for inspecting program memory.");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2024 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.
*
*/

#include "../common/CHIPCommandBridge.h"

#include <lib/core/Optional.h>

/**
* This command dump the memory graph of the program.
*/

class DumpMemoryGraphCommand : public CHIPCommandBridge
{
public:
DumpMemoryGraphCommand() : CHIPCommandBridge("dump-graph")
{
AddArgument("filepath", &mFilePath,
"An optional filepath to save the memory graph to. Defaults to 'darwin-framework-tool.memgraph");
}

/////////// CHIPCommandBridge Interface /////////
CHIP_ERROR RunCommand() override;
chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Milliseconds32(0); }

private:
chip::Optional<char *> mFilePath;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2024 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.
*
*/

#include "DumpMemoryGraphCommand.h"

#include "LeaksTool.h"

CHIP_ERROR DumpMemoryGraphCommand::RunCommand()
{
auto err = DumpMemoryGraph(mFilePath);
SetCommandExitStatus(err);
return err;
}
Loading

0 comments on commit 18941dc

Please sign in to comment.