F´ Flight Software - C/C++ Documentation  NASA-v1.6.0
A framework for building embedded system applications to NASA flight quality standards.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 "Fw/Types/BasicTypes.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) {
49  DeframerComponentBase::init(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.
154  if (isConnected_bufferOut_OutputPort(0)) {
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
Svc::DeframingProtocolInterface
interface supplied to the deframing protocol
Definition: DeframingProtocolInterface.hpp:29
Svc::DeframingProtocol::DEFRAMING_MORE_NEEDED
@ DEFRAMING_MORE_NEEDED
Definition: DeframingProtocol.hpp:43
Types::CircularBuffer::serialize
Fw::SerializeStatus serialize(const U8 *const buffer, const NATIVE_UINT_TYPE size)
Definition: CircularBuffer.cpp:48
FwPacketDescriptorType
#define FwPacketDescriptorType
Type representation for a packet descriptor.
Definition: FpConfig.hpp:58
Fw::SerializeBufferBase
Definition: Serializable.hpp:43
Fw::SerializeStatus
SerializeStatus
forward declaration for string
Definition: Serializable.hpp:14
Fw::ComPacket::FW_PACKET_UNKNOWN
@ FW_PACKET_UNKNOWN
Definition: ComPacket.hpp:28
Fw::Buffer::getData
U8 * getData() const
Definition: Buffer.cpp:60
U8
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.hpp:73
Fw::ComPacket::FW_PACKET_FILE
@ FW_PACKET_FILE
Definition: ComPacket.hpp:25
NATIVE_UINT_TYPE
unsigned int NATIVE_UINT_TYPE
native unsigned integer type declaration
Definition: BasicTypes.hpp:28
Fw::Buffer::setData
void setData(U8 *data)
Definition: Buffer.cpp:72
Svc::DeframingProtocol::DEFRAMING_INVALID_CHECKSUM
@ DEFRAMING_INVALID_CHECKSUM
Definition: DeframingProtocol.hpp:42
Svc::Deframer::Deframer
Deframer(const char *const compName)
Construct Deframer instance.
Definition: Deframer.cpp:39
Fw::ComPacket::FW_PACKET_COMMAND
@ FW_PACKET_COMMAND
Definition: ComPacket.hpp:22
Fw::Buffer
Definition: Buffer.hpp:43
Fw::Buffer::getSerializeRepr
SerializeBufferBase & getSerializeRepr()
Definition: Buffer.cpp:99
Deframer.hpp
Types::CircularBuffer::get_allocated_size
NATIVE_UINT_TYPE get_allocated_size() const
Definition: CircularBuffer.cpp:34
Svc::DeframingProtocol::DEFRAMING_STATUS_SUCCESS
@ DEFRAMING_STATUS_SUCCESS
Definition: DeframingProtocol.hpp:40
NATIVE_INT_TYPE
int NATIVE_INT_TYPE
native integer type declaration
Definition: BasicTypes.hpp:27
Fw::Buffer::getSize
U32 getSize() const
Definition: Buffer.cpp:64
Types::CircularBuffer::get_capacity
NATIVE_UINT_TYPE get_capacity() const
Definition: CircularBuffer.cpp:124
Fw::Buffer::setSize
void setSize(U32 size)
Definition: Buffer.cpp:79
Fw::SerializeBufferBase::setBuffLen
SerializeStatus setBuffLen(NATIVE_UINT_TYPE length)
sets buffer length manually after filling with data
Definition: Serializable.cpp:611
Types::CircularBuffer::rotate
Fw::SerializeStatus rotate(NATIVE_UINT_TYPE amount)
Definition: CircularBuffer.cpp:114
FwOpcodeType
#define FwOpcodeType
Type representation for a command opcode.
Definition: FpConfig.hpp:62
FW_ASSERT
#define FW_ASSERT(...)
Definition: Assert.hpp:9
Fw::SerializeBufferBase::deserialize
SerializeStatus deserialize(U8 &val)
deserialize 8-bit unsigned int
Definition: Serializable.cpp:294
Fw::SerializeBufferBase::setBuff
SerializeStatus setBuff(const U8 *src, NATIVE_UINT_TYPE length)
sets buffer contents and size
Definition: Serializable.cpp:598
Fw::Logger::logMsg
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
Svc::DeframingProtocol::setup
void setup(DeframingProtocolInterface &interface)
Definition: DeframingProtocol.cpp:21
Svc::DeframingProtocol::DeframingStatus
DeframingStatus
Status of the deframing call.
Definition: DeframingProtocol.hpp:39
Svc::Deframer::setup
void setup(DeframingProtocol &protocol)
Set up the instance.
Definition: Deframer.cpp:54
Svc::Deframer::~Deframer
~Deframer()
Destroy Deframer instance.
Definition: Deframer.cpp:52
Svc
Definition: ActiveRateGroupCfg.hpp:18
Svc::DeframingProtocol
Abstract base class representing a deframing protocol.
Definition: DeframingProtocol.hpp:33
Svc::DeframerCfg::RING_BUFFER_SIZE
static const U32 RING_BUFFER_SIZE
The size of the circular buffer in bytes.
Definition: DeframerCfg.hpp:15
Fw::ComBuffer
Definition: ComBuffer.hpp:21
Types::CircularBuffer::get_free_size
NATIVE_UINT_TYPE get_free_size() const
Definition: CircularBuffer.cpp:38
Svc::DeframerCfg::POLL_BUFFER_SIZE
static const U32 POLL_BUFFER_SIZE
The size of the polling buffer in bytes.
Definition: DeframerCfg.hpp:17
Svc::DeframingProtocol::deframe
virtual DeframingStatus deframe(Types::CircularBuffer &buffer, U32 &needed)=0
Fw::FW_SERIALIZE_OK
@ FW_SERIALIZE_OK
Serialization/Deserialization operation was successful.
Definition: Serializable.hpp:15
ComPacket.hpp
Logger.hpp
Svc::Deframer::init
void init(const NATIVE_INT_TYPE instance=0)
Initialize Deframer instance.
Definition: Deframer.cpp:48