GCC Code Coverage Report


Directory: Svc/FileDownlink/
File: FileDownlink.cpp
Date: 2026-09-03 21:17:43
Exec Total Coverage
Lines: 259 303 85.5%
Functions: 23 25 92.0%
Branches: 154 216 71.3%

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 9 FileDownlink ::FileDownlink(const char* const name)
27 : FileDownlinkComponentBase(name),
28 9 m_configured(false),
29 9 m_filesSent(this),
30 9 m_packetsSent(this),
31 9 m_warnings(this),
32 9 m_sequenceIndex(0),
33 9 m_curTimer(0),
34 9 m_bufferSize(0),
35 9 m_byteOffset(0),
36 9 m_endOffset(0),
37 9 m_lastCompletedType(Fw::FilePacket::T_NONE),
38 9 m_lastBufferId(0),
39
1/1
✓ Branch 7 taken 9 times.
9 m_curEntry(),
40
4/4
✓ Branch 10 taken 9 times.
✓ Branch 16 taken 9 times.
✓ Branch 22 taken 9 times.
✓ Branch 28 taken 9 times.
36 m_cntxId(0) {}
41
42 9 void FileDownlink ::configure(U32 cooldown, U32 cycleTime, U32 fileQueueDepth) {
43 9 this->m_cooldown = cooldown;
44 9 this->m_cycleTime = cycleTime;
45 9 this->m_configured = true;
46
47 Os::Queue::Status stat =
48
3/3
✓ Branch 7 taken 9 times.
✓ Branch 15 taken 9 times.
✓ Branch 18 taken 9 times.
9 m_fileQueue.create(this->getInstance(), Os::QueueString("fileDownlinkQueue"),
49 static_cast<FwSizeType>(fileQueueDepth), static_cast<FwSizeType>(sizeof(struct FileEntry)));
50 9 FW_ASSERT(stat == Os::Queue::OP_OK, static_cast<FwAssertArgType>(stat));
51 9 }
52
53 9 void FileDownlink ::configure(const char* directory) {
54 9 this->m_file.configureSandbox(directory);
55 9 }
56
57 9 void FileDownlink ::deinit() {
58 9 this->m_fileQueue.teardown();
59 9 FileDownlinkComponentBase::deinit();
60 9 }
61
62 void FileDownlink ::preamble() {
63 FW_ASSERT(this->m_configured == true);
64 }
65
66 18 FileDownlink ::~FileDownlink() {}
67
68 // ----------------------------------------------------------------------
69 // Handler implementations for user-defined typed input ports
70 // ----------------------------------------------------------------------
71
72 47 void FileDownlink ::Run_handler(const FwIndexType portNum, U32 context) {
73
3/4
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 30 times.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
47 switch (this->m_mode.get()) {
74 9 case Mode::IDLE: {
75 9 FwSizeType real_size = 0;
76 9 FwQueuePriorityType prio = 0;
77
1/1
✓ Branch 8 taken 9 times.
9 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 8 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
9 if (stat != Os::Queue::Status::OP_OK || sizeof(this->m_curEntry) != real_size) {
82 1 return;
83 }
84
85
1/1
✓ Branch 16 taken 8 times.
16 sendFile(this->m_curEntry.srcFilename, this->m_curEntry.destFilename, this->m_curEntry.offset,
86 8 this->m_curEntry.length);
87 8 break;
88 }
89 30 case Mode::COOLDOWN: {
90
2/2
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 25 times.
30 if (this->m_curTimer >= this->m_cooldown) {
91 5 this->m_curTimer = 0;
92 5 this->m_mode.set(Mode::IDLE);
93 } else {
94 25 this->m_curTimer += m_cycleTime;
95 }
96 30 break;
97 }
98 8 case Mode::WAIT: {
99 8 this->m_curTimer += m_cycleTime;
100 8 break;
101 }
102 default:
103 break;
104 }
105 }
106
107 1 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 2 taken 1 times.
1 struct FileEntry entry;
114 1 entry.offset = offset;
115 1 entry.length = length;
116 1 entry.source = FileDownlink::PORT;
117 1 entry.opCode = 0;
118 1 entry.cmdSeq = 0;
119 1 entry.context = m_cntxId++;
120
121 // Guard against filename overflow
122
2/3
✓ Branch 11 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
1 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 11 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
1 } 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 5 taken 1 times.
1 entry.srcFilename = sourceFilename;
130
1/1
✓ Branch 5 taken 1 times.
1 entry.destFilename = destFilename;
131
132 Os::Queue::Status status =
133
1/1
✓ Branch 6 taken 1 times.
1 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 1 times.
1 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 1 times.
1 return SendFileResponse(SendFileStatus::STATUS_OK, entry.context);
140 }
141 1 }
142
143 void FileDownlink ::pingIn_handler(const FwIndexType portNum, U32 key) {
144 this->pingOut_out(0, key);
145 }
146
147 14 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 8 taken 14 times.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 14 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 14 times.
14 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 14 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
6/8
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 10 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 9 times.
14 if (this->m_lastCompletedType == Fw::FilePacket::T_END || this->m_lastCompletedType == Fw::FilePacket::T_CANCEL) {
158
1/2
✗ Branch 6 not taken.
✓ Branch 7 taken 5 times.
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
2/2
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 1 times.
9 else if (this->m_mode.get() == Mode::WAIT) {
163 8 this->m_mode.set(Mode::DOWNLINK);
164 }
165
166 9 this->downlinkPacket();
167 }
168
169 // ----------------------------------------------------------------------
170 // Command handler implementations
171 // ----------------------------------------------------------------------
172
173 4 void FileDownlink ::SendFile_cmdHandler(const FwOpcodeType opCode,
174 const U32 cmdSeq,
175 const Fw::CmdStringArg& sourceFilename,
176 const Fw::CmdStringArg& destFilename) {
177
1/1
✓ Branch 2 taken 4 times.
4 struct FileEntry entry;
178 4 entry.offset = 0;
179 4 entry.length = 0;
180 4 entry.source = FileDownlink::COMMAND;
181 4 entry.opCode = opCode;
182 4 entry.cmdSeq = cmdSeq;
183 4 entry.context = std::numeric_limits<U32>::max();
184
185 // Guard against filename overflow
186
2/3
✓ Branch 7 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4 times.
4 if (sourceFilename.length() >= entry.srcFilename.getCapacity()) {
187 this->log_WARNING_HI_FilenameSourceOverflow();
188 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
189
2/3
✓ Branch 7 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4 times.
4 } 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
1/1
✓ Branch 5 taken 4 times.
4 entry.srcFilename = sourceFilename;
194
1/1
✓ Branch 5 taken 4 times.
4 entry.destFilename = destFilename;
195
196 Os::Queue::Status status =
197
1/1
✓ Branch 6 taken 4 times.
4 m_fileQueue.send(reinterpret_cast<U8*>(&entry), static_cast<FwSizeType>(sizeof(entry)), 0,
198 Os::Queue::BlockingType::NONBLOCKING);
199
200
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (status != Os::Queue::Status::OP_OK) {
201 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
202 }
203 }
204 8 }
205
206 3 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
1/1
✓ Branch 2 taken 3 times.
3 struct FileEntry entry;
213 3 entry.offset = startOffset;
214 3 entry.length = length;
215 3 entry.source = FileDownlink::COMMAND;
216 3 entry.opCode = opCode;
217 3 entry.cmdSeq = cmdSeq;
218 3 entry.context = std::numeric_limits<U32>::max();
219
220 // Guard against filename overflow
221
2/3
✓ Branch 7 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
3 if (sourceFilename.length() >= entry.srcFilename.getCapacity()) {
222 this->log_WARNING_HI_FilenameSourceOverflow();
223 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
224
2/3
✓ Branch 7 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
3 } 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
1/1
✓ Branch 5 taken 3 times.
3 entry.srcFilename = sourceFilename;
229
1/1
✓ Branch 5 taken 3 times.
3 entry.destFilename = destFilename;
230
231 Os::Queue::Status status =
232
1/1
✓ Branch 6 taken 3 times.
3 m_fileQueue.send(reinterpret_cast<U8*>(&entry), static_cast<FwSizeType>(sizeof(entry)), 0,
233 Os::Queue::BlockingType::NONBLOCKING);
234
235
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (status != Os::Queue::Status::OP_OK) {
236 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
237 }
238 }
239 6 }
240
241 2 void FileDownlink ::Cancel_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq) {
242 // Must be able to cancel in both downlink and waiting states
243
5/6
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
2 if (this->m_mode.get() == Mode::DOWNLINK || this->m_mode.get() == Mode::WAIT) {
244 1 this->m_mode.set(Mode::CANCEL);
245 }
246
2/2
✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
2 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
247 2 }
248
249 // ----------------------------------------------------------------------
250 // Private helper methods
251 // ----------------------------------------------------------------------
252
253 7 Fw::CmdResponse FileDownlink ::statusToCmdResp(SendFileStatus status) {
254
2/7
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 7 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
7 switch (status.e) {
255 7 case SendFileStatus::STATUS_OK:
256 7 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 8 void FileDownlink ::sendResponse(SendFileStatus resp) {
273 8 FW_ASSERT(this->m_curEntry.source == FileDownlink::COMMAND || this->m_curEntry.source == FileDownlink::PORT,
274 static_cast<FwAssertArgType>(this->m_curEntry.source));
275
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 1 times.
8 if (this->m_curEntry.source == FileDownlink::COMMAND) {
276
3/3
✓ Branch 7 taken 7 times.
✓ Branch 10 taken 7 times.
✓ Branch 21 taken 7 times.
7 this->cmdResponse_out(this->m_curEntry.opCode, this->m_curEntry.cmdSeq, statusToCmdResp(resp));
277 } else {
278
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 for (FwIndexType i = 0; i < this->getNum_FileComplete_OutputPorts(); i++) {
279
1/2
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 if (this->isConnected_FileComplete_OutputPort(i)) {
280
2/2
✓ Branch 13 taken 1 times.
✓ Branch 17 taken 1 times.
1 this->FileComplete_out(i, Svc::SendFileResponse(resp, this->m_curEntry.context));
281 }
282 }
283 }
284 8 }
285
286 8 void FileDownlink ::sendFile(const Fw::FileNameString& sourceFilename,
287 const Fw::FileNameString& destFilename,
288 U32 startOffset,
289 U32 length) {
290 // Open file for downlink
291 8 Os::File::Status status = this->m_file.open(sourceFilename, destFilename);
292
293 // Reject command if error when opening file
294
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 if (status != Os::File::OP_OK) {
295 2 this->m_mode.set(Mode::IDLE);
296
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (status == Os::File::OUTSIDE_SANDBOX) {
297 1 this->m_warnings.sourceOutOfSandbox();
298 } else {
299 1 this->m_warnings.fileOpenError();
300 }
301
2/2
✓ Branch 5 taken 2 times.
✓ Branch 8 taken 2 times.
2 sendResponse(FILEDOWNLINK_COMMAND_FAILURES_DISABLED ? SendFileStatus::STATUS_OK : SendFileStatus::STATUS_ERROR);
302 2 return;
303 }
304 6 const U32 fileSize = this->m_file.getSize();
305
306
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 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
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 } else if (startOffset >= fileSize) {
315 1 this->enterCooldown();
316 1 this->log_WARNING_HI_DownlinkPartialFail(this->m_file.getSourceName(), this->m_file.getDestName(), startOffset,
317 fileSize);
318
2/2
✓ Branch 5 taken 1 times.
✓ Branch 8 taken 1 times.
1 sendResponse(FILEDOWNLINK_COMMAND_FAILURES_DISABLED ? SendFileStatus::STATUS_OK
319 : SendFileStatus::STATUS_INVALID);
320 1 return;
321 // startOffset < fileSize here, so the subtraction cannot underflow and, unlike
322 // startOffset + length, cannot wrap
323
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 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 2 this->log_WARNING_LO_DownlinkPartialWarning(startOffset, length, fileSize, this->m_file.getSourceName(),
327 1 this->m_file.getDestName());
328 1 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
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 if (length > 0) {
342 2 this->log_ACTIVITY_HI_SendStarted(length, this->m_file.getSourceName(), this->m_file.getDestName());
343 2 this->m_endOffset = startOffset + length;
344 } else {
345 6 this->log_ACTIVITY_HI_SendStarted(fileSize - startOffset, this->m_file.getSourceName(),
346 3 this->m_file.getDestName());
347 3 this->m_endOffset = fileSize;
348 }
349 }
350
351 6 Os::File::Status FileDownlink ::sendDataPacket(U32& byteOffset) {
352 6 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
2/2
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 4 times.
6 if (byteOffset >= this->m_endOffset) {
356 2 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 4 const U32 remaining = this->m_endOffset - byteOffset;
363
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 const U32 dataSize = (remaining < maxDataSize) ? remaining : maxDataSize;
364 4 U8 buffer[maxDataSize];
365 // This will be last data packet sent
366
1/2
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
4 if (dataSize + byteOffset == this->m_endOffset) {
367 4 this->m_lastCompletedType = Fw::FilePacket::T_DATA;
368 }
369
370
1/1
✓ Branch 5 taken 4 times.
4 const Os::File::Status status = this->m_file.read(buffer, byteOffset, dataSize);
371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (status != Os::File::OP_OK) {
372 this->m_warnings.fileRead(status);
373 return status;
374 }
375
376 4 Fw::FilePacket::DataPacket dataPacket;
377
1/1
✓ Branch 6 taken 4 times.
4 dataPacket.initialize(this->m_sequenceIndex, byteOffset, static_cast<U16>(dataSize), buffer);
378 4 ++this->m_sequenceIndex;
379 4 Fw::FilePacket filePacket;
380
1/1
✓ Branch 1 taken 4 times.
4 filePacket.fromDataPacket(dataPacket);
381
1/1
✓ Branch 4 taken 4 times.
4 this->sendFilePacket(filePacket);
382
383 4 byteOffset += dataSize;
384
385 4 return Os::File::OP_OK;
386 }
387
388 1 void FileDownlink ::sendCancelPacket() {
389
1/1
✓ Branch 2 taken 1 times.
1 Fw::Buffer buffer;
390 1 Fw::FilePacket::CancelPacket cancelPacket;
391
1/1
✓ Branch 5 taken 1 times.
1 cancelPacket.initialize(this->m_sequenceIndex);
392
393 1 Fw::FilePacket filePacket;
394
1/1
✓ Branch 1 taken 1 times.
1 filePacket.fromCancelPacket(cancelPacket);
395
1/1
✓ Branch 4 taken 1 times.
1 this->getBuffer(buffer, CANCEL_PACKET);
396 1 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
2/2
✓ Branch 2 taken 1 times.
✓ Branch 8 taken 1 times.
1 buffer.getSerializer().serializeFrom(static_cast<FwPacketDescriptorType>(Fw::ComPacketType::FW_PACKET_FILE));
403 1 FW_ASSERT(status == Fw::FW_SERIALIZE_OK);
404
1/1
✓ Branch 2 taken 1 times.
2 Fw::Buffer offsetBuffer(buffer.getData() + sizeof(FwPacketDescriptorType),
405
2/2
✓ Branch 2 taken 1 times.
✓ Branch 7 taken 1 times.
2 buffer.getSize() - static_cast<Fw::Buffer::SizeType>(sizeof(FwPacketDescriptorType)));
406 // Serialize the filePacket content into the buffer
407
1/1
✓ Branch 1 taken 1 times.
1 status = filePacket.toBuffer(offsetBuffer);
408 1 FW_ASSERT(status == Fw::FW_SERIALIZE_OK);
409
1/1
✓ Branch 1 taken 1 times.
1 const U32 bufferSize = filePacket.bufferSize() + static_cast<U32>(sizeof(FwPacketDescriptorType));
410 1 FW_ASSERT(buffer.getSize() >= bufferSize, static_cast<FwAssertArgType>(buffer.getSize()),
411 static_cast<FwAssertArgType>(bufferSize));
412
1/1
✓ Branch 2 taken 1 times.
1 buffer.setSize(bufferSize);
413
1/1
✓ Branch 5 taken 1 times.
1 this->bufferSendOut_out(0, buffer);
414
1/1
✓ Branch 4 taken 1 times.
1 this->m_packetsSent.packetSent();
415 2 }
416
417 4 void FileDownlink ::sendEndPacket() {
418
1/1
✓ Branch 2 taken 4 times.
4 CFDP::Checksum checksum;
419
1/1
✓ Branch 4 taken 4 times.
4 this->m_file.getChecksum(checksum);
420
421 4 Fw::FilePacket::EndPacket endPacket;
422
1/1
✓ Branch 5 taken 4 times.
4 endPacket.initialize(this->m_sequenceIndex, checksum);
423
424 4 Fw::FilePacket filePacket;
425
1/1
✓ Branch 1 taken 4 times.
4 filePacket.fromEndPacket(endPacket);
426
1/1
✓ Branch 4 taken 4 times.
4 this->sendFilePacket(filePacket);
427 8 }
428
429 5 void FileDownlink ::sendStartPacket() {
430 5 Fw::FilePacket::StartPacket startPacket;
431
1/1
✓ Branch 14 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 4 taken 5 times.
5 this->sendFilePacket(filePacket);
436 5 }
437
438 13 void FileDownlink ::sendFilePacket(const Fw::FilePacket& filePacket) {
439
1/1
✓ Branch 2 taken 13 times.
13 const U32 bufferSize = filePacket.bufferSize() + static_cast<U32>(sizeof(FwPacketDescriptorType));
440 13 FW_ASSERT(this->m_buffer.getData() != nullptr);
441 13 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 4 taken 13 times.
✓ Branch 10 taken 13 times.
13 Fw::SerializeStatus status = this->m_buffer.getSerializer().serializeFrom(
445 static_cast<FwPacketDescriptorType>(Fw::ComPacketType::FW_PACKET_FILE));
446 13 FW_ASSERT(status == Fw::FW_SERIALIZE_OK);
447 // Serialize the filePacket content into the buffer, offset by the size of the packet descriptor
448 13 Fw::Buffer offsetBuffer(
449
1/1
✓ Branch 5 taken 13 times.
13 this->m_buffer.getData() + sizeof(FwPacketDescriptorType),
450
2/2
✓ Branch 6 taken 13 times.
✓ Branch 11 taken 13 times.
26 this->m_buffer.getSize() - static_cast<Fw::Buffer::SizeType>(sizeof(FwPacketDescriptorType)));
451
1/1
✓ Branch 2 taken 13 times.
13 status = filePacket.toBuffer(offsetBuffer);
452 13 FW_ASSERT(status == Fw::FW_SERIALIZE_OK);
453 // set the buffer size to the packet size
454
1/1
✓ Branch 6 taken 13 times.
13 this->m_buffer.setSize(bufferSize);
455
1/1
✓ Branch 8 taken 13 times.
13 this->bufferSendOut_out(0, this->m_buffer);
456 // restore buffer size to max
457
1/1
✓ Branch 6 taken 13 times.
13 this->m_buffer.setSize(FILEDOWNLINK_INTERNAL_BUFFER_SIZE);
458
1/1
✓ Branch 4 taken 13 times.
13 this->m_packetsSent.packetSent();
459 26 }
460
461 6 void FileDownlink ::enterCooldown() {
462 6 this->m_file.getOsFile().close();
463 6 this->m_mode.set(Mode::COOLDOWN);
464 6 this->m_lastCompletedType = Fw::FilePacket::T_NONE;
465 6 this->m_curTimer = 0;
466 6 }
467
468 9 void FileDownlink ::downlinkPacket() {
469 9 FW_ASSERT(this->m_lastCompletedType != Fw::FilePacket::T_NONE,
470 static_cast<FwAssertArgType>(this->m_lastCompletedType));
471 9 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
6/8
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 8 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 8 times.
9 if (this->m_mode.get() == Mode::CANCEL && this->m_lastCompletedType == Fw::FilePacket::T_START) {
475 1 this->sendCancelPacket();
476 1 this->m_lastCompletedType = Fw::FilePacket::T_CANCEL;
477 }
478 // If in downlink mode and currently downlinking data then continue with the next packer
479
6/8
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 8 times.
✓ Branch 11 taken 4 times.
✓ Branch 12 taken 4 times.
✓ Branch 13 taken 4 times.
✓ Branch 14 taken 4 times.
8 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 4 const Os::File::Status status = this->sendDataPacket(this->m_byteOffset);
482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 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
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
4 else if (this->m_lastCompletedType == Fw::FilePacket::T_DATA) {
493 4 this->sendEndPacket();
494 4 this->m_lastCompletedType = Fw::FilePacket::T_END;
495 }
496 9 this->m_mode.set(Mode::WAIT);
497 9 this->m_curTimer = 0;
498 }
499
500 5 void FileDownlink ::finishHelper(bool cancel) {
501 // Complete command and switch to IDLE
502
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (not cancel) {
503 4 this->m_filesSent.fileSent();
504 4 this->log_ACTIVITY_HI_FileSent(this->m_file.getSourceName(), this->m_file.getDestName());
505 } else {
506 1 this->log_ACTIVITY_HI_DownlinkCanceled(this->m_file.getSourceName(), this->m_file.getDestName());
507 }
508 5 this->enterCooldown();
509
2/2
✓ Branch 5 taken 5 times.
✓ Branch 8 taken 5 times.
5 sendResponse(SendFileStatus::STATUS_OK);
510 5 }
511
512 6 void FileDownlink ::getBuffer(Fw::Buffer& buffer, PacketType type) {
513 // Check type is correct
514 6 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 6 buffer.set(this->m_memoryStore[type], FILEDOWNLINK_INTERNAL_BUFFER_SIZE, m_lastBufferId);
518 6 m_lastBufferId++;
519 6 }
520 } // end namespace Svc
521