Add trace messages for automation (#12732)
Add a trace backend to linux/chip-tool which provides a simple
and flexible way to trace chip messages. The backend provides
handlers, which can be registered to handle the different
types of messages and extract the relevant data needed for
test automation.
Added additional optional flags to chip-tool which allows turning
on these traces and piping them either to a log or file. These
flags and tracing are only enabled when tracing is enabled at
compile time. Include trace compile with:
gn gen out/with_trace/ --args='import("//with_pw_trace.gni")'
The trace point is before the encrypt in SecureMessageCodec and
only enabled when chip_enable_transport_trace is defined at compile
time and a pw_trace backend is configured.
diff --git a/examples/chip-tool/BUILD.gn b/examples/chip-tool/BUILD.gn
index c78ea55..0ac0324 100644
--- a/examples/chip-tool/BUILD.gn
+++ b/examples/chip-tool/BUILD.gn
@@ -16,6 +16,7 @@
import("//build_overrides/chip.gni")
import("${chip_root}/build/chip/tools.gni")
+import("${chip_root}/src/lib/core/core.gni")
assert(chip_build_tools)
@@ -68,5 +69,13 @@
"${chip_root}/zzz_generated/chip-tool",
]
+ if (chip_enable_transport_trace) {
+ deps += [ "${chip_root}/examples/common/tracing:trace_handlers" ]
+ }
+
output_dir = root_out_dir
}
+
+group("default") {
+ deps = [ ":chip-tool" ]
+}
diff --git a/examples/chip-tool/README.md b/examples/chip-tool/README.md
index 61a23a6..cbe544a 100644
--- a/examples/chip-tool/README.md
+++ b/examples/chip-tool/README.md
@@ -29,6 +29,28 @@
which puts the binary at `SOME-PATH/chip-tool`.
+### Building with message tracing
+
+Message tracing allows capture of the secure messages which can be used for test
+automation.
+
+```
+gn gen out/with_trace/ --args='import("//with_pw_trace.gni")'
+ninja -C out/with_trace chip-tool
+```
+
+This enables tracing and adds additional flags to chip-tool to control where the
+traces should go:
+
+- --trace_file <file> Outputs trace data to the specified file.
+- --trace_log Outputs trace data to the chip log stream.
+
+For example:
+
+```
+out/with_trace/chip-tool --trace_file trace.log pairing <pairing_args>
+```
+
## Using the Client to commission a device
In order to send commands to a device, it must be commissioned with the client.
diff --git a/examples/chip-tool/commands/common/Commands.cpp b/examples/chip-tool/commands/common/Commands.cpp
index 555c03a..f289c4e 100644
--- a/examples/chip-tool/commands/common/Commands.cpp
+++ b/examples/chip-tool/commands/common/Commands.cpp
@@ -26,6 +26,79 @@
#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>
+#include <lib/support/CHIPArgParser.hpp>
+
+#include <core/CHIPBuildConfig.h>
+
+#if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
+#include "TraceHandlers.h"
+#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
+
+namespace {
+
+#if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
+enum
+{
+ kOptionTraceFile = 0x1000,
+ kOptionTraceLog,
+};
+
+bool HandleTraceOptions(const char * program, chip::ArgParser::OptionSet * options, int identifier, const char * name,
+ const char * value)
+{
+ switch (identifier)
+ {
+ case kOptionTraceLog:
+ chip::trace::SetTraceStream(new chip::trace::TraceStreamLog());
+ return true;
+ case kOptionTraceFile:
+ chip::trace::SetTraceStream(new chip::trace::TraceStreamFile(value));
+ return true;
+ default:
+ chip::ArgParser::PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", program, name);
+ return false;
+ }
+}
+
+chip::ArgParser::OptionDef traceCmdLineOptionDefs[] = { { "trace_file", chip::ArgParser::kArgumentRequired, kOptionTraceFile },
+ { "trace_log", chip::ArgParser::kNoArgument, kOptionTraceLog },
+ {} };
+
+const char * traceOptionHelp = " --trace_file <file>\n"
+ " Output trace data to the specified file.\n"
+ " --trace_log\n"
+ " Output trace data to the log stream.\n"
+ "\n";
+chip::ArgParser::OptionSet traceCmdLineOptions = { HandleTraceOptions, traceCmdLineOptionDefs, "TRACE OPTIONS", traceOptionHelp };
+#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
+
+const char * kAppName = "chip-tool";
+const char * kUsage = "Usage: chip-tool [options] cluster command_name [param1] [param2]";
+const char * kVersion = nullptr; // Unknown
+const char * kDescription = "A command line tool that uses Matter to send messages to a Matter server.";
+chip::ArgParser::HelpOptions helpOptions(kAppName, kUsage, kVersion, kDescription);
+
+chip::ArgParser::OptionSet * allOptions[] = {
+#if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
+ &traceCmdLineOptions,
+#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
+ &helpOptions, nullptr
+};
+
+int gPositionalArgc = 0;
+char ** gPositionalArgv = nullptr;
+const char * gProgramName = nullptr;
+
+bool GetPositionalArgs(const char * prog, int argc, char * argv[])
+{
+ gProgramName = prog;
+ gPositionalArgc = argc;
+ gPositionalArgv = argv;
+ return true;
+}
+
+} // namespace
+
void Commands::Register(const char * clusterName, commands_list commandsList)
{
for (auto & command : commandsList)
@@ -46,71 +119,81 @@
chip::Logging::SetLogFilter(mStorage.GetLoggingLevel());
- err = RunCommand(argc, argv);
+ VerifyOrExit(chip::ArgParser::ParseArgs("chip-tool", argc, argv, allOptions, GetPositionalArgs),
+ ChipLogError(chipTool, "Error parsing arguments"));
+
+#if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
+ chip::trace::InitTrace();
+#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
+
+ err = RunCommand();
VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(chipTool, "Run command failure: %s", chip::ErrorStr(err)));
exit:
+#if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
+ chip::trace::DeInitTrace();
+#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
return (err == CHIP_NO_ERROR) ? EXIT_SUCCESS : EXIT_FAILURE;
}
-CHIP_ERROR Commands::RunCommand(int argc, char ** argv)
+CHIP_ERROR Commands::RunCommand()
{
std::map<std::string, CommandsVector>::iterator cluster;
Command * command = nullptr;
- if (argc <= 1)
+ if (gPositionalArgc <= 0)
{
ChipLogError(chipTool, "Missing cluster name");
- ShowClusters(argv[0]);
+ ShowClusters(gProgramName);
return CHIP_ERROR_INVALID_ARGUMENT;
}
- cluster = GetCluster(argv[1]);
+ cluster = GetCluster(gPositionalArgv[0]);
if (cluster == mClusters.end())
{
- ChipLogError(chipTool, "Unknown cluster: %s", argv[1]);
- ShowClusters(argv[0]);
+ ChipLogError(chipTool, "Unknown cluster: %s", gPositionalArgv[1]);
+ ShowClusters(gProgramName);
return CHIP_ERROR_INVALID_ARGUMENT;
}
- if (argc <= 2)
+ if (gPositionalArgc <= 1)
{
ChipLogError(chipTool, "Missing command name");
- ShowCluster(argv[0], argv[1], cluster->second);
+ ShowCluster(gProgramName, gPositionalArgv[0], cluster->second);
return CHIP_ERROR_INVALID_ARGUMENT;
}
- if (!IsGlobalCommand(argv[2]))
+ if (!IsGlobalCommand(gPositionalArgv[1]))
{
- command = GetCommand(cluster->second, argv[2]);
+ command = GetCommand(cluster->second, gPositionalArgv[1]);
if (command == nullptr)
{
- ChipLogError(chipTool, "Unknown command: %s", argv[2]);
- ShowCluster(argv[0], argv[1], cluster->second);
+ ChipLogError(chipTool, "Unknown command: %s", gPositionalArgv[1]);
+ ShowCluster(gProgramName, gPositionalArgv[0], cluster->second);
return CHIP_ERROR_INVALID_ARGUMENT;
}
}
else
{
- if (argc <= 3)
+ if (gPositionalArgc <= 2)
{
ChipLogError(chipTool, "Missing attribute name");
- ShowClusterAttributes(argv[0], argv[1], argv[2], cluster->second);
+ ShowClusterAttributes(gProgramName, gPositionalArgv[0], gPositionalArgv[1], cluster->second);
return CHIP_ERROR_INVALID_ARGUMENT;
}
- command = GetGlobalCommand(cluster->second, argv[2], argv[3]);
+ command = GetGlobalCommand(cluster->second, gPositionalArgv[1], gPositionalArgv[2]);
if (command == nullptr)
{
- ChipLogError(chipTool, "Unknown attribute: %s", argv[3]);
- ShowClusterAttributes(argv[0], argv[1], argv[2], cluster->second);
+ ChipLogError(chipTool, "Unknown attribute: %s", gPositionalArgv[2]);
+ ShowClusterAttributes(gProgramName, gPositionalArgv[0], gPositionalArgv[1], cluster->second);
return CHIP_ERROR_INVALID_ARGUMENT;
}
}
- if (!command->InitArguments(argc - 3, &argv[3]))
+ if (!command->InitArguments(gPositionalArgc - 2, &gPositionalArgv[2]))
{
- ShowCommand(argv[0], argv[1], command);
+ ShowCommand(gProgramName, gPositionalArgv[0], command);
return CHIP_ERROR_INVALID_ARGUMENT;
}
diff --git a/examples/chip-tool/commands/common/Commands.h b/examples/chip-tool/commands/common/Commands.h
index 90dabbe..2196eaf 100644
--- a/examples/chip-tool/commands/common/Commands.h
+++ b/examples/chip-tool/commands/common/Commands.h
@@ -31,7 +31,8 @@
int Run(int argc, char ** argv);
private:
- CHIP_ERROR RunCommand(int argc, char ** argv);
+ CHIP_ERROR RunCommand();
+
std::map<std::string, CommandsVector>::iterator GetCluster(std::string clusterName);
Command * GetCommand(CommandsVector & commands, std::string commandName);
Command * GetGlobalCommand(CommandsVector & commands, std::string commandName, std::string attributeName);
diff --git a/examples/chip-tool/with_pw_trace.gni b/examples/chip-tool/with_pw_trace.gni
new file mode 100644
index 0000000..e433291
--- /dev/null
+++ b/examples/chip-tool/with_pw_trace.gni
@@ -0,0 +1,28 @@
+# Copyright (c) 2021 Project CHIP Authors
+#
+# 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.
+
+# add this gni as import in your build args to use pigweed in the example
+# 'import("//with_pw_rpc.gni")'
+
+import("//build_overrides/chip.gni")
+
+import("${chip_root}/config/standalone/args.gni")
+
+import("//build_overrides/pigweed.gni")
+
+cpp_standard = "gnu++17"
+
+pw_trace_BACKEND = "${chip_root}/examples/platform/linux/pw_trace_chip"
+
+chip_enable_transport_trace = true
diff --git a/examples/common/tracing/BUILD.gn b/examples/common/tracing/BUILD.gn
new file mode 100644
index 0000000..c05f869
--- /dev/null
+++ b/examples/common/tracing/BUILD.gn
@@ -0,0 +1,35 @@
+# Copyright (c) 2021 Project CHIP Authors
+#
+# 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.
+
+import("//build_overrides/pigweed.gni")
+
+import("//build_overrides/build.gni")
+import("//build_overrides/chip.gni")
+import("$dir_pw_build/target_types.gni")
+import("${chip_root}/src/lib/lib.gni")
+
+config("default_config") {
+ include_dirs = [ "." ]
+}
+
+source_set("trace_handlers") {
+ sources = [ "TraceHandlers.cpp" ]
+
+ deps = [
+ "$dir_pw_trace",
+ "${chip_root}/src/lib",
+ ]
+
+ public_configs = [ ":default_config" ]
+}
diff --git a/examples/common/tracing/README.md b/examples/common/tracing/README.md
new file mode 100644
index 0000000..154054b
--- /dev/null
+++ b/examples/common/tracing/README.md
@@ -0,0 +1,5 @@
+# Trace Handlers
+
+These are trace message handlers which get registered with pw_trace_chip and
+interpret the different CHIP messages to extract the useful information required
+for test automation.
diff --git a/examples/common/tracing/TraceHandlers.cpp b/examples/common/tracing/TraceHandlers.cpp
new file mode 100644
index 0000000..5842b3d
--- /dev/null
+++ b/examples/common/tracing/TraceHandlers.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2021 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 "TraceHandlers.h"
+
+#include <mutex>
+#include <stdint.h>
+#include <string>
+
+#include "pw_trace/trace.h"
+#include "pw_trace_chip/trace_chip.h"
+#include "transport/TraceMessage.h"
+#include <lib/support/logging/CHIPLogging.h>
+
+namespace chip {
+namespace trace {
+
+namespace {
+
+// Handles the output from the trace handlers.
+class TraceOutput
+{
+public:
+ ~TraceOutput() { DeleteStream(); }
+
+ void SetStream(TraceStream * stream)
+ {
+ std::lock_guard<std::mutex> guard(mLock);
+ if (mStream)
+ {
+ delete mStream;
+ mStream = nullptr;
+ }
+ mStream = stream;
+ }
+
+ void DeleteStream() { SetStream(nullptr); }
+
+ void Stream(const std::string & tag, const std::string & data)
+ {
+ std::lock_guard<std::mutex> guard(mLock);
+ if (mStream)
+ {
+ mStream->Stream(tag, data);
+ }
+ }
+
+ void Handler(const std::string & label)
+ {
+ std::lock_guard<std::mutex> guard(mLock);
+ if (mStream)
+ {
+ mStream->Handler(label);
+ }
+ }
+
+private:
+ std::mutex mLock;
+ TraceStream * mStream = nullptr;
+};
+
+TraceOutput output;
+
+// TODO: Framework this into a registry of handlers for different message types.
+bool TraceDefaultHandler(const TraceEventFields & trace)
+{
+ if (strcmp(trace.dataFormat, kTraceSecureMessageDataFormat) != 0 || trace.dataSize != sizeof(TraceSecureMessageData))
+ {
+ return false;
+ }
+
+ const TraceSecureMessageData * msg = reinterpret_cast<const TraceSecureMessageData *>(trace.dataBuffer);
+ output.Handler("Default");
+ output.Stream("ExchangeId", std::to_string(msg->payloadHeader->GetExchangeID()));
+ output.Stream("MsgType", std::to_string(msg->payloadHeader->GetMessageType()));
+ output.Stream("MessageCounter", std::to_string(msg->packetHeader->GetMessageCounter()));
+ output.Stream("PacketSize", std::to_string(msg->packetSize));
+
+ return true;
+}
+
+} // namespace
+
+void SetTraceStream(TraceStream * stream)
+{
+ output.SetStream(stream);
+}
+
+void InitTrace()
+{
+ RegisterTraceHandler(TraceDefaultHandler);
+}
+
+void DeInitTrace()
+{
+ UnregisterAllTraceHandlers();
+ output.DeleteStream();
+}
+
+} // namespace trace
+} // namespace chip
diff --git a/examples/common/tracing/TraceHandlers.h b/examples/common/tracing/TraceHandlers.h
new file mode 100644
index 0000000..434f253
--- /dev/null
+++ b/examples/common/tracing/TraceHandlers.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2021 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 <fstream>
+#include <iostream>
+#include <lib/support/logging/CHIPLogging.h>
+#include <string>
+#include <sys/time.h>
+
+namespace chip {
+namespace trace {
+
+class TraceStream
+{
+public:
+ virtual ~TraceStream() = default;
+ virtual void Stream(const std::string & tag, const std::string & data) = 0;
+ virtual void Handler(const std::string & label) = 0;
+};
+
+class TraceStreamLog : public TraceStream
+{
+public:
+ void Stream(const std::string & tag, const std::string & data) override
+ {
+ ChipLogAutomation(" %s: %s", tag.data(), data.data());
+ }
+ void Handler(const std::string & label) override { ChipLogAutomation("%s", label.data()); }
+};
+
+class TraceStreamFile : public TraceStream
+{
+public:
+ TraceStreamFile(const char * fileName) { mFile.open(fileName); }
+ ~TraceStreamFile() { mFile.close(); }
+
+ void Stream(const std::string & tag, const std::string & data) override
+ {
+ if (mFile.is_open())
+ {
+ mFile << " " << tag.data() << ": " << data.data() << "\n";
+ mFile.flush();
+ }
+ }
+ void Handler(const std::string & label) override
+ {
+ if (mFile.is_open())
+ {
+ struct timeval tv;
+ gettimeofday(&tv, nullptr);
+ mFile << label << " [" << tv.tv_sec << "." << tv.tv_usec << "]\n";
+ mFile.flush();
+ }
+ }
+
+private:
+ std::ofstream mFile;
+};
+
+void SetTraceStream(TraceStream * stream);
+void InitTrace();
+void DeInitTrace();
+
+} // namespace trace
+} // namespace chip
diff --git a/examples/platform/linux/pw_trace_chip/BUILD.gn b/examples/platform/linux/pw_trace_chip/BUILD.gn
new file mode 100644
index 0000000..91d4bbb
--- /dev/null
+++ b/examples/platform/linux/pw_trace_chip/BUILD.gn
@@ -0,0 +1,38 @@
+# Copyright (c) 2021 Project CHIP Authors
+#
+# 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.
+
+import("//build_overrides/chip.gni")
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/target_types.gni")
+
+config("public_include_path") {
+ include_dirs = [ "public" ]
+}
+
+config("backend_config") {
+ include_dirs = [ "public_overrides" ]
+}
+
+pw_source_set("pw_trace_chip") {
+ public_configs = [
+ ":backend_config",
+ ":public_include_path",
+ ]
+ include_dirs = [ "${chip_root}/src" ]
+ public_deps = [ "$dir_pw_status" ]
+ deps = [ "$dir_pw_trace:facade" ]
+ sources = [ "trace.cc" ]
+ public = [ "public_overrides/pw_trace_backend/trace_backend.h" ]
+}
diff --git a/examples/platform/linux/pw_trace_chip/public/pw_trace_chip/trace_chip.h b/examples/platform/linux/pw_trace_chip/public/pw_trace_chip/trace_chip.h
new file mode 100644
index 0000000..3eca633
--- /dev/null
+++ b/examples/platform/linux/pw_trace_chip/public/pw_trace_chip/trace_chip.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2021 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 <stdbool.h>
+#include <stdint.h>
+
+// Enable these trace types
+#define PW_TRACE_TYPE_INSTANT ::chip::trace::PW_TRACE_EVENT_TYPE_INSTANT
+#define PW_TRACE_TYPE_INSTANT_GROUP ::chip::trace::PW_TRACE_EVENT_TYPE_INSTANT_GROUP
+
+#define PW_TRACE_TYPE_DURATION_START ::chip::trace::PW_TRACE_EVENT_TYPE_DURATION_START
+#define PW_TRACE_TYPE_DURATION_END ::chip::trace::PW_TRACE_EVENT_TYPE_DURATION_END
+
+#define PW_TRACE_TYPE_DURATION_GROUP_START ::chip::trace::PW_TRACE_EVENT_TYPE_DURATION_GROUP_START
+#define PW_TRACE_TYPE_DURATION_GROUP_END ::chip::trace::PW_TRACE_EVENT_TYPE_DURATION_GROUP_END
+
+#define PW_TRACE_TYPE_ASYNC_START ::chip::trace::PW_TRACE_EVENT_TYPE_ASYNC_START
+#define PW_TRACE_TYPE_ASYNC_INSTANT ::chip::trace::PW_TRACE_EVENT_TYPE_ASYNC_STEP
+#define PW_TRACE_TYPE_ASYNC_END ::chip::trace::PW_TRACE_EVENT_TYPE_ASYNC_END
+
+namespace chip {
+namespace trace {
+
+typedef enum
+{
+ PW_TRACE_EVENT_TYPE_INVALID = 0,
+ PW_TRACE_EVENT_TYPE_INSTANT = 1,
+ PW_TRACE_EVENT_TYPE_INSTANT_GROUP = 2,
+ PW_TRACE_EVENT_TYPE_ASYNC_START = 3,
+ PW_TRACE_EVENT_TYPE_ASYNC_STEP = 4,
+ PW_TRACE_EVENT_TYPE_ASYNC_END = 5,
+ PW_TRACE_EVENT_TYPE_DURATION_START = 6,
+ PW_TRACE_EVENT_TYPE_DURATION_END = 7,
+ PW_TRACE_EVENT_TYPE_DURATION_GROUP_START = 8,
+ PW_TRACE_EVENT_TYPE_DURATION_GROUP_END = 9,
+} TraceEventType;
+
+// This should not be called directly, instead use the PW_TRACE_* macros.
+void TraceEvent(const char * module, const char * label, TraceEventType eventType, const char * group, uint32_t traceId,
+ uint8_t flags, const char * dataFormat, const void * dataBuffer, size_t dataSize);
+
+struct TraceEventFields
+{
+ const char * module;
+ const char * label;
+ TraceEventType eventType;
+ const char * group;
+ uint32_t traceId;
+ uint8_t flags;
+ const char * dataFormat;
+ const void * dataBuffer;
+ size_t dataSize;
+};
+
+typedef bool (*TraceHandlerCallback)(const TraceEventFields & trace);
+
+// Register a trace handler which gets called for all data trace events.
+void RegisterTraceHandler(TraceHandlerCallback callback);
+void UnregisterAllTraceHandlers();
+
+// These are what the facade actually calls.
+#define PW_TRACE(eventType, flags, label, group, traceId) \
+ do \
+ { \
+ ::chip::trace::TraceEvent(PW_TRACE_MODULE_NAME, label, eventType, group, traceId, flags, NULL, NULL, 0); \
+ } while (0)
+
+#define PW_TRACE_DATA(eventType, flags, label, group, traceId, dataFormat, data, size) \
+ do \
+ { \
+ ::chip::trace::TraceEvent(PW_TRACE_MODULE_NAME, label, eventType, group, traceId, flags, dataFormat, data, size); \
+ } while (0)
+
+} // namespace trace
+} // namespace chip
diff --git a/examples/platform/linux/pw_trace_chip/public_overrides/pw_trace_backend/trace_backend.h b/examples/platform/linux/pw_trace_chip/public_overrides/pw_trace_backend/trace_backend.h
new file mode 100644
index 0000000..cf6e094
--- /dev/null
+++ b/examples/platform/linux/pw_trace_chip/public_overrides/pw_trace_backend/trace_backend.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2021 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 "pw_trace_chip/trace_chip.h"
diff --git a/examples/platform/linux/pw_trace_chip/trace.cc b/examples/platform/linux/pw_trace_chip/trace.cc
new file mode 100644
index 0000000..427f22d
--- /dev/null
+++ b/examples/platform/linux/pw_trace_chip/trace.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2021 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 <mutex>
+#include <vector>
+
+#include "pw_trace_chip/trace_chip.h"
+
+#include "pw_trace/trace.h"
+
+namespace chip {
+namespace trace {
+namespace {
+
+std::mutex handlerLock;
+std::vector<TraceHandlerCallback> traceHandlers;
+
+} // namespace
+
+void TraceEvent(const char * module, const char * label, TraceEventType eventType, const char * group, uint32_t traceId,
+ uint8_t flags, const char * dataFormat, const void * dataBuffer, size_t dataSize)
+{
+ TraceEventFields fields = { module, label, eventType, group, traceId, flags, dataFormat, dataBuffer, dataSize };
+ std::lock_guard<std::mutex> guard(handlerLock);
+ for (const auto & handler : traceHandlers)
+ {
+ if (handler(fields))
+ {
+ return;
+ }
+ }
+}
+
+void RegisterTraceHandler(TraceHandlerCallback callback)
+{
+ std::lock_guard<std::mutex> guard(handlerLock);
+ traceHandlers.push_back(callback);
+}
+
+void UnregisterAllTraceHandlers()
+{
+ std::lock_guard<std::mutex> guard(handlerLock);
+ traceHandlers.clear();
+}
+
+} // namespace trace
+} // namespace chip
diff --git a/src/lib/core/BUILD.gn b/src/lib/core/BUILD.gn
index 3c04622..a58605a 100644
--- a/src/lib/core/BUILD.gn
+++ b/src/lib/core/BUILD.gn
@@ -60,6 +60,7 @@
"CHIP_CONFIG_MEMORY_DEBUG_CHECKS=${chip_config_memory_debug_checks}",
"CHIP_CONFIG_MEMORY_DEBUG_DMALLOC=${chip_config_memory_debug_dmalloc}",
"CHIP_CONFIG_PROVIDE_OBSOLESCENT_INTERFACES=false",
+ "CHIP_CONFIG_TRANSPORT_TRACE_ENABLED=${chip_enable_transport_trace}",
]
}
diff --git a/src/lib/core/core.gni b/src/lib/core/core.gni
index c33fd2a..7670b06 100644
--- a/src/lib/core/core.gni
+++ b/src/lib/core/core.gni
@@ -47,6 +47,9 @@
# Memory management debug option: use dmalloc
chip_config_memory_debug_dmalloc = false
+
+ # When enabled traces messages using pw_trace.
+ chip_enable_transport_trace = false
}
if (chip_target_style == "") {
diff --git a/src/transport/BUILD.gn b/src/transport/BUILD.gn
index 47ad0fe..4687c88 100644
--- a/src/transport/BUILD.gn
+++ b/src/transport/BUILD.gn
@@ -14,7 +14,9 @@
import("//build_overrides/chip.gni")
import("//build_overrides/nlio.gni")
+import("//build_overrides/pigweed.gni")
import("${chip_root}/src/ble/ble.gni")
+import("${chip_root}/src/lib/core/core.gni")
static_library("transport") {
output_name = "libTransportLayer"
@@ -51,6 +53,7 @@
"${chip_root}/src/crypto",
"${chip_root}/src/inet",
"${chip_root}/src/lib/core",
+ "${chip_root}/src/lib/core:chip_buildconfig",
"${chip_root}/src/lib/dnssd",
"${chip_root}/src/lib/support",
"${chip_root}/src/platform",
@@ -58,4 +61,8 @@
"${chip_root}/src/transport/raw",
"${nlio_root}:nlio",
]
+
+ if (chip_enable_transport_trace) {
+ deps = [ "$dir_pw_trace" ]
+ }
}
diff --git a/src/transport/SecureMessageCodec.cpp b/src/transport/SecureMessageCodec.cpp
index aa54b6e..4664985 100644
--- a/src/transport/SecureMessageCodec.cpp
+++ b/src/transport/SecureMessageCodec.cpp
@@ -29,6 +29,8 @@
#include <lib/support/SafeInt.h>
#include <transport/SecureMessageCodec.h>
+#include "transport/TraceMessage.h"
+
namespace chip {
using System::PacketBuffer;
@@ -60,6 +62,8 @@
uint8_t * data = msgBuf->Start();
uint16_t totalLen = msgBuf->TotalLength();
+ CHIP_TRACE_MESSAGE(payloadHeader, packetHeader, data, totalLen);
+
MessageAuthenticationCode mac;
ReturnErrorOnFailure(state->EncryptBeforeSend(data, totalLen, data, packetHeader, mac));
diff --git a/src/transport/TraceMessage.h b/src/transport/TraceMessage.h
new file mode 100644
index 0000000..b59ba91
--- /dev/null
+++ b/src/transport/TraceMessage.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright (c) 2021 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 <core/CHIPBuildConfig.h>
+#include <transport/raw/MessageHeader.h>
+
+#if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
+#include "pw_trace/trace.h"
+
+#define CHIP_TRACE_MESSAGE(payloadHeader, packetHeader, data, dataLen) \
+ do \
+ { \
+ ::chip::trace::TraceSecureMessageData _trace_data{ &payloadHeader, &packetHeader, data, dataLen }; \
+ PW_TRACE_INSTANT_DATA("SecureMsg", ::chip::trace::kTraceSecureMessageDataFormat, \
+ reinterpret_cast<const char *>(&_trace_data), sizeof(_trace_data)); \
+ } while (0)
+#else
+#define CHIP_TRACE_MESSAGE(payloadHeader, packetHeader, data, dataLen) \
+ do \
+ { \
+ } while (0)
+
+#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
+
+namespace chip {
+namespace trace {
+
+constexpr const char * kTraceSecureMessageDataFormat = "SecMsg";
+
+struct TraceSecureMessageData
+{
+ PayloadHeader * payloadHeader;
+ PacketHeader * packetHeader;
+ uint8_t * packetPayload;
+ size_t packetSize;
+};
+
+} // namespace trace
+} // namespace chip