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  NATIVE_UINT_TYPE 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(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(status == Fw::FW_SERIALIZE_OK, status, offset, 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, 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  m_inRing.get_allocated_size(),
257  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(needed <= remaining, needed, remaining);
265  m_inRing.rotate(needed);
266  FW_ASSERT(
267  m_inRing.get_allocated_size() == remaining - needed,
268  m_inRing.get_allocated_size(),
269  remaining,
270  needed
271  );
272  }
273  // More data needed
274  else if (status == DeframingProtocol::DEFRAMING_MORE_NEEDED) {
275  // Deframing protocol should not report "more is needed"
276  // unless more is needed
277  FW_ASSERT(needed > remaining, needed, remaining);
278  // Break out of loop: suspend deframing until we receive
279  // another buffer
280  break;
281  }
282  // Error occurred
283  else {
284  // Skip one byte of bad data
285  m_inRing.rotate(1);
286  FW_ASSERT(
287  m_inRing.get_allocated_size() == remaining - 1,
288  m_inRing.get_allocated_size(),
289  remaining
290  );
291  // Log checksum errors
292  // This is likely a real error, not an artifact of other data corruption
294  Fw::Logger::logMsg("[ERROR] Deframing checksum validation failed\n");
295  }
296  }
297  }
298 
299  // If more not needed, circular buffer should be empty
301  FW_ASSERT(remaining == 0, remaining);
302  }
303 
304 }
305 
306 } // 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
U32 FwPacketDescriptorType
Definition: FpConfig.h:53
U32 FwOpcodeType
Definition: FpConfig.h:56
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(NATIVE_UINT_TYPE length)
sets buffer length manually after filling with data
SerializeStatus setBuff(const U8 *src, NATIVE_UINT_TYPE length)
sets buffer contents and size
SerializeStatus deserialize(U8 &val)
deserialize 8-bit unsigned int
Auto-generated base for Deframer component.
void bufferDeallocate_out(NATIVE_INT_TYPE portNum, Fw::Buffer &fwBuffer)
Invoke output port bufferDeallocate.
void framedDeallocate_out(NATIVE_INT_TYPE portNum, Fw::Buffer &fwBuffer)
Invoke output port framedDeallocate.
Fw::Buffer bufferAllocate_out(NATIVE_INT_TYPE portNum, U32 size)
Invoke output port bufferAllocate.
Drv::PollStatus framedPoll_out(NATIVE_INT_TYPE portNum, Fw::Buffer &pollBuffer)
Invoke output port framedPoll.
void bufferOut_out(NATIVE_INT_TYPE portNum, Fw::Buffer &fwBuffer)
Invoke output port bufferOut.
void comOut_out(NATIVE_INT_TYPE portNum, Fw::ComBuffer &data, U32 context)
Invoke output port comOut.
bool isConnected_bufferOut_OutputPort(NATIVE_INT_TYPE portNum)
~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