blob: 31314ec7aeeca0fbb37927fddbf84050d098887e [file] [log] [blame]
Robert Oliver81e6e3e2020-06-25 14:43:40 -04001// Copyright 2020 The Pigweed Authors
2//
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
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
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
13// the License.
14//==============================================================================
15//
16#include "pw_trace_tokenized/trace_buffer.h"
17
18#include <span>
19
20#include "pw_ring_buffer/prefixed_entry_ring_buffer.h"
21#include "pw_trace_tokenized/trace_callback.h"
22
23namespace pw {
24namespace trace {
25namespace {
26
27class TraceBuffer {
28 public:
29 TraceBuffer() {
Adrien Larbanetd1ca56c2021-06-10 14:20:45 +000030 ring_buffer_.SetBuffer(raw_buffer_)
31 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
32 Callbacks::Instance()
33 .RegisterSink(
34 TraceSinkStartBlock, TraceSinkAddBytes, TraceSinkEndBlock, this)
35 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
Robert Oliver81e6e3e2020-06-25 14:43:40 -040036 }
37
38 static void TraceSinkStartBlock(void* user_data, size_t size) {
39 TraceBuffer* buffer = reinterpret_cast<TraceBuffer*>(user_data);
40 if (size > PW_TRACE_BUFFER_MAX_BLOCK_SIZE_BYTES) {
41 buffer->block_size_ = 0; // Skip this block
42 return;
43 }
44 buffer->block_size_ = static_cast<uint16_t>(size);
45 buffer->block_idx_ = 0;
46 }
47
48 static void TraceSinkAddBytes(void* user_data,
49 const void* bytes,
50 size_t size) {
51 TraceBuffer* buffer = reinterpret_cast<TraceBuffer*>(user_data);
52 if (buffer->block_size_ == 0 ||
53 buffer->block_idx_ + size > buffer->block_size_) {
54 return; // Block is too large, skipping.
55 }
56 memcpy(&buffer->current_block_[buffer->block_idx_], bytes, size);
57 buffer->block_idx_ += size;
58 }
59
60 static void TraceSinkEndBlock(void* user_data) {
61 TraceBuffer* buffer = reinterpret_cast<TraceBuffer*>(user_data);
62 if (buffer->block_idx_ != buffer->block_size_) {
63 return; // Block is too large, skipping.
64 }
Adrien Larbanetd1ca56c2021-06-10 14:20:45 +000065 buffer->ring_buffer_
66 .PushBack(std::span<const std::byte>(&buffer->current_block_[0],
67 buffer->block_size_))
68 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
Robert Oliver81e6e3e2020-06-25 14:43:40 -040069 }
70
71 pw::ring_buffer::PrefixedEntryRingBuffer& RingBuffer() {
72 return ring_buffer_;
73 };
74
Rob Oliver2489aa62021-08-24 16:03:21 -040075 ConstByteSpan DeringAndViewRawBuffer() {
Wyatt Heplerbad6d272022-02-16 07:15:07 -080076 ring_buffer_.Dering()
77 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
Rob Oliver2489aa62021-08-24 16:03:21 -040078 return ByteSpan(raw_buffer_, ring_buffer_.TotalUsedBytes());
79 }
80
Robert Oliver81e6e3e2020-06-25 14:43:40 -040081 private:
82 uint16_t block_size_ = 0;
83 uint16_t block_idx_ = 0;
84 std::byte current_block_[PW_TRACE_BUFFER_MAX_BLOCK_SIZE_BYTES];
85 std::byte raw_buffer_[PW_TRACE_BUFFER_SIZE_BYTES];
86 pw::ring_buffer::PrefixedEntryRingBuffer ring_buffer_{false};
87};
88
89#if PW_TRACE_BUFFER_SIZE_BYTES > 0
90TraceBuffer trace_buffer_instance;
91#endif // PW_TRACE_BUFFER_SIZE_BYTES > 0
92
93} // namespace
94
95void ClearBuffer() { trace_buffer_instance.RingBuffer().Clear(); }
96
97pw::ring_buffer::PrefixedEntryRingBuffer* GetBuffer() {
98 return &trace_buffer_instance.RingBuffer();
99}
100
Rob Oliver2489aa62021-08-24 16:03:21 -0400101ConstByteSpan DeringAndViewRawBuffer() {
102 return trace_buffer_instance.DeringAndViewRawBuffer();
103}
104
Robert Oliver81e6e3e2020-06-25 14:43:40 -0400105} // namespace trace
Adrien Larbanetd1ca56c2021-06-10 14:20:45 +0000106} // namespace pw