F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
Loading...
Searching...
No Matches
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
48Deframer ::~Deframer() {}
49
50void Deframer ::setup(DeframingProtocol& protocol) {
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
64void 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
73void 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
87void 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
104Fw::Buffer Deframer ::allocate(const U32 size) {
105 return bufferAllocate_out(0, size);
106}
107
108void 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());
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.
150 if (isConnected_bufferOut_OutputPort(0)) {
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
186void 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
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 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.
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.