#include "SourceHandler.h" #include #include #include "fsfw/cfdp/pdu/FileDataCreator.h" #include "fsfw/cfdp/pdu/MetadataPduCreator.h" #include "fsfw/filesystem/HasFileSystemIF.h" #include "fsfw/objectmanager.h" #include "fsfw/tmtcservices/TmTcMessage.h" using namespace returnvalue; cfdp::SourceHandler::SourceHandler(SourceHandlerParams params, FsfwParams fsfwParams) : sourceParams(std::move(params)), fsfwParams(fsfwParams) {} cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::fsmNacked() { ReturnValue_t result; if (step == TransactionStep::IDLE) { step = TransactionStep::TRANSACTION_START; } if (step == TransactionStep::TRANSACTION_START) { step = TransactionStep::CRC_PROCEDURE; } if (step == TransactionStep::CRC_PROCEDURE) { result = checksumGeneration(); if (result != OK) { // TODO: Some error handling } step = TransactionStep::SENDING_METADATA; } if (step == TransactionStep::SENDING_METADATA) { result = prepareAndSendMetadataPdu(); if (result != OK) { // TODO: Error handling } return fsmResult; } if (step == TransactionStep::SENDING_FILE_DATA) { result = prepareAndSendNextFileDataPdu(); if (result != OK) { // TODO: Error handling } return fsmResult; } if (step == TransactionStep::SENDING_EOF) { result = prepareAndSendEofPdu(); if (result != OK) { // TODO: Error handling } return fsmResult; } if (step == TransactionStep::WAIT_FOR_FINISH) { // TODO: In case this is a request with closure, wait for finish. // Done, issue notice of completion step = TransactionStep::NOTICE_OF_COMPLETION; } if (step == TransactionStep::NOTICE_OF_COMPLETION) { // TODO: Notice of completion // We are done, go back to idle state. // TODO: Possible reset state? step = TransactionStep::IDLE; state = CfdpState::IDLE; } return fsmResult; } cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::stateMachine() { if (state == cfdp::CfdpState::IDLE) { return fsmResult; } if (state == cfdp::CfdpState::BUSY_CLASS_1_NACKED) { return fsmNacked(); } return fsmResult; } ReturnValue_t cfdp::SourceHandler::checksumGeneration() { std::array buf{}; etl::crc32 crcCalc; uint64_t currentOffset = 0; FileOpParams params(transactionParams.destName.data(), transactionParams.fileSize.value()); while (currentOffset < transactionParams.fileSize.value()) { uint64_t readLen; if (currentOffset + buf.size() > transactionParams.fileSize.value()) { readLen = transactionParams.fileSize.value() - currentOffset; } else { readLen = buf.size(); } if (readLen > 0) { params.offset = currentOffset; params.size = readLen; auto result = sourceParams.user.vfs.readFromFile(params, buf.data(), buf.size()); if (result != OK) { // TODO: I think this is a case for a filestore rejection, but it might sense to print // a warning or trigger an event because this should generally not happen return FAILED; } crcCalc.add(buf.begin(), buf.begin() + readLen); } currentOffset += readLen; } transactionParams.crc = crcCalc.value(); return OK; } ReturnValue_t cfdp::SourceHandler::putRequest(PutRequestFull& putRequest, RemoteEntityCfg& cfg) { if (state != CfdpState::IDLE) { return SOURCE_TRANSACTION_PENDING; } if (putRequest.sourceNameSize > transactionParams.sourceName.size()) { return FAILED; } if (putRequest.destNameSize > transactionParams.destName.size()) { return FAILED; } std::memcpy(transactionParams.destName.data(), putRequest.destName, putRequest.destNameSize); std::memcpy(transactionParams.sourceName.data(), putRequest.sourceName, putRequest.sourceNameSize); transactionParams.sourceNameSize = putRequest.sourceNameSize; transactionParams.destNameSize = putRequest.destNameSize; FilesystemParams params(transactionParams.sourceName.data()); if (!sourceParams.user.vfs.fileExists(params)) { return FILE_DOES_NOT_EXIST; } transactionParams.closureRequested = putRequest.closureRequested; transactionParams.pduConf.mode = putRequest.transmissionMode; transactionParams.pduConf.destId = putRequest.destId; // Only used for PDU forwarding, file is sent to file receiver regularly here. transactionParams.pduConf.direction = Direction::TOWARDS_RECEIVER; transactionParams.pduConf.sourceId = sourceParams.cfg.localId; if (transactionParams.pduConf.mode == TransmissionMode::ACKNOWLEDGED) { state = cfdp::CfdpState::BUSY_CLASS_2_ACKED; } else if (transactionParams.pduConf.mode == TransmissionMode::UNACKNOWLEDGED) { state = cfdp::CfdpState::BUSY_CLASS_1_NACKED; } step = TransactionStep::IDLE; size_t fileSize = 0; sourceParams.user.vfs.getFileSize(params, fileSize); transactionParams.pduConf.largeFile = false; if (fileSize > UINT32_MAX) { transactionParams.pduConf.largeFile = true; } transactionParams.fileSize.setFileSize(fileSize, transactionParams.pduConf.largeFile); currentRemoteCfg = cfg; return OK; } ReturnValue_t cfdp::SourceHandler::prepareAndSendMetadataPdu() { cfdp::StringLv sourceName(transactionParams.sourceName.data(), transactionParams.sourceNameSize); cfdp::StringLv destName(transactionParams.sourceName.data(), transactionParams.sourceNameSize); auto metadataInfo = MetadataInfo(transactionParams.fileSize, sourceName, destName); auto metadataPdu = MetadataPduCreator(transactionParams.pduConf, metadataInfo); uint8_t* dataPtr; store_address_t storeId; ReturnValue_t result = fsfwParams.tcStore->getFreeElement(&storeId, metadataPdu.getSerializedSize(), &dataPtr); if (result != OK) { // TODO: Better error handling? return result; } size_t serializedLen = 0; result = metadataPdu.serializeBe(dataPtr, serializedLen, metadataPdu.getSerializedSize()); if (result != OK) { return result; } TmTcMessage tcMsg(storeId); result = fsfwParams.msgQueue->sendMessage(fsfwParams.packetDest.getReportReceptionQueue(), &tcMsg); if (result != OK) { return result; } // Advance FSM if everything works step = TransactionStep::SENDING_FILE_DATA; return OK; } ReturnValue_t cfdp::SourceHandler::prepareAndSendNextFileDataPdu() { // TODO: Implement // auto fileDataInfo = FileDataInfo(transactionParams.fileSize); // auto fileDataPdu = FileDataCreator(); // Advance FSM after all file data PDUs were sent step = TransactionStep::SENDING_EOF; return OK; } ReturnValue_t cfdp::SourceHandler::prepareAndSendEofPdu() { // TODO: Implement step = TransactionStep::WAIT_FOR_FINISH; return OK; } ReturnValue_t cfdp::SourceHandler::initialize() { if (fsfwParams.tmStore == nullptr) { fsfwParams.tmStore = ObjectManager::instance()->get(objects::TM_STORE); if (fsfwParams.tmStore == nullptr) { return FAILED; } } if (fsfwParams.tcStore == nullptr) { fsfwParams.tcStore = ObjectManager::instance()->get(objects::TC_STORE); if (fsfwParams.tcStore == nullptr) { return FAILED; } } if (fsfwParams.msgQueue == nullptr) { return FAILED; } return OK; }