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 <FpConfig.hpp>
19
20namespace Svc {
21
22// ----------------------------------------------------------------------
23// Static assertions
24// ----------------------------------------------------------------------
25
26static_assert(
28 "poll buffer size must be greater than zero"
29);
30static_assert(
32 "ring buffer size must be greater than zero"
33);
34
35// ----------------------------------------------------------------------
36// Construction, initialization, and destruction
37// ----------------------------------------------------------------------
38
39Deframer ::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
48void Deframer ::init(const NATIVE_INT_TYPE instance) {
49 DeframerComponentBase::init(instance);
50}
51
52Deframer ::~Deframer() {}
53
54void Deframer ::setup(DeframingProtocol& protocol) {
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
68void 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
77void 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
91void 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
108Fw::Buffer Deframer ::allocate(const U32 size) {
109 return bufferAllocate_out(0, size);
110}
111
112void 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());
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
190void 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
227void 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:7
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.
U8 * getData() const
Definition Buffer.cpp:60
U32 getSize() const
Definition Buffer.cpp:64
void setData(U8 *data)
Definition Buffer.cpp:72
void setSize(U32 size)
Definition Buffer.cpp:79
SerializeBufferBase & getSerializeRepr()
Definition Buffer.cpp:99
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
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
Abstract base class representing a deframing protocol.
DeframingStatus
Status of the deframing call.
void setup(DeframingProtocolInterface &interface)
interface supplied to the deframing protocol
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.
static const U32 RING_BUFFER_SIZE
The size of the circular buffer in bytes.