GCC Code Coverage Report


Directory: ./
File: Svc/Ccsds/CfdpManager/CfdpManager.cpp
Date: 2026-09-03 22:12:29
Exec Total Coverage
Lines: 0 352 0.0%
Functions: 0 40 0.0%
Branches: 0 228 0.0%

Line Branch Exec Source
1 // ======================================================================
2 // \title CfdpManager.cpp
3 // \author Brian Campuzano
4 // \brief cpp file for CfdpManager component implementation class
5 // ======================================================================
6
7 #include <Fw/Com/ComPacket.hpp>
8 #include <Fw/Prm/ParamValid.hpp>
9 #include <Os/QueueString.hpp>
10 #include <Svc/Ccsds/CfdpManager/CfdpManager.hpp>
11 #include <Svc/Ccsds/CfdpManager/Channel.hpp>
12 #include <Svc/Ccsds/CfdpManager/Engine.hpp>
13 #include <new>
14
15 namespace Svc {
16 namespace Ccsds {
17 namespace Cfdp {
18
19 // ----------------------------------------------------------------------
20 // Component construction and destruction
21 // ----------------------------------------------------------------------
22
23 CfdpManager ::CfdpManager(const char* const compName) : CfdpManagerComponentBase(compName), m_engine(nullptr) {}
24
25 CfdpManager ::~CfdpManager() {
26 // Clean up the queue resources allocated during initialization
27 this->deinit();
28
29 // If cleanup() was not called, clean up manually
30 if (this->m_engine != nullptr) {
31 this->cleanup();
32 }
33 }
34
35 void CfdpManager ::configure(Fw::MemAllocator& allocator, FwSizeType fileQueueDepth, FwEnumStoreType memId) {
36 // Allocate and initialize the CFDP engine
37 FwSizeType engineSize = sizeof(Engine);
38 this->m_engine = static_cast<Engine*>(allocator.allocate(memId, engineSize));
39 FW_ASSERT(this->m_engine != nullptr);
40 (void)new (this->m_engine) Engine(this);
41 this->m_engine->init(allocator, memId);
42
43 // Store allocator for cleanup
44 this->m_allocator = &allocator;
45 this->m_allocatorId = memId;
46
47 // Initialize telemetry counters to zero
48 for (U8 i = 0; i < Cfdp::NumChannels; i++) {
49 this->m_channelTelemetry[i] = Cfdp::ChannelTelemetry();
50 }
51
52 // Create the fileIn request handoff queue
53 this->m_fileInQueueDepth = fileQueueDepth;
54 Os::Queue::Status queueStat =
55 this->m_fileInQueue.create(this->getInstance(), Os::QueueString("cfdpFileInQueue"), fileQueueDepth,
56 static_cast<FwSizeType>(sizeof(FileInRequest)));
57 FW_ASSERT(queueStat == Os::Queue::OP_OK, static_cast<FwAssertArgType>(queueStat));
58 }
59
60 void CfdpManager ::deinit() {
61 this->m_fileInQueue.teardown();
62 CfdpManagerComponentBase::deinit();
63 }
64
65 void CfdpManager ::cleanup() {
66 // Only try to deallocate if both pointers are non-null
67 if ((this->m_allocator != nullptr) && (this->m_engine != nullptr)) {
68 // Manually call destructor since we used placement new
69 this->m_engine->~Engine();
70 // Deallocate the memory
71 this->m_allocator->deallocate(this->m_allocatorId, this->m_engine);
72 this->m_engine = nullptr;
73 }
74 }
75
76 // ----------------------------------------------------------------------
77 // Handler implementations for typed input ports
78 // ----------------------------------------------------------------------
79
80 void CfdpManager ::run1Hz_handler(FwIndexType portNum, U32 context) {
81 // The timer logic built into the CFDP engine requires it to be driven at 1 Hz
82 FW_ASSERT(this->m_engine != nullptr);
83
84 // Drain any port-initiated file send requests before cycling the engine
85 this->drainFileInQueue();
86
87 this->m_engine->cycle();
88
89 // Emit telemetry once per second
90 this->tlmWrite_ChannelTelemetry(this->m_channelTelemetry);
91 }
92
93 void CfdpManager ::drainFileInQueue() {
94 FW_ASSERT(this->m_engine != nullptr);
95
96 // Drain the whole queue; the depth bound guarantees the loop terminates.
97 for (FwSizeType drained = 0; drained < this->m_fileInQueueDepth; drained++) {
98 FileInRequest request;
99 FwSizeType actualSize = 0;
100 FwQueuePriorityType priority = 0;
101 Os::Queue::Status status =
102 this->m_fileInQueue.receive(reinterpret_cast<U8*>(&request), static_cast<FwSizeType>(sizeof(request)),
103 Os::Queue::BlockingType::NONBLOCKING, actualSize, priority);
104
105 // Queue empty (or any non-OK status) ends the drain for this cycle
106 if (status != Os::Queue::Status::OP_OK || actualSize != sizeof(request)) {
107 break;
108 }
109
110 // Look up the per-channel default parameters
111 Fw::ParamValid valid;
112 U8 channelId = this->paramGet_FileInDefaultChannel(valid);
113 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
114
115 // Reject an out-of-range channel parameter rather than letting it assert in Engine::txFile
116 if (channelId >= Cfdp::NumChannels) {
117 this->log_WARNING_LO_InvalidChannel(channelId, Cfdp::NumChannels);
118 this->sendFileComplete(Svc::SendFileStatus::STATUS_INVALID);
119 continue;
120 }
121
122 EntityId destEid = this->paramGet_FileInDefaultDestEntityId(valid);
123 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
124
125 Class::T cfdpClass = this->paramGet_FileInDefaultClass(valid);
126 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
127
128 Keep::T keep = this->paramGet_FileInDefaultKeep(valid);
129 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
130
131 U8 priorityParam = this->paramGet_FileInDefaultPriority(valid);
132 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
133
134 // Initiate the transfer on the active thread
135 Status::T txStatus =
136 this->m_engine->txFile(request.sourceFileName, request.destFileName, cfdpClass, keep, channelId,
137 priorityParam, destEid, TransactionInitType::INIT_BY_PORT);
138
139 // The caller already received queue-acceptance success; report the deferred initiation
140 // result via fileDoneOut so a failed initiation does not leave the caller waiting forever.
141 if (txStatus != Status::SUCCESS) {
142 this->log_WARNING_LO_SendFileInitiateFail(request.sourceFileName);
143 this->sendFileComplete(Svc::SendFileStatus::STATUS_ERROR);
144 }
145 }
146 }
147
148 void CfdpManager ::dataReturnIn_handler(FwIndexType portNum, Fw::Buffer& fwBuffer) {
149 // dataReturnIn is the allocated buffer coming back from the dataOut call
150 // Port mapping is the same from bufferAllocate -> dataOut -> dataReturnIn -> bufferDeallocate
151 FW_ASSERT(portNum < Cfdp::NumChannels, portNum, Cfdp::NumChannels);
152 this->bufferDeallocate_out(portNum, fwBuffer);
153 }
154
155 void CfdpManager ::dataIn_handler(FwIndexType portNum, Fw::Buffer& fwBuffer) {
156 // There is a direct mapping between port number and channel index
157 FW_ASSERT(portNum < Cfdp::NumChannels, portNum, Cfdp::NumChannels);
158 FW_ASSERT(portNum >= 0, portNum);
159
160 // Strip FW_PACKET_FILE descriptor (first 2 bytes) from buffer
161 // FprimeRouter sends the entire Space Packet data field, which includes the packet type descriptor
162 if (fwBuffer.getSize() < sizeof(FwPacketDescriptorType)) {
163 // Buffer too small - silently ignore
164 this->dataInReturn_out(portNum, fwBuffer);
165 return;
166 }
167
168 // Read and verify packet type descriptor
169 FwPacketDescriptorType packetType = 0;
170 Fw::SerializeStatus status = fwBuffer.getDeserializer().deserializeTo(packetType);
171 if (status != Fw::FW_SERIALIZE_OK || packetType != Fw::ComPacketType::FW_PACKET_FILE) {
172 // Invalid packet type - silently ignore (consistent with FileUplink behavior)
173 this->dataInReturn_out(portNum, fwBuffer);
174 return;
175 }
176
177 // Create a new buffer view that skips the descriptor
178 // The deserializer advanced past the 2-byte descriptor, but Engine::receivePdu
179 // calls getData() which returns the raw pointer from byte 0. We need to create
180 // a buffer that starts after the descriptor.
181 const FwSizeType descriptorSize = sizeof(FwPacketDescriptorType);
182 Fw::Buffer pduBuffer(fwBuffer.getData() + descriptorSize, fwBuffer.getSize() - descriptorSize,
183 fwBuffer.getContext());
184
185 // Pass the adjusted buffer to the engine
186 FW_ASSERT(this->m_engine != nullptr);
187 this->m_engine->receivePdu(static_cast<U8>(portNum), pduBuffer);
188
189 // Return buffer
190 this->dataInReturn_out(portNum, fwBuffer);
191 }
192
193 Svc::SendFileResponse CfdpManager ::fileIn_handler(FwIndexType portNum,
194 const Fw::StringBase& sourceFileName,
195 const Fw::StringBase& destFileName,
196 U32 offset,
197 U32 length) {
198 Svc::SendFileResponse response;
199 // Set context to portNum so we can identify this transaction later
200 response.set_context(static_cast<U32>(portNum));
201
202 // CFDP engine does not support partial file retransmit at this time
203 // Offset and length must be 0 to send the entire file
204 if (offset > 0 || length > 0) {
205 response.set_status(Svc::SendFileStatus::STATUS_INVALID);
206 this->log_WARNING_LO_UnsupportedSendFileArguments(offset, length);
207 return response;
208 }
209
210 // Copy the request into the internal queue instead of touching the engine here. This handler
211 // runs on the caller's thread (guarded port); the engine is mutated on the active thread when
212 // run1Hz drains the queue. The synchronous response only indicates that the request was
213 // accepted for processing; the final transfer result is delivered later via fileDoneOut.
214 FileInRequest request;
215
216 // Guard against filenames that would not fit in the queued request
217 if (sourceFileName.length() >= request.sourceFileName.getCapacity() ||
218 destFileName.length() >= request.destFileName.getCapacity()) {
219 response.set_status(Svc::SendFileStatus::STATUS_INVALID);
220 this->log_WARNING_LO_SendFileInitiateFail(sourceFileName);
221 return response;
222 }
223
224 request.sourceFileName = sourceFileName;
225 request.destFileName = destFileName;
226 request.context = static_cast<U32>(portNum);
227
228 Os::Queue::Status status =
229 this->m_fileInQueue.send(reinterpret_cast<U8*>(&request), static_cast<FwSizeType>(sizeof(request)), 0,
230 Os::Queue::BlockingType::NONBLOCKING);
231
232 if (status != Os::Queue::Status::OP_OK) {
233 // Queue full - reject the request so the caller can retry later
234 response.set_status(Svc::SendFileStatus::STATUS_BUSY);
235 this->log_WARNING_LO_SendFileInitiateFail(sourceFileName);
236 } else {
237 response.set_status(Svc::SendFileStatus::STATUS_OK);
238 }
239
240 return response;
241 }
242
243 void CfdpManager ::pingIn_handler(FwIndexType portNum, U32 key) {
244 // send ping response
245 this->pingOut_out(0, key);
246 }
247
248 // ----------------------------------------------------------------------
249 // Port calls that are invoked by the CFDP engine
250 // These functions are analogous to the functions in cf_cfdp_sbintf.*
251 // However these functions were not directly migrated due to the
252 // architectural differences between F' and cFE
253 // ----------------------------------------------------------------------
254
255 Status::T CfdpManager ::getPduBuffer(Fw::Buffer& buffer, Channel& channel, FwSizeType size) {
256 Status::T status = Status::ERROR;
257 FwIndexType portNum;
258
259 // There is a direct mapping between channel index and port number
260 portNum = static_cast<FwIndexType>(channel.getChannelId());
261
262 // Check if we have reached the maximum number of output PDUs for this cycle
263 U32 max_pdus = getMaxOutgoingPdusPerCycleParam(channel.getChannelId());
264 if (channel.getOutgoingCounter() >= max_pdus) {
265 status = Status::SEND_PDU_NO_BUF_AVAIL_ERROR;
266 } else {
267 buffer = this->bufferAllocate_out(portNum, size);
268 // Check the allocation was successful based on size
269 if (buffer.getSize() == size) {
270 channel.incrementOutgoingCounter();
271 status = Status::SUCCESS;
272 } else {
273 this->log_WARNING_LO_BuffersExhausted();
274 status = Status::SEND_PDU_NO_BUF_AVAIL_ERROR;
275 }
276 }
277 return status;
278 }
279
280 void CfdpManager ::returnPduBuffer(Channel& channel, Fw::Buffer& pduBuffer) {
281 FwIndexType portNum;
282
283 // There is a direct mapping between channel index and port number
284 portNum = static_cast<FwIndexType>(channel.getChannelId());
285
286 // Was unable to successfully populate the PDU buffer, return it
287 this->bufferDeallocate_out(portNum, pduBuffer);
288 }
289
290 void CfdpManager ::sendPduBuffer(Channel& channel, Fw::Buffer& pduBuffer) {
291 FwIndexType portNum;
292
293 // There is a direct mapping between channel index and port number
294 portNum = static_cast<FwIndexType>(channel.getChannelId());
295
296 // ComQueue expects buffers to start with a 2-byte packet descriptor (APID)
297 // The PDU data has already been serialized at offset PACKET_DESCRIPTOR_SIZE,
298 // so we just need to write the descriptor at the beginning
299
300 U8* bufferData = pduBuffer.getData();
301
302 // Write FW_PACKET_FILE descriptor at the beginning (big-endian U16)
303 const FwPacketDescriptorType descriptor = static_cast<FwPacketDescriptorType>(Fw::ComPacketType::FW_PACKET_FILE);
304 bufferData[0] = static_cast<U8>((descriptor >> 8) & 0xFF); // High byte
305 bufferData[1] = static_cast<U8>(descriptor & 0xFF); // Low byte
306
307 // Send buffer with descriptor
308 this->dataOut_out(portNum, pduBuffer);
309 }
310
311 void CfdpManager::sendFileComplete(Svc::SendFileStatus::T status) {
312 Svc::SendFileResponse response;
313 response.set_status(status);
314 response.set_context(0);
315
316 this->fileDoneOut_out(0, response);
317 }
318
319 // ----------------------------------------------------------------------
320 // Handler implementations for commands
321 // ----------------------------------------------------------------------
322
323 void CfdpManager ::SendFile_cmdHandler(FwOpcodeType opCode,
324 U32 cmdSeq,
325 U8 channelId,
326 EntityId destId,
327 const Class& cfdpClass,
328 const Keep& keep,
329 U8 priority,
330 const Fw::CmdStringArg& sourceFileName,
331 const Fw::CmdStringArg& destFileName) {
332 Fw::CmdResponse::T rspStatus = Fw::CmdResponse::OK;
333
334 // Check channel index is in range
335 rspStatus = this->checkCommandChannelIndex(channelId);
336 FW_ASSERT(this->m_engine != nullptr);
337
338 if (rspStatus == Fw::CmdResponse::OK) {
339 if (Status::SUCCESS !=
340 this->m_engine->txFile(sourceFileName, destFileName, cfdpClass.e, keep.e, channelId, priority, destId)) {
341 // Engine emits specific failure reason EVR (e.g., MaxTxTransactionsReached)
342 rspStatus = Fw::CmdResponse::EXECUTION_ERROR;
343 }
344 }
345
346 this->cmdResponse_out(opCode, cmdSeq, rspStatus);
347 }
348
349 void CfdpManager ::PlaybackDirectory_cmdHandler(FwOpcodeType opCode,
350 U32 cmdSeq,
351 U8 channelId,
352 EntityId destId,
353 const Class& cfdpClass,
354 const Keep& keep,
355 U8 priority,
356 const Fw::CmdStringArg& sourceDirectory,
357 const Fw::CmdStringArg& destDirectory) {
358 Fw::CmdResponse::T rspStatus = Fw::CmdResponse::OK;
359
360 FW_ASSERT(this->m_engine != nullptr);
361 // Check channel index is in range
362 rspStatus = this->checkCommandChannelIndex(channelId);
363
364 if (rspStatus == Fw::CmdResponse::OK) {
365 if (Status::SUCCESS == this->m_engine->playbackDir(sourceDirectory.toChar(), destDirectory.toChar(),
366 cfdpClass.e, keep.e, channelId, priority, destId)) {
367 this->log_ACTIVITY_LO_PlaybackInitiated(sourceDirectory);
368 } else {
369 // Engine emits specific failure reason EVR (e.g., PlaybackDirOpenFailed, PlaybackDirSlotUnavailable)
370 rspStatus = Fw::CmdResponse::EXECUTION_ERROR;
371 }
372 }
373
374 this->cmdResponse_out(opCode, cmdSeq, rspStatus);
375 }
376
377 void CfdpManager ::PollDirectory_cmdHandler(FwOpcodeType opCode,
378 U32 cmdSeq,
379 U8 channelId,
380 U8 pollId,
381 EntityId destId,
382 const Class& cfdpClass,
383 U8 priority,
384 U32 interval,
385 const Fw::CmdStringArg& sourceDirectory,
386 const Fw::CmdStringArg& destDirectory) {
387 Fw::CmdResponse::T rspStatus = Fw::CmdResponse::OK;
388
389 FW_ASSERT(this->m_engine != nullptr);
390 // Check channel index and poll index are in range
391 rspStatus = this->checkCommandChannelIndex(channelId);
392 if (rspStatus == Fw::CmdResponse::OK) {
393 rspStatus = this->checkCommandChannelPollIndex(pollId);
394 }
395 if (rspStatus == Fw::CmdResponse::OK) {
396 rspStatus = this->checkCommandPollInterval(interval);
397 }
398
399 if (rspStatus == Fw::CmdResponse::OK) {
400 if (Status::SUCCESS == this->m_engine->startPollDir(channelId, pollId, sourceDirectory, destDirectory,
401 cfdpClass.e, priority, destId, interval)) {
402 this->log_ACTIVITY_LO_PollDirInitiated(sourceDirectory, pollId);
403 } else {
404 // Failure EVR was already emitted
405 rspStatus = Fw::CmdResponse::EXECUTION_ERROR;
406 }
407 }
408
409 this->cmdResponse_out(opCode, cmdSeq, rspStatus);
410 }
411
412 void CfdpManager ::StopPollDirectory_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, U8 channelId, U8 pollId) {
413 Fw::CmdResponse::T rspStatus = Fw::CmdResponse::OK;
414
415 FW_ASSERT(this->m_engine != nullptr);
416 // Check channel index and poll index are in range
417 rspStatus = this->checkCommandChannelIndex(channelId);
418 if (rspStatus == Fw::CmdResponse::OK) {
419 rspStatus = this->checkCommandChannelPollIndex(pollId);
420 }
421
422 if ((rspStatus == Fw::CmdResponse::OK) && (Status::SUCCESS == this->m_engine->stopPollDir(channelId, pollId))) {
423 this->log_ACTIVITY_LO_PollDirStopped(channelId, pollId);
424 }
425 // Failure EVR was already emitted
426 // Not failing the command if the stop request failed
427 // This allows operators to reinforce state prior to calling PollDirectory
428
429 this->cmdResponse_out(opCode, cmdSeq, rspStatus);
430 }
431
432 void CfdpManager ::SetChannelFlow_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, U8 channelId, const Flow& flowState) {
433 Fw::CmdResponse::T rspStatus = Fw::CmdResponse::OK;
434
435 FW_ASSERT(this->m_engine != nullptr);
436 // Check channel index is in range
437 rspStatus = checkCommandChannelIndex(channelId);
438 if (rspStatus == Fw::CmdResponse::OK) {
439 this->m_engine->setChannelFlowState(channelId, flowState);
440 this->log_ACTIVITY_LO_SetFlowState(channelId, flowState);
441 }
442
443 this->cmdResponse_out(opCode, cmdSeq, rspStatus);
444 }
445
446 void CfdpManager ::SuspendResumeTransaction_cmdHandler(FwOpcodeType opCode,
447 U32 cmdSeq,
448 U8 channelId,
449 TransactionSeq transactionSeq,
450 EntityId entityId,
451 const SuspendResume& action) {
452 Fw::CmdResponse::T rspStatus = Fw::CmdResponse::OK;
453
454 FW_ASSERT(this->m_engine != nullptr);
455
456 rspStatus = checkCommandChannelIndex(channelId);
457
458 if (rspStatus == Fw::CmdResponse::OK) {
459 Status::T status = this->m_engine->setSuspendResumeTransaction(channelId, transactionSeq, entityId, action);
460 if (status == Status::SUCCESS) {
461 if (action == SuspendResume::SUSPEND) {
462 log_ACTIVITY_LO_TransactionSuspended(transactionSeq, entityId);
463 } else {
464 log_ACTIVITY_LO_TransactionResumed(transactionSeq, entityId);
465 }
466 } else {
467 log_WARNING_LO_TransactionNotFound(transactionSeq, entityId);
468 rspStatus = Fw::CmdResponse::EXECUTION_ERROR;
469 }
470 }
471
472 this->cmdResponse_out(opCode, cmdSeq, rspStatus);
473 }
474
475 void CfdpManager ::CancelTransaction_cmdHandler(FwOpcodeType opCode,
476 U32 cmdSeq,
477 U8 channelId,
478 TransactionSeq transactionSeq,
479 EntityId entityId) {
480 Fw::CmdResponse::T rspStatus = Fw::CmdResponse::OK;
481
482 FW_ASSERT(this->m_engine != nullptr);
483
484 rspStatus = checkCommandChannelIndex(channelId);
485
486 if (rspStatus == Fw::CmdResponse::OK) {
487 Status::T status = this->m_engine->cancelTransactionBySeq(channelId, transactionSeq, entityId);
488 if (status == Status::SUCCESS) {
489 log_ACTIVITY_HI_TransactionCanceled(transactionSeq, entityId);
490 } else {
491 log_WARNING_LO_TransactionNotFound(transactionSeq, entityId);
492 rspStatus = Fw::CmdResponse::EXECUTION_ERROR;
493 }
494 }
495
496 this->cmdResponse_out(opCode, cmdSeq, rspStatus);
497 }
498
499 void CfdpManager ::AbandonTransaction_cmdHandler(FwOpcodeType opCode,
500 U32 cmdSeq,
501 U8 channelId,
502 TransactionSeq transactionSeq,
503 EntityId entityId) {
504 Fw::CmdResponse::T rspStatus = Fw::CmdResponse::OK;
505
506 FW_ASSERT(this->m_engine != nullptr);
507
508 rspStatus = checkCommandChannelIndex(channelId);
509
510 if (rspStatus == Fw::CmdResponse::OK) {
511 Status::T status = this->m_engine->abandonTransaction(channelId, transactionSeq, entityId);
512 if (status == Status::SUCCESS) {
513 log_ACTIVITY_HI_TransactionAbandoned(transactionSeq, entityId);
514 } else {
515 log_WARNING_LO_TransactionNotFound(transactionSeq, entityId);
516 rspStatus = Fw::CmdResponse::EXECUTION_ERROR;
517 }
518 }
519
520 this->cmdResponse_out(opCode, cmdSeq, rspStatus);
521 }
522
523 void CfdpManager ::ResetCounters_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, U8 channelId) {
524 // 0xFF means reset all channels
525 if (channelId == 0xFF) {
526 for (U8 i = 0; i < Cfdp::NumChannels; i++) {
527 this->m_channelTelemetry[i] = Cfdp::ChannelTelemetry();
528 }
529 this->log_ACTIVITY_HI_ResetCounters(0xFF);
530 }
531 // Otherwise reset specific channel
532 else if (channelId < Cfdp::NumChannels) {
533 this->m_channelTelemetry[channelId] = Cfdp::ChannelTelemetry();
534 this->log_ACTIVITY_HI_ResetCounters(channelId);
535 } else {
536 // Invalid channel ID
537 this->log_WARNING_LO_InvalidChannel(channelId, Cfdp::NumChannels - 1);
538 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
539 return;
540 }
541
542 // Emit updated telemetry
543 this->tlmWrite_ChannelTelemetry(this->m_channelTelemetry);
544
545 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
546 }
547
548 // ----------------------------------------------------------------------
549 // Private command helper functions
550 // ----------------------------------------------------------------------
551
552 Fw::CmdResponse::T CfdpManager ::checkCommandChannelIndex(U8 channelIndex) {
553 if (channelIndex >= Cfdp::NumChannels) {
554 this->log_WARNING_LO_InvalidChannel(channelIndex, Cfdp::NumChannels);
555 return Fw::CmdResponse::VALIDATION_ERROR;
556 } else {
557 return Fw::CmdResponse::OK;
558 }
559 }
560
561 Fw::CmdResponse::T CfdpManager ::checkCommandChannelPollIndex(U8 pollIndex) {
562 if (pollIndex >= MaxPollingDirPerChan) {
563 this->log_WARNING_LO_InvalidChannelPoll(pollIndex, MaxPollingDirPerChan);
564 return Fw::CmdResponse::VALIDATION_ERROR;
565 } else {
566 return Fw::CmdResponse::OK;
567 }
568 }
569
570 Fw::CmdResponse::T CfdpManager ::checkCommandPollInterval(U32 interval) {
571 // A zero interval would arm the poll timer with no time remaining, which is
572 // not a valid polling configuration, so reject it here.
573 if (interval == 0) {
574 this->log_WARNING_LO_InvalidPollInterval(interval);
575 return Fw::CmdResponse::VALIDATION_ERROR;
576 } else {
577 return Fw::CmdResponse::OK;
578 }
579 }
580
581 // ----------------------------------------------------------------------
582 // Parameter helpers used by the CFDP engine
583 // ----------------------------------------------------------------------
584
585 EntityId CfdpManager::getLocalEidParam(void) {
586 Fw::ParamValid valid;
587
588 // Check for coding errors as all CFDP parameters must have a default
589 EntityId localEid = this->paramGet_LocalEid(valid);
590 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
591
592 return localEid;
593 }
594
595 U32 CfdpManager::getOutgoingFileChunkSizeParam(void) {
596 Fw::ParamValid valid;
597
598 // Check for coding errors as all CFDP parameters must have a default
599 U32 chunkSize = this->paramGet_OutgoingFileChunkSize(valid);
600 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
601
602 return chunkSize;
603 }
604 U32 CfdpManager::getRxCrcCalcBytesPerCycleParam(void) {
605 Fw::ParamValid valid;
606
607 // Check for coding errors as all CFDP parameters must have a default
608 U32 rxSize = this->paramGet_RxCrcCalcBytesPerCycle(valid);
609 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
610
611 return rxSize;
612 }
613
614 U8 CfdpManager::getPostInactivitySendRetriesParam(void) {
615 Fw::ParamValid valid;
616
617 // Check for coding errors as all CFDP parameters must have a default
618 U8 retries = this->paramGet_PostInactivitySendRetries(valid);
619 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
620
621 return retries;
622 }
623
624 Fw::String CfdpManager::getTmpDirParam(U8 channelIndex) {
625 Fw::ParamValid valid;
626
627 FW_ASSERT(channelIndex < Cfdp::NumChannels, channelIndex, Cfdp::NumChannels);
628
629 // Check for coding errors as all CFDP parameters must have a default
630 // Get the array first
631 ChannelArrayParams paramArray = paramGet_ChannelConfig(valid);
632 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
633
634 // Now get individual parameter
635 return paramArray[channelIndex].get_tmp_dir();
636 }
637
638 Fw::String CfdpManager::getFailDirParam(U8 channelIndex) {
639 Fw::ParamValid valid;
640
641 FW_ASSERT(channelIndex < Cfdp::NumChannels, channelIndex, Cfdp::NumChannels);
642
643 // Check for coding errors as all CFDP parameters must have a default
644 // Get the array first
645 ChannelArrayParams paramArray = paramGet_ChannelConfig(valid);
646 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
647
648 // Now get individual parameter
649 return paramArray[channelIndex].get_fail_dir();
650 }
651
652 U8 CfdpManager::getAckLimitParam(U8 channelIndex) {
653 Fw::ParamValid valid;
654
655 FW_ASSERT(channelIndex < Cfdp::NumChannels, channelIndex, Cfdp::NumChannels);
656
657 // Check for coding errors as all CFDP parameters must have a default
658 // Get the array first
659 ChannelArrayParams paramArray = paramGet_ChannelConfig(valid);
660 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
661
662 // Now get individual parameter
663 return paramArray[channelIndex].get_ack_limit();
664 }
665
666 U8 CfdpManager::getNackLimitParam(U8 channelIndex) {
667 Fw::ParamValid valid;
668
669 FW_ASSERT(channelIndex < Cfdp::NumChannels, channelIndex, Cfdp::NumChannels);
670
671 // Check for coding errors as all CFDP parameters must have a default
672 // Get the array first
673 ChannelArrayParams paramArray = paramGet_ChannelConfig(valid);
674 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
675
676 // Now get individual parameter
677 return paramArray[channelIndex].get_nack_limit();
678 }
679
680 U32 CfdpManager::getAckTimerParam(U8 channelIndex) {
681 Fw::ParamValid valid;
682
683 FW_ASSERT(channelIndex < Cfdp::NumChannels, channelIndex, Cfdp::NumChannels);
684
685 // Check for coding errors as all CFDP parameters must have a default
686 // Get the array first
687 ChannelArrayParams paramArray = paramGet_ChannelConfig(valid);
688 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
689
690 // Now get individual parameter
691 return paramArray[channelIndex].get_ack_timer();
692 }
693
694 U32 CfdpManager::getInactivityTimerParam(U8 channelIndex) {
695 Fw::ParamValid valid;
696
697 FW_ASSERT(channelIndex < Cfdp::NumChannels, channelIndex, Cfdp::NumChannels);
698
699 // Check for coding errors as all CFDP parameters must have a default
700 // Get the array first
701 ChannelArrayParams paramArray = paramGet_ChannelConfig(valid);
702 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
703
704 // Now get individual parameter
705 return paramArray[channelIndex].get_inactivity_timer();
706 }
707
708 Fw::Enabled CfdpManager::getDequeueEnabledParam(U8 channelIndex) {
709 Fw::ParamValid valid;
710
711 FW_ASSERT(channelIndex < Cfdp::NumChannels, channelIndex, Cfdp::NumChannels);
712
713 // Check for coding errors as all CFDP parameters must have a default
714 // Get the array first
715 ChannelArrayParams paramArray = paramGet_ChannelConfig(valid);
716 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
717
718 // Now get individual parameter
719 return paramArray[channelIndex].get_dequeue_enabled();
720 }
721
722 Fw::String CfdpManager::getMoveDirParam(U8 channelIndex) {
723 Fw::ParamValid valid;
724
725 FW_ASSERT(channelIndex < Cfdp::NumChannels, channelIndex, Cfdp::NumChannels);
726
727 // Check for coding errors as all CFDP parameters must have a default
728 // Get the array first
729 ChannelArrayParams paramArray = paramGet_ChannelConfig(valid);
730 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
731
732 // Now get individual parameter
733 return paramArray[channelIndex].get_move_dir();
734 }
735
736 U32 CfdpManager ::getMaxOutgoingPdusPerCycleParam(U8 channelIndex) {
737 Fw::ParamValid valid;
738
739 FW_ASSERT(channelIndex < Cfdp::NumChannels, channelIndex, Cfdp::NumChannels);
740
741 // Check for coding errors as all CFDP parameters must have a default
742 // Get the array first
743 ChannelArrayParams paramArray = paramGet_ChannelConfig(valid);
744 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
745
746 // Now get individual parameter
747 return paramArray[channelIndex].get_max_outgoing_pdus_per_cycle();
748 }
749
750 } // namespace Cfdp
751 } // namespace Ccsds
752 } // namespace Svc
753