F´ Flight Software - C/C++ Documentation NASA-v1.6.0
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
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.