| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // ====================================================================== | ||
| 2 | // \title Transaction.hpp | ||
| 3 | // \brief CFDP Transaction state machine class for TX and RX operations | ||
| 4 | // | ||
| 5 | // This file is a port of transaction state machine definitions 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_r.h (receive transaction state machine definitions) | ||
| 9 | // - cf_cfdp_s.h (send transaction state machine definitions) | ||
| 10 | // - cf_cfdp_dispatch.h (transaction dispatch definitions) | ||
| 11 | // | ||
| 12 | // This file contains the unified interface for CFDP transaction state | ||
| 13 | // machines, encompassing both TX (send) and RX (receive) operations. | ||
| 14 | // The implementation is split across TransactionTx.cpp and | ||
| 15 | // TransactionRx.cpp for maintainability. | ||
| 16 | // | ||
| 17 | // ====================================================================== | ||
| 18 | // | ||
| 19 | // NASA Docket No. GSC-18,447-1 | ||
| 20 | // | ||
| 21 | // Copyright (c) 2019 United States Government as represented by the | ||
| 22 | // Administrator of the National Aeronautics and Space Administration. | ||
| 23 | // All Rights Reserved. | ||
| 24 | // | ||
| 25 | // Licensed under the Apache License, Version 2.0 (the "License"); you may | ||
| 26 | // not use this file except in compliance with the License. You may obtain | ||
| 27 | // a copy of the License at | ||
| 28 | // | ||
| 29 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
| 30 | // | ||
| 31 | // Unless required by applicable law or agreed to in writing, software | ||
| 32 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
| 33 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 34 | // See the License for the specific language governing permissions and | ||
| 35 | // limitations under the License. | ||
| 36 | // | ||
| 37 | // ====================================================================== | ||
| 38 | |||
| 39 | #ifndef Svc_Ccsds_CfdpTransaction_HPP | ||
| 40 | #define Svc_Ccsds_CfdpTransaction_HPP | ||
| 41 | |||
| 42 | #include <Fw/Types/BasicTypes.hpp> | ||
| 43 | |||
| 44 | #include <Svc/Ccsds/CfdpManager/Types/PduBase.hpp> | ||
| 45 | #include <Svc/Ccsds/CfdpManager/Types/Types.hpp> | ||
| 46 | |||
| 47 | namespace Svc { | ||
| 48 | namespace Ccsds { | ||
| 49 | namespace Cfdp { | ||
| 50 | |||
| 51 | // Forward declarations | ||
| 52 | class CfdpManager; | ||
| 53 | class Engine; | ||
| 54 | class Channel; | ||
| 55 | class Transaction; | ||
| 56 | |||
| 57 | // ====================================================================== | ||
| 58 | // Dispatch Table Type Definitions | ||
| 59 | // ====================================================================== | ||
| 60 | |||
| 61 | /** | ||
| 62 | * @brief A member function pointer for dispatching actions to a handler, without existing PDU data | ||
| 63 | * | ||
| 64 | * This allows quick delegation to handler functions using dispatch tables. This version is | ||
| 65 | * used on the transmit side, where a PDU will likely be generated/sent by the handler being | ||
| 66 | * invoked. | ||
| 67 | * | ||
| 68 | * @note This is a member function pointer - invoke with: (txn->*fn)() | ||
| 69 | */ | ||
| 70 | using StateSendFunc = void (Transaction::*)(); | ||
| 71 | |||
| 72 | /** | ||
| 73 | * @brief A member function pointer for dispatching actions to a handler, with existing PDU data | ||
| 74 | * | ||
| 75 | * This allows quick delegation of PDUs to handler functions using dispatch tables. This version is | ||
| 76 | * used on the receive side where a PDU buffer is associated with the activity, which is then | ||
| 77 | * interpreted by the handler being invoked. | ||
| 78 | * | ||
| 79 | * @param[inout] buffer The buffer containing the PDU currently being received/processed | ||
| 80 | * @note This is a member function pointer - invoke with: (txn->*fn)(buffer) | ||
| 81 | */ | ||
| 82 | using StateRecvFunc = void (Transaction::*)(const Fw::Buffer& buffer); | ||
| 83 | |||
| 84 | /** | ||
| 85 | * @brief A table of transmit handler functions based on transaction state | ||
| 86 | * | ||
| 87 | * This reflects the main dispatch table for the transmit side of a transaction. | ||
| 88 | * Each possible state has a corresponding function pointer in the table to implement | ||
| 89 | * the PDU transmit action(s) associated with that state. | ||
| 90 | */ | ||
| 91 | struct TxnSendDispatchTable { | ||
| 92 | StateSendFunc tx[static_cast<U32>(TxnState::TXN_STATE_INVALID)]; /**< \brief Transmit handler function */ | ||
| 93 | }; | ||
| 94 | |||
| 95 | /** | ||
| 96 | * @brief A table of receive handler functions based on transaction state | ||
| 97 | * | ||
| 98 | * This reflects the main dispatch table for the receive side of a transaction. | ||
| 99 | * Each possible state has a corresponding function pointer in the table to implement | ||
| 100 | * the PDU receive action(s) associated with that state. | ||
| 101 | */ | ||
| 102 | struct TxnRecvDispatchTable { | ||
| 103 | /** \brief a separate recv handler for each possible file directive PDU in this state */ | ||
| 104 | StateRecvFunc rx[static_cast<U32>(TxnState::TXN_STATE_INVALID)]; | ||
| 105 | }; | ||
| 106 | |||
| 107 | /** | ||
| 108 | * @brief A table of receive handler functions based on file directive code | ||
| 109 | * | ||
| 110 | * For PDUs identified as a "file directive" type - generally anything other | ||
| 111 | * than file data - this provides a table to branch to a different handler | ||
| 112 | * function depending on the value of the file directive code. | ||
| 113 | */ | ||
| 114 | struct FileDirectiveDispatchTable { | ||
| 115 | /** \brief a separate recv handler for each possible file directive PDU in this state */ | ||
| 116 | StateRecvFunc fdirective[static_cast<U32>(FileDirective::FILE_DIRECTIVE_INVALID_MAX)]; | ||
| 117 | }; | ||
| 118 | |||
| 119 | /** | ||
| 120 | * @brief A dispatch table for receive file transactions, receive side | ||
| 121 | * | ||
| 122 | * This is used for "receive file" transactions upon receipt of a directive PDU. | ||
| 123 | * Depending on the sub-state of the transaction, a different action may be taken. | ||
| 124 | */ | ||
| 125 | struct RSubstateDispatchTable { | ||
| 126 | const FileDirectiveDispatchTable* state[static_cast<U32>(RxSubState::RX_SUB_STATE_NUM_STATES)]; | ||
| 127 | }; | ||
| 128 | |||
| 129 | /** | ||
| 130 | * @brief A dispatch table for send file transactions, receive side | ||
| 131 | * | ||
| 132 | * This is used for "send file" transactions upon receipt of a directive PDU. | ||
| 133 | * Depending on the sub-state of the transaction, a different action may be taken. | ||
| 134 | */ | ||
| 135 | struct SSubstateRecvDispatchTable { | ||
| 136 | const FileDirectiveDispatchTable* substate[static_cast<U32>(TxSubState::TX_SUB_STATE_NUM_STATES)]; | ||
| 137 | }; | ||
| 138 | |||
| 139 | /** | ||
| 140 | * @brief A dispatch table for send file transactions, transmit side | ||
| 141 | * | ||
| 142 | * This is used for "send file" transactions to generate the next PDU to be sent. | ||
| 143 | * Depending on the sub-state of the transaction, a different action may be taken. | ||
| 144 | */ | ||
| 145 | struct SSubstateSendDispatchTable { | ||
| 146 | StateSendFunc substate[static_cast<U32>(TxSubState::TX_SUB_STATE_NUM_STATES)]; | ||
| 147 | }; | ||
| 148 | |||
| 149 | /** | ||
| 150 | * @brief CFDP Transaction state machine class | ||
| 151 | * | ||
| 152 | * This class provides TX and RX state machine operations for CFDP transactions. | ||
| 153 | * Implementation is split across multiple files for maintainability: | ||
| 154 | * - TransactionTx.cpp: TX (send) state machine implementation | ||
| 155 | * - TransactionRx.cpp: RX (receive) state machine implementation | ||
| 156 | */ | ||
| 157 | class Transaction { | ||
| 158 | friend class Engine; | ||
| 159 | friend class Channel; | ||
| 160 | friend class CfdpManagerTester; | ||
| 161 | |||
| 162 | public: | ||
| 163 | // ---------------------------------------------------------------------- | ||
| 164 | // Construction and Destruction | ||
| 165 | // ---------------------------------------------------------------------- | ||
| 166 | |||
| 167 | //! Parameterized constructor for channel-bound transaction initialization | ||
| 168 | //! @param channel Pointer to the channel this transaction belongs to | ||
| 169 | //! @param channelId Channel ID number | ||
| 170 | //! @param engine Pointer to the CFDP engine | ||
| 171 | //! @param manager Pointer to the CfdpManager component | ||
| 172 | Transaction(Channel* channel, U8 channelId, Engine* engine, CfdpManager* manager); | ||
| 173 | |||
| 174 | ~Transaction(); | ||
| 175 | |||
| 176 | /** | ||
| 177 | * @brief Reset transaction to default state | ||
| 178 | * | ||
| 179 | * Resets the transaction to a clean state while preserving channel binding. | ||
| 180 | * Used when returning a transaction to the free pool for reuse. | ||
| 181 | */ | ||
| 182 | void reset(); | ||
| 183 | |||
| 184 | /** | ||
| 185 | * @brief Initialize transaction for outgoing file transfer | ||
| 186 | * | ||
| 187 | * Sets up transaction state for transmitting a file. | ||
| 188 | * | ||
| 189 | * @param cfdp_class CFDP class (1 or 2) | ||
| 190 | * @param keep Whether to keep file after transfer | ||
| 191 | * @param chan Channel number | ||
| 192 | * @param priority Transaction priority | ||
| 193 | */ | ||
| 194 | void initTxFile(Class::T cfdp_class, Keep::T keep, U8 chan, U8 priority); | ||
| 195 | |||
| 196 | /** | ||
| 197 | * @brief Static callback for finding transaction by sequence number | ||
| 198 | * | ||
| 199 | * C-style callback for list traversal. Used with CfdpCListTraverse. | ||
| 200 | * | ||
| 201 | * @param node List node pointer | ||
| 202 | * @param context Pointer to CfdpTraverseTransSeqArg | ||
| 203 | * @return Traversal status (CONTINUE or EXIT) | ||
| 204 | */ | ||
| 205 | static CListTraverseStatus findBySequenceNumberCallback(CListNode* node, void* context); | ||
| 206 | |||
| 207 | /** | ||
| 208 | * @brief Static callback for priority search | ||
| 209 | * | ||
| 210 | * C-style callback for list traversal. Used with CfdpCListTraverseR. | ||
| 211 | * | ||
| 212 | * @param node List node pointer | ||
| 213 | * @param context Pointer to CfdpTraversePriorityArg | ||
| 214 | * @return Traversal status (CONTINUE or EXIT) | ||
| 215 | */ | ||
| 216 | static CListTraverseStatus prioritySearchCallback(CListNode* node, void* context); | ||
| 217 | |||
| 218 | // ---------------------------------------------------------------------- | ||
| 219 | // Accessors | ||
| 220 | // ---------------------------------------------------------------------- | ||
| 221 | |||
| 222 | /** | ||
| 223 | * @brief Get transaction history | ||
| 224 | * @return Pointer to history structure | ||
| 225 | */ | ||
| 226 | ✗ | History* getHistory() const { return m_history; } | |
| 227 | |||
| 228 | /** | ||
| 229 | * @brief Get transaction priority | ||
| 230 | * @return Priority value | ||
| 231 | */ | ||
| 232 | ✗ | U8 getPriority() const { return m_priority; } | |
| 233 | |||
| 234 | /** | ||
| 235 | * @brief Get channel ID | ||
| 236 | * @return Channel ID number | ||
| 237 | */ | ||
| 238 | ✗ | U8 getChannelId() const { return m_chan_num; } | |
| 239 | |||
| 240 | /** | ||
| 241 | * @brief Get transaction class (CLASS_1 or CLASS_2) | ||
| 242 | * @return Transaction class | ||
| 243 | */ | ||
| 244 | ✗ | Class::T getClass() const { return m_txn_class; } | |
| 245 | |||
| 246 | /** | ||
| 247 | * @brief Get transaction state | ||
| 248 | * @return Transaction state | ||
| 249 | */ | ||
| 250 | ✗ | TxnState getState() const { return m_state; } | |
| 251 | |||
| 252 | // ---------------------------------------------------------------------- | ||
| 253 | // TX State Machine - Implemented in TransactionTx.cpp | ||
| 254 | // ---------------------------------------------------------------------- | ||
| 255 | |||
| 256 | /************************************************************************/ | ||
| 257 | /** @brief S1 receive PDU processing. | ||
| 258 | * | ||
| 259 | * @param buffer The buffer containing the PDU to process | ||
| 260 | */ | ||
| 261 | void s1Recv(const Fw::Buffer& buffer); | ||
| 262 | |||
| 263 | /************************************************************************/ | ||
| 264 | /** @brief S2 receive PDU processing. | ||
| 265 | * | ||
| 266 | * @param buffer The buffer containing the PDU to process | ||
| 267 | */ | ||
| 268 | void s2Recv(const Fw::Buffer& buffer); | ||
| 269 | |||
| 270 | /************************************************************************/ | ||
| 271 | /** @brief S1 dispatch function. | ||
| 272 | */ | ||
| 273 | void s1Tx(); | ||
| 274 | |||
| 275 | /************************************************************************/ | ||
| 276 | /** @brief S2 dispatch function. | ||
| 277 | */ | ||
| 278 | void s2Tx(); | ||
| 279 | |||
| 280 | /************************************************************************/ | ||
| 281 | /** @brief Perform acknowledgement timer tick (time-based) processing for S transactions. | ||
| 282 | * | ||
| 283 | * This is invoked as part of overall timer tick processing if the transaction | ||
| 284 | * has some sort of acknowledgement pending from the remote. | ||
| 285 | */ | ||
| 286 | void sAckTimerTick(); | ||
| 287 | |||
| 288 | /************************************************************************/ | ||
| 289 | /** @brief Perform tick (time-based) processing for S transactions. | ||
| 290 | * | ||
| 291 | * This function is called on every transaction by the engine on | ||
| 292 | * every scheduler cycle. This is where flags are checked to send EOF or | ||
| 293 | * FIN-ACK. If nothing else is sent, it checks to see if a NAK | ||
| 294 | * retransmit must occur. | ||
| 295 | * | ||
| 296 | * @param cont Unused, exists for compatibility with tick processor | ||
| 297 | */ | ||
| 298 | void sTick(I32* cont); | ||
| 299 | |||
| 300 | /************************************************************************/ | ||
| 301 | /** @brief Perform NAK response for TX transactions | ||
| 302 | * | ||
| 303 | * This function is called at tick processing time to send pending | ||
| 304 | * NAK responses. It indicates "cont" is 1 if there are more responses | ||
| 305 | * left to send. | ||
| 306 | * | ||
| 307 | * @param cont Set to 1 if a NAK was generated | ||
| 308 | */ | ||
| 309 | void sTickNak(I32* cont); | ||
| 310 | |||
| 311 | /************************************************************************/ | ||
| 312 | /** @brief Cancel an S transaction. | ||
| 313 | */ | ||
| 314 | void sCancel(); | ||
| 315 | |||
| 316 | /************************************************************************/ | ||
| 317 | /** @brief Sends an EOF for S1. | ||
| 318 | */ | ||
| 319 | void s1SubstateSendEof(); | ||
| 320 | |||
| 321 | /************************************************************************/ | ||
| 322 | /** @brief Triggers tick processing to send an EOF and wait for EOF-ACK for S2 | ||
| 323 | */ | ||
| 324 | void s2SubstateSendEof(); | ||
| 325 | |||
| 326 | /************************************************************************/ | ||
| 327 | /** @brief Standard state function to send the next file data PDU for active transaction. | ||
| 328 | * | ||
| 329 | * During the transfer of active transaction file data PDUs, the file | ||
| 330 | * offset is saved. This function sends the next chunk of data. If | ||
| 331 | * the file offset equals the file size, then transition to the EOF | ||
| 332 | * state. | ||
| 333 | */ | ||
| 334 | void sSubstateSendFileData(); | ||
| 335 | |||
| 336 | /************************************************************************/ | ||
| 337 | /** @brief Send filedata handling for S2. | ||
| 338 | * | ||
| 339 | * S2 will either respond to a NAK by sending retransmits, or in | ||
| 340 | * absence of a NAK, it will send more of the original file data. | ||
| 341 | */ | ||
| 342 | void s2SubstateSendFileData(); | ||
| 343 | |||
| 344 | /************************************************************************/ | ||
| 345 | /** @brief Send metadata PDU. | ||
| 346 | * | ||
| 347 | * Construct and send a metadata PDU. This function determines the | ||
| 348 | * size of the file to put in the metadata PDU. | ||
| 349 | */ | ||
| 350 | void sSubstateSendMetadata(); | ||
| 351 | |||
| 352 | /************************************************************************/ | ||
| 353 | /** @brief A FIN was received before file complete, so abandon the transaction. | ||
| 354 | * | ||
| 355 | * @param pdu The PDU to process | ||
| 356 | */ | ||
| 357 | void s2EarlyFin(const Fw::Buffer& pdu); | ||
| 358 | |||
| 359 | /************************************************************************/ | ||
| 360 | /** @brief S2 received FIN, so set flag to send FIN-ACK. | ||
| 361 | * | ||
| 362 | * @param pdu Buffer containing the FIN PDU to process | ||
| 363 | */ | ||
| 364 | void s2Fin(const Fw::Buffer& pdu); | ||
| 365 | |||
| 366 | /************************************************************************/ | ||
| 367 | /** @brief S2 NAK PDU received handling. | ||
| 368 | * | ||
| 369 | * Stores the segment requests from the NAK packet in the chunks | ||
| 370 | * structure. These can be used to generate re-transmit filedata | ||
| 371 | * PDUs. | ||
| 372 | * | ||
| 373 | * @param pdu Buffer containing the NAK PDU to process | ||
| 374 | */ | ||
| 375 | void s2Nak(const Fw::Buffer& pdu); | ||
| 376 | |||
| 377 | /************************************************************************/ | ||
| 378 | /** @brief S2 NAK handling but with arming the NAK timer. | ||
| 379 | * | ||
| 380 | * @param pdu Buffer containing the NAK PDU to process | ||
| 381 | */ | ||
| 382 | void s2NakArm(const Fw::Buffer& pdu); | ||
| 383 | |||
| 384 | /************************************************************************/ | ||
| 385 | /** @brief S2 received ACK PDU. | ||
| 386 | * | ||
| 387 | * Handles reception of an ACK PDU | ||
| 388 | * | ||
| 389 | * @param pdu Buffer containing the ACK PDU to process | ||
| 390 | */ | ||
| 391 | void s2EofAck(const Fw::Buffer& pdu); | ||
| 392 | |||
| 393 | private: | ||
| 394 | /*********************************************************************** | ||
| 395 | * | ||
| 396 | * Handler routines for send-file transactions | ||
| 397 | * These are not called from outside this module, but are declared here so they can be unit tested | ||
| 398 | * | ||
| 399 | ************************************************************************/ | ||
| 400 | |||
| 401 | /************************************************************************/ | ||
| 402 | /** @brief Send an EOF PDU. | ||
| 403 | * | ||
| 404 | * @retval Cfdp::Status::SUCCESS on success. | ||
| 405 | * @retval Cfdp::Status::SEND_PDU_NO_BUF_AVAIL_ERROR if message buffer cannot be obtained. | ||
| 406 | * @retval Cfdp::Status::ERROR if an error occurred while building/serializing the packet. | ||
| 407 | */ | ||
| 408 | Status::T sSendEof(); | ||
| 409 | |||
| 410 | Status::T sSendFileData(FileSize foffs, FileSize bytes_to_read, U8 calc_crc, FileSize* bytes_processed); | ||
| 411 | |||
| 412 | Status::T sCheckAndRespondNak(bool* nakProcessed); | ||
| 413 | |||
| 414 | Status::T sSendFinAck(); | ||
| 415 | |||
| 416 | public: | ||
| 417 | // ---------------------------------------------------------------------- | ||
| 418 | // RX State Machine - Implemented in TransactionRx.cpp | ||
| 419 | // ---------------------------------------------------------------------- | ||
| 420 | |||
| 421 | /************************************************************************/ | ||
| 422 | /** @brief R1 receive PDU processing. | ||
| 423 | * | ||
| 424 | * @param buffer The buffer containing the PDU to process | ||
| 425 | */ | ||
| 426 | void r1Recv(const Fw::Buffer& buffer); | ||
| 427 | |||
| 428 | /************************************************************************/ | ||
| 429 | /** @brief R2 receive PDU processing. | ||
| 430 | * | ||
| 431 | * @param buffer The buffer containing the PDU to process | ||
| 432 | */ | ||
| 433 | void r2Recv(const Fw::Buffer& buffer); | ||
| 434 | |||
| 435 | /************************************************************************/ | ||
| 436 | /** @brief Perform acknowledgement timer tick (time-based) processing for R transactions. | ||
| 437 | * | ||
| 438 | * This is invoked as part of overall timer tick processing if the transaction | ||
| 439 | * has some sort of acknowledgement pending from the remote. | ||
| 440 | */ | ||
| 441 | void rAckTimerTick(); | ||
| 442 | |||
| 443 | /************************************************************************/ | ||
| 444 | /** @brief Perform tick (time-based) processing for R transactions. | ||
| 445 | * | ||
| 446 | * This function is called on every transaction by the engine on | ||
| 447 | * every scheduler cycle. This is where flags are checked to send ACK, | ||
| 448 | * NAK, and FIN. It checks for inactivity timer and processes the | ||
| 449 | * ACK timer. The ACK timer is what triggers re-sends of PDUs | ||
| 450 | * that require acknowledgment. | ||
| 451 | * | ||
| 452 | * @param cont Ignored/Unused | ||
| 453 | */ | ||
| 454 | void rTick(I32* cont); | ||
| 455 | |||
| 456 | /************************************************************************/ | ||
| 457 | /** @brief Cancel an R transaction. | ||
| 458 | */ | ||
| 459 | void rCancel(); | ||
| 460 | |||
| 461 | /************************************************************************/ | ||
| 462 | /** @brief Initialize a transaction structure for R. | ||
| 463 | */ | ||
| 464 | void rInit(); | ||
| 465 | |||
| 466 | /************************************************************************/ | ||
| 467 | /** @brief Helper function to store transaction status code and set send_fin flag. | ||
| 468 | * | ||
| 469 | * @param txn_stat Status Code value to set within transaction | ||
| 470 | */ | ||
| 471 | void r2SetFinTxnStatus(TxnStatus txn_stat); | ||
| 472 | |||
| 473 | /************************************************************************/ | ||
| 474 | /** @brief CFDP R1 transaction reset function. | ||
| 475 | * | ||
| 476 | * All R transactions use this call to indicate the transaction | ||
| 477 | * state can be returned to the system. While this function currently | ||
| 478 | * only calls the transaction reset logic, it is here as a placeholder. | ||
| 479 | */ | ||
| 480 | void r1Reset(); | ||
| 481 | |||
| 482 | /************************************************************************/ | ||
| 483 | /** @brief CFDP R2 transaction reset function. | ||
| 484 | * | ||
| 485 | * Handles reset logic for R2, then calls R1 reset logic. | ||
| 486 | */ | ||
| 487 | void r2Reset(); | ||
| 488 | |||
| 489 | /************************************************************************/ | ||
| 490 | /** @brief Checks that the transaction file's CRC matches expected. | ||
| 491 | * | ||
| 492 | * @retval Cfdp::Status::SUCCESS on CRC match, otherwise Cfdp::Status::CFDP_ERROR. | ||
| 493 | * | ||
| 494 | * @param expected_crc Expected CRC | ||
| 495 | */ | ||
| 496 | Status::T rCheckCrc(U32 expected_crc); | ||
| 497 | |||
| 498 | /************************************************************************/ | ||
| 499 | /** @brief Checks R2 transaction state for transaction completion status. | ||
| 500 | * | ||
| 501 | * This function is called anywhere there's a desire to know if the | ||
| 502 | * transaction has completed. It may trigger other actions by setting | ||
| 503 | * flags to be handled during tick processing. In order for a | ||
| 504 | * transaction to be complete, it must have had its meta-data PDU | ||
| 505 | * received, the EOF must have been received, and there must be | ||
| 506 | * no gaps in the file. EOF is not checked in this function, because | ||
| 507 | * it's only called from functions after EOF is received. | ||
| 508 | * | ||
| 509 | * @param ok_to_send_nak If set to 0, suppress sending of a NAK packet | ||
| 510 | */ | ||
| 511 | void r2Complete(I32 ok_to_send_nak); | ||
| 512 | |||
| 513 | // ---------------------------------------------------------------------- | ||
| 514 | // Dispatch Methods (ported from cf_cfdp_dispatch.c) | ||
| 515 | // ---------------------------------------------------------------------- | ||
| 516 | |||
| 517 | /************************************************************************/ | ||
| 518 | /** @brief Dispatch function for received PDUs on receive-file transactions | ||
| 519 | * | ||
| 520 | * Receive file transactions primarily only react/respond to received PDUs. | ||
| 521 | * This function dispatches to the appropriate handler based on the | ||
| 522 | * transaction substate and PDU type. | ||
| 523 | * | ||
| 524 | * @param buffer Buffer containing the PDU to dispatch | ||
| 525 | * @param dispatch Dispatch table for file directive PDUs | ||
| 526 | * @param fd_fn Function to handle file data PDUs | ||
| 527 | */ | ||
| 528 | void rDispatchRecv(const Fw::Buffer& buffer, const RSubstateDispatchTable* dispatch, StateRecvFunc fd_fn); | ||
| 529 | |||
| 530 | /************************************************************************/ | ||
| 531 | /** @brief Dispatch function for received PDUs on send-file transactions | ||
| 532 | * | ||
| 533 | * Send file transactions also react/respond to received PDUs. | ||
| 534 | * Note that a file data PDU is not expected here. | ||
| 535 | * | ||
| 536 | * @param buffer Buffer containing the PDU to dispatch | ||
| 537 | * @param dispatch Dispatch table for file directive PDUs | ||
| 538 | */ | ||
| 539 | void sDispatchRecv(const Fw::Buffer& buffer, const SSubstateRecvDispatchTable* dispatch); | ||
| 540 | |||
| 541 | /************************************************************************/ | ||
| 542 | /** @brief Dispatch function to send/generate PDUs on send-file transactions | ||
| 543 | * | ||
| 544 | * Send file transactions generate PDUs each cycle based on the | ||
| 545 | * transaction state. This does not have an existing PDU buffer at | ||
| 546 | * the time of dispatch, but one may be generated by the invoked function. | ||
| 547 | * | ||
| 548 | * @param dispatch State-based dispatch table | ||
| 549 | */ | ||
| 550 | void sDispatchTransmit(const SSubstateSendDispatchTable* dispatch); | ||
| 551 | |||
| 552 | /************************************************************************/ | ||
| 553 | /** @brief Top-level Dispatch function to send a PDU based on current state | ||
| 554 | * | ||
| 555 | * This does not have an existing PDU buffer at the time of dispatch, | ||
| 556 | * but one may be generated by the invoked function. | ||
| 557 | * | ||
| 558 | * @param dispatch Transaction State-based Dispatch table | ||
| 559 | */ | ||
| 560 | void txStateDispatch(const TxnSendDispatchTable* dispatch); | ||
| 561 | |||
| 562 | private: | ||
| 563 | /************************************************************************/ | ||
| 564 | /** @brief Process a filedata PDU on a transaction. | ||
| 565 | * | ||
| 566 | * @retval Cfdp::Status::SUCCESS on success. Cfdp::Status::CFDP_ERROR on error. | ||
| 567 | * | ||
| 568 | * @param pdu Buffer containing the file data PDU to process | ||
| 569 | */ | ||
| 570 | Status::T rProcessFd(const Fw::Buffer& pdu); | ||
| 571 | |||
| 572 | /************************************************************************/ | ||
| 573 | /** @brief Processing receive EOF common functionality for R1/R2. | ||
| 574 | * | ||
| 575 | * This function is used for both R1 and R2 EOF receive. It calls | ||
| 576 | * the unmarshaling function and then checks known transaction | ||
| 577 | * data against the PDU. | ||
| 578 | * | ||
| 579 | * @retval Cfdp::Status::SUCCESS on success. Returns anything else on error. | ||
| 580 | * | ||
| 581 | * @param pdu Buffer containing the EOF PDU to process | ||
| 582 | */ | ||
| 583 | Status::T rSubstateRecvEof(const Fw::Buffer& pdu); | ||
| 584 | |||
| 585 | /************************************************************************/ | ||
| 586 | /** @brief Process receive EOF for R1. | ||
| 587 | * | ||
| 588 | * Only need to confirm CRC for R1. | ||
| 589 | * | ||
| 590 | * @param pdu Buffer containing the EOF PDU to process | ||
| 591 | */ | ||
| 592 | void r1SubstateRecvEof(const Fw::Buffer& pdu); | ||
| 593 | |||
| 594 | /************************************************************************/ | ||
| 595 | /** @brief Process receive EOF for R2. | ||
| 596 | * | ||
| 597 | * For R2, need to trigger the send of EOF-ACK and then call the | ||
| 598 | * check complete function which will either send NAK or FIN. | ||
| 599 | * | ||
| 600 | * @param pdu Buffer containing the EOF PDU to process | ||
| 601 | */ | ||
| 602 | void r2SubstateRecvEof(const Fw::Buffer& pdu); | ||
| 603 | |||
| 604 | /************************************************************************/ | ||
| 605 | /** @brief Process received file data for R1. | ||
| 606 | * | ||
| 607 | * For R1, only need to digest the CRC. | ||
| 608 | * | ||
| 609 | * @param pdu Buffer containing the file data PDU to process | ||
| 610 | */ | ||
| 611 | void r1SubstateRecvFileData(const Fw::Buffer& pdu); | ||
| 612 | |||
| 613 | /************************************************************************/ | ||
| 614 | /** @brief Process received file data for R2. | ||
| 615 | * | ||
| 616 | * For R2, the CRC is checked after the whole file is received | ||
| 617 | * since there may be gaps. Instead, insert file received range | ||
| 618 | * data into chunks. Once NAK has been received, this function | ||
| 619 | * always checks for completion. This function also re-arms | ||
| 620 | * the ACK timer. | ||
| 621 | * | ||
| 622 | * @param pdu Buffer containing the file data PDU to process | ||
| 623 | */ | ||
| 624 | void r2SubstateRecvFileData(const Fw::Buffer& pdu); | ||
| 625 | |||
| 626 | /************************************************************************/ | ||
| 627 | /** @brief Loads a single NAK segment request. | ||
| 628 | * | ||
| 629 | * This is a callback function used with CfdpChunkList::computeGaps(). | ||
| 630 | * For each gap found, this function adds a segment request to the NAK PDU. | ||
| 631 | * | ||
| 632 | * @param chunk Pointer to the gap chunk information | ||
| 633 | * @param nak Pointer to the NAK PDU being constructed | ||
| 634 | */ | ||
| 635 | void r2GapCompute(const Chunk* chunk, NakPdu& nak); | ||
| 636 | |||
| 637 | /** | ||
| 638 | * @brief Static wrapper for r2GapCompute callback | ||
| 639 | * @param chunk Gap chunk | ||
| 640 | * @param opaque Pointer to GapComputeContext struct | ||
| 641 | */ | ||
| 642 | static void r2GapComputeWrapper(const Chunk* chunk, void* opaque); | ||
| 643 | |||
| 644 | /************************************************************************/ | ||
| 645 | /** @brief Send a NAK PDU for R2. | ||
| 646 | * | ||
| 647 | * NAK PDU is sent when there are gaps in the received data. The | ||
| 648 | * chunks class tracks this and generates the NAK PDU by calculating | ||
| 649 | * gaps internally and calling r2GapCompute(). There is a special | ||
| 650 | * case where if a metadata PDU has not been received, then a NAK | ||
| 651 | * packet will be sent to request another. | ||
| 652 | * | ||
| 653 | * @retval Cfdp::Status::SUCCESS on success. Cfdp::Status::CFDP_ERROR on error. | ||
| 654 | */ | ||
| 655 | Status::T rSubstateSendNak(); | ||
| 656 | |||
| 657 | /************************************************************************/ | ||
| 658 | /** @brief Calculate up to the configured amount of bytes of CRC. | ||
| 659 | * | ||
| 660 | * The RxCrcCalcBytesPerCycle parameter specifies the number of bytes | ||
| 661 | * to calculate per transaction per scheduler cycle. At each cycle, the file is | ||
| 662 | * read and this number of bytes are calculated. This function will set | ||
| 663 | * the checksum error condition code if the final CRC does not match. | ||
| 664 | * | ||
| 665 | * @par PTFO | ||
| 666 | * Increase throughput by consuming all CRC bytes per scheduler cycle in | ||
| 667 | * transaction-order. This would require a change to the meaning | ||
| 668 | * of the RxCrcCalcBytesPerCycle parameter. | ||
| 669 | * | ||
| 670 | * @retval Cfdp::Status::SUCCESS on completion. | ||
| 671 | * @retval Cfdp::Status::CFDP_ERROR on non-completion. | ||
| 672 | */ | ||
| 673 | Status::T r2CalcCrcChunk(); | ||
| 674 | |||
| 675 | /************************************************************************/ | ||
| 676 | /** @brief Send a FIN PDU. | ||
| 677 | * | ||
| 678 | * @retval Cfdp::Status::SUCCESS on success. Cfdp::Status::CFDP_ERROR on error. | ||
| 679 | */ | ||
| 680 | Status::T r2SubstateSendFin(); | ||
| 681 | |||
| 682 | /************************************************************************/ | ||
| 683 | /** @brief Process receive FIN-ACK PDU. | ||
| 684 | * | ||
| 685 | * This is the end of an R2 transaction. Simply reset the transaction | ||
| 686 | * state. | ||
| 687 | * | ||
| 688 | * @param pdu Buffer containing the ACK PDU to process | ||
| 689 | */ | ||
| 690 | void r2RecvFinAck(const Fw::Buffer& pdu); | ||
| 691 | |||
| 692 | /************************************************************************/ | ||
| 693 | /** @brief Process receive metadata PDU for R2. | ||
| 694 | * | ||
| 695 | * It's possible that metadata PDU was missed in cf_cfdp.c, or that | ||
| 696 | * it was re-sent. This function checks if it was already processed, | ||
| 697 | * and if not, handles it. If there was a temp file opened due to | ||
| 698 | * missed metadata PDU, it will move the file to the correct | ||
| 699 | * destination according to the metadata PDU. | ||
| 700 | * | ||
| 701 | * @param pdu Buffer containing the metadata PDU to process | ||
| 702 | */ | ||
| 703 | void r2RecvMd(const Fw::Buffer& pdu); | ||
| 704 | |||
| 705 | /************************************************************************/ | ||
| 706 | /** @brief Logs an inactivity timer expired event. | ||
| 707 | */ | ||
| 708 | void rSendInactivityEvent(); | ||
| 709 | |||
| 710 | private: | ||
| 711 | // ---------------------------------------------------------------------- | ||
| 712 | // Member Variables | ||
| 713 | // ---------------------------------------------------------------------- | ||
| 714 | |||
| 715 | /** | ||
| 716 | * @brief High-level transaction state | ||
| 717 | * | ||
| 718 | * Each engine is commanded to do something, which is the overall state. | ||
| 719 | */ | ||
| 720 | TxnState m_state; | ||
| 721 | |||
| 722 | /** | ||
| 723 | * @brief Transaction class (CLASS_1 or CLASS_2) | ||
| 724 | * | ||
| 725 | * Set at initialization and never changes. | ||
| 726 | */ | ||
| 727 | Class::T m_txn_class; | ||
| 728 | |||
| 729 | /** | ||
| 730 | * @brief Pointer to history entry | ||
| 731 | * | ||
| 732 | * Holds active filenames and possibly other info. | ||
| 733 | */ | ||
| 734 | History* m_history; | ||
| 735 | |||
| 736 | /** | ||
| 737 | * @brief Pointer to chunk wrapper | ||
| 738 | * | ||
| 739 | * For gap tracking, only used on class 2. | ||
| 740 | */ | ||
| 741 | CfdpChunkWrapper* m_chunks; | ||
| 742 | |||
| 743 | /** | ||
| 744 | * @brief Inactivity timer | ||
| 745 | * | ||
| 746 | * Set to the overall inactivity timer of a remote. | ||
| 747 | */ | ||
| 748 | Timer m_inactivity_timer; | ||
| 749 | |||
| 750 | /** | ||
| 751 | * @brief ACK/NAK timer | ||
| 752 | * | ||
| 753 | * Called ack_timer, but is also nak_timer. | ||
| 754 | */ | ||
| 755 | Timer m_ack_timer; | ||
| 756 | |||
| 757 | /** | ||
| 758 | * @brief File size | ||
| 759 | */ | ||
| 760 | FileSize m_fsize; | ||
| 761 | |||
| 762 | /** | ||
| 763 | * @brief File offset for next read | ||
| 764 | */ | ||
| 765 | FileSize m_foffs; | ||
| 766 | |||
| 767 | /** | ||
| 768 | * @brief File descriptor | ||
| 769 | */ | ||
| 770 | Os::File m_fd; | ||
| 771 | |||
| 772 | /** | ||
| 773 | * @brief CRC checksum object | ||
| 774 | */ | ||
| 775 | CFDP::Checksum m_crc; | ||
| 776 | |||
| 777 | /** | ||
| 778 | * @brief Keep file flag | ||
| 779 | */ | ||
| 780 | Keep::T m_keep; | ||
| 781 | |||
| 782 | /** | ||
| 783 | * @brief Channel number | ||
| 784 | * | ||
| 785 | * If ever more than one engine, this may need to change to pointer. | ||
| 786 | */ | ||
| 787 | U8 m_chan_num; | ||
| 788 | |||
| 789 | /** | ||
| 790 | * @brief Priority | ||
| 791 | */ | ||
| 792 | U8 m_priority; | ||
| 793 | |||
| 794 | /** | ||
| 795 | * @brief Transaction initiation method | ||
| 796 | * | ||
| 797 | * Indicates whether this transaction was initiated via command or port. | ||
| 798 | * Used to determine whether completion should be notified via FileComplete port. | ||
| 799 | */ | ||
| 800 | TransactionInitType m_initType; | ||
| 801 | |||
| 802 | /** | ||
| 803 | * @brief Circular list node | ||
| 804 | * | ||
| 805 | * For connection to a CList (intrusive linked list). | ||
| 806 | */ | ||
| 807 | CListNode m_cl_node; | ||
| 808 | |||
| 809 | /** | ||
| 810 | * @brief Pointer to playback entry | ||
| 811 | * | ||
| 812 | * nullptr if transaction does not belong to a playback. | ||
| 813 | */ | ||
| 814 | Playback* m_pb; | ||
| 815 | |||
| 816 | /** | ||
| 817 | * @brief State-specific data (TX or RX) | ||
| 818 | */ | ||
| 819 | CfdpStateData m_state_data; | ||
| 820 | |||
| 821 | /** | ||
| 822 | * @brief State flags (TX or RX) | ||
| 823 | * | ||
| 824 | * Note: The flags here look a little strange, because there are different | ||
| 825 | * flags for TX and RX. Both types share the same type of flag, though. | ||
| 826 | * Since RX flags plus the global flags is over one byte, storing them this | ||
| 827 | * way allows 2 bytes to cover all possible flags. Please ignore the | ||
| 828 | * duplicate declarations of the "all" flags. | ||
| 829 | */ | ||
| 830 | CfdpStateFlags m_flags; | ||
| 831 | |||
| 832 | /** | ||
| 833 | * @brief Reference to the wrapper F' component | ||
| 834 | * | ||
| 835 | * Used to send PDUs. | ||
| 836 | */ | ||
| 837 | CfdpManager* m_cfdpManager; | ||
| 838 | |||
| 839 | /** | ||
| 840 | * @brief Pointer to the channel wrapper | ||
| 841 | * | ||
| 842 | * The channel this transaction belongs to. | ||
| 843 | */ | ||
| 844 | Channel* m_chan; | ||
| 845 | |||
| 846 | /** | ||
| 847 | * @brief Pointer to the CFDP engine | ||
| 848 | * | ||
| 849 | * The engine this transaction belongs to. | ||
| 850 | */ | ||
| 851 | Engine* m_engine; | ||
| 852 | }; | ||
| 853 | |||
| 854 | } // namespace Cfdp | ||
| 855 | } // namespace Ccsds | ||
| 856 | } // namespace Svc | ||
| 857 | |||
| 858 | #endif // Svc_Ccsds_CfdpTransaction_HPP | ||
| 859 |