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