GCC Code Coverage Report


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