F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
FrameAccumulator.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title FrameAccumulator.cpp
3 // \author mstarch
4 // \brief cpp file for FrameAccumulator component implementation class
5 // ======================================================================
6 
9 #include "Fw/Types/Assert.hpp"
10 
11 namespace Svc {
12 
13 // ----------------------------------------------------------------------
14 // Component construction and destruction
15 // ----------------------------------------------------------------------
16 
17 FrameAccumulator ::FrameAccumulator(const char* const compName)
19  m_detector(nullptr),
20  m_memoryAllocator(nullptr),
21  m_memory(nullptr),
22  m_allocatorId(0) {}
23 
25 
27  FwEnumStoreType allocationId,
28  Fw::MemAllocator& allocator,
29  FwSizeType store_size) {
30  bool recoverable = false;
31  U8* const data = static_cast<U8*>(allocator.allocate(allocationId, store_size, recoverable));
32  FW_ASSERT(data != nullptr);
33  m_inRing.setup(data, store_size);
34 
35  this->m_detector = &detector;
36  this->m_allocatorId = allocationId;
37  this->m_memoryAllocator = &allocator;
38  this->m_memory = data;
39 }
40 
42  // If configuration happened, we must deallocate
43  if (this->m_memoryAllocator != nullptr) {
44  this->m_memoryAllocator->deallocate(this->m_allocatorId, this->m_memory);
45  this->m_memory = nullptr;
46  }
47 }
48 
49 // ----------------------------------------------------------------------
50 // Handler implementations for user-defined typed input ports
51 // ----------------------------------------------------------------------
52 
53 void FrameAccumulator ::dataIn_handler(FwIndexType portNum, Fw::Buffer& buffer, const ComCfg::FrameContext& context) {
54  // Check whether there is data to process
55  if (buffer.isValid()) {
56  this->processBuffer(buffer, context);
57  }
58  // Return ownership of the incoming data
59  this->dataReturnOut_out(0, buffer, context);
60 }
61 
62 void FrameAccumulator ::processBuffer(Fw::Buffer& buffer, const ComCfg::FrameContext& context) {
63  const FwSizeType bufferSize = buffer.getSize();
64  U8* const bufferData = buffer.getData();
65  // Current offset into buffer
66  FwSizeType offset = 0;
67  // Remaining data in buffer
68  FwSizeType remaining = bufferSize;
69 
70  for (FwSizeType i = 0; i < bufferSize; ++i) {
71  // If there is no data left or no space, exit the loop
72  if (remaining == 0 || this->m_inRing.get_free_size() == 0) {
73  break;
74  }
75  // Compute the size of data to serialize
76  const FwSizeType ringFreeSize = this->m_inRing.get_free_size();
77  const FwSizeType serSize = (ringFreeSize <= remaining) ? ringFreeSize : remaining;
78  // Serialize data into the ring buffer
79  const Fw::SerializeStatus status = this->m_inRing.serialize(&bufferData[offset], serSize);
80  // If data does not fit, there is a coding error
81  FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast<FwAssertArgType>(status),
82  static_cast<FwAssertArgType>(offset), static_cast<FwAssertArgType>(serSize));
83  // Process the data
84  this->processRing(context);
85  // Update buffer offset and remaining
86  offset += serSize;
87  remaining -= serSize;
88  }
89  // Either all the bytes from the data buffer must be processed, or the ring must be full
90  FW_ASSERT(remaining == 0 || this->m_inRing.get_free_size() == 0, static_cast<FwAssertArgType>(remaining));
91 }
92 
93 void FrameAccumulator ::processRing(const ComCfg::FrameContext& context) {
94  FW_ASSERT(this->m_detector != nullptr);
95 
96  // The number of remaining bytes in the ring buffer
97  FwSizeType remaining = 0;
98  // The protocol status
99  FrameDetector::Status status = FrameDetector::Status::FRAME_DETECTED;
100  // The ring buffer capacity
101  const FwSizeType ringCapacity = this->m_inRing.get_capacity();
102 
103  // Process the ring buffer looking for at least the header
104  for (FwSizeType i = 0; i < ringCapacity; i++) {
105  // Get the number of bytes remaining in the ring buffer
106  remaining = this->m_inRing.get_allocated_size();
107  // If there are none, we are done
108  if (remaining == 0) {
109  break;
110  }
111  // size_out is a return variable we initialize to zero, but it should be overwritten
112  FwSizeType size_out = 0;
113  // Attempt to detect the frame without changing the circular buffer
114  status = this->m_detector->detect(this->m_inRing, size_out);
115  // Detect must not consume data in the ring buffer
116  FW_ASSERT(m_inRing.get_allocated_size() == remaining,
117  static_cast<FwAssertArgType>(m_inRing.get_allocated_size()), static_cast<FwAssertArgType>(remaining));
118 
119  // Drop frames that are too large to handle (can't fit in the accumulation circular buffer)
120  if (size_out > ringCapacity) {
121  // Detector reports a size_out larger than the accumulation buffer capacity, we will never be able
122  // to process it. Log a warning and discard a byte, then keep iterating to look for a new frame
124  // Discard a single byte of data and start again
125  (void)this->m_inRing.rotate(1);
126  FW_ASSERT(m_inRing.get_allocated_size() == remaining - 1,
127  static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
128  static_cast<FwAssertArgType>(remaining));
129  continue;
130  }
131 
132  // On successful detection, consume data from the ring buffer and place it into an allocated frame
133  if (status == FrameDetector::FRAME_DETECTED) {
134  // size_out must be set (non-zero) and must fit within the remaining data
135  FW_ASSERT(size_out != 0);
136  FW_ASSERT(size_out <= remaining, static_cast<FwAssertArgType>(size_out),
137  static_cast<FwAssertArgType>(remaining));
138  Fw::Buffer buffer = this->bufferAllocate_out(0, size_out);
139  if (buffer.isValid()) {
140  // Copy data out of ring buffer into the allocated buffer
141  Fw::SerializeStatus serialize_status = this->m_inRing.peek(buffer.getData(), size_out);
142  buffer.setSize(size_out);
143  FW_ASSERT(serialize_status == Fw::SerializeStatus::FW_SERIALIZE_OK);
144  // Consume (rotate) the data from the ring buffer
145  serialize_status = this->m_inRing.rotate(size_out);
146  FW_ASSERT(serialize_status == Fw::SerializeStatus::FW_SERIALIZE_OK);
147  FW_ASSERT(m_inRing.get_allocated_size() == remaining - size_out,
148  static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
149  static_cast<FwAssertArgType>(remaining), static_cast<FwAssertArgType>(size_out));
150  this->dataOut_out(0, buffer, context);
151  } else {
152  // No buffer is available
154  // In the case where no buffer is available and the circular buffer is full, we have to drop the buffer
155  // as there is no other way to retry. Without dropping it, the back pressure would assert the
156  // processing call, which is built on the assumption that at least one byte would process
157  if (this->m_inRing.get_free_size() == 0) {
158  // Discard the whole frame as a last attempt to keep the system afloat
159  Fw::SerializeStatus serialize_status = this->m_inRing.rotate(size_out);
160  FW_ASSERT(serialize_status == Fw::SerializeStatus::FW_SERIALIZE_OK);
161  FW_ASSERT(m_inRing.get_allocated_size() == remaining - size_out,
162  static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
163  static_cast<FwAssertArgType>(remaining), static_cast<FwAssertArgType>(size_out));
165  }
166  break;
167  }
168  }
169  // More data needed
170  else if (status == FrameDetector::MORE_DATA_NEEDED) {
171  // Detection should report "more is needed" and set size_out to something larger than available data
172  FW_ASSERT(size_out > remaining, static_cast<FwAssertArgType>(size_out),
173  static_cast<FwAssertArgType>(remaining));
174  // Break out of loop: suspend detection until we receive another buffer
175  break;
176  }
177  // No frame was detected or an unknown status was received
178  else {
179  // Discard a single byte of data and start again
180  (void)this->m_inRing.rotate(1);
181  FW_ASSERT(m_inRing.get_allocated_size() == remaining - 1,
182  static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
183  static_cast<FwAssertArgType>(remaining));
184  }
185  }
186 }
187 
188 void FrameAccumulator ::dataReturnIn_handler(FwIndexType portNum,
189  Fw::Buffer& fwBuffer,
190  const ComCfg::FrameContext& context) {
191  // Frame buffer ownership is returned to the component. Component had allocated with a buffer manager,
192  // so we return it to the buffer manager for deallocation
193  this->bufferDeallocate_out(0, fwBuffer);
194 }
195 
196 } // namespace Svc
Serialization/Deserialization operation was successful.
void dataOut_out(FwIndexType portNum, Fw::Buffer &data, const ComCfg::FrameContext &context) const
Invoke output port dataOut.
virtual void * allocate(const FwEnumStoreType identifier, FwSizeType &size, bool &recoverable, FwSizeType alignment=alignof(std::max_align_t))=0
PlatformSizeType FwSizeType
void dataReturnOut_out(FwIndexType portNum, Fw::Buffer &data, const ComCfg::FrameContext &context) const
Invoke output port dataReturnOut.
I32 FwEnumStoreType
void setSize(FwSizeType size)
Definition: Buffer.cpp:75
U8 * getData() const
Definition: Buffer.cpp:56
SerializeStatus
forward declaration for string
Fw::SerializeStatus serialize(const U8 *const buffer, const FwSizeType size)
Status
status returned from the detection step
Frame detected. Extract frame and return with new data.
FrameAccumulator(const char *const compName)
Construct FrameAccumulator object.
~FrameAccumulator()
Destroy FrameAccumulator object.
bool isValid() const
Definition: Buffer.cpp:52
Fw::SerializeStatus rotate(FwSizeType amount)
FwSizeType get_allocated_size() const
void bufferDeallocate_out(FwIndexType portNum, Fw::Buffer &fwBuffer) const
Invoke output port bufferDeallocate.
More data is needed to detect a frame. Keep current data and return with more.
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:53
FwSizeType get_capacity() const
void cleanup()
Deallocate internal resources (set up by configure() call)
FwSizeType getSize() const
Definition: Buffer.cpp:60
virtual Status detect(const Types::CircularBuffer &data, FwSizeType &size_out) const =0
detect if a frame is available within the circular buffer
Memory Allocation base class.
void log_WARNING_HI_FrameDetectionSizeError(FwSizeType size_out) const
Fw::SerializeStatus peek(char &value, FwSizeType offset=0) const
PlatformIndexType FwIndexType
void setup(U8 *const buffer, const FwSizeType size)
void configure(const FrameDetector &detector, FwEnumStoreType allocationId, Fw::MemAllocator &allocator, FwSizeType store_size)
configure memory allocation for the circular buffer
FwSizeType get_free_size() const
Fw::Buffer bufferAllocate_out(FwIndexType portNum, FwSizeType size) const
Invoke output port bufferAllocate.
Type used to pass context info between components during framing/deframing.
Auto-generated base for FrameAccumulator component.
RateGroupDivider component implementation.
virtual void deallocate(const FwEnumStoreType identifier, void *ptr)=0
interface class used to codify what must be supported to allow frame detection
#define FW_ASSERT(...)
Definition: Assert.hpp:14
PlatformAssertArgType FwAssertArgType
The type of arguments to assert functions.