1 // Copyright 2020 The Pigweed Authors
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
7 // https://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
14 //==============================================================================
16 // This file provides the interface for working with the tokenized trace
25 #ifndef PW_TRACE_GET_TIME_DELTA
27 #include <type_traits>
29 #endif // PW_TRACE_GET_TIME_DELTA
31 #include "pw_status/status.h"
32 #include "pw_tokenizer/tokenize.h"
33 #include "pw_trace_tokenized/config.h"
34 #include "pw_trace_tokenized/internal/trace_tokenized_internal.h"
40 using EventType = pw_trace_EventType;
44 // Simple ring buffer which is suitable for use in a critical section.
45 template <size_t kSize>
48 struct QueueEventBlock {
55 std::byte data_buffer[PW_TRACE_BUFFER_MAX_DATA_SIZE_BYTES];
58 pw::Status TryPushBack(uint32_t trace_token,
63 const void* data_buffer,
66 return pw::Status::ResourceExhausted();
68 event_queue_[head_].trace_token = trace_token;
69 event_queue_[head_].event_type = event_type;
70 event_queue_[head_].module = module;
71 event_queue_[head_].trace_id = trace_id;
72 event_queue_[head_].flags = flags;
73 event_queue_[head_].data_size = data_size;
74 for (size_t i = 0; i < data_size; i++) {
75 event_queue_[head_].data_buffer[i] =
76 reinterpret_cast<const std::byte*>(data_buffer)[i];
78 head_ = (head_ + 1) % kSize;
80 return pw::OkStatus();
83 const volatile QueueEventBlock* PeekFront() const {
87 return &event_queue_[tail_];
92 tail_ = (tail_ + 1) % kSize;
93 is_empty_ = (tail_ == head_);
103 bool IsEmpty() const { return is_empty_; }
104 bool IsFull() const { return !is_empty_ && (head_ == tail_); }
107 std::array<volatile QueueEventBlock, kSize> event_queue_;
108 volatile size_t head_ = 0; // Next write
109 volatile size_t tail_ = 0; // Next read
110 volatile bool is_empty_ =
111 true; // Used to distinquish if head==tail is empty or full
114 } // namespace internal
116 class TokenizedTraceImpl {
118 void Enable(bool enable) {
119 if (enable != enabled_ && enable) {
120 event_queue_.Clear();
124 bool IsEnabled() const { return enabled_; }
126 void HandleTraceEvent(uint32_t trace_token,
127 EventType event_type,
131 const void* data_buffer,
135 using TraceQueue = internal::TraceQueue<PW_TRACE_QUEUE_SIZE_EVENTS>;
136 PW_TRACE_TIME_TYPE last_trace_time_ = 0;
137 bool enabled_ = false;
138 TraceQueue event_queue_;
140 void HandleNextItemInQueue(
141 const volatile TraceQueue::QueueEventBlock* event_block);
144 // A singleton object of the TokenizedTraceImpl class which can be used to
145 // interface with trace using the C++ API.
146 // Example: pw::trace::TokenizedTrace::Instance().Enable(true);
147 class TokenizedTrace {
149 static TokenizedTraceImpl& Instance() { return instance_; };
152 static TokenizedTraceImpl instance_;
157 #endif // __cplusplus
159 // PW_TRACE_SET_ENABLED is used to enable or disable tracing.
160 #define PW_TRACE_SET_ENABLED(enabled) pw_trace_Enable(enabled)
162 // PW_TRACE_REF provides the uint32_t token value for a specific trace event.
163 // this can be used in the callback to perform specific actions for that trace.
164 // All the fields must match exactly to generate the correct trace reference.
165 // If the trace does not have a group, use PW_TRACE_GROUP_LABEL_DEFAULT.
167 // For example this can be used to skip a specific trace:
168 // pw_trace_TraceEventReturnFlags TraceEventCallback(
169 // uint32_t trace_ref,
170 // pw_trace_EventType event_type,
171 // const char* module,
172 // uint32_t trace_id,
174 // auto skip_trace_ref = PW_TRACE_REF(PW_TRACE_TYPE_INSTANT,
175 // "test_module", // Module
176 // "test_label", // Label
177 // PW_TRACE_FLAGS_DEFAULT,
178 // PW_TRACE_GROUP_LABEL_DEFAULT);
179 // if (trace_ref == skip_trace_ref) {
180 // return PW_TRACE_EVENT_RETURN_FLAGS_SKIP_EVENT;
185 // The above trace ref would provide the tokenize value for the string:
186 // "1|0|test_module||test_label"
189 // #define PW_TRACE_MODULE test_module
190 // PW_TRACE_INSTANT_DATA_FLAG(2, "label", "group", id, "%d", 5, 1);
191 // Would internally generate a token value for the string:
192 // "1|2|test_module|group|label|%d"
193 // The trace_id, and data value are runtime values and not included in the
195 #define PW_TRACE_REF(event_type, module, label, flags, group) \
196 PW_TOKENIZE_STRING_DOMAIN("trace", \
197 PW_STRINGIFY(event_type) "|" PW_STRINGIFY( \
198 flags) "|" module "|" group "|" label)
200 #define PW_TRACE_REF_DATA(event_type, module, label, flags, group, type) \
201 PW_TOKENIZE_STRING_DOMAIN( \
203 PW_STRINGIFY(event_type) "|" PW_STRINGIFY(flags) "|" module "|" group \