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 
48 void Deframer ::init(const NATIVE_INT_TYPE instance) {
50 }
51 
53 
55  // Check that this is the first time we are calling setup
56  FW_ASSERT(m_protocol == nullptr);
57  // Assign the protocol passed in to m_protocol
58  m_protocol = &protocol;
59  // Pass *this as the DeframingProtocolInstance to protocol setup
60  // Deframer is derived from and implements DeframingProtocolInterface
61  protocol.setup(*this);
62 }
63 
64 // ----------------------------------------------------------------------
65 // Handler implementations for user-defined typed input ports
66 // ----------------------------------------------------------------------
67 
68 void Deframer ::cmdResponseIn_handler(
69  NATIVE_INT_TYPE portNum,
70  FwOpcodeType opcode,
71  U32 cmdSeq,
72  const Fw::CmdResponse& response
73 ) {
74  // Nothing to do
75 }
76 
77 void Deframer ::framedIn_handler(
78  const NATIVE_INT_TYPE portNum,
79  Fw::Buffer& recvBuffer,
80  const Drv::RecvStatus& recvStatus
81 ) {
82  // Check whether there is data to process
83  if (recvStatus.e == Drv::RecvStatus::RECV_OK) {
84  // There is: process the data
85  processBuffer(recvBuffer);
86  }
87  // Deallocate the buffer
88  framedDeallocate_out(0, recvBuffer);
89 }
90 
91 void Deframer ::schedIn_handler(
92  const NATIVE_INT_TYPE portNum,
93  U32 context
94 ) {
95  // Check for data
96  Fw::Buffer buffer(m_pollBuffer, sizeof(m_pollBuffer));
97  const Drv::PollStatus status = framedPoll_out(0, buffer);
98  if (status.e == Drv::PollStatus::POLL_OK) {
99  // Data exists: process it
100  processBuffer(buffer);
101  }
102 }
103 
104 // ----------------------------------------------------------------------
105 // Implementation of DeframingProtocolInterface
106 // ----------------------------------------------------------------------
107 
108 Fw::Buffer Deframer ::allocate(const U32 size) {
109  return bufferAllocate_out(0, size);
110 }
111 
112 void Deframer ::route(Fw::Buffer& packetBuffer) {
113 
114  // Read the packet type from the packet buffer
117  {
118  Fw::SerializeBufferBase& serial = packetBuffer.getSerializeRepr();
119  status = serial.setBuffLen(packetBuffer.getSize());
120  FW_ASSERT(status == Fw::FW_SERIALIZE_OK);
121  status = serial.deserialize(packetType);
122  }
123 
124  // Whether to deallocate the packet buffer
125  bool deallocate = true;
126 
127  // Process the packet
128  if (status == Fw::FW_SERIALIZE_OK) {
129  U8 *const packetData = packetBuffer.getData();
130  const U32 packetSize = packetBuffer.getSize();
131  switch (packetType) {
132  // Handle a command packet
134  // Allocate a com buffer on the stack
135  Fw::ComBuffer com;
136  // Copy the contents of the packet buffer into the com buffer
137  status = com.setBuff(packetData, packetSize);
138  if (status == Fw::FW_SERIALIZE_OK) {
139  // Send the com buffer
140  comOut_out(0, com, 0);
141  }
142  else {
144  "[ERROR] Serializing com buffer failed with status %d\n",
145  status
146  );
147  }
148  break;
149  }
150  // Handle a file packet
152  // If the file uplink output port is connected,
153  // send the file packet. Otherwise take no action.
155  // Shift the packet buffer to skip the packet type
156  // The FileUplink component does not expect the packet
157  // type to be there.
158  packetBuffer.setData(packetData + sizeof(packetType));
159  packetBuffer.setSize(static_cast<U32>(packetSize - sizeof(packetType)));
160  // Send the packet buffer
161  bufferOut_out(0, packetBuffer);
162  // Transfer ownership of the buffer to the receiver
163  deallocate = false;
164  }
165  break;
166  }
167  // Take no action for other packet types
168  default:
169  break;
170  }
171  }
172  else {
174  "[ERROR] Deserializing packet type failed with status %d\n",
175  status
176  );
177  }
178 
179  if (deallocate) {
180  // Deallocate the packet buffer
181  bufferDeallocate_out(0, packetBuffer);
182  }
183 
184 }
185 
186 // ----------------------------------------------------------------------
187 // Helper methods
188 // ----------------------------------------------------------------------
189 
190 void Deframer ::processBuffer(Fw::Buffer& buffer) {
191 
192  const U32 bufferSize = buffer.getSize();
193  U8 *const bufferData = buffer.getData();
194  // Current offset into buffer
195  U32 offset = 0;
196  // Remaining data in buffer
197  U32 remaining = bufferSize;
198 
199  for (U32 i = 0; i < bufferSize; ++i) {
200  // If there is no data left, exit the loop
201  if (remaining == 0) {
202  break;
203  }
204  // Compute the size of data to serialize
205  const NATIVE_UINT_TYPE ringFreeSize = m_inRing.get_free_size();
206  const NATIVE_UINT_TYPE serSize = (ringFreeSize <= remaining) ?
207  ringFreeSize : static_cast<NATIVE_UINT_TYPE>(remaining);
208  // Serialize data into the ring buffer
209  const Fw::SerializeStatus status =
210  m_inRing.serialize(&bufferData[offset], serSize);
211  // If data does not fit, there is a coding error
212  FW_ASSERT(
213  status == Fw::FW_SERIALIZE_OK,
214  static_cast<FwAssertArgType>(status),
215  static_cast<FwAssertArgType>(offset),
216  static_cast<FwAssertArgType>(serSize));
217  // Process the data
218  processRing();
219  // Update buffer offset and remaining
220  offset += serSize;
221  remaining -= serSize;
222  }
223 
224  // In every iteration, either remaining == 0 and we break out
225  // of the loop, or we consume at least one byte from the buffer.
226  // So there should be no data left in the buffer.
227  FW_ASSERT(remaining == 0, static_cast<FwAssertArgType>(remaining));
228 
229 }
230 
231 void Deframer ::processRing() {
232 
233  FW_ASSERT(m_protocol != nullptr);
234 
235  // The number of remaining bytes in the ring buffer
236  U32 remaining = 0;
237  // The protocol status
240  // The ring buffer capacity
241  const NATIVE_UINT_TYPE ringCapacity = m_inRing.get_capacity();
242 
243  // Process the ring buffer looking for at least the header
244  for (U32 i = 0; i < ringCapacity; i++) {
245  // Get the number of bytes remaining in the ring buffer
246  remaining = m_inRing.get_allocated_size();
247  // If there are none, we are done
248  if (remaining == 0) {
249  break;
250  }
251  // Needed is an out-only variable
252  // Initialize it to zero
253  U32 needed = 0;
254  // Call the deframe method of the protocol, getting
255  // needed and status
256  status = m_protocol->deframe(m_inRing, needed);
257  // Deframing protocol must not consume data in the ring buffer
258  FW_ASSERT(
259  m_inRing.get_allocated_size() == remaining,
260  static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
261  static_cast<FwAssertArgType>(remaining)
262  );
263  // On successful deframing, consume data from the ring buffer now
265  // If deframing succeeded, protocol should set needed
266  // to a non-zero value
267  FW_ASSERT(needed != 0);
268  FW_ASSERT(
269  needed <= remaining,
270  static_cast<FwAssertArgType>(needed),
271  static_cast<FwAssertArgType>(remaining));
272  m_inRing.rotate(needed);
273  FW_ASSERT(
274  m_inRing.get_allocated_size() == remaining - needed,
275  static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
276  static_cast<FwAssertArgType>(remaining),
277  static_cast<FwAssertArgType>(needed)
278  );
279  }
280  // More data needed
281  else if (status == DeframingProtocol::DEFRAMING_MORE_NEEDED) {
282  // Deframing protocol should not report "more is needed"
283  // unless more is needed
284  FW_ASSERT(
285  needed > remaining,
286  static_cast<FwAssertArgType>(needed),
287  static_cast<FwAssertArgType>(remaining));
288  // Break out of loop: suspend deframing until we receive
289  // another buffer
290  break;
291  }
292  // Error occurred
293  else {
294  // Skip one byte of bad data
295  m_inRing.rotate(1);
296  FW_ASSERT(
297  m_inRing.get_allocated_size() == remaining - 1,
298  static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
299  static_cast<FwAssertArgType>(remaining)
300  );
301  // Log checksum errors
302  // This is likely a real error, not an artifact of other data corruption
304  Fw::Logger::logMsg("[ERROR] Deframing checksum validation failed\n");
305  }
306  }
307  }
308 
309  // If more not needed, circular buffer should be empty
311  FW_ASSERT(remaining == 0, static_cast<FwAssertArgType>(remaining));
312  }
313 
314 }
315 
316 } // end namespace Svc
#define FW_ASSERT(...)
Definition: Assert.hpp:14
PlatformIntType NATIVE_INT_TYPE
Definition: BasicTypes.h:51
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:26
PlatformUIntType NATIVE_UINT_TYPE
Definition: BasicTypes.h:52
PlatformAssertArgType FwAssertArgType
Definition: FpConfig.h:34
U32 FwPacketDescriptorType
Definition: FpConfig.h:74
U32 FwOpcodeType
Definition: FpConfig.h:78
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 logMsg(const char *fmt, POINTER_CAST a0=0, POINTER_CAST a1=0, POINTER_CAST a2=0, POINTER_CAST a3=0, POINTER_CAST a4=0, POINTER_CAST a5=0, POINTER_CAST a6=0, POINTER_CAST a7=0, POINTER_CAST a8=0, POINTER_CAST a9=0)
Definition: Logger.cpp:18
void init()
Object initializer.
Definition: ObjBase.cpp:27
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:52
void setup(DeframingProtocol &protocol)
Set up the instance.
Definition: Deframer.cpp:54
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