Skip to content

Commit

Permalink
Fix chip-tool logging to work for various interesting data types. (#1…
Browse files Browse the repository at this point in the history
…1404)

Optional values, nullable types, etc, etc.

Fixes #11214
Fixes #11215
  • Loading branch information
bzbarsky-apple authored and pull[bot] committed May 5, 2023
1 parent 82f4a1d commit b77a3f0
Show file tree
Hide file tree
Showing 2 changed files with 3,125 additions and 1,300 deletions.
224 changes: 149 additions & 75 deletions examples/chip-tool/templates/commands.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,156 @@
#pragma once

#include <cstdint>
#include <string>
#include <type_traits>

#include <app-common/zap-generated/cluster-objects.h>
#include <app/data-model/DecodableList.h>
#include <app/data-model/Nullable.h>
#include <commands/clusters/ModelCommand.h>
#include <lib/core/CHIPSafeCasts.h>
#include <lib/support/BytesToHex.h>
#include <lib/support/Span.h>
#include <lib/support/TypeTraits.h>
#include <zap-generated/CHIPClientCallbacks.h>
#include <zap-generated/CHIPClusters.h>

// Value logging functions. The non-generated ones depend on the
// generated ones, so are placed here.
namespace {

{{#zcl_clusters}}
{{#zcl_structs}}
CHIP_ERROR LogValue(const char * label, size_t indent, {{zapTypeToDecodableClusterObjectType name ns=parent.name isArgument=true}} value);
{{/zcl_structs}}
{{/zcl_clusters}}

#if CHIP_PROGRESS_LOGGING
std::string IndentStr(size_t indent)
{
std::string str;
for (size_t i = 0; i < indent; ++i) {
str.append(" ");
}
return str;
}
#endif // CHIP_PROGRESS_LOGGING

template <typename X, typename std::enable_if_t<std::is_integral<X>::value && !std::is_same<std::remove_cv_t<std::remove_reference_t<X>>, bool>::value, int> = 0>
CHIP_ERROR LogValue(const char * label, size_t indent, X value)
{
ChipLogProgress(chipTool, "%s%s: %s", IndentStr(indent).c_str(), label, std::to_string(value).c_str());
return CHIP_NO_ERROR;
}

CHIP_ERROR LogValue(const char * label, size_t indent, bool value)
{
ChipLogProgress(chipTool, "%s%s: %s", IndentStr(indent).c_str(), label, value ? "TRUE" : "FALSE");
return CHIP_NO_ERROR;
}

template <typename X, typename std::enable_if_t<std::is_enum<X>::value, int> = 0>
CHIP_ERROR LogValue(const char * label, size_t indent, X value)
{
return LogValue(label, indent, chip::to_underlying(value));
}


CHIP_ERROR LogValue(const char * label, size_t indent, chip::CharSpan value)
{
ChipLogProgress(chipTool, "%s%s: %.*s", IndentStr(indent).c_str(), label, static_cast<int>(value.size()), value.data());
return CHIP_NO_ERROR;
}

CHIP_ERROR LogValue(const char * label, size_t indent, chip::ByteSpan value)
{
ChipLogProgress(chipTool, "%s%s: %zu", IndentStr(indent).c_str(), label, value.size());
return CHIP_NO_ERROR;
}

template <typename X>
CHIP_ERROR LogValue(const char * label, size_t indent, chip::BitFlags<X> value)
{
return LogValue(label, indent, value.Raw());
}

template <typename T>
CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::DataModel::DecodableList<T> & value)
{
size_t count = 0;
CHIP_ERROR err = value.ComputeSize(&count);
if (err != CHIP_NO_ERROR)
{
return err;
}
ChipLogProgress(chipTool, "%s%s: %zu entries", IndentStr(indent).c_str(), label, count);

auto iter = value.begin();
size_t i = 0;
while (iter.Next())
{
++i;
std::string itemLabel = std::string("[") + std::to_string(i) + "]";
ReturnErrorOnFailure(LogValue(itemLabel.c_str(), indent + 1, iter.GetValue()));
}
if (iter.GetStatus() != CHIP_NO_ERROR)
{
ChipLogProgress(chipTool, "%sList truncated due to invalid value", IndentStr(indent+1).c_str());
}
return iter.GetStatus();
}


template <typename T>
CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::DataModel::Nullable<T> & value)
{
if (!value.IsNull())
{
return LogValue(label, indent, value.Value());
}
ChipLogProgress(chipTool, "%s%s: null", IndentStr(indent).c_str(), label);
return CHIP_NO_ERROR;
}

template <typename T>
CHIP_ERROR LogValue(const char * label, size_t indent, const chip::Optional<T> & value)
{
if (value.HasValue())
{
return LogValue(label, indent, value.Value());
}

return CHIP_NO_ERROR;
}

// We output helpers for all structs here, including ones we might not actually
// be logging.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
{{#zcl_clusters}}
{{#zcl_structs}}
CHIP_ERROR LogValue(const char * label, size_t indent, {{zapTypeToDecodableClusterObjectType name ns=parent.name isArgument=true}} value)
{
ChipLogProgress(chipTool, "%s%s: {", IndentStr(indent).c_str(), label);
{{#zcl_struct_items}}
{
CHIP_ERROR err = LogValue("{{asUpperCamelCase label}}", indent + 1, value.{{asLowerCamelCase label}});
if (err != CHIP_NO_ERROR)
{
ChipLogProgress(chipTool, "%sStruct truncated due to invalid value for '{{asUpperCamelCase label}}'", IndentStr(indent + 1).c_str());
return err;
}
}
{{/zcl_struct_items}}
ChipLogProgress(chipTool, "%s}", IndentStr(indent).c_str());
return CHIP_NO_ERROR;
}
{{/zcl_structs}}
{{/zcl_clusters}}
#pragma GCC diagnostic pop

} // anonymous namespace

static void OnDefaultSuccessResponse(void * context)
{
ChipLogProgress(chipTool, "Default Success Response");
Expand Down Expand Up @@ -136,69 +277,10 @@ static void OnCharStringAttributeResponse(void * context, const chip::CharSpan v
{{#if isList}}
static void On{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}ListAttributeResponse(void * context, {{zapTypeToDecodableClusterObjectType type ns=parent.name isArgument=true}} list)
{
ModelCommand * command = static_cast<ModelCommand *>(context);

size_t count = 0;
CHIP_ERROR err = list.ComputeSize(&count);
if (err != CHIP_NO_ERROR) {
command->SetCommandExitStatus(err);
return;
}

ChipLogProgress(chipTool, "On{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}ListAttributeResponse: %zu entries", count);
CHIP_ERROR err = LogValue("On{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}ListAttributeResponse", 0, list);

auto iter = list.begin();
uint16_t i = 0;
while (iter.Next())
{
++i;
#if CHIP_PROGRESS_LOGGING
auto & entry = iter.GetValue();
{{#if isStruct}}
ChipLogProgress(chipTool, "{{type}}[%" PRIu16 "]:", i);
{{#chip_attribute_list_entryTypes}}
{{~#*inline "field"}}entry.{{asLowerCamelCase name}}{{#if isOptional}}.Value(){{/if}}{{/inline~}}
{{~#*inline "fieldValue"}}{{>field}}{{#if isNullable}}.Value(){{/if}}{{/inline~}}
{{#if isOptional}}
if (entry.{{asLowerCamelCase name}}.HasValue()) {
{{/if}}
{{#if isNullable}}
if ({{>field}}.IsNull()) {
ChipLogProgress(chipTool, " {{asSymbol label}}: null");
} else {
{{/if}}
{{#if isArray}}
{{! TODO: Add support for printing list member of struct element of list attribute }}
ChipLogProgress(chipTool, " {{asSymbol label}}: list member of struct element of list attribute printing not supported yet");
{{else if (isOctetString type)}}
ChipLogProgress(Zcl, " {{asSymbol label}}: %zu", {{>fieldValue}}.size());
{{else if (isCharString type)}}
ChipLogProgress(Zcl, " {{asSymbol label}}: %.*s", static_cast<int>({{>fieldValue}}.size()), {{>fieldValue}}.data());
{{else if isStruct}}
{{! TODO: Add support for printing struct member of struct element of list attribute }}
ChipLogProgress(chipTool, " {{asSymbol label}}: struct member of struct element of list attribute printing not supported yet");
{{else}}
ChipLogProgress(chipTool, " {{asSymbol label}}: {{asPrintFormat type}}", {{>fieldValue}});
{{/if}}
{{#if isNullable}}
}
{{/if}}
{{#if isOptional}}
}
{{/if}}
{{/chip_attribute_list_entryTypes}}
{{else}}
{{#if (isOctetString type)}}
ChipLogProgress(Zcl, " {{asSymbol label}}: %zu", entry.size());
{{else if (isCharString type)}}
ChipLogProgress(Zcl, " {{asSymbol label}}: %.*s", static_cast<int>(entry.size()), entry.data());
{{else}}
ChipLogProgress(chipTool, "{{type}}[%" PRIu16 "]: {{asPrintFormat type}}", i, entry);
{{/if}}
{{/if}}
#endif // CHIP_PROGRESS_LOGGING
}
command->SetCommandExitStatus(iter.GetStatus());
ModelCommand * command = static_cast<ModelCommand *>(context);
command->SetCommandExitStatus(err);
}

{{/if}}
Expand All @@ -210,23 +292,15 @@ static void On{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}ListAttri
static void On{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}Success(void * context, const chip::app::Clusters::{{asUpperCamelCase parent.name}}::Commands::{{asUpperCamelCase name}}::DecodableType & data)
{
ChipLogProgress(Zcl, "Received {{asUpperCamelCase name}}:");
CHIP_ERROR err = CHIP_NO_ERROR;
{{#chip_cluster_response_arguments}}
{{~#*inline "field"}}data.{{asLowerCamelCase label}}{{/inline~}}
{{#if isArray}}
ChipLogProgress(Zcl, " {{label}}: Array printing is not implemented yet.");
{{else if isOptional}}
ChipLogProgress(Zcl, " {{label}}: Optional printing is not implemented yet.");
{{else if (isOctetString type)}}
ChipLogProgress(Zcl, " {{label}}: %zu", {{>field}}.size());
{{else if (isCharString type)}}
ChipLogProgress(Zcl, " {{label}}: %.*s", static_cast<int>({{>field}}.size()), {{>field}}.data());
{{else}}
ChipLogProgress(Zcl, " {{label}}: {{asPrintFormat type}}", {{>field}});
{{/if}}
if (err == CHIP_NO_ERROR) {
err = LogValue("{{asLowerCamelCase label}}", 1, data.{{asLowerCamelCase label}});
}
{{/chip_cluster_response_arguments}}

ModelCommand * command = static_cast<ModelCommand *>(context);
command->SetCommandExitStatus(CHIP_NO_ERROR);
command->SetCommandExitStatus(err);
};

{{/chip_cluster_responses}}
Expand Down
Loading

0 comments on commit b77a3f0

Please sign in to comment.