GCC Code Coverage Report


Directory: ./
File: Svc/FileDownlink/FileDownlink.cpp
Date: 2026-09-03 22:12:29
Exec Total Coverage
Lines: 40 296 13.5%
Functions: 7 25 28.0%
Branches: 11 200 5.5%

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 void FileDownlink ::configure(const char* directory) {
54 this->m_file.configureSandbox(directory);
55 }
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 235 void FileDownlink ::Run_handler(const FwIndexType portNum, U32 context) {
73
1/4
✓ Branch 1 taken 235 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
235 switch (this->m_mode.get()) {
74 235 case Mode::IDLE: {
75 235 FwSizeType real_size = 0;
76 235 FwQueuePriorityType prio = 0;
77
1/1
✓ Branch 1 taken 235 times.
235 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
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 235 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
235 if (stat != Os::Queue::Status::OP_OK || sizeof(this->m_curEntry) != real_size) {
82 235 return;
83 }
84
85 sendFile(this->m_curEntry.srcFilename, this->m_curEntry.destFilename, this->m_curEntry.offset,
86 this->m_curEntry.length);
87 break;
88 }
89 case Mode::COOLDOWN: {
90 if (this->m_curTimer >= this->m_cooldown) {
91 this->m_curTimer = 0;
92 this->m_mode.set(Mode::IDLE);
93 } else {
94 this->m_curTimer += m_cycleTime;
95 }
96 break;
97 }
98 case Mode::WAIT: {
99 this->m_curTimer += m_cycleTime;
100 break;
101 }
102 default:
103 break;
104 }
105 }
106
107 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 struct FileEntry entry;
114 entry.offset = offset;
115 entry.length = length;
116 entry.source = FileDownlink::PORT;
117 entry.opCode = 0;
118 entry.cmdSeq = 0;
119 entry.context = m_cntxId++;
120
121 // Guard against filename overflow
122 if (sourceFilename.length() >= entry.srcFilename.getCapacity()) {
123 this->log_WARNING_HI_FilenameSourceOverflow();
124 return SendFileResponse(SendFileStatus::STATUS_ERROR, std::numeric_limits<U32>::max());
125 } 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 entry.srcFilename = sourceFilename;
130 entry.destFilename = destFilename;
131
132 Os::Queue::Status status =
133 m_fileQueue.send(reinterpret_cast<U8*>(&entry), static_cast<FwSizeType>(sizeof(entry)), 0,
134 Os::Queue::BlockingType::NONBLOCKING);
135
136 if (status != Os::Queue::Status::OP_OK) {
137 return SendFileResponse(SendFileStatus::STATUS_ERROR, std::numeric_limits<U32>::max());
138 }
139 return SendFileResponse(SendFileStatus::STATUS_OK, entry.context);
140 }
141 }
142
143 59 void FileDownlink ::pingIn_handler(const FwIndexType portNum, U32 key) {
144 59 this->pingOut_out(0, key);
145 59 }
146
147 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 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 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 if (this->m_lastCompletedType == Fw::FilePacket::T_END || this->m_lastCompletedType == Fw::FilePacket::T_CANCEL) {
158 finishHelper(this->m_lastCompletedType == Fw::FilePacket::T_CANCEL);
159 return;
160 }
161 // If waiting and a buffer is in-bound, then switch to downlink mode
162 else if (this->m_mode.get() == Mode::WAIT) {
163 this->m_mode.set(Mode::DOWNLINK);
164 }
165
166 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 void FileDownlink ::sendResponse(SendFileStatus resp) {
273 FW_ASSERT(this->m_curEntry.source == FileDownlink::COMMAND || this->m_curEntry.source == FileDownlink::PORT,
274 static_cast<FwAssertArgType>(this->m_curEntry.source));
275 if (this->m_curEntry.source == FileDownlink::COMMAND) {
276 this->cmdResponse_out(this->m_curEntry.opCode, this->m_curEntry.cmdSeq, statusToCmdResp(resp));
277 } else {
278 for (FwIndexType i = 0; i < this->getNum_FileComplete_OutputPorts(); i++) {
279 if (this->isConnected_FileComplete_OutputPort(i)) {
280 this->FileComplete_out(i, Svc::SendFileResponse(resp, this->m_curEntry.context));
281 }
282 }
283 }
284 }
285
286 void FileDownlink ::sendFile(const Fw::FileNameString& sourceFilename,
287 const Fw::FileNameString& destFilename,
288 U32 startOffset,
289 U32 length) {
290 // Open file for downlink
291 Os::File::Status status = this->m_file.open(sourceFilename, destFilename);
292
293 // Reject command if error when opening file
294 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 const U32 fileSize = this->m_file.getSize();
305
306 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 } 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 } 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 this->getBuffer(this->m_buffer, FILE_PACKET);
333 this->sendStartPacket();
334 this->m_mode.set(Mode::WAIT);
335 this->m_sequenceIndex = 1;
336 this->m_curTimer = 0;
337 this->m_byteOffset = startOffset;
338 this->m_lastCompletedType = Fw::FilePacket::T_START;
339
340 // zero length means read until end of file
341 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 this->log_ACTIVITY_HI_SendStarted(fileSize - startOffset, this->m_file.getSourceName(),
346 this->m_file.getDestName());
347 this->m_endOffset = fileSize;
348 }
349 }
350
351 Os::File::Status FileDownlink ::sendDataPacket(U32& byteOffset) {
352 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 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 const U32 remaining = this->m_endOffset - byteOffset;
363 const U32 dataSize = (remaining < maxDataSize) ? remaining : maxDataSize;
364 U8 buffer[maxDataSize];
365 // This will be last data packet sent
366 if (dataSize + byteOffset == this->m_endOffset) {
367 this->m_lastCompletedType = Fw::FilePacket::T_DATA;
368 }
369
370 const Os::File::Status status = this->m_file.read(buffer, byteOffset, dataSize);
371 if (status != Os::File::OP_OK) {
372 this->m_warnings.fileRead(status);
373 return status;
374 }
375
376 Fw::FilePacket::DataPacket dataPacket;
377 dataPacket.initialize(this->m_sequenceIndex, byteOffset, static_cast<U16>(dataSize), buffer);
378 ++this->m_sequenceIndex;
379 Fw::FilePacket filePacket;
380 filePacket.fromDataPacket(dataPacket);
381 this->sendFilePacket(filePacket);
382
383 byteOffset += dataSize;
384
385 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 void FileDownlink ::sendEndPacket() {
418 CFDP::Checksum checksum;
419 this->m_file.getChecksum(checksum);
420
421 Fw::FilePacket::EndPacket endPacket;
422 endPacket.initialize(this->m_sequenceIndex, checksum);
423
424 Fw::FilePacket filePacket;
425 filePacket.fromEndPacket(endPacket);
426 this->sendFilePacket(filePacket);
427 }
428
429 void FileDownlink ::sendStartPacket() {
430 Fw::FilePacket::StartPacket startPacket;
431 startPacket.initialize(this->m_file.getSize(), this->m_file.getSourceName().toChar(),
432 this->m_file.getDestName().toChar());
433 Fw::FilePacket filePacket;
434 filePacket.fromStartPacket(startPacket);
435 this->sendFilePacket(filePacket);
436 }
437
438 void FileDownlink ::sendFilePacket(const Fw::FilePacket& filePacket) {
439 const U32 bufferSize = filePacket.bufferSize() + static_cast<U32>(sizeof(FwPacketDescriptorType));
440 FW_ASSERT(this->m_buffer.getData() != nullptr);
441 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 Fw::SerializeStatus status = this->m_buffer.getSerializer().serializeFrom(
445 static_cast<FwPacketDescriptorType>(Fw::ComPacketType::FW_PACKET_FILE));
446 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 this->m_buffer.getData() + sizeof(FwPacketDescriptorType),
450 this->m_buffer.getSize() - static_cast<Fw::Buffer::SizeType>(sizeof(FwPacketDescriptorType)));
451 status = filePacket.toBuffer(offsetBuffer);
452 FW_ASSERT(status == Fw::FW_SERIALIZE_OK);
453 // set the buffer size to the packet size
454 this->m_buffer.setSize(bufferSize);
455 this->bufferSendOut_out(0, this->m_buffer);
456 // restore buffer size to max
457 this->m_buffer.setSize(FILEDOWNLINK_INTERNAL_BUFFER_SIZE);
458 this->m_packetsSent.packetSent();
459 }
460
461 void FileDownlink ::enterCooldown() {
462 this->m_file.getOsFile().close();
463 this->m_mode.set(Mode::COOLDOWN);
464 this->m_lastCompletedType = Fw::FilePacket::T_NONE;
465 this->m_curTimer = 0;
466 }
467
468 void FileDownlink ::downlinkPacket() {
469 FW_ASSERT(this->m_lastCompletedType != Fw::FilePacket::T_NONE,
470 static_cast<FwAssertArgType>(this->m_lastCompletedType));
471 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 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 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 const Os::File::Status status = this->sendDataPacket(this->m_byteOffset);
482 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 else if (this->m_lastCompletedType == Fw::FilePacket::T_DATA) {
493 this->sendEndPacket();
494 this->m_lastCompletedType = Fw::FilePacket::T_END;
495 }
496 this->m_mode.set(Mode::WAIT);
497 this->m_curTimer = 0;
498 }
499
500 void FileDownlink ::finishHelper(bool cancel) {
501 // Complete command and switch to IDLE
502 if (not cancel) {
503 this->m_filesSent.fileSent();
504 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 this->enterCooldown();
509 sendResponse(SendFileStatus::STATUS_OK);
510 }
511
512 void FileDownlink ::getBuffer(Fw::Buffer& buffer, PacketType type) {
513 // Check type is correct
514 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 buffer.set(this->m_memoryStore[type], FILEDOWNLINK_INTERNAL_BUFFER_SIZE, m_lastBufferId);
518 m_lastBufferId++;
519 }
520 } // end namespace Svc
521