F´ Flight Software - C/C++ Documentation  devel
A framework for building embedded system applications to NASA flight quality standards.
Deframer.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title Deframer.cpp
3 // \author mstarch, bocchino
4 // \brief cpp file for Deframer component implementation class
5 //
6 // \copyright
7 // Copyright 2009-2022, by the California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10 //
11 // ======================================================================
12 
13 #include <cstring>
14 
15 #include "Fw/Com/ComPacket.hpp"
16 #include "Fw/Logger/Logger.hpp"
17 #include <FpConfig.hpp>
19 
20 namespace Svc {
21 
22 // ----------------------------------------------------------------------
23 // Static assertions
24 // ----------------------------------------------------------------------
25 
26 static_assert(
28  "poll buffer size must be greater than zero"
29 );
30 static_assert(
32  "ring buffer size must be greater than zero"
33 );
34 
35 // ----------------------------------------------------------------------
36 // Construction, initialization, and destruction
37 // ----------------------------------------------------------------------
38 
39 Deframer ::Deframer(const char* const compName) :
40  DeframerComponentBase(compName),
42  m_protocol(nullptr),
43  m_inRing(m_ringBuffer, sizeof m_ringBuffer)
44 {
45  (void) memset(m_pollBuffer, 0, sizeof m_pollBuffer);
46 }
47 
49 
51  // Check that this is the first time we are calling setup
52  FW_ASSERT(m_protocol == nullptr);
53  // Assign the protocol passed in to m_protocol
54  m_protocol = &protocol;
55  // Pass *this as the DeframingProtocolInstance to protocol setup
56  // Deframer is derived from and implements DeframingProtocolInterface
57  protocol.setup(*this);
58 }
59 
60 // ----------------------------------------------------------------------
61 // Handler implementations for user-defined typed input ports
62 // ----------------------------------------------------------------------
63 
64 void Deframer ::cmdResponseIn_handler(
65  NATIVE_INT_TYPE portNum,
66  FwOpcodeType opcode,
67  U32 cmdSeq,
68  const Fw::CmdResponse& response
69 ) {
70  // Nothing to do
71 }
72 
73 void Deframer ::framedIn_handler(
74  const NATIVE_INT_TYPE portNum,
75  Fw::Buffer& recvBuffer,
76  const Drv::RecvStatus& recvStatus
77 ) {
78  // Check whether there is data to process
79  if (recvStatus.e == Drv::RecvStatus::RECV_OK) {
80  // There is: process the data
81  processBuffer(recvBuffer);
82  }
83  // Deallocate the buffer
84  framedDeallocate_out(0, recvBuffer);
85 }
86 
87 void Deframer ::schedIn_handler(
88  const NATIVE_INT_TYPE portNum,
89  U32 context
90 ) {
91  // Check for data
92  Fw::Buffer buffer(m_pollBuffer, sizeof(m_pollBuffer));
93  const Drv::PollStatus status = framedPoll_out(0, buffer);
94  if (status.e == Drv::PollStatus::POLL_OK) {
95  // Data exists: process it
96  processBuffer(buffer);
97  }
98 }
99 
100 // ----------------------------------------------------------------------
101 // Implementation of DeframingProtocolInterface
102 // ----------------------------------------------------------------------
103 
104 Fw::Buffer Deframer ::allocate(const U32 size) {
105  return bufferAllocate_out(0, size);
106 }
107 
108 void Deframer ::route(Fw::Buffer& packetBuffer) {
109 
110  // Read the packet type from the packet buffer
113  {
114  Fw::SerializeBufferBase& serial = packetBuffer.getSerializeRepr();
115  status = serial.setBuffLen(packetBuffer.getSize());
116  FW_ASSERT(status == Fw::FW_SERIALIZE_OK);
117  status = serial.deserialize(packetType);
118  }
119 
120  // Whether to deallocate the packet buffer
121  bool deallocate = true;
122 
123  // Process the packet
124  if (status == Fw::FW_SERIALIZE_OK) {
125  U8 *const packetData = packetBuffer.getData();
126  const U32 packetSize = packetBuffer.getSize();
127  switch (packetType) {
128  // Handle a command packet
130  // Allocate a com buffer on the stack
131  Fw::ComBuffer com;
132  // Copy the contents of the packet buffer into the com buffer
133  status = com.setBuff(packetData, packetSize);
134  if (status == Fw::FW_SERIALIZE_OK) {
135  // Send the com buffer
136  comOut_out(0, com, 0);
137  }
138  else {
140  "[ERROR] Serializing com buffer failed with status %d\n",
141  status
142  );
143  }
144  break;
145  }
146  // Handle a file packet
148  // If the file uplink output port is connected,
149  // send the file packet. Otherwise take no action.
151  // Shift the packet buffer to skip the packet type
152  // The FileUplink component does not expect the packet
153  // type to be there.
154  packetBuffer.setData(packetData + sizeof(packetType));
155  packetBuffer.setSize(static_cast<U32>(packetSize - sizeof(packetType)));
156  // Send the packet buffer
157  bufferOut_out(0, packetBuffer);
158  // Transfer ownership of the buffer to the receiver
159  deallocate = false;
160  }
161  break;
162  }
163  // Take no action for other packet types
164  default:
165  break;
166  }
167  }
168  else {
170  "[ERROR] Deserializing packet type failed with status %d\n",
171  status
172  );
173  }
174 
175  if (deallocate) {
176  // Deallocate the packet buffer
177  bufferDeallocate_out(0, packetBuffer);
178  }
179 
180 }
181 
182 // ----------------------------------------------------------------------
183 // Helper methods
184 // ----------------------------------------------------------------------
185 
186 void Deframer ::processBuffer(Fw::Buffer& buffer) {
187 
188  const U32 bufferSize = buffer.getSize();
189  U8 *const bufferData = buffer.getData();
190  // Current offset into buffer
191  U32 offset = 0;
192  // Remaining data in buffer
193  U32 remaining = bufferSize;
194 
195  for (U32 i = 0; i < bufferSize; ++i) {
196  // If there is no data left, exit the loop
197  if (remaining == 0) {
198  break;
199  }
200  // Compute the size of data to serialize
201  const NATIVE_UINT_TYPE ringFreeSize = m_inRing.get_free_size();
202  const NATIVE_UINT_TYPE serSize = (ringFreeSize <= remaining) ?
203  ringFreeSize : static_cast<NATIVE_UINT_TYPE>(remaining);
204  // Serialize data into the ring buffer
205  const Fw::SerializeStatus status =
206  m_inRing.serialize(&bufferData[offset], serSize);
207  // If data does not fit, there is a coding error
208  FW_ASSERT(
209  status == Fw::FW_SERIALIZE_OK,
210  static_cast<FwAssertArgType>(status),
211  static_cast<FwAssertArgType>(offset),
212  static_cast<FwAssertArgType>(serSize));
213  // Process the data
214  processRing();
215  // Update buffer offset and remaining
216  offset += serSize;
217  remaining -= serSize;
218  }
219 
220  // In every iteration, either remaining == 0 and we break out
221  // of the loop, or we consume at least one byte from the buffer.
222  // So there should be no data left in the buffer.
223  FW_ASSERT(remaining == 0, static_cast<FwAssertArgType>(remaining));
224 
225 }
226 
227 void Deframer ::processRing() {
228 
229  FW_ASSERT(m_protocol != nullptr);
230 
231  // The number of remaining bytes in the ring buffer
232  U32 remaining = 0;
233  // The protocol status
236  // The ring buffer capacity
237  const NATIVE_UINT_TYPE ringCapacity = m_inRing.get_capacity();
238 
239  // Process the ring buffer looking for at least the header
240  for (U32 i = 0; i < ringCapacity; i++) {
241  // Get the number of bytes remaining in the ring buffer
242  remaining = m_inRing.get_allocated_size();
243  // If there are none, we are done
244  if (remaining == 0) {
245  break;
246  }
247  // Needed is an out-only variable
248  // Initialize it to zero
249  U32 needed = 0;
250  // Call the deframe method of the protocol, getting
251  // needed and status
252  status = m_protocol->deframe(m_inRing, needed);
253  // Deframing protocol must not consume data in the ring buffer
254  FW_ASSERT(
255  m_inRing.get_allocated_size() == remaining,
256  static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
257  static_cast<FwAssertArgType>(remaining)
258  );
259  // On successful deframing, consume data from the ring buffer now
261  // If deframing succeeded, protocol should set needed
262  // to a non-zero value
263  FW_ASSERT(needed != 0);
264  FW_ASSERT(
265  needed <= remaining,
266  static_cast<FwAssertArgType>(needed),
267  static_cast<FwAssertArgType>(remaining));
268  m_inRing.rotate(needed);
269  FW_ASSERT(
270  m_inRing.get_allocated_size() == remaining - needed,
271  static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
272  static_cast<FwAssertArgType>(remaining),
273  static_cast<FwAssertArgType>(needed)
274  );
275  }
276  // More data needed
277  else if (status == DeframingProtocol::DEFRAMING_MORE_NEEDED) {
278  // Deframing protocol should not report "more is needed"
279  // unless more is needed
280  FW_ASSERT(
281  needed > remaining,
282  static_cast<FwAssertArgType>(needed),
283  static_cast<FwAssertArgType>(remaining));
284  // Break out of loop: suspend deframing until we receive
285  // another buffer
286  break;
287  }
288  // Error occurred
289  else {
290  // Skip one byte of bad data
291  m_inRing.rotate(1);
292  FW_ASSERT(
293  m_inRing.get_allocated_size() == remaining - 1,
294  static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
295  static_cast<FwAssertArgType>(remaining)
296  );
297  // Log checksum errors
298  // This is likely a real error, not an artifact of other data corruption
300  Fw::Logger::log("[ERROR] Deframing checksum validation failed\n");
301  }
302  }
303  }
304 
305  // If more not needed, circular buffer should be empty
307  FW_ASSERT(remaining == 0, static_cast<FwAssertArgType>(remaining));
308  }
309 
310 }
311 
312 } // end namespace Svc
#define FW_ASSERT(...)
Definition: Assert.hpp:14
PlatformIntType NATIVE_INT_TYPE
Definition: BasicTypes.h:55
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:30
PlatformUIntType NATIVE_UINT_TYPE
Definition: BasicTypes.h:56
PlatformAssertArgType FwAssertArgType
Definition: FpConfig.h:39
U32 FwPacketDescriptorType
Definition: FpConfig.h:87
U32 FwOpcodeType
Definition: FpConfig.h:91
C++-compatible configuration header for fprime configuration.
T e
The raw enum value.
@ POLL_OK
Poll successfully received data.
Status associated with the received data.
@ RECV_OK
Receive worked as expected.
T e
The raw enum value.
U8 * getData() const
Definition: Buffer.cpp:68
U32 getSize() const
Definition: Buffer.cpp:72
void setData(U8 *data)
Definition: Buffer.cpp:80
void setSize(U32 size)
Definition: Buffer.cpp:87
SerializeBufferBase & getSerializeRepr()
Definition: Buffer.cpp:107
Enum representing a command response.
static void log(const char *format,...)
log a formated string with supplied arguments
Definition: Logger.cpp:21
SerializeStatus setBuffLen(Serializable::SizeType length)
sets buffer length manually after filling with data
SerializeStatus setBuff(const U8 *src, Serializable::SizeType length)
sets buffer contents and size
SerializeStatus deserialize(U8 &val)
deserialize 8-bit unsigned int
Auto-generated base for Deframer component.
void bufferDeallocate_out(FwIndexType portNum, Fw::Buffer &fwBuffer)
Invoke output port bufferDeallocate.
void framedDeallocate_out(FwIndexType portNum, Fw::Buffer &fwBuffer)
Invoke output port framedDeallocate.
void bufferOut_out(FwIndexType portNum, Fw::Buffer &fwBuffer)
Invoke output port bufferOut.
Fw::Buffer bufferAllocate_out(FwIndexType portNum, U32 size)
Invoke output port bufferAllocate.
Drv::PollStatus framedPoll_out(FwIndexType portNum, Fw::Buffer &pollBuffer)
Invoke output port framedPoll.
bool isConnected_bufferOut_OutputPort(FwIndexType portNum)
void comOut_out(FwIndexType portNum, Fw::ComBuffer &data, U32 context)
Invoke output port comOut.
~Deframer()
Destroy Deframer instance.
Definition: Deframer.cpp:48
void setup(DeframingProtocol &protocol)
Set up the instance.
Definition: Deframer.cpp:50
Deframer(const char *const compName)
Construct Deframer instance.
Definition: Deframer.cpp:39
Abstract base class representing a deframing protocol.
virtual DeframingStatus deframe(Types::CircularBuffer &buffer, U32 &needed)=0
DeframingStatus
Status of the deframing call.
void setup(DeframingProtocolInterface &interface)
interface supplied to the deframing protocol
Fw::SerializeStatus serialize(const U8 *const buffer, const NATIVE_UINT_TYPE size)
NATIVE_UINT_TYPE get_free_size() const
NATIVE_UINT_TYPE get_allocated_size() const
NATIVE_UINT_TYPE get_capacity() const
Fw::SerializeStatus rotate(NATIVE_UINT_TYPE amount)
SerializeStatus
forward declaration for string
@ FW_SERIALIZE_OK
Serialization/Deserialization operation was successful.
static const U32 POLL_BUFFER_SIZE
The size of the polling buffer in bytes.
Definition: DeframerCfg.hpp:17
static const U32 RING_BUFFER_SIZE
The size of the circular buffer in bytes.
Definition: DeframerCfg.hpp:15