aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Roth <davidroth@google.com>2023-11-08 00:42:03 +0000
committerCQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-11-08 00:42:03 +0000
commite2c73889399ce97f00d56bd5b2e742888a8db69e (patch)
tree64d4651266cfc4887eaffe3ae159edc30f8a8abd
parent53027c0a50b85feb8815d1dc67349da8975fb67d (diff)
downloadpigweed-e2c73889399ce97f00d56bd5b2e742888a8db69e.tar.gz
pw_trace_tokenized: Add a transfer based trace service
Change-Id: Idac3ae2726d7ba081771bb672159c68c3467683b Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/168833 Commit-Queue: Dave Roth <davidroth@google.com> Reviewed-by: Armando Montanez <amontanez@google.com>
-rw-r--r--pw_trace_tokenized/BUILD.bazel67
-rw-r--r--pw_trace_tokenized/BUILD.gn49
-rw-r--r--pw_trace_tokenized/CMakeLists.txt26
-rw-r--r--pw_trace_tokenized/base_trace_service.cc76
-rw-r--r--pw_trace_tokenized/public/pw_trace_tokenized/base_trace_service.h43
-rw-r--r--pw_trace_tokenized/public/pw_trace_tokenized/trace_service_pwpb.h38
-rw-r--r--pw_trace_tokenized/pw_trace_protos/trace_rpc.proto4
-rw-r--r--pw_trace_tokenized/pw_trace_protos/trace_service.options13
-rw-r--r--pw_trace_tokenized/pw_trace_protos/trace_service.proto53
-rw-r--r--pw_trace_tokenized/py/BUILD.gn11
-rw-r--r--pw_trace_tokenized/py/pyproject.toml16
-rw-r--r--pw_trace_tokenized/py/setup.cfg29
-rw-r--r--pw_trace_tokenized/trace_service_pwpb.cc75
-rw-r--r--pw_trace_tokenized/trace_service_pwpb_test.cc130
14 files changed, 579 insertions, 51 deletions
diff --git a/pw_trace_tokenized/BUILD.bazel b/pw_trace_tokenized/BUILD.bazel
index 4263ef3ef..6e76328e9 100644
--- a/pw_trace_tokenized/BUILD.bazel
+++ b/pw_trace_tokenized/BUILD.bazel
@@ -18,6 +18,7 @@ load(
"pw_cc_library",
"pw_cc_test",
)
+load("//pw_build/bazel_internal:py_proto_library.bzl", "py_proto_library")
load("//pw_protobuf_compiler:pw_proto_library.bzl", "pw_proto_library")
package(default_visibility = ["//visibility:public"])
@@ -58,6 +59,43 @@ pw_cc_library(
)
pw_cc_library(
+ name = "base_trace_service",
+ srcs = [
+ "base_trace_service.cc",
+ ],
+ hdrs = [
+ "public/pw_trace_tokenized/base_trace_service.h",
+ ],
+ includes = [
+ "public",
+ ],
+ deps = [
+ ":buffer",
+ ":pw_trace_tokenized",
+ "//pw_ring_buffer",
+ "//pw_stream",
+ ],
+)
+
+pw_cc_library(
+ name = "trace_service_pwpb",
+ srcs = [
+ "trace_service_pwpb.cc",
+ ],
+ hdrs = [
+ "public/pw_trace_tokenized/trace_service_pwpb.h",
+ ],
+ includes = [
+ "public",
+ ],
+ deps = [
+ ":base_trace_service",
+ ":protos_cc.pwpb_rpc",
+ "//pw_chrono:system_clock",
+ ],
+)
+
+pw_cc_library(
name = "trace_rpc_service",
srcs = [
"trace_rpc_service_nanopb.cc",
@@ -121,10 +159,14 @@ proto_library(
srcs = [
"pw_trace_protos/trace.proto",
"pw_trace_protos/trace_rpc.proto",
+ "pw_trace_protos/trace_service.proto",
+ ],
+ deps = [
+ "//pw_chrono:chrono_proto",
],
# TODO(tpudlik): We should provide trace_rpc.options to nanopb here, but the
# current proto codegen implementation provides no mechanism for doing so.
- # inputs = [ "pw_trace_protos/trace_rpc.options" ]
+ # inputs = [ "pw_trace_protos/trace_rpc.options", "pw_trace_protos/trace_service.options"]
)
pw_proto_library(
@@ -132,6 +174,13 @@ pw_proto_library(
deps = [":protos"],
)
+py_proto_library(
+ name = "proto_py",
+ # TODO(b/241456982): Get this target to build.
+ tags = ["manual"],
+ deps = [":protos"],
+)
+
pw_cc_library(
name = "pw_trace_tokenized_fake_time",
srcs = [
@@ -190,6 +239,22 @@ pw_cc_test(
],
)
+pw_cc_test(
+ name = "trace_service_pwpb_test",
+ srcs = [
+ "trace_service_pwpb_test.cc",
+ ],
+ # TODO(b/260641850): Get pw_trace_tokenized building in Bazel.
+ tags = ["manual"],
+ deps = [
+ ":pw_trace_host_trace_time",
+ ":trace_service_pwpb",
+ "//pw_chrono:system_clock",
+ "//pw_rpc/pwpb:test_method_context",
+ "//pw_trace",
+ ],
+)
+
pw_cc_library(
name = "pw_trace_host_trace_time",
srcs = ["host_trace_time.cc"],
diff --git a/pw_trace_tokenized/BUILD.gn b/pw_trace_tokenized/BUILD.gn
index 0e7be3121..c2c928e91 100644
--- a/pw_trace_tokenized/BUILD.gn
+++ b/pw_trace_tokenized/BUILD.gn
@@ -62,6 +62,7 @@ pw_test_group("tests") {
":trace_tokenized_test",
":tokenized_trace_buffer_test",
":tokenized_trace_buffer_log_test",
+ ":trace_service_pwpb_test",
]
}
@@ -101,8 +102,14 @@ pw_proto_library("protos") {
sources = [
"pw_trace_protos/trace.proto",
"pw_trace_protos/trace_rpc.proto",
+ "pw_trace_protos/trace_service.proto",
]
- inputs = [ "pw_trace_protos/trace_rpc.options" ]
+ inputs = [
+ "pw_trace_protos/trace_rpc.options",
+ "pw_trace_protos/trace_service.options",
+ ]
+ python_package = "py"
+ deps = [ "$dir_pw_chrono:protos" ]
}
pw_source_set("trace_rpc_service") {
@@ -120,6 +127,46 @@ pw_source_set("trace_rpc_service") {
]
}
+pw_source_set("base_trace_service") {
+ public_configs = [ ":public_include_path" ]
+ public_deps = [
+ ":core",
+ ":tokenized_trace_buffer",
+ ]
+ deps = [
+ "$dir_pw_ring_buffer",
+ "$dir_pw_stream",
+ ]
+ sources = [
+ "base_trace_service.cc",
+ "public/pw_trace_tokenized/base_trace_service.h",
+ ]
+}
+
+pw_source_set("trace_service_pwpb") {
+ public_configs = [ ":public_include_path" ]
+ public_deps = [
+ ":base_trace_service",
+ ":protos.pwpb_rpc",
+ ]
+ deps = [ "$dir_pw_chrono:system_clock" ]
+ sources = [
+ "public/pw_trace_tokenized/trace_service_pwpb.h",
+ "trace_service_pwpb.cc",
+ ]
+}
+
+pw_test("trace_service_pwpb_test") {
+ enable_if = _pw_trace_tokenized_is_selected
+ deps = [
+ ":trace_service_pwpb",
+ "$dir_pw_chrono:system_clock",
+ "$dir_pw_rpc/pwpb:test_method_context",
+ "$dir_pw_trace",
+ ]
+ sources = [ "trace_service_pwpb_test.cc" ]
+}
+
pw_source_set("tokenized_trace_buffer") {
deps = [ ":core" ]
public_deps = [
diff --git a/pw_trace_tokenized/CMakeLists.txt b/pw_trace_tokenized/CMakeLists.txt
index e8780f6a4..bc6268f90 100644
--- a/pw_trace_tokenized/CMakeLists.txt
+++ b/pw_trace_tokenized/CMakeLists.txt
@@ -69,8 +69,12 @@ pw_add_library(pw_trace_tokenized.trace_buffer STATIC
pw_proto_library(pw_trace_tokenized.protos
SOURCES
pw_trace_protos/trace_rpc.proto
+ pw_trace_protos/trace_service.proto
INPUTS
pw_trace_protos/trace_rpc.options
+ pw_trace_protos/trace_service.options
+ DEPS
+ pw_chrono.protos
)
pw_add_library(pw_trace_tokenized.rpc_service STATIC
@@ -87,3 +91,25 @@ pw_add_library(pw_trace_tokenized.rpc_service STATIC
pw_tokenizer
pw_status
)
+
+pw_add_library(pw_trace_tokenized.base_trace_service STATIC
+ SOURCES
+ base_trace_service.cc
+ PRIVATE_DEPS
+ pw_log
+ pw_stream
+ pw_ring_buffer
+ PUBLIC_DEPS
+ pw_trace_tokenized
+ pw_trace_tokenized.trace_buffer
+)
+
+pw_add_library(pw_trace_tokenized.trace_service_pwpb STATIC
+ SOURCES
+ trace_service_pwpb.cc
+ PRIVATE_DEPS
+ pw_chrono.system_clock
+ PUBLIC_DEPS
+ pw_trace_tokenized.base_trace_service
+ pw_trace_tokenized.protos.pwpb_rpc
+)
diff --git a/pw_trace_tokenized/base_trace_service.cc b/pw_trace_tokenized/base_trace_service.cc
new file mode 100644
index 000000000..56331f377
--- /dev/null
+++ b/pw_trace_tokenized/base_trace_service.cc
@@ -0,0 +1,76 @@
+// Copyright 2023 The Pigweed 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
+//
+// https://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 "pw_trace_tokenized/base_trace_service.h"
+
+#include "pw_log/log.h"
+#include "pw_trace_tokenized/trace_buffer.h"
+
+namespace pw::trace {
+BaseTraceService::BaseTraceService(TokenizedTracer& tokenized_tracer,
+ stream::Writer& trace_writer)
+ : tokenized_tracer_(tokenized_tracer), trace_writer_(trace_writer) {
+ tokenized_tracer_.Enable(false);
+}
+
+Status BaseTraceService::Start() {
+ PW_LOG_INFO("Starting Tracing");
+
+ if (tokenized_tracer_.IsEnabled()) {
+ PW_LOG_INFO("Tracing already started");
+ return Status::FailedPrecondition();
+ }
+
+ tokenized_tracer_.Enable(true);
+
+ return OkStatus();
+}
+
+Status BaseTraceService::Stop() {
+ PW_LOG_INFO("Stopping Tracing");
+
+ if (!tokenized_tracer_.IsEnabled()) {
+ PW_LOG_INFO("Tracing not started");
+ return Status::FailedPrecondition();
+ }
+
+ tokenized_tracer_.Enable(false);
+
+ auto ring_buffer = trace::GetBuffer();
+
+ if (ring_buffer->EntryCount() == 0) {
+ PW_LOG_WARN("EntryCount(%zu)", ring_buffer->EntryCount());
+ return Status::Unavailable();
+ } else if (ring_buffer->CheckForCorruption() != OkStatus()) {
+ PW_LOG_ERROR("EntryCount(%zu), Corruption(%d)",
+ ring_buffer->EntryCount(),
+ ring_buffer->CheckForCorruption().code());
+ return Status::Unavailable();
+ }
+
+ PW_LOG_INFO("EntryCount(%zu)", ring_buffer->EntryCount());
+
+ ConstByteSpan inner_trace_span = trace::DeringAndViewRawBuffer();
+ if (auto status = trace_writer_.Write(inner_trace_span);
+ status != OkStatus()) {
+ PW_LOG_ERROR("Failed to write trace data: %d)", status.code());
+ return status;
+ }
+
+ ring_buffer->Clear();
+
+ return OkStatus();
+}
+
+} // namespace pw::trace
diff --git a/pw_trace_tokenized/public/pw_trace_tokenized/base_trace_service.h b/pw_trace_tokenized/public/pw_trace_tokenized/base_trace_service.h
new file mode 100644
index 000000000..d6f219a36
--- /dev/null
+++ b/pw_trace_tokenized/public/pw_trace_tokenized/base_trace_service.h
@@ -0,0 +1,43 @@
+// Copyright 2023 The Pigweed 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
+//
+// https://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 <cstdint>
+#include <optional>
+
+#include "pw_status/status.h"
+#include "pw_stream/stream.h"
+#include "pw_trace_tokenized/trace_tokenized.h"
+
+namespace pw::trace {
+class BaseTraceService {
+ public:
+ BaseTraceService(TokenizedTracer& tokenized_tracer,
+ stream::Writer& trace_writer);
+
+ void SetTransferId(uint32_t id) { transfer_id_ = id; }
+
+ protected:
+ Status Start();
+ Status Stop();
+
+ private:
+ TokenizedTracer& tokenized_tracer_;
+ stream::Writer& trace_writer_;
+
+ protected:
+ std::optional<uint32_t> transfer_id_;
+};
+
+} // namespace pw::trace
diff --git a/pw_trace_tokenized/public/pw_trace_tokenized/trace_service_pwpb.h b/pw_trace_tokenized/public/pw_trace_tokenized/trace_service_pwpb.h
new file mode 100644
index 000000000..c915dfb34
--- /dev/null
+++ b/pw_trace_tokenized/public/pw_trace_tokenized/trace_service_pwpb.h
@@ -0,0 +1,38 @@
+// Copyright 2023 The Pigweed 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
+//
+// https://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_protos/trace_service.rpc.pwpb.h"
+#include "pw_trace_tokenized/base_trace_service.h"
+
+namespace pw::trace {
+
+class TraceService final
+ : public proto::pw_rpc::pwpb::TraceService::Service<TraceService>,
+ public BaseTraceService {
+ public:
+ TraceService(TokenizedTracer& tokenized_tracer, stream::Writer& trace_writer);
+
+ Status Start(const proto::pwpb::StartRequest::Message& request,
+ proto::pwpb::StartResponse::Message& response);
+
+ Status Stop(const proto::pwpb::StopRequest::Message& request,
+ proto::pwpb::StopResponse::Message& response);
+
+ Status GetClockParameters(
+ const proto::pwpb::ClockParametersRequest::Message& request,
+ proto::pwpb::ClockParametersResponse::Message& response);
+};
+
+} // namespace pw::trace
diff --git a/pw_trace_tokenized/pw_trace_protos/trace_rpc.proto b/pw_trace_tokenized/pw_trace_protos/trace_rpc.proto
index 39971e7c3..2b9b3bc28 100644
--- a/pw_trace_tokenized/pw_trace_protos/trace_rpc.proto
+++ b/pw_trace_tokenized/pw_trace_protos/trace_rpc.proto
@@ -15,6 +15,10 @@ syntax = "proto3";
package pw.trace;
+// TODO: b/309643763 - This service has been deprecated in favor of the tracing
+// service defined in trace_service.proto
+// This service will be deleted once existing clients have been migrated awaw
+// from it, so please don't use this for any new projects.
service TraceService {
rpc Enable(TraceEnableMessage) returns (TraceEnableMessage) {}
rpc IsEnabled(Empty) returns (TraceEnableMessage) {}
diff --git a/pw_trace_tokenized/pw_trace_protos/trace_service.options b/pw_trace_tokenized/pw_trace_protos/trace_service.options
new file mode 100644
index 000000000..714d9397f
--- /dev/null
+++ b/pw_trace_tokenized/pw_trace_protos/trace_service.options
@@ -0,0 +1,13 @@
+// Copyright 2023 The Pigweed 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
+//
+// https://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.
diff --git a/pw_trace_tokenized/pw_trace_protos/trace_service.proto b/pw_trace_tokenized/pw_trace_protos/trace_service.proto
new file mode 100644
index 000000000..62be6fe9b
--- /dev/null
+++ b/pw_trace_tokenized/pw_trace_protos/trace_service.proto
@@ -0,0 +1,53 @@
+// Copyright 2023 The Pigweed 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
+//
+// https://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.
+syntax = "proto3";
+
+package pw.trace.proto;
+
+import "pw_chrono_protos/chrono.proto";
+
+// TODO: b/309643763 - This is the prefered service for tracing, and the service
+// defined in trace_rpc.proto has been deprecated and will be removed once
+// existings clients migrate to this service.
+service TraceService {
+ // Start will enable tracing, populating the trace ring buffer.
+ rpc Start(StartRequest) returns (StartResponse) {}
+
+ // On stop the ring buffer will be written to the configured
+ // stream. No data is written to the stream until Stop is called.
+ rpc Stop(StopRequest) returns (StopResponse) {}
+
+ // Returns the clock paramaters of the system.
+ rpc GetClockParameters(ClockParametersRequest)
+ returns (ClockParametersResponse) {}
+}
+
+message StartRequest {}
+
+message StartResponse {}
+
+message StopRequest {}
+
+message StopResponse {
+ // as a convenience, the file id is returned on stop which can be
+ // used to start a transfer directly, rather that requiring a user
+ // list the files to obtain the file id.
+ optional uint32 file_id = 1;
+}
+
+message ClockParametersRequest {}
+
+message ClockParametersResponse {
+ pw.chrono.ClockParameters clock_parameters = 1;
+}
diff --git a/pw_trace_tokenized/py/BUILD.gn b/pw_trace_tokenized/py/BUILD.gn
index 78c7f998d..4ad26412b 100644
--- a/pw_trace_tokenized/py/BUILD.gn
+++ b/pw_trace_tokenized/py/BUILD.gn
@@ -17,10 +17,12 @@ import("//build_overrides/pigweed.gni")
import("$dir_pw_build/python.gni")
pw_python_package("py") {
- setup = [
- "pyproject.toml",
- "setup.cfg",
- ]
+ generate_setup = {
+ metadata = {
+ name = "pw_trace_tokenized"
+ version = "0.0.1"
+ }
+ }
sources = [
"pw_trace_tokenized/__init__.py",
"pw_trace_tokenized/get_trace.py",
@@ -34,4 +36,5 @@ pw_python_package("py") {
]
pylintrc = "$dir_pigweed/.pylintrc"
mypy_ini = "$dir_pigweed/.mypy.ini"
+ proto_library = "..:protos"
}
diff --git a/pw_trace_tokenized/py/pyproject.toml b/pw_trace_tokenized/py/pyproject.toml
deleted file mode 100644
index 798b747ec..000000000
--- a/pw_trace_tokenized/py/pyproject.toml
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 The Pigweed 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
-#
-# https://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.
-[build-system]
-requires = ['setuptools', 'wheel']
-build-backend = 'setuptools.build_meta'
diff --git a/pw_trace_tokenized/py/setup.cfg b/pw_trace_tokenized/py/setup.cfg
deleted file mode 100644
index 98038d397..000000000
--- a/pw_trace_tokenized/py/setup.cfg
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright 2021 The Pigweed 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
-#
-# https://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.
-[metadata]
-name = pw_trace_tokenized
-version = 0.0.1
-author = Pigweed Authors
-author_email = pigweed-developers@googlegroups.com
-description = pw_trace backend to tokenize trace events
-
-[options]
-packages = find:
-zip_safe = False
-install_requires =
- pyserial>=3.5,<4.0
- types-pyserial>=3.5,<4.0
-
-[options.package_data]
-pw_trace_tokenized = py.typed
diff --git a/pw_trace_tokenized/trace_service_pwpb.cc b/pw_trace_tokenized/trace_service_pwpb.cc
new file mode 100644
index 000000000..af4b90a7c
--- /dev/null
+++ b/pw_trace_tokenized/trace_service_pwpb.cc
@@ -0,0 +1,75 @@
+// Copyright 2023 The Pigweed 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
+//
+// https://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 "pw_trace_tokenized/trace_service_pwpb.h"
+
+#include "pw_chrono/system_clock.h"
+
+namespace pw::trace {
+
+TraceService::TraceService(TokenizedTracer& tokenized_tracer,
+ stream::Writer& trace_writer)
+ : BaseTraceService(tokenized_tracer, trace_writer) {}
+
+Status TraceService::Start(
+ const proto::pwpb::StartRequest::Message& /*request*/,
+ proto::pwpb::StartResponse::Message& /*response*/) {
+ return BaseTraceService::Start();
+}
+
+Status TraceService::Stop(const proto::pwpb::StopRequest::Message& /*request*/,
+ proto::pwpb::StopResponse::Message& response) {
+ if (auto status = BaseTraceService::Stop(); status != pw::OkStatus()) {
+ return status;
+ }
+
+ response.file_id = transfer_id_;
+ return pw::OkStatus();
+}
+
+Status TraceService::GetClockParameters(
+ const proto::pwpb::ClockParametersRequest::Message& /*request*/,
+ proto::pwpb::ClockParametersResponse::Message& response) {
+ response.clock_parameters.tick_period_seconds_numerator =
+ PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_NUMERATOR;
+ response.clock_parameters.tick_period_seconds_denominator =
+ PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_DENOMINATOR;
+
+ switch (chrono::SystemClock::epoch) {
+ case chrono::Epoch::kUnknown:
+ response.clock_parameters.epoch_type =
+ chrono::pwpb::EpochType::Enum::kUnknown;
+ break;
+ case chrono::Epoch::kTimeSinceBoot:
+ response.clock_parameters.epoch_type =
+ chrono::pwpb::EpochType::Enum::kTimeSinceBoot;
+ break;
+ case chrono::Epoch::kUtcWallClock:
+ response.clock_parameters.epoch_type =
+ chrono::pwpb::EpochType::Enum::kUtcWallClock;
+ break;
+ case chrono::Epoch::kGpsWallClock:
+ response.clock_parameters.epoch_type =
+ chrono::pwpb::EpochType::Enum::kGpsWallClock;
+ break;
+ case chrono::Epoch::kTaiWallClock:
+ response.clock_parameters.epoch_type =
+ chrono::pwpb::EpochType::Enum::kTaiWallClock;
+ break;
+ }
+
+ return pw::OkStatus();
+}
+
+} // namespace pw::trace
diff --git a/pw_trace_tokenized/trace_service_pwpb_test.cc b/pw_trace_tokenized/trace_service_pwpb_test.cc
new file mode 100644
index 000000000..008210193
--- /dev/null
+++ b/pw_trace_tokenized/trace_service_pwpb_test.cc
@@ -0,0 +1,130 @@
+// Copyright 2023 The Pigweed 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
+//
+// https://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 "pw_trace_tokenized/trace_service_pwpb.h"
+
+#include "gtest/gtest.h"
+#include "pw_chrono/system_clock.h"
+#include "pw_rpc/pwpb/test_method_context.h"
+#include "pw_stream/memory_stream.h"
+#include "pw_trace/trace.h"
+#include "pw_trace_tokenized/trace_tokenized.h"
+
+namespace pw::trace {
+
+class TraceServiceTest : public ::testing::Test {
+ public:
+ TraceServiceTest() {}
+
+ static constexpr uint32_t kTraceTransferHandlerId = 7;
+};
+
+TEST_F(TraceServiceTest, Start) {
+ auto& tracer = trace::GetTokenizedTracer();
+
+ std::array<std::byte, PW_TRACE_BUFFER_SIZE_BYTES> dest_buffer;
+ stream::MemoryWriter writer(dest_buffer);
+ PW_PWPB_TEST_METHOD_CONTEXT(TraceService, Start)
+ context(tracer, writer);
+
+ ASSERT_FALSE(tracer.IsEnabled());
+ ASSERT_EQ(context.call({}), OkStatus());
+ ASSERT_TRUE(tracer.IsEnabled());
+
+ // multiple calls to start are disallowed
+ ASSERT_EQ(context.call({}), Status::FailedPrecondition());
+}
+
+TEST_F(TraceServiceTest, Stop) {
+ auto& tracer = trace::GetTokenizedTracer();
+
+ std::array<std::byte, PW_TRACE_BUFFER_SIZE_BYTES> dest_buffer;
+ stream::MemoryWriter writer(dest_buffer);
+ PW_PWPB_TEST_METHOD_CONTEXT(TraceService, Stop)
+ context(tracer, writer);
+ context.service().SetTransferId(kTraceTransferHandlerId);
+
+ tracer.Enable(true);
+ PW_TRACE_INSTANT("TestTrace");
+
+ ASSERT_EQ(context.call({}), OkStatus());
+ ASSERT_FALSE(tracer.IsEnabled());
+ EXPECT_EQ(kTraceTransferHandlerId, context.response().file_id);
+ EXPECT_LT(0u, writer.bytes_written());
+}
+
+TEST_F(TraceServiceTest, StopNoTransferHandlerId) {
+ auto& tracer = trace::GetTokenizedTracer();
+
+ std::array<std::byte, PW_TRACE_BUFFER_SIZE_BYTES> dest_buffer;
+ stream::MemoryWriter writer(dest_buffer);
+ PW_PWPB_TEST_METHOD_CONTEXT(TraceService, Stop)
+ context(tracer, writer);
+
+ tracer.Enable(true);
+ PW_TRACE_INSTANT("TestTrace");
+
+ ASSERT_EQ(context.call({}), OkStatus());
+ ASSERT_FALSE(tracer.IsEnabled());
+ EXPECT_FALSE(context.response().file_id.has_value());
+ EXPECT_LT(0u, writer.bytes_written());
+}
+
+TEST_F(TraceServiceTest, StopNotStarted) {
+ auto& tracer = trace::GetTokenizedTracer();
+
+ std::array<std::byte, PW_TRACE_BUFFER_SIZE_BYTES> dest_buffer;
+ stream::MemoryWriter writer(dest_buffer);
+ PW_PWPB_TEST_METHOD_CONTEXT(TraceService, Stop)
+ context(tracer, writer);
+
+ // stopping while tracing is disabled results in FailedPrecondition
+ ASSERT_EQ(context.call({}), Status::FailedPrecondition());
+}
+
+TEST_F(TraceServiceTest, StopNoData) {
+ auto& tracer = trace::GetTokenizedTracer();
+
+ std::array<std::byte, PW_TRACE_BUFFER_SIZE_BYTES> dest_buffer;
+ stream::MemoryWriter writer(dest_buffer);
+ PW_PWPB_TEST_METHOD_CONTEXT(TraceService, Stop)
+ context(tracer, writer);
+
+ tracer.Enable(true);
+
+ // stopping with no trace data results in Unavailable
+ ASSERT_EQ(context.call({}), Status::Unavailable());
+}
+
+TEST_F(TraceServiceTest, GetClockParameters) {
+ auto& tracer = trace::GetTokenizedTracer();
+
+ std::array<std::byte, PW_TRACE_BUFFER_SIZE_BYTES> dest_buffer;
+ stream::MemoryWriter writer(dest_buffer);
+
+ PW_PWPB_TEST_METHOD_CONTEXT(TraceService, GetClockParameters)
+ context(tracer, writer);
+
+ ASSERT_EQ(context.call({}), OkStatus());
+ EXPECT_EQ(PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_NUMERATOR,
+ context.response().clock_parameters.tick_period_seconds_numerator);
+ EXPECT_EQ(
+ PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_DENOMINATOR,
+ context.response().clock_parameters.tick_period_seconds_denominator);
+ EXPECT_EQ(
+ static_cast<int32_t>(chrono::SystemClock::epoch),
+ static_cast<int32_t>(*context.response().clock_parameters.epoch_type));
+}
+
+} // namespace pw::trace