// CfdpClass2Sender.hpp #ifndef CFDP_CLASS2_SENDER_HPP #define CFDP_CLASS2_SENDER_HPP #include #include #include #include namespace Svc { class CfdpClass2Sender { public: // Core components required by CFDP Class 2 spec enum class PduType { FILE_DIRECTIVE, FILE_DATA }; enum class DirectiveCode { EOF_PDU = 0x04, FINISHED_PDU = 0x05, ACK_PDU = 0x06, METADATA_PDU = 0x07, NAK_PDU = 0x08, PROMPT_PDU = 0x09, KEEPALIVE_PDU = 0x0C }; // Constructor sets up initial state for transaction CfdpClass2Sender(); // Primary interface for starting file transfer void initiateTransaction(const Fw::String& sourceFileName, const Fw::String& destFileName, U32 destinationId); // Processes incoming PDUs for acknowledgments void processIncomingPdu(const Fw::SerialBuffer& pduData); // Handles retransmission based on NAKs void handleNak(const Fw::SerialBuffer& nakPdu); // Periodic processing of timers and retransmission logic void doDispatch(); private: // Internal helper methods void transmitFileData(); void sendEofPdu(); void sendMetadataPdu(); void processAckPdu(const Fw::SerialBuffer& ackPdu); // Transaction state struct TransactionState { Fw::String sourceFileName; Fw::String destFileName; U32 destinationId; U32 sequenceNum; U32 fileSize; U32 offset; bool eofSent; bool transactionComplete; Utils::Hash checksum; }; TransactionState m_state; // Retransmission buffer for reliability struct RetransmitBufferEntry { Fw::SerialBuffer pduData; U32 retryCount; U32 lastTransmitTime; }; std::unordered_map m_retransmitBuffer; }; } // namespace Svc #endif // CfdpClass2Sender.cpp #include "CfdpClass2Sender.hpp" namespace Svc { CfdpClass2Sender::CfdpClass2Sender() { // Initialize transaction state m_state.sequenceNum = 0; m_state.offset = 0; m_state.eofSent = false; m_state.transactionComplete = false; } void CfdpClass2Sender::initiateTransaction(const Fw::String& sourceFileName, const Fw::String& destFileName, U32 destinationId) { // Set up new transaction m_state.sourceFileName = sourceFileName; m_state.destFileName = destFileName; m_state.destinationId = destinationId; m_state.sequenceNum++; m_state.offset = 0; m_state.eofSent = false; m_state.transactionComplete = false; // Start by sending metadata PDU sendMetadataPdu(); // Begin file transmission transmitFileData(); } void CfdpClass2Sender::processIncomingPdu(const Fw::SerialBuffer& pduData) { // Extract PDU type and directive code U8 pduType; pduData.deserialize(pduType); if (pduType == static_cast(PduType::FILE_DIRECTIVE)) { U8 directiveCode; pduData.deserialize(directiveCode); switch(static_cast(directiveCode)) { case DirectiveCode::ACK_PDU: processAckPdu(pduData); break; case DirectiveCode::NAK_PDU: handleNak(pduData); break; default: // Log unexpected directive break; } } } void CfdpClass2Sender::handleNak(const Fw::SerialBuffer& nakPdu) { // Extract NAK info - sequence/offset ranges needing retransmission U32 startOffset, endOffset; nakPdu.deserialize(startOffset); nakPdu.deserialize(endOffset); // Look up PDUs in retransmission buffer and resend for (const auto& entry : m_retransmitBuffer) { if (entry.first >= startOffset && entry.first <= endOffset) { // Retransmit this PDU // Implementation would send using F' port } } } void CfdpClass2Sender::doDispatch() { // Check for PDUs needing retransmission U32 currentTime = 0; // Would get from F' time for (auto& entry : m_retransmitBuffer) { if ((currentTime - entry.second.lastTransmitTime) > RETRANSMIT_TIMEOUT) { if (entry.second.retryCount < MAX_RETRIES) { // Retransmit PDU entry.second.retryCount++; entry.second.lastTransmitTime = currentTime; } else { // Max retries exceeded - handle error } } } } void CfdpClass2Sender::sendMetadataPdu() { // Build Metadata PDU with file info // Implementation would serialize PDU and send using F' port } void CfdpClass2Sender::transmitFileData() { // Read and transmit file data in chunks // Implementation would: // 1. Read file chunk // 2. Build File Data PDU // 3. Add to retransmit buffer // 4. Send using F' port } void CfdpClass2Sender::sendEofPdu() { // Build EOF PDU with checksum // Implementation would: // 1. Finalize checksum // 2. Build EOF PDU // 3. Add to retransmit buffer // 4. Send using F' port } void CfdpClass2Sender::processAckPdu(const Fw::SerialBuffer& ackPdu) { // Handle ACKs by removing PDUs from retransmit buffer U32 ackSequence; ackPdu.deserialize(ackSequence); m_retransmitBuffer.erase(ackSequence); if (m_state.eofSent && m_retransmitBuffer.empty()) { m_state.transactionComplete = true; } } } // namespace Svc