GCC Code Coverage Report


Directory: Svc/Ccsds/CfdpManager/
File: Types/Tlv.cpp
Date: 2026-09-03 21:16:27
Exec Total Coverage
Lines: 108 120 90.0%
Functions: 22 22 100.0%
Branches: 46 63 73.0%

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