GCC Code Coverage Report


Directory: Svc/Ccsds/CfdpManager/
File: Types/MetadataPdu.cpp
Date: 2026-11-03 21:17:54
Exec Total Coverage
Lines: 93 114 81.6%
Functions: 6 6 100.0%
Branches: 46 67 68.7%

Line Branch Exec Source
1 // ======================================================================
2 // \title MetadataPdu.cpp
3 // \author Brian Campuzano
4 // \brief cpp file for CFDP Metadata PDU
5 // ======================================================================
6
7 #include <Fw/Types/Assert.hpp>
8 #include <Fw/Types/StringUtils.hpp>
9 #include <Svc/Ccsds/CfdpManager/Types/MetadataPdu.hpp>
10 #include <config/CfdpCfg.hpp>
11
12 namespace Svc {
13 namespace Ccsds {
14 namespace Cfdp {
15
16 109 void MetadataPdu::initialize(PduDirection direction,
17 Cfdp::Class::T txmMode,
18 EntityId sourceEid,
19 TransactionSeq transactionSeq,
20 EntityId destEid,
21 FileSize fileSize,
22 const Fw::String& sourceFilename,
23 const Fw::String& destFilename,
24 ChecksumType checksumType,
25 U8 closureRequested) {
26 109 this->m_header.initialize(PduTypeEnum::METADATA, direction, txmMode, sourceEid, transactionSeq, destEid);
27
28 109 this->m_fileSize = fileSize;
29
30 // Enforce MaxFilePathSize for source filename
31 109 FwSizeType srcLen = sourceFilename.length();
32 109 FW_ASSERT(srcLen <= MaxFilePathSize, static_cast<FwAssertArgType>(srcLen), MaxFilePathSize);
33 109 this->m_sourceFilename = sourceFilename;
34
35 // Enforce MaxFilePathSize for destination filename
36 109 FwSizeType dstLen = destFilename.length();
37 109 FW_ASSERT(dstLen <= MaxFilePathSize, static_cast<FwAssertArgType>(dstLen), MaxFilePathSize);
38 109 this->m_destFilename = destFilename;
39
40 109 this->m_checksumType = checksumType;
41 109 this->m_closureRequested = closureRequested;
42 109 }
43
44 214 U32 MetadataPdu::getBufferSize() const {
45 214 U32 size = this->m_header.getBufferSize();
46
47 // Directive code: 1 byte
48 // Segmentation control byte (includes closure requested and checksum type): 1 byte
49 // File size: variable
50 214 size += static_cast<U32>(sizeof(U8) + sizeof(U8) + sizeof(FileSize));
51
52 // Source filename LV: length(1) + value(n)
53 214 size += 1 + static_cast<U32>(this->m_sourceFilename.length());
54
55 // Dest filename LV: length(1) + value(n)
56 214 size += 1 + static_cast<U32>(this->m_destFilename.length());
57
58 214 return size;
59 }
60
61 109 Fw::SerializeStatus MetadataPdu::serializeTo(Fw::SerialBufferBase& buffer, Fw::Endianness mode) const {
62 109 return this->toSerialBuffer(buffer);
63 }
64
65 98 Fw::SerializeStatus MetadataPdu::deserializeFrom(Fw::SerialBufferBase& buffer, Fw::Endianness mode) {
66 // Deserialize header first
67
1/1
✓ Branch 4 taken 98 times.
98 Fw::SerializeStatus status = this->m_header.fromSerialBuffer(buffer);
68
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 if (status != Fw::FW_SERIALIZE_OK) {
69 ✗ return status;
70 }
71
72 // Validate this is a directive PDU (not file data)
73
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 98 times.
98 if (this->m_header.m_pduType != PduType::PDU_TYPE_DIRECTIVE) {
74 ✗ return Fw::FW_DESERIALIZE_TYPE_MISMATCH;
75 }
76
77 // Validate directive code
78 98 U8 directiveCode;
79
1/1
✓ Branch 7 taken 98 times.
98 status = buffer.deserializeTo(directiveCode);
80
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 if (status != Fw::FW_SERIALIZE_OK) {
81 ✗ return status;
82 }
83
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 if (directiveCode != static_cast<U8>(FileDirective::FILE_DIRECTIVE_METADATA)) {
84 ✗ return Fw::FW_DESERIALIZE_TYPE_MISMATCH;
85 }
86
87 // Now set the type to PduTypeEnum::METADATA since we've validated it
88 98 this->m_header.m_type = PduTypeEnum::METADATA;
89
90 // Deserialize the metadata body
91
1/1
✓ Branch 4 taken 98 times.
98 return this->fromSerialBuffer(buffer);
92 }
93
94 109 Fw::SerializeStatus MetadataPdu::toSerialBuffer(Fw::SerialBufferBase& serialBuffer) const {
95 109 FW_ASSERT(this->m_header.m_type == PduTypeEnum::METADATA);
96
97 // Calculate PDU data length (everything after header)
98
2/2
✓ Branch 7 taken 109 times.
✓ Branch 15 taken 109 times.
109 U32 dataLength = this->getBufferSize() - this->m_header.getBufferSize();
99
100 // Update header with data length
101 109 PduHeader headerCopy = this->m_header;
102 109 headerCopy.setPduDataLength(static_cast<U16>(dataLength));
103
104 // Serialize header
105
1/1
✓ Branch 1 taken 109 times.
109 Fw::SerializeStatus status = headerCopy.toSerialBuffer(serialBuffer);
106
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
109 if (status != Fw::FW_SERIALIZE_OK) {
107 ✗ return status;
108 }
109
110 // Directive code (METADATA = 7)
111 109 U8 directiveCode = static_cast<U8>(FileDirective::FILE_DIRECTIVE_METADATA);
112
1/1
✓ Branch 7 taken 109 times.
109 status = serialBuffer.serializeFrom(directiveCode);
113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
109 if (status != Fw::FW_SERIALIZE_OK) {
114 ✗ return status;
115 }
116
117 // Parameter field byte (CCSDS 727.0-B-5 Table 5-9)
118 // bit 7: reserved (0)
119 // bit 6: closure_requested
120 // bits 5-4: reserved (00b)
121 // bits 3-0: checksum_type
122 109 U8 segmentationControl = 0;
123 109 segmentationControl =
124 109 static_cast<U8>(segmentationControl | static_cast<U8>((this->m_closureRequested & 0x01U) << 6));
125 109 segmentationControl = static_cast<U8>(segmentationControl | (static_cast<U8>(this->m_checksumType) & 0x0FU));
126
127
1/1
✓ Branch 7 taken 109 times.
109 status = serialBuffer.serializeFrom(segmentationControl);
128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
109 if (status != Fw::FW_SERIALIZE_OK) {
129 ✗ return status;
130 }
131
132 // File size (FileSize)
133
1/1
✓ Branch 11 taken 109 times.
109 status = serialBuffer.serializeFrom(this->m_fileSize);
134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
109 if (status != Fw::FW_SERIALIZE_OK) {
135 ✗ return status;
136 }
137
138 // Source filename LV
139
1/1
✓ Branch 11 taken 109 times.
109 U8 sourceFilenameLength = static_cast<U8>(this->m_sourceFilename.length());
140
1/1
✓ Branch 7 taken 109 times.
109 status = serialBuffer.serializeFrom(sourceFilenameLength);
141
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
109 if (status != Fw::FW_SERIALIZE_OK) {
142 ✗ return status;
143 }
144
145 // Serialize source filename bytes without length prefix
146
1/1
✓ Branch 18 taken 109 times.
109 status = serialBuffer.serializeFrom(reinterpret_cast<const U8*>(this->m_sourceFilename.toChar()),
147 sourceFilenameLength, Fw::Serialization::OMIT_LENGTH);
148
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
109 if (status != Fw::FW_SERIALIZE_OK) {
149 ✗ return status;
150 }
151
152 // Destination filename LV
153
1/1
✓ Branch 11 taken 109 times.
109 U8 destFilenameLength = static_cast<U8>(this->m_destFilename.length());
154
1/1
✓ Branch 7 taken 109 times.
109 status = serialBuffer.serializeFrom(destFilenameLength);
155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
109 if (status != Fw::FW_SERIALIZE_OK) {
156 ✗ return status;
157 }
158
159 // Serialize dest filename bytes without length prefix
160
1/1
✓ Branch 18 taken 109 times.
109 status = serialBuffer.serializeFrom(reinterpret_cast<const U8*>(this->m_destFilename.toChar()), destFilenameLength,
161 Fw::Serialization::OMIT_LENGTH);
162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
109 if (status != Fw::FW_SERIALIZE_OK) {
163 ✗ return status;
164 }
165
166 109 return Fw::FW_SERIALIZE_OK;
167 }
168
169 98 Fw::SerializeStatus MetadataPdu::fromSerialBuffer(Fw::SerialBufferBase& serialBuffer) {
170 98 FW_ASSERT(this->m_header.m_type == PduTypeEnum::METADATA);
171
172 // Directive code already read by union wrapper
173
174 // Segmentation control byte
175 98 U8 segmentationControl;
176
1/1
✓ Branch 7 taken 98 times.
98 Fw::SerializeStatus status = serialBuffer.deserializeTo(segmentationControl);
177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 if (status != Fw::FW_SERIALIZE_OK) {
178 ✗ return status;
179 }
180
181 98 this->m_closureRequested = (segmentationControl >> 6) & 0x01;
182 98 U8 checksumTypeVal = segmentationControl & 0x0F;
183 98 this->m_checksumType = static_cast<ChecksumType>(checksumTypeVal);
184
185 // File size
186
1/1
✓ Branch 10 taken 98 times.
98 status = serialBuffer.deserializeTo(this->m_fileSize);
187
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 if (status != Fw::FW_SERIALIZE_OK) {
188 ✗ return status;
189 }
190
191 // Source filename LV
192 98 U8 sourceFilenameLength;
193
1/1
✓ Branch 7 taken 98 times.
98 status = serialBuffer.deserializeTo(sourceFilenameLength);
194
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 if (status != Fw::FW_SERIALIZE_OK) {
195 ✗ return status;
196 }
197
198 // Validate filename length against MaxFilePathSize
199
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 if (sourceFilenameLength > MaxFilePathSize) {
200 ✗ return Fw::FW_DESERIALIZE_SIZE_MISMATCH;
201 }
202
203 // Validate filename is not empty
204
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 if (sourceFilenameLength == 0) {
205 ✗ return Fw::FW_DESERIALIZE_SIZE_MISMATCH;
206 }
207
208 // Read filename into temporary buffer
209 98 U8 sourceFilenameBuffer[MaxFilePathSize + 1];
210 98 FwSizeType actualLength = sourceFilenameLength;
211
1/1
✓ Branch 7 taken 98 times.
98 status = serialBuffer.deserializeTo(sourceFilenameBuffer, actualLength, Fw::Serialization::OMIT_LENGTH);
212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 if (status != Fw::FW_SERIALIZE_OK) {
213 ✗ return status;
214 }
215 // Null-terminate before assigning to Fw::String
216 98 sourceFilenameBuffer[sourceFilenameLength] = '\0';
217
1/1
✓ Branch 6 taken 98 times.
98 this->m_sourceFilename = reinterpret_cast<const CHAR*>(sourceFilenameBuffer);
218
219 // Destination filename LV
220 98 U8 destFilenameLength;
221
1/1
✓ Branch 7 taken 98 times.
98 status = serialBuffer.deserializeTo(destFilenameLength);
222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 if (status != Fw::FW_SERIALIZE_OK) {
223 ✗ return status;
224 }
225
226 // Validate filename length against MaxFilePathSize
227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 if (destFilenameLength > MaxFilePathSize) {
228 ✗ return Fw::FW_DESERIALIZE_SIZE_MISMATCH;
229 }
230
231 // Validate filename is not empty
232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 if (destFilenameLength == 0) {
233 ✗ return Fw::FW_DESERIALIZE_SIZE_MISMATCH;
234 }
235
236 // Read filename into temporary buffer
237 98 U8 destFilenameBuffer[MaxFilePathSize + 1];
238 98 actualLength = destFilenameLength;
239
1/1
✓ Branch 7 taken 98 times.
98 status = serialBuffer.deserializeTo(destFilenameBuffer, actualLength, Fw::Serialization::OMIT_LENGTH);
240
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 97 times.
98 if (status != Fw::FW_SERIALIZE_OK) {
241 1 return status;
242 }
243 // Null-terminate before assigning to Fw::String
244 97 destFilenameBuffer[destFilenameLength] = '\0';
245
1/1
✓ Branch 6 taken 97 times.
97 this->m_destFilename = reinterpret_cast<const CHAR*>(destFilenameBuffer);
246
247 97 return Fw::FW_SERIALIZE_OK;
248 }
249
250 } // namespace Cfdp
251 } // namespace Ccsds
252 } // namespace Svc
253