GCC Code Coverage Report


Directory: ./
File: Types/Tlv.cpp
Date: 2026-09-23 22:12:37
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