GCC Code Coverage Report


Directory: Svc/Ccsds/CfdpManager/Types/
File: Tlv.cpp
Date: 2026-09-03 21:16:30
Exec Total Coverage
Lines: 107 120 89.2%
Functions: 22 22 100.0%
Branches: 45 63 71.4%

Line Branch Exec Source
1 // ======================================================================
2 // \title Tlv.cpp
3 // \author Brian Campuzano
4 // \brief cpp file for CFDP TLV (Type-Length-Value) classes
5 // ======================================================================
6
7 #include <Fw/Types/Assert.hpp>
8 #include <Svc/Ccsds/CfdpManager/Types/Tlv.hpp>
9 #include <cstring>
10
11 namespace Svc {
12 namespace Ccsds {
13 namespace Cfdp {
14
15 // ======================================================================
16 // TlvData
17 // ======================================================================
18
19 300 TlvData::TlvData() : m_dataLength(0) {
20 // Initialize union to zero
21
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 300 times.
300 memset(this->m_rawData, 0, sizeof(this->m_rawData));
22 300 }
23
24 42 void TlvData::setEntityId(EntityId eid) {
25 42 this->m_eid = eid;
26 // Entity ID length depends on the value
27 // For now, use sizeof(EntityId) as the length
28 42 this->m_dataLength = sizeof(EntityId);
29 42 }
30
31 19 void TlvData::setData(const U8* data, U8 length) {
32 // length is U8 so it's always <= 255, assertion is redundant
33 19 FW_ASSERT(data != nullptr);
34
35
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
19 memcpy(this->m_rawData, data, length);
36 19 this->m_dataLength = length;
37 19 }
38
39 23 EntityId TlvData::getEntityId() const {
40 23 return this->m_eid;
41 }
42
43 12 const U8* TlvData::getData() const {
44 12 return this->m_rawData;
45 }
46
47 47 U8 TlvData::getLength() const {
48 47 return this->m_dataLength;
49 }
50
51 // ======================================================================
52 // Tlv
53 // ======================================================================
54
55 300 Tlv::Tlv() : m_type(TlvType::TLV_TYPE_ENTITY_ID) {
56 // Default constructor
57 300 }
58
59 30 void Tlv::initialize(EntityId eid) {
60 30 this->m_type = TlvType::TLV_TYPE_ENTITY_ID;
61 30 this->m_data.setEntityId(eid);
62 30 }
63
64 11 void Tlv::initialize(TlvType type, const U8* data, U8 length) {
65 11 this->m_type = type;
66 11 this->m_data.setData(data, length);
67 11 }
68
69 14 TlvType Tlv::getType() const {
70 14 return this->m_type;
71 }
72
73 19 const TlvData& Tlv::getData() const {
74 19 return this->m_data;
75 }
76
77 23 U32 Tlv::getEncodedSize() const {
78 // Type (1 byte) + Length (1 byte) + Data (variable)
79 23 return 2 + this->m_data.getLength();
80 }
81
82 20 Fw::SerializeStatus Tlv::toSerialBuffer(Fw::SerialBufferBase& serialBuffer) const {
83 Fw::SerializeStatus status;
84
85 // Serialize type byte
86 20 status = serialBuffer.serializeFrom(static_cast<U8>(this->m_type));
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (status != Fw::FW_SERIALIZE_OK) {
88 return status;
89 }
90
91 // Serialize length byte
92 20 U8 length = this->m_data.getLength();
93 20 status = serialBuffer.serializeFrom(length);
94
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (status != Fw::FW_SERIALIZE_OK) {
95 return status;
96 }
97
98 // Serialize data
99
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 8 times.
20 if (this->m_type == TlvType::TLV_TYPE_ENTITY_ID) {
100 // For Entity ID, serialize as EntityId
101 12 EntityId eid = this->m_data.getEntityId();
102 12 status = serialBuffer.serializeFrom(eid);
103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (status != Fw::FW_SERIALIZE_OK) {
104 return status;
105 }
106 } else {
107 // For other types, serialize raw data
108 8 const U8* data = this->m_data.getData();
109
2/2
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 8 times.
320 for (U8 i = 0; i < length; i++) {
110 312 status = serialBuffer.serializeFrom(data[i]);
111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 312 times.
312 if (status != Fw::FW_SERIALIZE_OK) {
112 return status;
113 }
114 }
115 }
116
117 20 return Fw::FW_SERIALIZE_OK;
118 }
119
120 20 Fw::SerializeStatus Tlv::fromSerialBuffer(Fw::SerialBufferBase& serialBuffer) {
121 Fw::SerializeStatus status;
122
123 // Deserialize type byte
124 20 U8 typeVal;
125
1/1
✓ Branch 7 taken 20 times.
20 status = serialBuffer.deserializeTo(typeVal);
126
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (status != Fw::FW_SERIALIZE_OK) {
127 return status;
128 }
129 20 this->m_type = static_cast<TlvType>(typeVal);
130
131 // Deserialize length byte
132 20 U8 length;
133
1/1
✓ Branch 7 taken 20 times.
20 status = serialBuffer.deserializeTo(length);
134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (status != Fw::FW_SERIALIZE_OK) {
135 return status;
136 }
137
138 // Deserialize data
139
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 8 times.
20 if (this->m_type == TlvType::TLV_TYPE_ENTITY_ID) {
140 // For Entity ID, read length bytes and convert to EntityId
141 // Per CFDP spec, Entity IDs can be 1, 2, 4, or 8 bytes
142 // We support up to sizeof(EntityId) bytes
143
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (length > sizeof(EntityId)) {
144 return Fw::FW_DESERIALIZE_FORMAT_ERROR;
145 }
146
147 // Read length bytes as raw data, then convert to EntityId (big-endian)
148 12 U8 rawData[sizeof(EntityId)];
149
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 memset(rawData, 0, sizeof(rawData)); // Zero-pad
150
151
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 12 times.
60 for (U8 i = 0; i < length; i++) {
152
1/1
✓ Branch 9 taken 48 times.
48 status = serialBuffer.deserializeTo(rawData[i]);
153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 if (status != Fw::FW_SERIALIZE_OK) {
154 return status;
155 }
156 }
157
158 // Convert big-endian bytes to EntityId
159 12 EntityId eid = 0;
160
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 12 times.
60 for (U8 i = 0; i < length; i++) {
161 48 eid = (eid << 8) | rawData[i];
162 }
163
164 12 this->m_data.setEntityId(eid);
165 } else {
166 // For other types, deserialize raw data
167 8 U8 rawData[256];
168
2/2
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 8 times.
320 for (U8 i = 0; i < length; i++) {
169
1/1
✓ Branch 9 taken 312 times.
312 status = serialBuffer.deserializeTo(rawData[i]);
170
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 312 times.
312 if (status != Fw::FW_SERIALIZE_OK) {
171 return status;
172 }
173 }
174
1/1
✓ Branch 4 taken 8 times.
8 this->m_data.setData(rawData, length);
175 }
176
177 20 return Fw::FW_SERIALIZE_OK;
178 }
179
180 // ======================================================================
181 // TlvList
182 // ======================================================================
183
184
2/2
✓ Branch 6 taken 256 times.
✓ Branch 7 taken 64 times.
320 TlvList::TlvList() : m_numTlv(0) {
185 // Default constructor
186 64 }
187
188 35 bool TlvList::appendTlv(const Tlv& tlv) {
189
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 33 times.
35 if (this->m_numTlv >= MaxTlv) {
190 2 return false; // List is full
191 }
192
193 33 this->m_tlvs[this->m_numTlv] = tlv;
194 33 this->m_numTlv++;
195 33 return true;
196 }
197
198 33 void TlvList::clear() {
199 33 this->m_numTlv = 0;
200 33 }
201
202 22 U8 TlvList::getNumTlv() const {
203 22 return this->m_numTlv;
204 }
205
206 20 const Tlv& TlvList::getTlv(U8 index) const {
207 20 FW_ASSERT(index < this->m_numTlv, index, this->m_numTlv);
208 20 return this->m_tlvs[index];
209 }
210
211 33 U32 TlvList::getEncodedSize() const {
212 33 U32 size = 0;
213
2/2
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 33 times.
51 for (U8 i = 0; i < this->m_numTlv; i++) {
214 18 size += this->m_tlvs[i].getEncodedSize();
215 }
216 33 return size;
217 }
218
219 27 Fw::SerializeStatus TlvList::toSerialBuffer(Fw::SerialBufferBase& serialBuffer) const {
220 Fw::SerializeStatus status;
221
222 // Encode all TLVs
223
2/2
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 27 times.
44 for (U8 i = 0; i < this->m_numTlv; i++) {
224 17 status = this->m_tlvs[i].toSerialBuffer(serialBuffer);
225
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (status != Fw::FW_SERIALIZE_OK) {
226 return status;
227 }
228 }
229
230 27 return Fw::FW_SERIALIZE_OK;
231 }
232
233 27 Fw::SerializeStatus TlvList::fromSerialBuffer(Fw::SerialBufferBase& serialBuffer) {
234 Fw::SerializeStatus status;
235
236 // Clear existing TLVs
237 27 this->m_numTlv = 0;
238
239 // Decode TLVs until buffer is exhausted or max count reached
240
5/6
✓ Branch 7 taken 17 times.
✓ Branch 8 taken 27 times.
✓ Branch 10 taken 17 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 17 times.
✓ Branch 13 taken 27 times.
44 while (serialBuffer.getDeserializeSizeLeft() > 0 && this->m_numTlv < MaxTlv) {
241 17 status = this->m_tlvs[this->m_numTlv].fromSerialBuffer(serialBuffer);
242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (status != Fw::FW_SERIALIZE_OK) {
243 // If we fail to decode a TLV, stop (could be end of buffer or invalid data)
244 // Only return error if we haven't successfully decoded any TLVs yet
245 if (this->m_numTlv == 0) {
246 return status;
247 } else {
248 // We've decoded some TLVs successfully, so consider this a success
249 break;
250 }
251 }
252 17 this->m_numTlv++;
253 }
254
255 27 return Fw::FW_SERIALIZE_OK;
256 }
257
258 } // namespace Cfdp
259 } // namespace Ccsds
260 } // namespace Svc
261