F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
CircularBuffer.cpp
Go to the documentation of this file.
1 /*
2  * CircularBuffer.cpp:
3  *
4  * Buffer used to efficiently store data in ring data structure. Uses an externally supplied
5  * data store as the backing for this buffer. Thus it is dependent on receiving sole ownership
6  * of the supplied buffer.
7  *
8  * This implementation file contains the function definitions.
9  *
10  * Created on: Apr 4, 2019
11  * Author: lestarch
12  * Revised March 2022
13  * Author: bocchino
14  */
15 #include <Fw/FPrimeBasicTypes.hpp>
16 #include <Fw/Types/Assert.hpp>
18 
19 namespace Types {
20 
22  : m_store(nullptr), m_store_size(0), m_head_idx(0), m_allocated_size(0), m_high_water_mark(0) {}
23 
24 CircularBuffer ::CircularBuffer(U8* const buffer, const FwSizeType size)
25  : m_store(nullptr), m_store_size(0), m_head_idx(0), m_allocated_size(0), m_high_water_mark(0) {
26  setup(buffer, size);
27 }
28 
29 void CircularBuffer ::setup(U8* const buffer, const FwSizeType size) {
30  FW_ASSERT(size > 0);
31  FW_ASSERT(buffer != nullptr);
32  FW_ASSERT(m_store == nullptr && m_store_size == 0); // Not already setup
33 
34  // Initialize buffer data
35  m_store = buffer;
36  m_store_size = size;
37  m_head_idx = 0;
38  m_allocated_size = 0;
39  m_high_water_mark = 0;
40 }
41 
43  return m_allocated_size;
44 }
45 
47  FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called
48  FW_ASSERT(m_allocated_size <= m_store_size, static_cast<FwAssertArgType>(m_allocated_size));
49  return m_store_size - m_allocated_size;
50 }
51 
52 FwSizeType CircularBuffer ::advance_idx(FwSizeType idx, FwSizeType amount) const {
53  FW_ASSERT(idx < m_store_size, static_cast<FwAssertArgType>(idx));
54  return (idx + amount) % m_store_size;
55 }
56 
57 Fw::SerializeStatus CircularBuffer ::serialize(const U8* const buffer, const FwSizeType size) {
58  FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called
59  FW_ASSERT(buffer != nullptr);
60  // Check there is sufficient space
61  if (size > get_free_size()) {
63  }
64  // Copy in all the supplied data
65  FwSizeType idx = advance_idx(m_head_idx, m_allocated_size);
66  for (FwSizeType i = 0; i < size; i++) {
67  FW_ASSERT(idx < m_store_size, static_cast<FwAssertArgType>(idx));
68  m_store[idx] = buffer[i];
69  idx = advance_idx(idx);
70  }
71  m_allocated_size += size;
72  FW_ASSERT(m_allocated_size <= this->get_capacity(), static_cast<FwAssertArgType>(m_allocated_size));
73  m_high_water_mark = (m_high_water_mark > m_allocated_size) ? m_high_water_mark : m_allocated_size;
74  return Fw::FW_SERIALIZE_OK;
75 }
76 
77 template <typename T>
78 Fw::SerializeStatus CircularBuffer ::serialize_impl(const T& serializable, const FwSizeType size) {
79  FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called
80  // Check there is sufficient space
81  if (size > get_free_size()) {
83  }
84  const FwSizeType idx = advance_idx(m_head_idx, m_allocated_size);
85  // Wrapping slot: serialize into a stack staging buffer, then byte-copy in with wrap-around
86  if ((idx + size) > m_store_size) {
87  FW_ASSERT(size <= STAGING_BUFFER_SIZE, static_cast<FwAssertArgType>(size),
88  static_cast<FwAssertArgType>(STAGING_BUFFER_SIZE));
89  U8 staging[STAGING_BUFFER_SIZE > 0 ? STAGING_BUFFER_SIZE : 1] = {};
90  Fw::ExternalSerializeBuffer stagingBuffer(staging, size);
91  const Fw::SerializeStatus stagingStatus = stagingBuffer.serializeFrom(serializable);
92  if (stagingStatus != Fw::FW_SERIALIZE_OK) {
93  return stagingStatus;
94  }
95  return this->serialize(staging, size);
96  }
97  // Linear slot: serialize directly into the store
98  Fw::ExternalSerializeBuffer slot(&m_store[idx], size);
99  const Fw::SerializeStatus status = slot.serializeFrom(serializable);
100  if (status != Fw::FW_SERIALIZE_OK) {
101  return status;
102  }
103  m_allocated_size += size;
104  FW_ASSERT(m_allocated_size <= this->get_capacity(), static_cast<FwAssertArgType>(m_allocated_size));
105  m_high_water_mark = (m_high_water_mark > m_allocated_size) ? m_high_water_mark : m_allocated_size;
106  return Fw::FW_SERIALIZE_OK;
107 }
108 
110  return this->serialize_impl(serializable, size);
111 }
112 
114  return this->serialize_impl(buffer, size);
115 }
116 
118  FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called
119  return peek(reinterpret_cast<U8&>(value), offset);
120 }
121 
123  FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called
124  // Check there is sufficient data
125  if ((sizeof(U8) + offset) > m_allocated_size) {
127  }
128  const FwSizeType idx = advance_idx(m_head_idx, offset);
129  FW_ASSERT(idx < m_store_size, static_cast<FwAssertArgType>(idx));
130  value = m_store[idx];
131  return Fw::FW_SERIALIZE_OK;
132 }
133 
135  FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called
136  // Check there is sufficient data
137  if ((sizeof(U32) + offset) > m_allocated_size) {
139  }
140  value = 0;
141  FwSizeType idx = advance_idx(m_head_idx, offset);
142 
143  // Deserialize all the bytes from network format
144  for (FwSizeType i = 0; i < sizeof(U32); i++) {
145  FW_ASSERT(idx < m_store_size, static_cast<FwAssertArgType>(idx));
146  value = (value << 8) | static_cast<U32>(m_store[idx]);
147  idx = advance_idx(idx);
148  }
149  return Fw::FW_SERIALIZE_OK;
150 }
151 
153  FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called
154  FW_ASSERT(buffer != nullptr);
155  // Check there is sufficient data
156  if ((size + offset) > m_allocated_size) {
158  }
159  FwSizeType idx = advance_idx(m_head_idx, offset);
160  // Deserialize all the bytes from network format
161  for (FwSizeType i = 0; i < size; i++) {
162  FW_ASSERT(idx < m_store_size, static_cast<FwAssertArgType>(idx));
163  buffer[i] = m_store[idx];
164  idx = advance_idx(idx);
165  }
166  return Fw::FW_SERIALIZE_OK;
167 }
168 
169 template <typename T>
170 Fw::SerializeStatus CircularBuffer ::peek_impl(T& serializable, FwSizeType size, FwSizeType offset) const {
171  FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called
172  // Check there is sufficient data
173  if ((size + offset) > m_allocated_size) {
175  }
176  const FwSizeType idx = advance_idx(m_head_idx, offset);
177  // Wrapping slot: byte-copy out with wrap-around into a stack staging buffer, then deserialize
178  if ((idx + size) > m_store_size) {
179  FW_ASSERT(size <= STAGING_BUFFER_SIZE, static_cast<FwAssertArgType>(size),
180  static_cast<FwAssertArgType>(STAGING_BUFFER_SIZE));
181  U8 staging[STAGING_BUFFER_SIZE > 0 ? STAGING_BUFFER_SIZE : 1];
182  const Fw::SerializeStatus peekStatus = this->peek(staging, size, offset);
183  if (peekStatus != Fw::FW_SERIALIZE_OK) {
184  return peekStatus;
185  }
186  Fw::ExternalSerializeBuffer stagingBuffer(staging, size);
187  const Fw::SerializeStatus status = stagingBuffer.setBuffLen(size);
188  FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast<FwAssertArgType>(status));
189  return stagingBuffer.deserializeTo(serializable);
190  }
191  // Linear slot: deserialize directly from the store
192  Fw::ExternalSerializeBuffer slot(&m_store[idx], size);
193  Fw::SerializeStatus status = slot.setBuffLen(size);
194  FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast<FwAssertArgType>(status));
195  return slot.deserializeTo(serializable);
196 }
197 
199  return this->peek_impl(serializable, size, offset);
200 }
201 
203  return this->peek_impl(buffer, size, offset);
204 }
205 
207  FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called
208  // Check there is sufficient data
209  if (amount > m_allocated_size) {
211  }
212  m_head_idx = advance_idx(m_head_idx, amount);
213  m_allocated_size -= amount;
214  return Fw::FW_SERIALIZE_OK;
215 }
216 
218  FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called
219  // Check there is sufficient data
220  if (amount > m_allocated_size) {
222  }
223  // Simply reduce the allocated size without moving the head
224  m_allocated_size -= amount;
225  return Fw::FW_SERIALIZE_OK;
226 }
227 
229  FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called
230  return m_store_size;
231 }
232 
234  return m_high_water_mark;
235 }
236 
238  m_high_water_mark = 0;
239 }
240 
241 } // End Namespace Types
Serialization/Deserialization operation was successful.
Deserialization buffer was empty when trying to read more data.
PlatformSizeType FwSizeType
No room left in the buffer to serialize data.
SerializeStatus
forward declaration for string
FwSizeType get_high_water_mark() const
Fw::SerializeStatus serialize(const U8 *const buffer, const FwSizeType size)
External serialize buffer with no copy semantics.
Fw::SerializeStatus rotate(FwSizeType amount)
FwSizeType get_allocated_size() const
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:54
FwSizeType get_capacity() const
Fw::SerializeStatus peek(char &value, FwSizeType offset=0) const
void setup(U8 *const buffer, const FwSizeType size)
FwSizeType get_free_size() const
Fw::SerializeStatus trim(FwSizeType amount)
#define FW_ASSERT(...)
Definition: Assert.hpp:14