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  // The buffer is not necessarily a full frame, so the attached context has no meaning and we ignore it
57  this->processBuffer(buffer);
58  }
59  // Return ownership of the incoming data
60  this->dataReturnOut_out(0, buffer, context);
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  buffer.setSize(static_cast<Fw::Buffer::SizeType>(size_out));
132  FW_ASSERT(serialize_status == Fw::SerializeStatus::FW_SERIALIZE_OK);
133  // Consume (rotate) the data from the ring buffer
134  serialize_status = this->m_inRing.rotate(size_out);
135  FW_ASSERT(serialize_status == Fw::SerializeStatus::FW_SERIALIZE_OK);
136  FW_ASSERT(m_inRing.get_allocated_size() == remaining - size_out,
137  static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
138  static_cast<FwAssertArgType>(remaining), static_cast<FwAssertArgType>(size_out));
139  ComCfg::FrameContext context;
140  this->dataOut_out(0, buffer, context);
141  } else {
142  // No buffer is available, we need to exit and try again later
144  break;
145  }
146  }
147  // More data needed
148  else if (status == FrameDetector::MORE_DATA_NEEDED) {
149  // size_out can never be larger than the capacity of the ring. Otherwise all uplink will fail.
150  FW_ASSERT(size_out < m_inRing.get_capacity(), static_cast<FwAssertArgType>(size_out));
151  // Detection should report "more is needed" and set size_out to something larger than available data
152  FW_ASSERT(size_out > remaining, static_cast<FwAssertArgType>(size_out),
153  static_cast<FwAssertArgType>(remaining));
154  // Break out of loop: suspend detection until we receive another buffer
155  break;
156  }
157  // No frame was detected or an unknown status was received
158  else {
159  // Discard a single byte of data and start again
160  (void)this->m_inRing.rotate(1);
161  FW_ASSERT(m_inRing.get_allocated_size() == remaining - 1,
162  static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
163  static_cast<FwAssertArgType>(remaining));
164  }
165  }
166 }
167 
168 void FrameAccumulator ::dataReturnIn_handler(FwIndexType portNum,
169  Fw::Buffer& fwBuffer,
170  const ComCfg::FrameContext& context) {
171  // Frame buffer ownership is returned to the component. Component had allocated with a buffer manager,
172  // so we return it to the buffer manager for deallocation
173  this->bufferDeallocate_out(0, fwBuffer);
174 }
175 
176 } // namespace Svc
Serialization/Deserialization operation was successful.
Fw::Buffer bufferAllocate_out(FwIndexType portNum, FwSizeType size)
Invoke output port bufferAllocate.
PlatformSizeType FwSizeType
I32 FwEnumStoreType
void setSize(FwSizeType size)
Definition: Buffer.cpp:75
virtual void * allocate(const FwEnumStoreType identifier, FwSizeType &size, bool &recoverable)=0
Allocate memory.
U8 * getData() const
Definition: Buffer.cpp:56
void dataReturnOut_out(FwIndexType portNum, Fw::Buffer &data, const ComCfg::FrameContext &context)
Invoke output port dataReturnOut.
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.
void dataOut_out(FwIndexType portNum, Fw::Buffer &data, const ComCfg::FrameContext &context)
Invoke output port dataOut.
~FrameAccumulator()
Destroy FrameAccumulator object.
bool isValid() const
Definition: Buffer.cpp:52
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: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
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.
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.