GCC Code Coverage Report


Directory: ./
File: Svc/Ccsds/CfdpManager/Channel.hpp
Date: 2026-09-03 22:12:29
Exec Total Coverage
Lines: 0 23 0.0%
Functions: 0 13 0.0%
Branches: 0 0 -%

Line Branch Exec Source
1 // ======================================================================
2 // \title Channel.hpp
3 // \brief CFDP Channel operations
4 //
5 // This file is a port of channel-specific functions from the following files
6 // from the NASA Core Flight System (cFS) CFDP (CF) Application, version 3.0.0,
7 // adapted for use within the F-Prime (F') framework:
8 // - cf_cfdp.c (channel processing functions)
9 // - cf_utils.c (channel transaction and resource management)
10 //
11 // ======================================================================
12 //
13 // NASA Docket No. GSC-18,447-1
14 //
15 // Copyright (c) 2019 United States Government as represented by the
16 // Administrator of the National Aeronautics and Space Administration.
17 // All Rights Reserved.
18 //
19 // Licensed under the Apache License, Version 2.0 (the "License");
20 // you may not use this file except in compliance with the License.
21 // You may obtain a copy of the License at
22 //
23 // http://www.apache.org/licenses/LICENSE-2.0
24 //
25 // Unless required by applicable law or agreed to in writing, software
26 // distributed under the License is distributed on an "AS IS" BASIS,
27 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28 // See the License for the specific language governing permissions and
29 // limitations under the License.
30 //
31 // ======================================================================
32
33 #ifndef CFDP_CHANNEL_HPP
34 #define CFDP_CHANNEL_HPP
35
36 #include <Fw/Types/Assert.hpp>
37 #include <Fw/Types/MemAllocator.hpp>
38
39 #include <Svc/Ccsds/CfdpManager/Types/Types.hpp>
40
41 namespace Svc {
42 namespace Ccsds {
43 namespace Cfdp {
44
45 // Forward declarations
46 class Engine;
47 class Transaction;
48
49 /**
50 * @brief CFDP Channel class
51 *
52 * Encapsulates channel-specific operations for CFDP protocol processing.
53 * Each channel manages its own set of transactions, playback directories,
54 * and polling directories.
55 */
56 class Channel {
57 public:
58 // ----------------------------------------------------------------------
59 // Construction
60 // ----------------------------------------------------------------------
61
62 /**
63 * @brief Construct a Channel
64 *
65 * @param engine Pointer to parent CFDP engine
66 * @param channelId Channel ID (index)
67 * @param cfdpManager Pointer to parent CfdpManager component
68 * @param allocator Memory allocator for dynamic allocation
69 * @param memId Memory allocation identifier
70 */
71 Channel(Engine* engine, U8 channelId, CfdpManager* cfdpManager, Fw::MemAllocator& allocator, FwEnumStoreType memId);
72
73 /**
74 * @brief Destruct a Channel
75 */
76 ~Channel();
77
78 /**
79 * @brief Clean up dynamically allocated resources
80 *
81 * Must be called before destruction to free internal arrays
82 *
83 * @param allocator Memory allocator used during construction
84 * @param memId Memory allocation identifier
85 */
86 void cleanup(Fw::MemAllocator& allocator, FwEnumStoreType memId);
87
88 // Disable copy constructor and assignment operator
89 // Channel manages dynamic resources and should not be copied
90 Channel(const Channel&) = delete;
91 Channel& operator=(const Channel&) = delete;
92
93 // ----------------------------------------------------------------------
94 // Channel Processing
95 // ----------------------------------------------------------------------
96
97 /**
98 * @brief Cycle the TX side of this channel
99 *
100 * Processes outgoing transactions and sends PDUs for this channel.
101 */
102 void cycleTx();
103
104 /**
105 * @brief Tick all transactions on this channel
106 *
107 * Processes timer expirations and retransmissions for all active transactions.
108 */
109 void tickTransactions();
110
111 /**
112 * @brief Process all playback directories for this channel
113 */
114 void processPlaybackDirectories();
115
116 /**
117 * @brief Process all polling directories for this channel
118 */
119 void processPollingDirectories();
120
121 // ----------------------------------------------------------------------
122 // Transaction Management
123 // ----------------------------------------------------------------------
124
125 /**
126 * @brief Find an unused transaction on this channel
127 *
128 * @param direction Intended direction of data flow (TX or RX)
129 *
130 * @returns Pointer to a free transaction
131 * @retval nullptr if no free transactions available.
132 */
133 Transaction* findUnusedTransaction(Direction direction);
134
135 /**
136 * @brief Finds an active transaction by sequence number
137 *
138 * This function traverses the active rx, pending, txa, and txw
139 * transaction queues and looks for the requested transaction.
140 *
141 * @param transaction_sequence_number Sequence number to find
142 * @param src_eid Entity ID associated with sequence number
143 *
144 * @returns Pointer to the given transaction if found
145 * @retval nullptr if the transaction is not found
146 */
147 Transaction* findTransactionBySequenceNumber(TransactionSeq transaction_sequence_number, EntityId src_eid);
148
149 /**
150 * @brief Traverses all transactions on all active queues and performs an operation on them
151 *
152 * @param fn Callback to invoke for all traversed transactions
153 * @param context Opaque object to pass to all callbacks
154 *
155 * @returns Number of transactions traversed
156 */
157 I32 traverseAllTransactions(CfdpTraverseAllTransactionsFunc fn, void* context);
158
159 /**
160 * @brief Returns a history structure back to its unused state
161 *
162 * There's nothing to do currently other than remove the history
163 * from its current queue and put it back on QueueId::HIST_FREE.
164 *
165 * @param history Pointer to the history entry
166 */
167 void resetHistory(History* history);
168
169 // ----------------------------------------------------------------------
170 // Channel State Management
171 // ----------------------------------------------------------------------
172
173 /**
174 * @brief Get the channel ID
175 *
176 * @returns Channel ID
177 */
178 inline U8 getChannelId() const { return m_channelId; }
179
180 /**
181 * @brief Get the outgoing PDU counter for this cycle
182 *
183 * @returns Current outgoing PDU count
184 */
185 inline U32 getOutgoingCounter() const { return m_outgoingCounter; }
186
187 /**
188 * @brief Increment the outgoing PDU counter
189 */
190 inline void incrementOutgoingCounter() { ++m_outgoingCounter; }
191
192 /**
193 * @brief Reset the outgoing PDU counter to zero
194 */
195 inline void resetOutgoingCounter() { m_outgoingCounter = 0; }
196
197 /**
198 * @brief Get the number of commanded TX transactions
199 *
200 * @returns Number of commanded TX transactions
201 */
202 inline U32 getNumCmdTx() const { return m_numCmdTx; }
203
204 /**
205 * @brief Increment the command TX counter for this channel
206 */
207 inline void incrementCmdTxCounter() { ++m_numCmdTx; }
208
209 /**
210 * @brief Decrement the command TX counter for this channel
211 */
212 void decrementCmdTxCounter();
213
214 /**
215 * @brief Check if current transaction matches and clear if so
216 *
217 * @param txn Transaction to check against current
218 */
219 void clearCurrentIfMatch(Transaction* txn);
220
221 /**
222 * @brief Set current transaction
223 *
224 * Used when a transaction cannot make progress this cycle
225 * (e.g., throttle limit reached, file transfer complete).
226 *
227 * @param txn Transaction to set as current
228 */
229 void setCurrentTxn(const Transaction* txn);
230
231 /**
232 * @brief Set the flow state for this channel
233 *
234 * @param flowState New flow state (NORMAL or FROZEN)
235 */
236 inline void setFlowState(Flow::T flowState) { m_flowState = flowState; }
237
238 /**
239 * @brief Get the flow state for this channel
240 *
241 * @returns Current flow state
242 */
243 inline Flow::T getFlowState() const { return m_flowState; }
244
245 /**
246 * @brief Get a playback directory entry
247 *
248 * @param index Index of playback directory
249 * @returns Pointer to playback directory
250 */
251 inline Playback* getPlayback(U32 index) {
252 FW_ASSERT(index < MaxCommandedPlaybackDirectoriesPerChan);
253 return &m_playback[index];
254 }
255
256 /**
257 * @brief Get a polling directory entry
258 *
259 * @param index Index of polling directory
260 * @returns Pointer to polling directory
261 */
262 inline CfdpPollDir* getPollDir(U32 index) {
263 FW_ASSERT(index < MaxPollingDirPerChan);
264 return &m_polldir[index];
265 }
266
267 /**
268 * @brief Get a transaction by index (for testing)
269 *
270 * @param index Transaction index within this channel
271 * @returns Pointer to transaction
272 */
273 Transaction* getTransaction(U32 index);
274
275 /**
276 * @brief Get a history by index (for testing)
277 *
278 * @param index History index within this channel
279 * @returns Pointer to history entry
280 */
281 History* getHistory(U32 index);
282
283 // ----------------------------------------------------------------------
284 // Resource Management
285 // ----------------------------------------------------------------------
286
287 /**
288 * @brief Gets the head of the chunk list for this channel + direction
289 *
290 * The chunk list contains structs that are available for tracking the chunks
291 * associated with files in transit. An entry needs to be pulled from this
292 * list for every transaction, and returned to this list when the transaction
293 * completes.
294 *
295 * @param direction Whether this is TX or RX
296 *
297 * @returns Pointer to list head
298 */
299 CListNode** getChunkListHead(U8 direction);
300
301 /**
302 * @brief Find unused chunks for this channel
303 *
304 * @param dir Direction (TX or RX)
305 *
306 * @returns Pointer to unused chunk wrapper
307 * @retval nullptr if no chunks available
308 */
309 CfdpChunkWrapper* findUnusedChunks(Direction dir);
310
311 // ----------------------------------------------------------------------
312 // Transaction Management
313 // ----------------------------------------------------------------------
314
315 /**
316 * @brief Free a transaction from the queue it's on
317 *
318 * NOTE: this leaves the transaction in a bad state,
319 * so it must be followed by placing the transaction on
320 * another queue. Need this function because the path of
321 * freeing a transaction (returning to default state)
322 * means that it must be removed from the current queue
323 * otherwise if the structure is cleared the queue
324 * will become corrupted due to other nodes on the queue
325 * pointing to an invalid node
326 *
327 * @param txn Pointer to the transaction object
328 */
329 void dequeueTransaction(Transaction* txn);
330
331 /**
332 * @brief Move a transaction from one queue to another
333 *
334 * @param txn Pointer to the transaction object
335 * @param queue Index of destination queue
336 */
337 void moveTransaction(Transaction* txn, QueueId::T queue);
338
339 /**
340 * @brief Frees and resets a transaction and returns it for later use
341 *
342 * @param txn Pointer to the transaction object
343 */
344 void freeTransaction(Transaction* txn);
345
346 /**
347 * @brief Recover resources associated with a transaction
348 *
349 * Wipes all data in the transaction struct and returns everything to its
350 * relevant FREE list so it can be used again.
351 *
352 * Notably, should any PDUs arrive after this that is related to this
353 * transaction, these PDUs will not be identifiable, and no longer associable
354 * to this transaction.
355 *
356 * It is imperative that nothing uses the txn struct after this call,
357 * as it will now be invalid. This is effectively like free().
358 *
359 * @param txn Pointer to the transaction object
360 */
361 void recycleTransaction(Transaction* txn);
362
363 /**
364 * @brief Insert a transaction into a priority sorted transaction queue
365 *
366 * This function works by walking the queue in reverse to find a
367 * transaction with a higher priority than the given transaction.
368 * The given transaction is then inserted after that one, since it
369 * would be the next lower priority.
370 *
371 * @param txn Pointer to the transaction object
372 * @param queue Index of queue to insert into
373 */
374 void insertSortPrio(Transaction* txn, QueueId::T queue);
375
376 // ----------------------------------------------------------------------
377 // Queue Management
378 // ----------------------------------------------------------------------
379
380 /**
381 * @brief Remove a node from a channel queue
382 *
383 * @param queueidx Queue index
384 * @param node Node to remove
385 */
386 inline void removeFromQueue(QueueId::T queueidx, CListNode* node);
387
388 /**
389 * @brief Insert a node after another in a channel queue
390 *
391 * @param queueidx Queue index
392 * @param start Node to insert after
393 * @param after Node to insert
394 */
395 inline void insertAfterInQueue(QueueId::T queueidx, CListNode* start, CListNode* after);
396
397 /**
398 * @brief Insert a node at the back of a channel queue
399 *
400 * @param queueidx Queue index
401 * @param node Node to insert
402 */
403 inline void insertBackInQueue(QueueId::T queueidx, CListNode* node);
404
405 // ----------------------------------------------------------------------
406 // Callback methods (public so wrappers can call them)
407 // ----------------------------------------------------------------------
408
409 /**
410 * @brief Traverse callback for cycling the first active transaction
411 *
412 * @param node List node being traversed
413 * @param context Callback context (CycleTxArgs*)
414 * @returns Traversal status (CONT or EXIT)
415 */
416 CListTraverseStatus cycleTxFirstActive(CListNode* node, void* context);
417
418 /**
419 * @brief Traverse callback for ticking a transaction
420 *
421 * @param node List node being traversed
422 * @param context Callback context (TickArgs*)
423 * @returns Traversal status (CONT or EXIT)
424 */
425 CListTraverseStatus doTick(CListNode* node, void* context);
426
427 // ----------------------------------------------------------------------
428 // Static callback wrappers (for function pointer callbacks)
429 // ----------------------------------------------------------------------
430
431 /**
432 * @brief Static wrapper for cycleTxFirstActive callback
433 * @param node CList node
434 * @param context Pointer to Channel instance
435 * @return Traversal status
436 */
437 static CListTraverseStatus cycleTxFirstActiveWrapper(CListNode* node, void* context);
438
439 /**
440 * @brief Static wrapper for doTick callback
441 * @param node CList node
442 * @param context Pointer to Channel instance
443 * @return Traversal status
444 */
445 static CListTraverseStatus doTickWrapper(CListNode* node, void* context);
446
447 /**
448 * @brief Static wrapper for traverseAllTransactions callback
449 * @param node CList node
450 * @param context Pointer to TraverseAllContext struct
451 * @return Traversal status
452 */
453 static CListTraverseStatus traverseAllTransactionsWrapper(CListNode* node, void* context);
454
455 private:
456 // ----------------------------------------------------------------------
457 // Private helper methods
458 // ----------------------------------------------------------------------
459
460 /**
461 * @brief Step each active playback directory
462 *
463 * Check if a playback directory needs iterated, and if so does, and
464 * if a valid file is found initiates playback on it.
465 *
466 * @param pb The playback state
467 */
468 void processPlaybackDirectory(Playback* pb);
469
470 /**
471 * @brief Update playback/poll counted state
472 *
473 * @param pb Playback state
474 * @param up Whether to increment (1) or decrement (0)
475 * @param counter Counter to update
476 */
477 void updatePollPbCounted(Playback* pb, I32 up, U8* counter);
478
479 private:
480 // ----------------------------------------------------------------------
481 // Member variables
482 // ----------------------------------------------------------------------
483
484 Engine* m_engine; //!< Parent CFDP engine
485
486 CListNode* m_qs[QueueId::NUM]; //!< Transaction queues
487 CListNode* m_cs[static_cast<U32>(Direction::DIRECTION_NUM)]; //!< Command/history lists
488
489 U32 m_numCmdTx; //!< Number of commanded TX transactions
490
491 Playback m_playback[MaxCommandedPlaybackDirectoriesPerChan]; //!< Playback state
492 CfdpPollDir m_polldir[MaxPollingDirPerChan]; //!< Polling directory state
493
494 const Transaction* m_currentTxn; //!< Current transaction during channel cycle
495 CfdpManager* m_cfdpManager; //!< Reference to F' component for parameters
496
497 U8 m_tickType; //!< Type of tick being processed
498 U8 m_channelId; //!< Channel ID (index into engine array)
499
500 Flow::T m_flowState; //!< Channel flow state (normal/frozen)
501 U32 m_outgoingCounter; //!< PDU throttling counter
502
503 // Per-channel resource arrays (dynamically allocated, moved from Engine)
504 Transaction* m_transactions; //!< Array of CFDP_NUM_TRANSACTIONS_PER_CHANNEL
505 History* m_histories; //!< Array of NumHistoriesPerChannel
506 CfdpChunkWrapper* m_chunks; //!< Array of CFDP_NUM_TRANSACTIONS_PER_CHANNEL * Direction::DIRECTION_NUM
507 Chunk* m_chunkMem; //!< Chunk memory backing store
508
509 U32 m_dirMaxChunks[static_cast<U32>(
510 Direction::DIRECTION_NUM)]; //!< Max chunks per direction (RX/TX) for this channel
511
512 // Friend declarations for testing
513 friend class CfdpManagerTester;
514 };
515
516 // ----------------------------------------------------------------------
517 // Inline function implementations
518 // ----------------------------------------------------------------------
519
520 inline void Channel::removeFromQueue(QueueId::T queueidx, CListNode* node) {
521 CfdpCListRemove(&m_qs[queueidx], node);
522 }
523
524 inline void Channel::insertAfterInQueue(QueueId::T queueidx, CListNode* start, CListNode* after) {
525 CfdpCListInsertAfter(&m_qs[queueidx], start, after);
526 }
527
528 inline void Channel::insertBackInQueue(QueueId::T queueidx, CListNode* node) {
529 CfdpCListInsertBack(&m_qs[queueidx], node);
530 }
531
532 } // namespace Cfdp
533 } // namespace Ccsds
534 } // namespace Svc
535
536 #endif // CFDP_CHANNEL_HPP
537