GCC Code Coverage Report


Directory: Svc/Ccsds/CfdpManager/Types/
File: NakPdu.cpp
Date: 2026-09-03 21:16:30
Exec Total Coverage
Lines: 70 85 82.4%
Functions: 8 8 100.0%
Branches: 33 49 67.3%

Line Branch Exec Source
1 // ======================================================================
2 // \title NakPdu.cpp
3 // \author Brian Campuzano
4 // \brief cpp file for CFDP NAK (Negative Acknowledge) PDU
5 // ======================================================================
6
7 #include <Fw/Types/Assert.hpp>
8 #include <Svc/Ccsds/CfdpManager/Types/NakPdu.hpp>
9
10 namespace Svc {
11 namespace Ccsds {
12 namespace Cfdp {
13
14 15 void NakPdu::initialize(PduDirection direction,
15 Cfdp::Class::T txmMode,
16 EntityId sourceEid,
17 TransactionSeq transactionSeq,
18 EntityId destEid,
19 FileSize scopeStart,
20 FileSize scopeEnd) {
21 // Initialize header with PduTypeEnum::NEGATIVE_ACK type
22 15 this->m_header.initialize(PduTypeEnum::NEGATIVE_ACK, direction, txmMode, sourceEid, transactionSeq, destEid);
23
24 15 this->m_scopeStart = scopeStart;
25 15 this->m_scopeEnd = scopeEnd;
26 15 this->m_numSegments = 0;
27 15 }
28
29 70 bool NakPdu::addSegment(FileSize offsetStart, FileSize offsetEnd) {
30
2/2
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 69 times.
70 if (this->m_numSegments >= NakMaxSegments) {
31 1 return false;
32 }
33 69 this->m_segments[this->m_numSegments].offsetStart = offsetStart;
34 69 this->m_segments[this->m_numSegments].offsetEnd = offsetEnd;
35 69 this->m_numSegments++;
36 69 return true;
37 }
38
39 1 void NakPdu::clearSegments() {
40 1 this->m_numSegments = 0;
41 1 }
42
43 16 U32 NakPdu::getBufferSize() const {
44 16 U32 size = this->m_header.getBufferSize();
45
46 // Directive code: 1 byte (FileDirective::FILE_DIRECTIVE_NAK)
47 // Scope start: sizeof(FileSize) bytes
48 // Scope end: sizeof(FileSize) bytes
49 // Segment requests: m_numSegments * (2 * sizeof(FileSize)) bytes
50 16 size += static_cast<U32>(sizeof(U8) + sizeof(FileSize) + sizeof(FileSize));
51 16 size += static_cast<U32>(this->m_numSegments * (sizeof(FileSize) + sizeof(FileSize)));
52
53 16 return size;
54 }
55
56 12 Fw::SerializeStatus NakPdu::serializeTo(Fw::SerialBufferBase& buffer, Fw::Endianness mode) const {
57 12 return this->toSerialBuffer(buffer);
58 }
59
60 12 Fw::SerializeStatus NakPdu::deserializeFrom(Fw::SerialBufferBase& buffer, Fw::Endianness mode) {
61 // Deserialize header first
62
1/1
✓ Branch 4 taken 12 times.
12 Fw::SerializeStatus status = this->m_header.fromSerialBuffer(buffer);
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (status != Fw::FW_SERIALIZE_OK) {
64 return status;
65 }
66
67 // Validate this is a directive PDU (not file data)
68
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
12 if (this->m_header.m_pduType != PduType::PDU_TYPE_DIRECTIVE) {
69 return Fw::FW_DESERIALIZE_TYPE_MISMATCH;
70 }
71
72 // Validate directive code
73 12 U8 directiveCode;
74
1/1
✓ Branch 7 taken 12 times.
12 status = buffer.deserializeTo(directiveCode);
75
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (status != Fw::FW_SERIALIZE_OK) {
76 return status;
77 }
78
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (directiveCode != static_cast<U8>(FileDirective::FILE_DIRECTIVE_NAK)) {
79 return Fw::FW_DESERIALIZE_TYPE_MISMATCH;
80 }
81
82 // Now set the type to PduTypeEnum::NEGATIVE_ACK since we've validated it
83 12 this->m_header.m_type = PduTypeEnum::NEGATIVE_ACK;
84
85 // Deserialize the NAK body
86
1/1
✓ Branch 4 taken 12 times.
12 return this->fromSerialBuffer(buffer);
87 }
88
89 12 Fw::SerializeStatus NakPdu::toSerialBuffer(Fw::SerialBufferBase& serialBuffer) const {
90 12 FW_ASSERT(this->m_header.m_type == PduTypeEnum::NEGATIVE_ACK);
91
92 // Calculate PDU data length (everything after header)
93
2/2
✓ Branch 7 taken 12 times.
✓ Branch 15 taken 12 times.
12 U32 dataLength = this->getBufferSize() - this->m_header.getBufferSize();
94
95 // Update header with data length
96 12 PduHeader headerCopy = this->m_header;
97 12 headerCopy.setPduDataLength(static_cast<U16>(dataLength));
98
99 // Serialize header
100
1/1
✓ Branch 1 taken 12 times.
12 Fw::SerializeStatus status = headerCopy.toSerialBuffer(serialBuffer);
101
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (status != Fw::FW_SERIALIZE_OK) {
102 return status;
103 }
104
105 // Directive code (NAK = 8)
106 12 U8 directiveCodeByte = static_cast<U8>(FileDirective::FILE_DIRECTIVE_NAK);
107
1/1
✓ Branch 7 taken 12 times.
12 status = serialBuffer.serializeFrom(directiveCodeByte);
108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (status != Fw::FW_SERIALIZE_OK) {
109 return status;
110 }
111
112 // Scope start (file offset)
113
1/1
✓ Branch 11 taken 12 times.
12 status = serialBuffer.serializeFrom(this->m_scopeStart);
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (status != Fw::FW_SERIALIZE_OK) {
115 return status;
116 }
117
118 // Scope end (file offset)
119
1/1
✓ Branch 11 taken 12 times.
12 status = serialBuffer.serializeFrom(this->m_scopeEnd);
120
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (status != Fw::FW_SERIALIZE_OK) {
121 return status;
122 }
123
124 // Serialize segment requests
125
2/2
✓ Branch 4 taken 64 times.
✓ Branch 5 taken 12 times.
76 for (U8 i = 0; i < this->m_numSegments; i++) {
126 // Segment start offset
127
1/1
✓ Branch 11 taken 64 times.
64 status = serialBuffer.serializeFrom(this->m_segments[i].offsetStart);
128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
64 if (status != Fw::FW_SERIALIZE_OK) {
129 return status;
130 }
131
132 // Segment end offset
133
1/1
✓ Branch 11 taken 64 times.
64 status = serialBuffer.serializeFrom(this->m_segments[i].offsetEnd);
134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
64 if (status != Fw::FW_SERIALIZE_OK) {
135 return status;
136 }
137 }
138
139 12 return Fw::FW_SERIALIZE_OK;
140 }
141
142 12 Fw::SerializeStatus NakPdu::fromSerialBuffer(Fw::SerialBufferBase& serialBuffer) {
143 12 FW_ASSERT(this->m_header.m_type == PduTypeEnum::NEGATIVE_ACK);
144
145 // Directive code already read by fromBuffer()
146
147 // Scope start (file offset)
148 12 Fw::SerializeStatus status = serialBuffer.deserializeTo(this->m_scopeStart);
149
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (status != Fw::FW_SERIALIZE_OK) {
150 return status;
151 }
152
153 // Scope end (file offset)
154 12 status = serialBuffer.deserializeTo(this->m_scopeEnd);
155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (status != Fw::FW_SERIALIZE_OK) {
156 return status;
157 }
158
159 // Calculate number of segment requests from remaining buffer size
160 // Each segment is 2 * sizeof(FileSize) bytes
161 12 Fw::Serializable::SizeType remainingBytes = serialBuffer.getDeserializeSizeLeft();
162 12 U32 segmentSize = static_cast<U32>(sizeof(FileSize) + sizeof(FileSize));
163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 U32 numSegsCalculated = static_cast<U32>(remainingBytes / segmentSize);
164 12 this->m_numSegments = static_cast<U8>(numSegsCalculated);
165
166 // Limit to max segments
167
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
12 if (this->m_numSegments > NakMaxSegments) {
168 this->m_numSegments = NakMaxSegments;
169 }
170
171 // Deserialize segment requests
172
2/2
✓ Branch 4 taken 64 times.
✓ Branch 5 taken 12 times.
76 for (U8 i = 0; i < this->m_numSegments; i++) {
173 // Segment start offset
174 64 status = serialBuffer.deserializeTo(this->m_segments[i].offsetStart);
175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
64 if (status != Fw::FW_SERIALIZE_OK) {
176 return status;
177 }
178
179 // Segment end offset
180 64 status = serialBuffer.deserializeTo(this->m_segments[i].offsetEnd);
181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
64 if (status != Fw::FW_SERIALIZE_OK) {
182 return status;
183 }
184 }
185
186 12 return Fw::FW_SERIALIZE_OK;
187 }
188
189 } // namespace Cfdp
190 } // namespace Ccsds
191 } // namespace Svc
192