| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // ====================================================================== | ||
| 2 | // \title Utils.cpp | ||
| 3 | // \brief CFDP utility functions | ||
| 4 | // | ||
| 5 | // This file is a port of the cf_utils.c file from the | ||
| 6 | // NASA Core Flight System (cFS) CFDP (CF) Application, | ||
| 7 | // version 3.0.0, adapted for use within the F-Prime (F') framework. | ||
| 8 | // | ||
| 9 | // The CFDP general utility functions source file | ||
| 10 | // | ||
| 11 | // Various odds and ends are put here. | ||
| 12 | // | ||
| 13 | // ====================================================================== | ||
| 14 | // | ||
| 15 | // NASA Docket No. GSC-18,447-1 | ||
| 16 | // | ||
| 17 | // Copyright (c) 2019 United States Government as represented by the | ||
| 18 | // Administrator of the National Aeronautics and Space Administration. | ||
| 19 | // All Rights Reserved. | ||
| 20 | // | ||
| 21 | // Licensed under the Apache License, Version 2.0 (the "License"); you may | ||
| 22 | // not use this file except in compliance with the License. You may obtain | ||
| 23 | // a copy of the License at | ||
| 24 | // | ||
| 25 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
| 26 | // | ||
| 27 | // Unless required by applicable law or agreed to in writing, software | ||
| 28 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
| 29 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 30 | // See the License for the specific language governing permissions and | ||
| 31 | // limitations under the License. | ||
| 32 | // | ||
| 33 | // ====================================================================== | ||
| 34 | |||
| 35 | #include <Svc/Ccsds/CfdpManager/Clist.hpp> | ||
| 36 | #include <Svc/Ccsds/CfdpManager/Engine.hpp> | ||
| 37 | #include <Svc/Ccsds/CfdpManager/Utils.hpp> | ||
| 38 | |||
| 39 | namespace Svc { | ||
| 40 | namespace Ccsds { | ||
| 41 | namespace Cfdp { | ||
| 42 | |||
| 43 | ✗ | AckTxnStatus GetTxnStatus(Transaction* txn) { | |
| 44 | AckTxnStatus LocalStatus; | ||
| 45 | |||
| 46 | // check if this is still an active Tx (not in holdover or drop etc) | ||
| 47 | // in theory this should never be called on S1 because there is no fin-ack to send, | ||
| 48 | // but including it for completeness (because it is an active txn) | ||
| 49 | ✗ | if (txn == nullptr) { | |
| 50 | ✗ | LocalStatus = AckTxnStatus::ACK_TXN_STATUS_UNRECOGNIZED; | |
| 51 | } else | ||
| 52 | ✗ | switch (txn->getState()) { | |
| 53 | ✗ | case TxnState::TXN_STATE_S1: | |
| 54 | case TxnState::TXN_STATE_R1: | ||
| 55 | case TxnState::TXN_STATE_S2: | ||
| 56 | case TxnState::TXN_STATE_R2: | ||
| 57 | ✗ | LocalStatus = AckTxnStatus::ACK_TXN_STATUS_ACTIVE; | |
| 58 | ✗ | break; | |
| 59 | |||
| 60 | ✗ | case TxnState::TXN_STATE_DROP: | |
| 61 | case TxnState::TXN_STATE_HOLD: | ||
| 62 | ✗ | LocalStatus = AckTxnStatus::ACK_TXN_STATUS_TERMINATED; | |
| 63 | ✗ | break; | |
| 64 | |||
| 65 | ✗ | default: | |
| 66 | ✗ | LocalStatus = AckTxnStatus::ACK_TXN_STATUS_INVALID; | |
| 67 | ✗ | break; | |
| 68 | } | ||
| 69 | |||
| 70 | ✗ | return LocalStatus; | |
| 71 | } | ||
| 72 | |||
| 73 | // Static member function - can access private members | ||
| 74 | ✗ | CListTraverseStatus Transaction::findBySequenceNumberCallback(CListNode* node, void* context) { | |
| 75 | ✗ | Transaction* txn = container_of_cpp(node, &Transaction::m_cl_node); | |
| 76 | ✗ | CListTraverseStatus ret = CLIST_TRAVERSE_CONTINUE; | |
| 77 | ✗ | CfdpTraverseTransSeqArg* seqContext = static_cast<CfdpTraverseTransSeqArg*>(context); | |
| 78 | |||
| 79 | ✗ | if (txn->m_history && (txn->m_history->src_eid == seqContext->src_eid) && | |
| 80 | ✗ | (txn->m_history->seq_num == seqContext->transaction_sequence_number)) { | |
| 81 | ✗ | seqContext->txn = txn; | |
| 82 | ✗ | ret = CLIST_TRAVERSE_EXIT; // exit early | |
| 83 | } | ||
| 84 | |||
| 85 | ✗ | return ret; | |
| 86 | } | ||
| 87 | |||
| 88 | // Static member function - can access private members | ||
| 89 | ✗ | CListTraverseStatus Transaction::prioritySearchCallback(CListNode* node, void* context) { | |
| 90 | ✗ | Transaction* txn = container_of_cpp(node, &Transaction::m_cl_node); | |
| 91 | ✗ | CfdpTraversePriorityArg* arg = static_cast<CfdpTraversePriorityArg*>(context); | |
| 92 | |||
| 93 | ✗ | if (txn->m_priority <= arg->priority) { | |
| 94 | // found it! | ||
| 95 | // | ||
| 96 | // the current transaction's prio is less than desired (higher) | ||
| 97 | ✗ | arg->txn = txn; | |
| 98 | ✗ | return CLIST_TRAVERSE_EXIT; | |
| 99 | } | ||
| 100 | |||
| 101 | ✗ | return CLIST_TRAVERSE_CONTINUE; | |
| 102 | } | ||
| 103 | |||
| 104 | // Legacy wrappers for backward compatibility | ||
| 105 | ✗ | CListTraverseStatus FindTransactionBySequenceNumberImpl(CListNode* node, void* context) { | |
| 106 | ✗ | return Transaction::findBySequenceNumberCallback(node, context); | |
| 107 | } | ||
| 108 | |||
| 109 | ✗ | CListTraverseStatus PrioSearch(CListNode* node, void* context) { | |
| 110 | ✗ | return Transaction::prioritySearchCallback(node, context); | |
| 111 | } | ||
| 112 | |||
| 113 | ✗ | bool TxnStatusIsError(TxnStatus txn_stat) { | |
| 114 | // The value of TxnStatus::TXN_STATUS_UNDEFINED (-1) indicates a transaction is in progress and no error | ||
| 115 | // has occurred yet. This will be set to TxnStatus::TXN_STATUS_NO_ERROR (0) after successful completion | ||
| 116 | // of the transaction (FIN/EOF). Anything else indicates a problem has occurred. | ||
| 117 | ✗ | return (txn_stat > TxnStatus::TXN_STATUS_NO_ERROR); | |
| 118 | } | ||
| 119 | |||
| 120 | ✗ | ConditionCode TxnStatusToConditionCode(TxnStatus txn_stat) { | |
| 121 | ConditionCode result; | ||
| 122 | |||
| 123 | ✗ | if (!TxnStatusIsError(txn_stat)) { | |
| 124 | // If no status has been set (TxnStatus::TXN_STATUS_UNDEFINED), treat that as NO_ERROR for | ||
| 125 | // the purpose of CFDP CC. This can occur e.g. when sending ACK PDUs and no errors | ||
| 126 | // have happened yet, but the transaction is not yet complete and thus not final. | ||
| 127 | ✗ | result = ConditionCode::CONDITION_CODE_NO_ERROR; | |
| 128 | } else { | ||
| 129 | ✗ | switch (txn_stat) { | |
| 130 | // The definition of TxnStatus is such that the 4-bit codes (0-15) share the same | ||
| 131 | // numeric values as the CFDP condition codes, and can be put directly into the 4-bit | ||
| 132 | // CC field of a FIN/ACK/EOF PDU. Extended codes use the upper bits (>15) to differentiate | ||
| 133 | ✗ | case TxnStatus::TXN_STATUS_NO_ERROR: | |
| 134 | case TxnStatus::TXN_STATUS_POS_ACK_LIMIT_REACHED: | ||
| 135 | case TxnStatus::TXN_STATUS_KEEP_ALIVE_LIMIT_REACHED: | ||
| 136 | case TxnStatus::TXN_STATUS_INVALID_TRANSMISSION_MODE: | ||
| 137 | case TxnStatus::TXN_STATUS_FILESTORE_REJECTION: | ||
| 138 | case TxnStatus::TXN_STATUS_FILE_CHECKSUM_FAILURE: | ||
| 139 | case TxnStatus::TXN_STATUS_FILE_SIZE_ERROR: | ||
| 140 | case TxnStatus::TXN_STATUS_NAK_LIMIT_REACHED: | ||
| 141 | case TxnStatus::TXN_STATUS_INACTIVITY_DETECTED: | ||
| 142 | case TxnStatus::TXN_STATUS_INVALID_FILE_STRUCTURE: | ||
| 143 | case TxnStatus::TXN_STATUS_CHECK_LIMIT_REACHED: | ||
| 144 | case TxnStatus::TXN_STATUS_UNSUPPORTED_CHECKSUM_TYPE: | ||
| 145 | case TxnStatus::TXN_STATUS_SUSPEND_REQUEST_RECEIVED: | ||
| 146 | case TxnStatus::TXN_STATUS_CANCEL_REQUEST_RECEIVED: | ||
| 147 | ✗ | result = static_cast<ConditionCode>(txn_stat); | |
| 148 | ✗ | break; | |
| 149 | |||
| 150 | // Extended status codes below here --- | ||
| 151 | // There are no CFDP CCs to directly represent these status codes. Normally this should | ||
| 152 | // not happen as the engine should not be sending a CFDP CC (FIN/ACK/EOF PDU) for a | ||
| 153 | // transaction that is not in a valid CFDP-defined state. This should be translated | ||
| 154 | // to the closest CFDP CC per the intent/meaning of the transaction status code. | ||
| 155 | |||
| 156 | ✗ | case TxnStatus::TXN_STATUS_ACK_LIMIT_NO_FIN: | |
| 157 | case TxnStatus::TXN_STATUS_ACK_LIMIT_NO_EOF: | ||
| 158 | // this is similar to the inactivity timeout (no fin-ack) | ||
| 159 | ✗ | result = ConditionCode::CONDITION_CODE_INACTIVITY_DETECTED; | |
| 160 | ✗ | break; | |
| 161 | |||
| 162 | ✗ | default: | |
| 163 | // Catch-all: any invalid protocol state will cancel the transaction, and thus this | ||
| 164 | // is the closest CFDP CC in practice for all other unhandled errors. | ||
| 165 | ✗ | result = ConditionCode::CONDITION_CODE_CANCEL_REQUEST_RECEIVED; | |
| 166 | ✗ | break; | |
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | ✗ | return result; | |
| 171 | } | ||
| 172 | |||
| 173 | } // namespace Cfdp | ||
| 174 | } // namespace Ccsds | ||
| 175 | } // namespace Svc | ||
| 176 |