GCC Code Coverage Report


Directory: ./
File: Svc/FileDownlink/FileDownlink.cpp
Date: 2026-11-03 22:10:14
Exec Total Coverage
Lines: 177 296 59.8%
Functions: 20 25 80.0%
Branches: 86 200 43.0%

Line Branch Exec Source
1 // ======================================================================
2 // \title FileDownlink.hpp
3 // \author bocchino, mstarch
4 // \brief hpp file for FileDownlink component implementation class
5 //
6 // \copyright
7 // Copyright 2009-2015, by the California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10 // ======================================================================
11
12 #include <Fw/Com/ComPacket.hpp>
13 #include <Fw/FPrimeBasicTypes.hpp>
14 #include <Fw/Types/Assert.hpp>
15 #include <Fw/Types/StringUtils.hpp>
16 #include <Os/QueueString.hpp>
17 #include <Svc/FileDownlink/FileDownlink.hpp>
18 #include <limits>
19
20 namespace Svc {
21
22 // ----------------------------------------------------------------------
23 // Construction, initialization, and destruction
24 // ----------------------------------------------------------------------
25
26 1 FileDownlink ::FileDownlink(const char* const name)
27 : FileDownlinkComponentBase(name),
28 1 m_configured(false),
29 1 m_filesSent(this),
30 1 m_packetsSent(this),
31 1 m_warnings(this),
32 1 m_sequenceIndex(0),
33 1 m_curTimer(0),
34 1 m_bufferSize(0),
35 1 m_byteOffset(0),
36 1 m_endOffset(0),
37 1 m_lastCompletedType(Fw::FilePacket::T_NONE),
38 1 m_lastBufferId(0),
39
1/1
✓ Branch 1 taken 1 times.
1 m_curEntry(),
40
4/4
✓ Branch 2 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 8 taken 1 times.
✓ Branch 11 taken 1 times.
3 m_cntxId(0) {}
41
42 1 void FileDownlink ::configure(U32 cooldown, U32 cycleTime, U32 fileQueueDepth) {
43 1 this->m_cooldown = cooldown;
44 1 this->m_cycleTime = cycleTime;
45 1 this->m_configured = true;
46
47 Os::Queue::Status stat =
48
3/3
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 7 taken 1 times.
1 m_fileQueue.create(this->getInstance(), Os::QueueString("fileDownlinkQueue"),
49 static_cast<FwSizeType>(fileQueueDepth), static_cast<FwSizeType>(sizeof(struct FileEntry)));
50 1 FW_ASSERT(stat == Os::Queue::OP_OK, static_cast<FwAssertArgType>(stat));
51 1 }
52
53 2 void FileDownlink ::configure(const char* directory) {
54 2 this->m_file.configureSandbox(directory);
55 2 }
56
57 1 void FileDownlink ::deinit() {
58 1 this->m_fileQueue.teardown();
59 1 FileDownlinkComponentBase::deinit();
60 1 }
61
62 1 void FileDownlink ::preamble() {
63 1 FW_ASSERT(this->m_configured == true);
64 1 }
65
66 2 FileDownlink ::~FileDownlink() {}
67
68 // ----------------------------------------------------------------------
69 // Handler implementations for user-defined typed input ports
70 // ----------------------------------------------------------------------
71
72 262 void FileDownlink ::Run_handler(const FwIndexType portNum, U32 context) {
73
2/4
✓ Branch 1 taken 252 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
262 switch (this->m_mode.get()) {
74 252 case Mode::IDLE: {
75 252 FwSizeType real_size = 0;
76 252 FwQueuePriorityType prio = 0;
77
1/1
✓ Branch 1 taken 252 times.
252 Os::Queue::Status stat = m_fileQueue.receive(reinterpret_cast<U8*>(&this->m_curEntry),
78 static_cast<FwSizeType>(sizeof(this->m_curEntry)),
79 Os::Queue::BlockingType::NONBLOCKING, real_size, prio);
80
81
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 247 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
252 if (stat != Os::Queue::Status::OP_OK || sizeof(this->m_curEntry) != real_size) {
82 247 return;
83 }
84
85
1/1
✓ Branch 1 taken 5 times.
5 sendFile(this->m_curEntry.srcFilename, this->m_curEntry.destFilename, this->m_curEntry.offset,
86 this->m_curEntry.length);
87 5 break;
88 }
89 10 case Mode::COOLDOWN: {
90
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (this->m_curTimer >= this->m_cooldown) {
91 5 this->m_curTimer = 0;
92 5 this->m_mode.set(Mode::IDLE);
93 } else {
94 5 this->m_curTimer += m_cycleTime;
95 }
96 10 break;
97 }
98 ✗ case Mode::WAIT: {
99 ✗ this->m_curTimer += m_cycleTime;
100 ✗ break;
101 }
102 ✗ default:
103 ✗ break;
104 }
105 }
106
107 5 Svc::SendFileResponse FileDownlink ::SendFile_handler(
108 const FwIndexType portNum,
109 const Fw::StringBase& sourceFilename, // lgtm[cpp/large-parameter] dictated by command architecture
110 const Fw::StringBase& destFilename, // lgtm[cpp/large-parameter] dictated by command architecture
111 U32 offset,
112 U32 length) {
113
1/1
✓ Branch 1 taken 5 times.
5 struct FileEntry entry;
114 5 entry.offset = offset;
115 5 entry.length = length;
116 5 entry.source = FileDownlink::PORT;
117 5 entry.opCode = 0;
118 5 entry.cmdSeq = 0;
119 5 entry.context = m_cntxId++;
120
121 // Guard against filename overflow
122
2/3
✓ Branch 1 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
5 if (sourceFilename.length() >= entry.srcFilename.getCapacity()) {
123 ✗ this->log_WARNING_HI_FilenameSourceOverflow();
124 ✗ return SendFileResponse(SendFileStatus::STATUS_ERROR, std::numeric_limits<U32>::max());
125
2/3
✓ Branch 1 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
5 } else if (destFilename.length() >= entry.destFilename.getCapacity()) {
126 ✗ this->log_WARNING_HI_FilenameDestinationOverflow();
127 ✗ return SendFileResponse(SendFileStatus::STATUS_ERROR, std::numeric_limits<U32>::max());
128 } else {
129
1/1
✓ Branch 1 taken 5 times.
5 entry.srcFilename = sourceFilename;
130
1/1
✓ Branch 1 taken 5 times.
5 entry.destFilename = destFilename;
131
132 Os::Queue::Status status =
133
1/1
✓ Branch 1 taken 5 times.
5 m_fileQueue.send(reinterpret_cast<U8*>(&entry), static_cast<FwSizeType>(sizeof(entry)), 0,
134 Os::Queue::BlockingType::NONBLOCKING);
135
136
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (status != Os::Queue::Status::OP_OK) {
137 ✗ return SendFileResponse(SendFileStatus::STATUS_ERROR, std::numeric_limits<U32>::max());
138 }
139
1/1
✓ Branch 1 taken 5 times.
5 return SendFileResponse(SendFileStatus::STATUS_OK, entry.context);
140 }
141 5 }
142
143 66 void FileDownlink ::pingIn_handler(const FwIndexType portNum, U32 key) {
144 66 this->pingOut_out(0, key);
145 66 }
146
147 30 void FileDownlink ::bufferReturn_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) {
148 // If this is a stale buffer (old, timed-out, or both), then ignore its return.
149 // File downlink actions only respond to the return of the most-recently-sent buffer.
150
3/6
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 30 times.
30 if (this->m_lastBufferId != fwBuffer.getContext() + 1 || this->m_mode.get() == Mode::IDLE) {
151 ✗ return;
152 }
153 // Non-ignored buffers cannot be returned in "DOWNLINK" and "IDLE" state. Only in "WAIT", "CANCEL" state.
154 30 FW_ASSERT(this->m_mode.get() == Mode::WAIT || this->m_mode.get() == Mode::CANCEL,
155 static_cast<FwAssertArgType>(this->m_mode.get()));
156 // If the last packet has been sent (and is returning now) then finish the file
157
3/4
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25 times.
30 if (this->m_lastCompletedType == Fw::FilePacket::T_END || this->m_lastCompletedType == Fw::FilePacket::T_CANCEL) {
158 5 finishHelper(this->m_lastCompletedType == Fw::FilePacket::T_CANCEL);
159 5 return;
160 }
161 // If waiting and a buffer is in-bound, then switch to downlink mode
162
1/2
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
25 else if (this->m_mode.get() == Mode::WAIT) {
163 25 this->m_mode.set(Mode::DOWNLINK);
164 }
165
166 25 this->downlinkPacket();
167 }
168
169 // ----------------------------------------------------------------------
170 // Command handler implementations
171 // ----------------------------------------------------------------------
172
173 ✗ void FileDownlink ::SendFile_cmdHandler(const FwOpcodeType opCode,
174 const U32 cmdSeq,
175 const Fw::CmdStringArg& sourceFilename,
176 const Fw::CmdStringArg& destFilename) {
177 ✗ struct FileEntry entry;
178 ✗ entry.offset = 0;
179 ✗ entry.length = 0;
180 ✗ entry.source = FileDownlink::COMMAND;
181 ✗ entry.opCode = opCode;
182 ✗ entry.cmdSeq = cmdSeq;
183 ✗ entry.context = std::numeric_limits<U32>::max();
184
185 // Guard against filename overflow
186 ✗ if (sourceFilename.length() >= entry.srcFilename.getCapacity()) {
187 ✗ this->log_WARNING_HI_FilenameSourceOverflow();
188 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
189 ✗ } else if (destFilename.length() >= entry.destFilename.getCapacity()) {
190 ✗ this->log_WARNING_HI_FilenameDestinationOverflow();
191 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
192 } else {
193 ✗ entry.srcFilename = sourceFilename;
194 ✗ entry.destFilename = destFilename;
195
196 Os::Queue::Status status =
197 ✗ m_fileQueue.send(reinterpret_cast<U8*>(&entry), static_cast<FwSizeType>(sizeof(entry)), 0,
198 Os::Queue::BlockingType::NONBLOCKING);
199
200 ✗ if (status != Os::Queue::Status::OP_OK) {
201 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
202 }
203 }
204 ✗ }
205
206 ✗ void FileDownlink ::SendPartial_cmdHandler(FwOpcodeType opCode,
207 U32 cmdSeq,
208 const Fw::CmdStringArg& sourceFilename,
209 const Fw::CmdStringArg& destFilename,
210 U32 startOffset,
211 U32 length) {
212 ✗ struct FileEntry entry;
213 ✗ entry.offset = startOffset;
214 ✗ entry.length = length;
215 ✗ entry.source = FileDownlink::COMMAND;
216 ✗ entry.opCode = opCode;
217 ✗ entry.cmdSeq = cmdSeq;
218 ✗ entry.context = std::numeric_limits<U32>::max();
219
220 // Guard against filename overflow
221 ✗ if (sourceFilename.length() >= entry.srcFilename.getCapacity()) {
222 ✗ this->log_WARNING_HI_FilenameSourceOverflow();
223 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
224 ✗ } else if (destFilename.length() >= entry.destFilename.getCapacity()) {
225 ✗ this->log_WARNING_HI_FilenameDestinationOverflow();
226 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
227 } else {
228 ✗ entry.srcFilename = sourceFilename;
229 ✗ entry.destFilename = destFilename;
230
231 Os::Queue::Status status =
232 ✗ m_fileQueue.send(reinterpret_cast<U8*>(&entry), static_cast<FwSizeType>(sizeof(entry)), 0,
233 Os::Queue::BlockingType::NONBLOCKING);
234
235 ✗ if (status != Os::Queue::Status::OP_OK) {
236 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
237 }
238 }
239 ✗ }
240
241 ✗ void FileDownlink ::Cancel_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq) {
242 // Must be able to cancel in both downlink and waiting states
243 ✗ if (this->m_mode.get() == Mode::DOWNLINK || this->m_mode.get() == Mode::WAIT) {
244 ✗ this->m_mode.set(Mode::CANCEL);
245 }
246 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
247 ✗ }
248
249 // ----------------------------------------------------------------------
250 // Private helper methods
251 // ----------------------------------------------------------------------
252
253 ✗ Fw::CmdResponse FileDownlink ::statusToCmdResp(SendFileStatus status) {
254 ✗ switch (status.e) {
255 ✗ case SendFileStatus::STATUS_OK:
256 ✗ return Fw::CmdResponse::OK;
257 ✗ case SendFileStatus::STATUS_ERROR:
258 ✗ return Fw::CmdResponse::EXECUTION_ERROR;
259 ✗ case SendFileStatus::STATUS_INVALID:
260 ✗ return Fw::CmdResponse::VALIDATION_ERROR;
261 ✗ case SendFileStatus::STATUS_BUSY:
262 ✗ return Fw::CmdResponse::BUSY;
263 ✗ default:
264 // Trigger assertion if given unknown status
265 ✗ FW_ASSERT(false);
266 }
267
268 // It's impossible to reach this, but added to suppress gcc missing return warning
269 ✗ return Fw::CmdResponse::EXECUTION_ERROR;
270 }
271
272 5 void FileDownlink ::sendResponse(SendFileStatus resp) {
273 5 FW_ASSERT(this->m_curEntry.source == FileDownlink::COMMAND || this->m_curEntry.source == FileDownlink::PORT,
274 static_cast<FwAssertArgType>(this->m_curEntry.source));
275
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (this->m_curEntry.source == FileDownlink::COMMAND) {
276 ✗ this->cmdResponse_out(this->m_curEntry.opCode, this->m_curEntry.cmdSeq, statusToCmdResp(resp));
277 } else {
278
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
10 for (FwIndexType i = 0; i < this->getNum_FileComplete_OutputPorts(); i++) {
279
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 if (this->isConnected_FileComplete_OutputPort(i)) {
280
2/2
✓ Branch 2 taken 5 times.
✓ Branch 5 taken 5 times.
5 this->FileComplete_out(i, Svc::SendFileResponse(resp, this->m_curEntry.context));
281 }
282 }
283 }
284 5 }
285
286 5 void FileDownlink ::sendFile(const Fw::FileNameString& sourceFilename,
287 const Fw::FileNameString& destFilename,
288 U32 startOffset,
289 U32 length) {
290 // Open file for downlink
291 5 Os::File::Status status = this->m_file.open(sourceFilename, destFilename);
292
293 // Reject command if error when opening file
294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (status != Os::File::OP_OK) {
295 ✗ this->m_mode.set(Mode::IDLE);
296 ✗ if (status == Os::File::OUTSIDE_SANDBOX) {
297 ✗ this->m_warnings.sourceOutOfSandbox();
298 } else {
299 ✗ this->m_warnings.fileOpenError();
300 }
301 ✗ sendResponse(FILEDOWNLINK_COMMAND_FAILURES_DISABLED ? SendFileStatus::STATUS_OK : SendFileStatus::STATUS_ERROR);
302 ✗ return;
303 }
304 5 const U32 fileSize = this->m_file.getSize();
305
306
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (fileSize == 0) {
307 ✗ this->m_file.getOsFile().close();
308 ✗ this->m_mode.set(Mode::IDLE);
309 ✗ this->m_warnings.zeroSize();
310 ✗ sendResponse(FILEDOWNLINK_COMMAND_FAILURES_DISABLED ? SendFileStatus::STATUS_OK
311 : SendFileStatus::STATUS_INVALID);
312 ✗ return;
313
314
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (startOffset >= fileSize) {
315 ✗ this->enterCooldown();
316 ✗ this->log_WARNING_HI_DownlinkPartialFail(this->m_file.getSourceName(), this->m_file.getDestName(), startOffset,
317 fileSize);
318 ✗ sendResponse(FILEDOWNLINK_COMMAND_FAILURES_DISABLED ? SendFileStatus::STATUS_OK
319 : SendFileStatus::STATUS_INVALID);
320 ✗ return;
321 // startOffset < fileSize here, so the subtraction cannot underflow and, unlike
322 // startOffset + length, cannot wrap
323
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (length > fileSize - startOffset) {
324 // If the amount to downlink is greater than the file size, emit a Warning and then allow
325 // the file to be downlinked anyway
326 ✗ this->log_WARNING_LO_DownlinkPartialWarning(startOffset, length, fileSize, this->m_file.getSourceName(),
327 ✗ this->m_file.getDestName());
328 ✗ length = fileSize - startOffset;
329 }
330
331 // Send file and switch to WAIT mode
332 5 this->getBuffer(this->m_buffer, FILE_PACKET);
333 5 this->sendStartPacket();
334 5 this->m_mode.set(Mode::WAIT);
335 5 this->m_sequenceIndex = 1;
336 5 this->m_curTimer = 0;
337 5 this->m_byteOffset = startOffset;
338 5 this->m_lastCompletedType = Fw::FilePacket::T_START;
339
340 // zero length means read until end of file
341
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (length > 0) {
342 ✗ this->log_ACTIVITY_HI_SendStarted(length, this->m_file.getSourceName(), this->m_file.getDestName());
343 ✗ this->m_endOffset = startOffset + length;
344 } else {
345 5 this->log_ACTIVITY_HI_SendStarted(fileSize - startOffset, this->m_file.getSourceName(),
346 5 this->m_file.getDestName());
347 5 this->m_endOffset = fileSize;
348 }
349 }
350
351 20 Os::File::Status FileDownlink ::sendDataPacket(U32& byteOffset) {
352 20 const U32 maxDataSize =
353 FILEDOWNLINK_INTERNAL_BUFFER_SIZE - Fw::FilePacket::DataPacket::HEADERSIZE - sizeof(FwPacketDescriptorType);
354 // The caller is required to maintain byteOffset < m_endOffset.
355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (byteOffset >= this->m_endOffset) {
356 ✗ return Os::File::INVALID_ARGUMENT;
357 }
358 // Subtraction cannot underflow given the check above; comparing the remainder against
359 // maxDataSize (rather than byteOffset + maxDataSize against m_endOffset) also avoids an
360 // addition that could wrap when byteOffset is near the top of the U32 range. dataSize is
361 // therefore always <= maxDataSize, i.e. never larger than the buffer below.
362 20 const U32 remaining = this->m_endOffset - byteOffset;
363
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 15 times.
20 const U32 dataSize = (remaining < maxDataSize) ? remaining : maxDataSize;
364 U8 buffer[maxDataSize];
365 // This will be last data packet sent
366
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 15 times.
20 if (dataSize + byteOffset == this->m_endOffset) {
367 5 this->m_lastCompletedType = Fw::FilePacket::T_DATA;
368 }
369
370
1/1
✓ Branch 1 taken 20 times.
20 const Os::File::Status status = this->m_file.read(buffer, byteOffset, dataSize);
371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (status != Os::File::OP_OK) {
372 ✗ this->m_warnings.fileRead(status);
373 ✗ return status;
374 }
375
376 Fw::FilePacket::DataPacket dataPacket;
377
1/1
✓ Branch 1 taken 20 times.
20 dataPacket.initialize(this->m_sequenceIndex, byteOffset, static_cast<U16>(dataSize), buffer);
378 20 ++this->m_sequenceIndex;
379 20 Fw::FilePacket filePacket;
380
1/1
✓ Branch 1 taken 20 times.
20 filePacket.fromDataPacket(dataPacket);
381
1/1
✓ Branch 1 taken 20 times.
20 this->sendFilePacket(filePacket);
382
383 20 byteOffset += dataSize;
384
385 20 return Os::File::OP_OK;
386 }
387
388 ✗ void FileDownlink ::sendCancelPacket() {
389 ✗ Fw::Buffer buffer;
390 Fw::FilePacket::CancelPacket cancelPacket;
391 ✗ cancelPacket.initialize(this->m_sequenceIndex);
392
393 ✗ Fw::FilePacket filePacket;
394 ✗ filePacket.fromCancelPacket(cancelPacket);
395 ✗ this->getBuffer(buffer, CANCEL_PACKET);
396 ✗ FW_ASSERT(buffer.getSize() >= filePacket.bufferSize() + sizeof(FwPacketDescriptorType),
397 static_cast<FwAssertArgType>(buffer.getSize()),
398 static_cast<FwAssertArgType>(filePacket.bufferSize() + sizeof(FwPacketDescriptorType)));
399
400 // Serialize the packet descriptor FW_PACKET_FILE to the buffer
401 Fw::SerializeStatus status =
402 ✗ buffer.getSerializer().serializeFrom(static_cast<FwPacketDescriptorType>(Fw::ComPacketType::FW_PACKET_FILE));
403 ✗ FW_ASSERT(status == Fw::FW_SERIALIZE_OK);
404 ✗ Fw::Buffer offsetBuffer(buffer.getData() + sizeof(FwPacketDescriptorType),
405 ✗ buffer.getSize() - static_cast<Fw::Buffer::SizeType>(sizeof(FwPacketDescriptorType)));
406 // Serialize the filePacket content into the buffer
407 ✗ status = filePacket.toBuffer(offsetBuffer);
408 ✗ FW_ASSERT(status == Fw::FW_SERIALIZE_OK);
409 ✗ const U32 bufferSize = filePacket.bufferSize() + static_cast<U32>(sizeof(FwPacketDescriptorType));
410 ✗ FW_ASSERT(buffer.getSize() >= bufferSize, static_cast<FwAssertArgType>(buffer.getSize()),
411 static_cast<FwAssertArgType>(bufferSize));
412 ✗ buffer.setSize(bufferSize);
413 ✗ this->bufferSendOut_out(0, buffer);
414 ✗ this->m_packetsSent.packetSent();
415 ✗ }
416
417 5 void FileDownlink ::sendEndPacket() {
418
1/1
✓ Branch 1 taken 5 times.
5 CFDP::Checksum checksum;
419
1/1
✓ Branch 1 taken 5 times.
5 this->m_file.getChecksum(checksum);
420
421 Fw::FilePacket::EndPacket endPacket;
422
1/1
✓ Branch 1 taken 5 times.
5 endPacket.initialize(this->m_sequenceIndex, checksum);
423
424 5 Fw::FilePacket filePacket;
425
1/1
✓ Branch 1 taken 5 times.
5 filePacket.fromEndPacket(endPacket);
426
1/1
✓ Branch 1 taken 5 times.
5 this->sendFilePacket(filePacket);
427 5 }
428
429 5 void FileDownlink ::sendStartPacket() {
430 Fw::FilePacket::StartPacket startPacket;
431
1/1
✓ Branch 5 taken 5 times.
5 startPacket.initialize(this->m_file.getSize(), this->m_file.getSourceName().toChar(),
432 5 this->m_file.getDestName().toChar());
433 5 Fw::FilePacket filePacket;
434
1/1
✓ Branch 1 taken 5 times.
5 filePacket.fromStartPacket(startPacket);
435
1/1
✓ Branch 1 taken 5 times.
5 this->sendFilePacket(filePacket);
436 5 }
437
438 30 void FileDownlink ::sendFilePacket(const Fw::FilePacket& filePacket) {
439
1/1
✓ Branch 1 taken 30 times.
30 const U32 bufferSize = filePacket.bufferSize() + static_cast<U32>(sizeof(FwPacketDescriptorType));
440 30 FW_ASSERT(this->m_buffer.getData() != nullptr);
441 30 FW_ASSERT(this->m_buffer.getSize() >= bufferSize, static_cast<FwAssertArgType>(bufferSize),
442 static_cast<FwAssertArgType>(this->m_buffer.getSize()));
443 // Serialize packet descriptor FW_PACKET_FILE to the buffer
444
2/2
✓ Branch 1 taken 30 times.
✓ Branch 4 taken 30 times.
30 Fw::SerializeStatus status = this->m_buffer.getSerializer().serializeFrom(
445 static_cast<FwPacketDescriptorType>(Fw::ComPacketType::FW_PACKET_FILE));
446 30 FW_ASSERT(status == Fw::FW_SERIALIZE_OK);
447 // Serialize the filePacket content into the buffer, offset by the size of the packet descriptor
448 Fw::Buffer offsetBuffer(
449 60 this->m_buffer.getData() + sizeof(FwPacketDescriptorType),
450
3/3
✓ Branch 1 taken 30 times.
✓ Branch 4 taken 30 times.
✓ Branch 7 taken 30 times.
30 this->m_buffer.getSize() - static_cast<Fw::Buffer::SizeType>(sizeof(FwPacketDescriptorType)));
451
1/1
✓ Branch 1 taken 30 times.
30 status = filePacket.toBuffer(offsetBuffer);
452 30 FW_ASSERT(status == Fw::FW_SERIALIZE_OK);
453 // set the buffer size to the packet size
454
1/1
✓ Branch 1 taken 30 times.
30 this->m_buffer.setSize(bufferSize);
455
1/1
✓ Branch 1 taken 30 times.
30 this->bufferSendOut_out(0, this->m_buffer);
456 // restore buffer size to max
457
1/1
✓ Branch 1 taken 30 times.
30 this->m_buffer.setSize(FILEDOWNLINK_INTERNAL_BUFFER_SIZE);
458
1/1
✓ Branch 1 taken 30 times.
30 this->m_packetsSent.packetSent();
459 30 }
460
461 5 void FileDownlink ::enterCooldown() {
462 5 this->m_file.getOsFile().close();
463 5 this->m_mode.set(Mode::COOLDOWN);
464 5 this->m_lastCompletedType = Fw::FilePacket::T_NONE;
465 5 this->m_curTimer = 0;
466 5 }
467
468 25 void FileDownlink ::downlinkPacket() {
469 25 FW_ASSERT(this->m_lastCompletedType != Fw::FilePacket::T_NONE,
470 static_cast<FwAssertArgType>(this->m_lastCompletedType));
471 25 FW_ASSERT(this->m_mode.get() == Mode::CANCEL || this->m_mode.get() == Mode::DOWNLINK,
472 static_cast<FwAssertArgType>(this->m_mode.get()));
473 // If canceled mode and currently downlinking data then send a cancel packet
474
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 25 times.
25 if (this->m_mode.get() == Mode::CANCEL && this->m_lastCompletedType == Fw::FilePacket::T_START) {
475 ✗ this->sendCancelPacket();
476 ✗ this->m_lastCompletedType = Fw::FilePacket::T_CANCEL;
477 }
478 // If in downlink mode and currently downlinking data then continue with the next packer
479
5/6
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 20 times.
✓ Branch 6 taken 5 times.
25 else if (this->m_mode.get() == Mode::DOWNLINK && this->m_lastCompletedType == Fw::FilePacket::T_START) {
480 // Send the next packet, or fail doing so
481 20 const Os::File::Status status = this->sendDataPacket(this->m_byteOffset);
482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (status != Os::File::OP_OK) {
483 ✗ this->log_WARNING_HI_SendDataFail(this->m_file.getSourceName(), this->m_byteOffset);
484 ✗ this->enterCooldown();
485 ✗ this->sendResponse(FILEDOWNLINK_COMMAND_FAILURES_DISABLED ? SendFileStatus::STATUS_OK
486 : SendFileStatus::STATUS_ERROR);
487 // Don't go to wait state
488 ✗ return;
489 }
490 }
491 // If in downlink mode or cancel and finished downlinking data then send the last packet
492
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 else if (this->m_lastCompletedType == Fw::FilePacket::T_DATA) {
493 5 this->sendEndPacket();
494 5 this->m_lastCompletedType = Fw::FilePacket::T_END;
495 }
496 25 this->m_mode.set(Mode::WAIT);
497 25 this->m_curTimer = 0;
498 }
499
500 5 void FileDownlink ::finishHelper(bool cancel) {
501 // Complete command and switch to IDLE
502
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (not cancel) {
503 5 this->m_filesSent.fileSent();
504 5 this->log_ACTIVITY_HI_FileSent(this->m_file.getSourceName(), this->m_file.getDestName());
505 } else {
506 ✗ this->log_ACTIVITY_HI_DownlinkCanceled(this->m_file.getSourceName(), this->m_file.getDestName());
507 }
508 5 this->enterCooldown();
509
2/2
✓ Branch 1 taken 5 times.
✓ Branch 4 taken 5 times.
5 sendResponse(SendFileStatus::STATUS_OK);
510 5 }
511
512 5 void FileDownlink ::getBuffer(Fw::Buffer& buffer, PacketType type) {
513 // Check type is correct
514 5 FW_ASSERT(type < COUNT_PACKET_TYPE && type >= 0, static_cast<FwAssertArgType>(type));
515 // Wrap the buffer around our indexed memory.
516 // Set a known ID (context) to look for later
517 5 buffer.set(this->m_memoryStore[type], FILEDOWNLINK_INTERNAL_BUFFER_SIZE, m_lastBufferId);
518 5 m_lastBufferId++;
519 5 }
520 } // end namespace Svc
521