GCC Code Coverage Report


Directory: Svc/Ccsds/CfdpManager/
File: Types/NakPdu.cpp
Date: 2026-09-03 21:16:27
Exec Total Coverage
Lines: 73 85 85.9%
Functions: 8 8 100.0%
Branches: 36 49 73.5%

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