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 
8 #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) {
54  // Check whether there is data to process
55  if (buffer.isValid()) {
56  this->processBuffer(buffer);
57  }
58  // TODO: rework the uplink deallocation logic to use the bufferReturn chaining pattern
59  // Deallocate the buffer
60  this->bufferDeallocate_out(0, buffer);
61 }
62 
63 void FrameAccumulator ::processBuffer(Fw::Buffer& buffer) {
64  const FwSizeType bufferSize = buffer.getSize();
65  U8* const bufferData = buffer.getData();
66  // Current offset into buffer
67  FwSizeType offset = 0;
68  // Remaining data in buffer
69  FwSizeType remaining = bufferSize;
70 
71  for (FwSizeType i = 0; i < bufferSize; ++i) {
72  // If there is no data left or no space, exit the loop
73  if (remaining == 0 || this->m_inRing.get_free_size() == 0) {
74  break;
75  }
76  // Compute the size of data to serialize
77  const FwSizeType ringFreeSize = this->m_inRing.get_free_size();
78  const FwSizeType serSize = (ringFreeSize <= remaining) ? ringFreeSize : remaining;
79  // Serialize data into the ring buffer
80  const Fw::SerializeStatus status = this->m_inRing.serialize(&bufferData[offset], serSize);
81  // If data does not fit, there is a coding error
82  FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast<FwAssertArgType>(status),
83  static_cast<FwAssertArgType>(offset), static_cast<FwAssertArgType>(serSize));
84  // Process the data
85  this->processRing();
86  // Update buffer offset and remaining
87  offset += serSize;
88  remaining -= serSize;
89  }
90  // Either all the bytes from the data buffer must be processed, or the ring must be full
91  FW_ASSERT(remaining == 0 || this->m_inRing.get_free_size() == 0, static_cast<FwAssertArgType>(remaining));
92 }
93 
94 void FrameAccumulator ::processRing() {
95  FW_ASSERT(this->m_detector != nullptr);
96 
97  // The number of remaining bytes in the ring buffer
98  FwSizeType remaining = 0;
99  // The protocol status
100  FrameDetector::Status status = FrameDetector::Status::FRAME_DETECTED;
101  // The ring buffer capacity
102  const FwSizeType ringCapacity = this->m_inRing.get_capacity();
103 
104  // Process the ring buffer looking for at least the header
105  for (FwSizeType i = 0; i < ringCapacity; i++) {
106  // Get the number of bytes remaining in the ring buffer
107  remaining = this->m_inRing.get_allocated_size();
108  // If there are none, we are done
109  if (remaining == 0) {
110  break;
111  }
112  // size_out is a return variable we initialize to zero, but it should be overwritten
113  FwSizeType size_out = 0;
114  // Attempt to detect the frame without changing the circular buffer
115  status = this->m_detector->detect(this->m_inRing, size_out);
116  // Detect must not consume data in the ring buffer
117  FW_ASSERT(m_inRing.get_allocated_size() == remaining,
118  static_cast<FwAssertArgType>(m_inRing.get_allocated_size()), static_cast<FwAssertArgType>(remaining));
119  // On successful detection, consume data from the ring buffer and place it into an allocated frame
120  if (status == FrameDetector::FRAME_DETECTED) {
121  // size_out must be set to the size of the buffer and must fit within the existing data
122  FW_ASSERT(size_out != 0);
123  FW_ASSERT(size_out <= remaining, static_cast<FwAssertArgType>(size_out),
124  static_cast<FwAssertArgType>(remaining));
125  // check for overflow before casting down to U32
126  FW_ASSERT(size_out <= std::numeric_limits<U32>::max());
127  Fw::Buffer buffer = this->bufferAllocate_out(0, static_cast<U32>(size_out));
128  if (buffer.isValid()) {
129  // Copy data out of ring buffer into the allocated buffer
130  Fw::SerializeStatus serialize_status = this->m_inRing.peek(buffer.getData(), size_out);
131  FW_ASSERT(serialize_status == Fw::SerializeStatus::FW_SERIALIZE_OK);
132  // Consume (rotate) the data from the ring buffer
133  serialize_status = this->m_inRing.rotate(size_out);
134  FW_ASSERT(serialize_status == Fw::SerializeStatus::FW_SERIALIZE_OK);
135  FW_ASSERT(m_inRing.get_allocated_size() == remaining - size_out,
136  static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
137  static_cast<FwAssertArgType>(remaining), static_cast<FwAssertArgType>(size_out));
138  ComCfg::FrameContext context;
139  this->frameOut_out(0, buffer, context);
140  } else {
141  // No buffer is available, we need to exit and try again later
143  break;
144  }
145  }
146  // More data needed
147  else if (status == FrameDetector::MORE_DATA_NEEDED) {
148  // size_out can never be larger than the capacity of the ring. Otherwise all uplink will fail.
149  FW_ASSERT(size_out < m_inRing.get_capacity(), static_cast<FwAssertArgType>(size_out));
150  // Detection should report "more is needed" and set size_out to something larger than available data
151  FW_ASSERT(size_out > remaining, static_cast<FwAssertArgType>(size_out),
152  static_cast<FwAssertArgType>(remaining));
153  // Break out of loop: suspend detection until we receive another buffer
154  break;
155  }
156  // No frame was detected or an unknown status was received
157  else {
158  // Discard a single byte of data and start again
159  (void)this->m_inRing.rotate(1);
160  FW_ASSERT(m_inRing.get_allocated_size() == remaining - 1,
161  static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
162  static_cast<FwAssertArgType>(remaining));
163  }
164  }
165 }
166 } // namespace Svc
Serialization/Deserialization operation was successful.
Fw::Buffer bufferAllocate_out(FwIndexType portNum, U32 size)
Invoke output port bufferAllocate.
PlatformSizeType FwSizeType
I32 FwEnumStoreType
virtual void * allocate(const FwEnumStoreType identifier, FwSizeType &size, bool &recoverable)=0
Allocate memory.
void frameOut_out(FwIndexType portNum, Fw::Buffer &data, const ComCfg::FrameContext &context)
Invoke output port frameOut.
U8 * getData() const
Definition: Buffer.cpp:68
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:64
Fw::SerializeStatus rotate(FwSizeType amount)
void bufferDeallocate_out(FwIndexType portNum, Fw::Buffer &fwBuffer)
Invoke output port bufferDeallocate.
FwSizeType get_allocated_size() const
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:56
FwSizeType get_capacity() const
void cleanup()
Deallocate internal resources (set up by configure() call)
virtual Status detect(const Types::CircularBuffer &data, FwSizeType &size_out) const =0
detect if a frame is available within the circular buffer
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
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
Deallocate memory.
SizeType getSize() const
Definition: Buffer.cpp:72
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.