fsfw-example-hosted/bsp_hosted/core/CfdpHandler.cpp

147 lines
6.2 KiB
C++
Raw Normal View History

2022-09-07 18:21:16 +02:00
#include "CfdpHandler.h"
2022-09-08 11:26:29 +02:00
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
2022-09-08 12:09:24 +02:00
#include "fsfw/cfdp/pdu/AckPduReader.h"
2022-09-07 18:21:16 +02:00
#include "fsfw/ipc/QueueFactory.h"
2022-09-08 11:26:29 +02:00
#include "fsfw/tmtcservices/TmTcMessage.h"
2022-09-07 18:21:16 +02:00
using namespace returnvalue;
2022-09-07 18:38:25 +02:00
using namespace cfdp;
2022-09-08 11:26:29 +02:00
CfdpHandler::CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg)
: SystemObject(fsfwParams.objectId),
UserBase(fsfwParams.vfs),
destHandler(DestHandlerParams(cfdpCfg.cfg, *this, *this, cfdpCfg.packetInfoList,
cfdpCfg.lostSegmentsList),
FsfwParams(fsfwParams.packetDest, nullptr, this, fsfwParams.tcStore,
fsfwParams.tmStore)) {
2022-09-07 18:40:10 +02:00
// TODO: Make queue params configurable, or better yet, expect it to be passed externally
2022-09-07 18:21:16 +02:00
msgQueue = QueueFactory::instance()->createMessageQueue();
destHandler.setMsgQueue(*msgQueue);
}
[[nodiscard]] const char* CfdpHandler::getName() const { return "CFDP Handler"; }
2022-09-07 18:38:25 +02:00
[[nodiscard]] uint32_t CfdpHandler::getIdentifier() const {
2022-09-08 11:26:29 +02:00
return destHandler.getDestHandlerParams().cfg.localId.getValue();
2022-09-07 18:21:16 +02:00
}
2022-09-07 18:38:25 +02:00
[[nodiscard]] MessageQueueId_t CfdpHandler::getRequestQueue() const { return msgQueue->getId(); }
2022-09-07 18:21:16 +02:00
ReturnValue_t CfdpHandler::initialize() {
ReturnValue_t result = destHandler.initialize();
if (result != OK) {
return result;
}
2022-09-08 11:26:29 +02:00
tcStore = destHandler.getTcStore();
tmStore = destHandler.getTmStore();
2022-09-07 18:21:16 +02:00
return SystemObject::initialize();
}
2022-09-07 18:38:25 +02:00
ReturnValue_t CfdpHandler::performOperation(uint8_t operationCode) {
// TODO: Receive TC packets and route them to source and dest handler, depending on which is
// correct or more appropriate
2022-09-08 11:26:29 +02:00
ReturnValue_t status;
ReturnValue_t result = OK;
TmTcMessage tmtcMsg;
for (status = msgQueue->receiveMessage(&tmtcMsg); status == returnvalue::OK;
status = msgQueue->receiveMessage(&tmtcMsg)) {
result = handleCfdpPacket(tmtcMsg);
if (result != OK) {
status = result;
}
}
2022-09-08 11:53:18 +02:00
auto& fsmRes = destHandler.performStateMachine();
// TODO: Error handling?
while(fsmRes.callStatus == CallStatus::CALL_AGAIN) {
destHandler.performStateMachine();
// TODO: Error handling?
}
2022-09-08 11:26:29 +02:00
return status;
2022-09-07 18:38:25 +02:00
}
void CfdpHandler::transactionIndication(const cfdp::TransactionId& id) {}
void CfdpHandler::eofSentIndication(const cfdp::TransactionId& id) {}
void CfdpHandler::transactionFinishedIndication(const cfdp::TransactionFinishedParams& params) {}
void CfdpHandler::metadataRecvdIndication(const cfdp::MetadataRecvdParams& params) {}
void CfdpHandler::fileSegmentRecvdIndication(const cfdp::FileSegmentRecvdParams& params) {}
void CfdpHandler::reportIndication(const cfdp::TransactionId& id, cfdp::StatusReportIF& report) {}
void CfdpHandler::suspendedIndication(const cfdp::TransactionId& id, cfdp::ConditionCode code) {}
void CfdpHandler::resumedIndication(const cfdp::TransactionId& id, size_t progress) {}
void CfdpHandler::faultIndication(const cfdp::TransactionId& id, cfdp::ConditionCode code,
size_t progress) {}
void CfdpHandler::abandonedIndication(const cfdp::TransactionId& id, cfdp::ConditionCode code,
size_t progress) {}
void CfdpHandler::eofRecvIndication(const cfdp::TransactionId& id) {}
bool CfdpHandler::getRemoteCfg(const cfdp::EntityId& remoteId, cfdp::RemoteEntityCfg** cfg) {
return false;
}
2022-09-08 11:26:29 +02:00
ReturnValue_t CfdpHandler::handleCfdpPacket(TmTcMessage& msg) {
auto accessorPair = tcStore->getData(msg.getStorageId());
PduHeaderReader reader(accessorPair.second.data(), accessorPair.second.size());
ReturnValue_t result = reader.parseData();
if (result != returnvalue::OK) {
2022-09-08 11:53:18 +02:00
return INVALID_PDU_FORMAT;
2022-09-08 11:26:29 +02:00
}
// The CFDP distributor should have taken care of ensuring the destination ID is correct
PduTypes type = reader.getPduType();
// Only the destination handler can process these PDUs
if (type == PduTypes::FILE_DATA) {
2022-09-08 11:53:18 +02:00
// Disable auto-deletion of packet
accessorPair.second.release();
PacketInfo info(type, msg.getStorageId());
result = destHandler.passPacket(info);
2022-09-08 11:26:29 +02:00
} else {
// Route depending on directive type. Retrieve directive type from raw stream for better
2022-09-08 11:53:18 +02:00
// performance (with sanity and directive code check). The routing is based on section 4.5 of
// the CFDP standard which specifies the PDU forwarding procedure.
// PDU header only. Invalid supplied data. A directive packet should have a valid data field
// with at least one byte being the directive code
const uint8_t* pduDataField = reader.getPduDataField();
if(pduDataField == nullptr) {
return INVALID_PDU_FORMAT;
}
if (not FileDirectiveReader::checkFileDirective(pduDataField[0])) {
return INVALID_DIRECTIVE_FIELD;
}
auto directive = static_cast<FileDirectives>(pduDataField[0]);
2022-09-08 12:09:24 +02:00
auto passToDestHandler = [&]() {
2022-09-08 11:53:18 +02:00
accessorPair.second.release();
PacketInfo info(type, msg.getStorageId(), directive);
result = destHandler.passPacket(info);
2022-09-08 12:09:24 +02:00
};
auto passToSourceHandler = [&]() {
2022-09-08 11:53:18 +02:00
2022-09-08 12:09:24 +02:00
};
if(directive == FileDirectives::METADATA or directive == FileDirectives::EOF_DIRECTIVE or
directive == FileDirectives::PROMPT) {
// Section b) of 4.5.3: These PDUs should always be targeted towards the file receiver a.k.a.
// the destination handler
passToDestHandler();
2022-09-08 11:53:18 +02:00
} else if(directive == FileDirectives::FINISH or directive == FileDirectives::NAK or directive == FileDirectives::KEEP_ALIVE) {
// Section c) of 4.5.3: These PDUs should always be targeted towards the file sender a.k.a.
// the source handler
2022-09-08 12:09:24 +02:00
passToSourceHandler();
2022-09-08 11:53:18 +02:00
} else if(directive == FileDirectives::ACK) {
2022-09-08 12:09:24 +02:00
// Section a): Recipient depends of the type of PDU that is being acknowledged. We can simply
// extract the PDU type from the raw stream. If it is an EOF PDU, this packet is passed to
// the source handler, for a Finished PDU, it is passed to the destination handler.
FileDirectives ackedDirective;
if (not AckPduReader::checkAckedDirectiveField(pduDataField[1], ackedDirective)) {
// TODO: appropriate error
}
if(ackedDirective == FileDirectives::EOF_DIRECTIVE) {
passToSourceHandler();
} else if(ackedDirective == FileDirectives::FINISH) {
passToDestHandler();
}
2022-09-08 11:53:18 +02:00
}
2022-09-08 11:26:29 +02:00
}
2022-09-08 11:53:18 +02:00
return result;
2022-09-08 11:26:29 +02:00
}