GCC Code Coverage Report


Directory: ./
File: Svc/FileUplink/FileUplink.cpp
Date: 2026-09-03 22:12:29
Exec Total Coverage
Lines: 102 135 75.6%
Functions: 12 14 85.7%
Branches: 44 73 60.3%

Line Branch Exec Source
1 // ======================================================================
2 // \title FileUplink.cpp
3 // \author bocchino
4 // \brief cpp file for FileUplink component implementation class
5 //
6 // \copyright
7 // Copyright 2009-2016, by the California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10 //
11 // ======================================================================
12
13 #include <Fw/Com/ComPacket.hpp>
14 #include <Fw/FPrimeBasicTypes.hpp>
15 #include <Fw/Types/Assert.hpp>
16 #include <Svc/FileUplink/FileUplink.hpp>
17
18 namespace Svc {
19
20 // ----------------------------------------------------------------------
21 // Construction, initialization, and destruction
22 // ----------------------------------------------------------------------
23
24 1 FileUplink::FileUplink(const char* const name)
25 : FileUplinkComponentBase(name),
26 1 m_receiveMode(START),
27 1 m_lastSequenceIndex(0),
28 1 m_lastPacketWriteStatus(Os::File::MAX_STATUS),
29 1 m_filesReceived(this),
30 1 m_filesReceivedFailed(this),
31 1 m_packetsReceived(this),
32
1/1
✓ Branch 2 taken 1 times.
2 m_warnings(this) {}
33
34 2 FileUplink::~FileUplink() {}
35
36 1 void FileUplink::configure(const char* directory) {
37 1 this->m_file.osFile.configure(directory);
38 1 }
39
40 // ----------------------------------------------------------------------
41 // Handler implementations for user-defined typed input ports
42 // ----------------------------------------------------------------------
43
44 6 void FileUplink::bufferSendIn_handler(const FwIndexType portNum, Fw::Buffer& buffer) {
45 // If packet is too small to contain a packet type, log + deallocate and return
46
2/3
✓ Branch 1 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
6 if (buffer.getSize() < sizeof(FwPacketDescriptorType)) {
47 this->log_WARNING_HI_InvalidPacketReceived(Fw::ComPacketType::FW_PACKET_UNKNOWN);
48 this->bufferSendOut_out(0, buffer);
49 return;
50 }
51
52 // Read the packet type from the packet buffer
53 6 FwPacketDescriptorType packetType = 0;
54
2/2
✓ Branch 1 taken 6 times.
✓ Branch 4 taken 6 times.
6 Fw::SerializeStatus status = buffer.getDeserializer().deserializeTo(packetType);
55 6 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
56
57 // If packet type is not a file packet, log + deallocate and return
58
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (packetType != Fw::ComPacketType::FW_PACKET_FILE) {
59 this->log_WARNING_HI_InvalidPacketReceived(packetType);
60 this->bufferSendOut_out(0, buffer);
61 return;
62 }
63
64 // Deserialize the file packet contents into Fw::FilePacket (remove packet type token)
65 12 Fw::Buffer packetBuffer(buffer.getData() + sizeof(packetType),
66
3/3
✓ Branch 1 taken 6 times.
✓ Branch 4 taken 6 times.
✓ Branch 7 taken 6 times.
6 buffer.getSize() - static_cast<Fw::Buffer::SizeType>(sizeof(packetType)));
67 6 Fw::FilePacket filePacket;
68
1/1
✓ Branch 1 taken 6 times.
6 status = filePacket.fromBuffer(packetBuffer);
69
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (status != Fw::FW_SERIALIZE_OK) {
70 this->log_WARNING_HI_DecodeError(status);
71 } else {
72
1/1
✓ Branch 1 taken 6 times.
6 Fw::FilePacket::Type header_type = filePacket.asHeader().getType();
73
3/5
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 switch (header_type) {
74 2 case Fw::FilePacket::T_START:
75
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2 this->handleStartPacket(filePacket.asStartPacket());
76 2 break;
77 2 case Fw::FilePacket::T_DATA:
78
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2 this->handleDataPacket(filePacket.asDataPacket());
79 2 break;
80 2 case Fw::FilePacket::T_END:
81
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2 this->handleEndPacket(filePacket.asEndPacket());
82 2 break;
83 case Fw::FilePacket::T_CANCEL:
84 this->handleCancelPacket();
85 break;
86 default:
87 FW_ASSERT(false);
88 break;
89 }
90 }
91
1/1
✓ Branch 1 taken 6 times.
6 this->bufferSendOut_out(0, buffer);
92 6 }
93
94 59 void FileUplink::pingIn_handler(const FwIndexType portNum, U32 key) {
95 // return key
96 59 this->pingOut_out(0, key);
97 59 }
98
99 // ----------------------------------------------------------------------
100 // Private helper functions
101 // ----------------------------------------------------------------------
102
103 2 void FileUplink::handleStartPacket(const Fw::FilePacket::StartPacket& startPacket) {
104 // Clear all event throttles in preparation for new start packet
105 2 this->log_WARNING_HI_FileWriteError_ThrottleClear();
106 2 this->log_WARNING_HI_InvalidReceiveMode_ThrottleClear();
107 2 this->log_WARNING_HI_PacketOutOfBounds_ThrottleClear();
108 2 this->log_WARNING_HI_PacketOutOfOrder_ThrottleClear();
109 2 this->m_packetsReceived.packetReceived();
110
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (this->m_receiveMode != START) {
111 this->m_file.osFile.close();
112 this->m_warnings.invalidReceiveMode(Fw::FilePacket::T_START);
113 }
114 2 const Os::File::Status status = this->m_file.open(startPacket);
115
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (status == Os::File::OP_OK) {
116 1 this->goToDataMode();
117 } else {
118 1 this->m_warnings.fileOpen(this->m_file.name);
119 1 this->goToStartMode();
120 }
121 2 }
122
123 2 void FileUplink::handleDataPacket(const Fw::FilePacket::DataPacket& dataPacket) {
124 2 this->m_packetsReceived.packetReceived();
125
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (this->m_receiveMode != DATA) {
126 1 this->m_warnings.invalidReceiveMode(Fw::FilePacket::T_DATA);
127 1 return;
128 }
129
130 1 const U32 sequenceIndex = dataPacket.asHeader().getSequenceIndex();
131
132 // skip this packet if it is a duplicate and it has already been written
133
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
1 if (this->m_lastPacketWriteStatus == Os::File::OP_OK && this->checkDuplicatedPacket(sequenceIndex)) {
134 return;
135 }
136
137 1 this->checkSequenceIndex(sequenceIndex);
138 1 const U32 byteOffset = dataPacket.getByteOffset();
139 1 const U32 dataSize = dataPacket.getDataSize();
140
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
1 if ((std::numeric_limits<U32>::max() - byteOffset < dataSize) || (byteOffset + dataSize > this->m_file.size)) {
141 this->m_warnings.packetOutOfBounds(sequenceIndex, this->m_file.name);
142 return;
143 }
144 1 FW_ASSERT(dataPacket.getData() != nullptr);
145 1 const Os::File::Status status = this->m_file.write(dataPacket.getData(), byteOffset, dataSize);
146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (status != Os::File::OP_OK) {
147 this->m_warnings.fileWrite(this->m_file.name);
148 }
149
150 1 this->m_lastPacketWriteStatus = status;
151 }
152
153 2 void FileUplink::handleEndPacket(const Fw::FilePacket::EndPacket& endPacket) {
154 2 this->m_packetsReceived.packetReceived();
155
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (this->m_receiveMode == DATA) {
156 1 this->checkSequenceIndex(endPacket.asHeader().getSequenceIndex());
157
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (this->compareChecksums(endPacket)) {
158 1 this->m_filesReceived.fileReceived();
159 1 this->log_ACTIVITY_HI_FileReceived(this->m_file.name);
160
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (this->isConnected_fileAnnounce_OutputPort(0)) {
161 this->fileAnnounce_out(0, this->m_file.name);
162 }
163 } else {
164 // compareChecksums() has already issued the BadChecksum warning. The
165 // file failed its integrity check, so it is not announced or reported
166 // as successfully received; record the failed transfer instead.
167 this->m_filesReceivedFailed.fileReceivedFailed();
168 }
169 } else {
170 1 this->m_warnings.invalidReceiveMode(Fw::FilePacket::T_END);
171 }
172 2 this->goToStartMode();
173 2 }
174
175 void FileUplink::handleCancelPacket() {
176 this->m_packetsReceived.packetReceived();
177 this->log_ACTIVITY_HI_UplinkCanceled();
178 this->goToStartMode();
179 }
180
181 2 void FileUplink::checkSequenceIndex(const U32 sequenceIndex) {
182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (sequenceIndex != this->m_lastSequenceIndex + 1) {
183 this->m_warnings.packetOutOfOrder(sequenceIndex, this->m_lastSequenceIndex);
184 }
185 2 this->m_lastSequenceIndex = sequenceIndex;
186 2 }
187
188 bool FileUplink::checkDuplicatedPacket(const U32 sequenceIndex) {
189 // check for duplicate packet
190 if (sequenceIndex == this->m_lastSequenceIndex) {
191 this->m_warnings.packetDuplicate(sequenceIndex);
192 return true;
193 }
194
195 return false;
196 }
197
198 1 bool FileUplink::compareChecksums(const Fw::FilePacket::EndPacket& endPacket) {
199
1/1
✓ Branch 1 taken 1 times.
1 CFDP::Checksum computed;
200
1/1
✓ Branch 1 taken 1 times.
1 CFDP::Checksum stored;
201
1/1
✓ Branch 1 taken 1 times.
1 this->m_file.getChecksum(computed);
202
1/1
✓ Branch 1 taken 1 times.
1 endPacket.getChecksum(stored);
203
1/1
✓ Branch 1 taken 1 times.
1 const bool match = (computed == stored);
204
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!match) {
205 this->m_warnings.badChecksum(computed.getValue(), stored.getValue());
206 }
207 1 return match;
208 1 }
209
210 3 void FileUplink::goToStartMode() {
211 3 this->m_file.osFile.close();
212 3 this->m_receiveMode = START;
213 3 this->m_lastSequenceIndex = 0;
214 3 this->m_lastPacketWriteStatus = Os::File::MAX_STATUS;
215 3 }
216
217 1 void FileUplink::goToDataMode() {
218 1 this->m_receiveMode = DATA;
219 1 this->m_lastSequenceIndex = 0;
220 1 this->m_lastPacketWriteStatus = Os::File::MAX_STATUS;
221 1 }
222
223 } // namespace Svc
224