From 5907f8ee9d6b100bebf7cfcfd4808504e3703967 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 3 Dec 2021 15:37:49 +0100 Subject: [PATCH] Added CFDP packet stack This PR adds the packet stack for the CCSDS File Delivery Protocol. It also refactors the existing TMTC infastructure to allow sending of CFDP packets to the CCSDS handlers. This includes the whole PDU (Protocol Data Unit) stack: - File Data PDUs and all file directive PDUs - ACK PDU - NAK PDU - Metadata PDU - Finished PDU - Prompt PDU - Keep Alive PDU - EOF PDU The PR includes a full set of unittests for the packet stack with a coverage of 90+ %. The refactoring of the existing TMTC infastructure includes non-ideal solutions like diamond inheritance. Avoiding this solution would require refactoring the packet stack. This would be a good idea anyway because the existing stack is tightly coupled to the FSFW, making reuse more difficult if only the stack is planned to be used without the store functionalities etc. The PDU implementation provided here is only weakly coupled to the FSFW, only using components like returnvalues or the Serialization modules. There are dedicated serializers and deserializers, which also helps in creating small focused modules which are easy to test. Some of the modules here were provied by Matthias Tompert. --- CMakeLists.txt | 4 +- README.md | 2 +- .../fsfwconfig/devices/logicalAddresses.h | 2 +- src/fsfw/CMakeLists.txt | 1 + src/fsfw/FSFW.h.in | 4 + src/fsfw/cfdp/CFDPHandler.cpp | 60 ++ src/fsfw/cfdp/CFDPHandler.h | 62 ++ src/fsfw/cfdp/CFDPMessage.cpp | 21 + src/fsfw/cfdp/CFDPMessage.h | 23 + src/fsfw/cfdp/CMakeLists.txt | 7 + src/fsfw/cfdp/FileSize.h | 83 +++ src/fsfw/cfdp/definitions.h | 153 +++++ src/fsfw/cfdp/pdu/AckInfo.cpp | 52 ++ src/fsfw/cfdp/pdu/AckInfo.h | 33 + src/fsfw/cfdp/pdu/AckPduDeserializer.cpp | 38 ++ src/fsfw/cfdp/pdu/AckPduDeserializer.h | 26 + src/fsfw/cfdp/pdu/AckPduSerializer.cpp | 38 ++ src/fsfw/cfdp/pdu/AckPduSerializer.h | 30 + src/fsfw/cfdp/pdu/CMakeLists.txt | 32 + src/fsfw/cfdp/pdu/EofInfo.cpp | 58 ++ src/fsfw/cfdp/pdu/EofInfo.h | 33 + src/fsfw/cfdp/pdu/EofPduDeserializer.cpp | 68 ++ src/fsfw/cfdp/pdu/EofPduDeserializer.h | 18 + src/fsfw/cfdp/pdu/EofPduSerializer.cpp | 46 ++ src/fsfw/cfdp/pdu/EofPduSerializer.h | 22 + src/fsfw/cfdp/pdu/FileDataDeserializer.cpp | 52 ++ src/fsfw/cfdp/pdu/FileDataDeserializer.h | 22 + src/fsfw/cfdp/pdu/FileDataInfo.cpp | 104 +++ src/fsfw/cfdp/pdu/FileDataInfo.h | 45 ++ src/fsfw/cfdp/pdu/FileDataSerializer.cpp | 54 ++ src/fsfw/cfdp/pdu/FileDataSerializer.h | 23 + .../cfdp/pdu/FileDirectiveDeserializer.cpp | 55 ++ src/fsfw/cfdp/pdu/FileDirectiveDeserializer.h | 41 ++ src/fsfw/cfdp/pdu/FileDirectiveSerializer.cpp | 39 ++ src/fsfw/cfdp/pdu/FileDirectiveSerializer.h | 28 + src/fsfw/cfdp/pdu/FinishedInfo.cpp | 111 ++++ src/fsfw/cfdp/pdu/FinishedInfo.h | 45 ++ src/fsfw/cfdp/pdu/FinishedPduDeserializer.cpp | 90 +++ src/fsfw/cfdp/pdu/FinishedPduDeserializer.h | 21 + src/fsfw/cfdp/pdu/FinishedPduSerializer.cpp | 47 ++ src/fsfw/cfdp/pdu/FinishedPduSerializer.h | 22 + src/fsfw/cfdp/pdu/HeaderDeserializer.cpp | 136 ++++ src/fsfw/cfdp/pdu/HeaderDeserializer.h | 93 +++ src/fsfw/cfdp/pdu/HeaderSerializer.cpp | 135 ++++ src/fsfw/cfdp/pdu/HeaderSerializer.h | 64 ++ .../cfdp/pdu/KeepAlivePduDeserializer.cpp | 20 + src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.h | 18 + src/fsfw/cfdp/pdu/KeepAlivePduSerializer.cpp | 26 + src/fsfw/cfdp/pdu/KeepAlivePduSerializer.h | 21 + src/fsfw/cfdp/pdu/MetadataInfo.cpp | 115 ++++ src/fsfw/cfdp/pdu/MetadataInfo.h | 49 ++ src/fsfw/cfdp/pdu/MetadataPduDeserializer.cpp | 58 ++ src/fsfw/cfdp/pdu/MetadataPduDeserializer.h | 18 + src/fsfw/cfdp/pdu/MetadataPduSerializer.cpp | 54 ++ src/fsfw/cfdp/pdu/MetadataPduSerializer.h | 23 + src/fsfw/cfdp/pdu/NakInfo.cpp | 83 +++ src/fsfw/cfdp/pdu/NakInfo.h | 40 ++ src/fsfw/cfdp/pdu/NakPduDeserializer.cpp | 58 ++ src/fsfw/cfdp/pdu/NakPduDeserializer.h | 22 + src/fsfw/cfdp/pdu/NakPduSerializer.cpp | 49 ++ src/fsfw/cfdp/pdu/NakPduSerializer.h | 41 ++ src/fsfw/cfdp/pdu/PduConfig.cpp | 8 + src/fsfw/cfdp/pdu/PduConfig.h | 36 ++ src/fsfw/cfdp/pdu/PduHeaderIF.h | 37 ++ src/fsfw/cfdp/pdu/PromptPduDeserializer.cpp | 22 + src/fsfw/cfdp/pdu/PromptPduDeserializer.h | 18 + src/fsfw/cfdp/pdu/PromptPduSerializer.cpp | 27 + src/fsfw/cfdp/pdu/PromptPduSerializer.h | 18 + src/fsfw/cfdp/pdu/VarLenField.cpp | 127 ++++ src/fsfw/cfdp/pdu/VarLenField.h | 45 ++ src/fsfw/cfdp/tlv/CMakeLists.txt | 10 + src/fsfw/cfdp/tlv/EntityIdTlv.cpp | 68 ++ src/fsfw/cfdp/tlv/EntityIdTlv.h | 39 ++ src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.cpp | 64 ++ src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.h | 39 ++ src/fsfw/cfdp/tlv/FilestoreRequestTlv.cpp | 83 +++ src/fsfw/cfdp/tlv/FilestoreRequestTlv.h | 45 ++ src/fsfw/cfdp/tlv/FilestoreResponseTlv.cpp | 124 ++++ src/fsfw/cfdp/tlv/FilestoreResponseTlv.h | 50 ++ src/fsfw/cfdp/tlv/FilestoreTlvBase.h | 176 ++++++ src/fsfw/cfdp/tlv/FlowLabelTlv.cpp | 5 + src/fsfw/cfdp/tlv/FlowLabelTlv.h | 13 + src/fsfw/cfdp/tlv/Lv.cpp | 88 +++ src/fsfw/cfdp/tlv/Lv.h | 53 ++ src/fsfw/cfdp/tlv/MessageToUserTlv.cpp | 8 + src/fsfw/cfdp/tlv/MessageToUserTlv.h | 13 + src/fsfw/cfdp/tlv/Tlv.cpp | 114 ++++ src/fsfw/cfdp/tlv/Tlv.h | 64 ++ src/fsfw/cfdp/tlv/TlvIF.h | 16 + src/fsfw/controller/ExtendedControllerBase.h | 7 +- src/fsfw/devicehandlers/AssemblyBase.h | 2 +- .../devicehandlers/DeviceCommunicationIF.h | 7 +- src/fsfw/devicehandlers/DeviceHandlerBase.h | 22 +- src/fsfw/devicehandlers/DeviceHandlerIF.h | 3 +- src/fsfw/ipc/FwMessageTypes.h | 1 + src/fsfw/objectmanager/frameworkObjects.h | 3 + src/fsfw/osal/linux/CMakeLists.txt | 1 + src/fsfw/osal/linux/MessageQueue.cpp | 6 +- src/fsfw/returnvalues/FwClassIds.h | 1 + src/fsfw/serialize/SerialBufferAdapter.cpp | 2 +- src/fsfw/serialize/SerialBufferAdapter.h | 2 +- src/fsfw/subsystem/SubsystemBase.h | 3 +- src/fsfw/tcdistribution/CCSDSDistributor.cpp | 116 ++-- src/fsfw/tcdistribution/CCSDSDistributor.h | 81 +-- src/fsfw/tcdistribution/CCSDSDistributorIF.h | 49 +- src/fsfw/tcdistribution/CFDPDistributor.cpp | 147 +++++ src/fsfw/tcdistribution/CFDPDistributor.h | 72 +++ src/fsfw/tcdistribution/CFDPDistributorIF.h | 27 + src/fsfw/tcdistribution/CMakeLists.txt | 5 +- src/fsfw/tcdistribution/PUSDistributor.cpp | 12 +- src/fsfw/tcdistribution/PUSDistributor.h | 108 ++-- src/fsfw/tcdistribution/PUSDistributorIF.h | 24 +- src/fsfw/tcdistribution/TcPacketCheckCFDP.cpp | 13 + src/fsfw/tcdistribution/TcPacketCheckCFDP.h | 35 ++ src/fsfw/tcdistribution/TcPacketCheckIF.h | 31 + ...TcPacketCheck.cpp => TcPacketCheckPUS.cpp} | 18 +- .../{TcPacketCheck.h => TcPacketCheckPUS.h} | 25 +- src/fsfw/tmtcpacket/CMakeLists.txt | 1 + .../tmtcpacket/RedirectableDataPointerIF.h | 34 + src/fsfw/tmtcpacket/SpacePacket.cpp | 26 +- src/fsfw/tmtcpacket/SpacePacket.h | 2 +- src/fsfw/tmtcpacket/SpacePacketBase.cpp | 12 +- src/fsfw/tmtcpacket/SpacePacketBase.h | 12 +- src/fsfw/tmtcpacket/cfdp/CFDPPacket.cpp | 20 + src/fsfw/tmtcpacket/cfdp/CFDPPacket.h | 27 + src/fsfw/tmtcpacket/cfdp/CFDPPacketStored.cpp | 97 +++ src/fsfw/tmtcpacket/cfdp/CFDPPacketStored.h | 67 ++ src/fsfw/tmtcpacket/cfdp/CMakeLists.txt | 4 + src/fsfw/tmtcpacket/pus/tc/CMakeLists.txt | 2 +- src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp | 26 +- src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h | 7 +- .../{TcPacketBase.cpp => TcPacketPusBase.cpp} | 8 +- .../tc/{TcPacketBase.h => TcPacketPusBase.h} | 12 +- .../tmtcpacket/pus/tc/TcPacketStoredBase.cpp | 12 +- .../tmtcpacket/pus/tc/TcPacketStoredBase.h | 12 +- src/fsfw/tmtcpacket/pus/tc/TcPacketStoredIF.h | 15 +- .../tmtcpacket/pus/tc/TcPacketStoredPus.cpp | 13 +- .../tmtcpacket/pus/tc/TcPacketStoredPus.h | 4 +- src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp | 10 +- src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h | 3 +- src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp | 13 +- src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h | 4 +- .../tmtcpacket/pus/tm/TmPacketStoredBase.cpp | 6 +- .../tmtcpacket/pus/tm/TmPacketStoredBase.h | 3 +- .../tmtcpacket/pus/tm/TmPacketStoredPusA.cpp | 8 +- .../tmtcpacket/pus/tm/TmPacketStoredPusA.h | 12 +- .../tmtcpacket/pus/tm/TmPacketStoredPusC.cpp | 9 +- .../tmtcpacket/pus/tm/TmPacketStoredPusC.h | 12 +- .../tmtcservices/CommandingServiceBase.cpp | 591 +++++++++--------- src/fsfw/tmtcservices/CommandingServiceBase.h | 560 ++++++++--------- src/fsfw/tmtcservices/PusServiceBase.cpp | 156 ++--- src/fsfw/tmtcservices/PusServiceBase.h | 226 +++---- src/fsfw/tmtcservices/PusVerificationReport.h | 2 +- .../tmtcservices/VerificationReporter.cpp | 4 +- src/fsfw/tmtcservices/VerificationReporter.h | 4 +- tests/src/fsfw_tests/unit/CMakeLists.txt | 1 + tests/src/fsfw_tests/unit/cfdp/CMakeLists.txt | 12 + tests/src/fsfw_tests/unit/cfdp/testAckPdu.cpp | 101 +++ tests/src/fsfw_tests/unit/cfdp/testCfdp.cpp | 372 +++++++++++ tests/src/fsfw_tests/unit/cfdp/testEofPdu.cpp | 124 ++++ .../src/fsfw_tests/unit/cfdp/testFileData.cpp | 175 ++++++ .../fsfw_tests/unit/cfdp/testFinishedPdu.cpp | 196 ++++++ .../fsfw_tests/unit/cfdp/testKeepAlivePdu.cpp | 84 +++ .../fsfw_tests/unit/cfdp/testMetadataPdu.cpp | 185 ++++++ tests/src/fsfw_tests/unit/cfdp/testNakPdu.cpp | 160 +++++ .../fsfw_tests/unit/cfdp/testPromptPdu.cpp | 71 +++ .../src/fsfw_tests/unit/cfdp/testTlvsLvs.cpp | 334 ++++++++++ 167 files changed, 7801 insertions(+), 1121 deletions(-) create mode 100644 src/fsfw/cfdp/CFDPHandler.cpp create mode 100644 src/fsfw/cfdp/CFDPHandler.h create mode 100644 src/fsfw/cfdp/CFDPMessage.cpp create mode 100644 src/fsfw/cfdp/CFDPMessage.h create mode 100644 src/fsfw/cfdp/CMakeLists.txt create mode 100644 src/fsfw/cfdp/FileSize.h create mode 100644 src/fsfw/cfdp/definitions.h create mode 100644 src/fsfw/cfdp/pdu/AckInfo.cpp create mode 100644 src/fsfw/cfdp/pdu/AckInfo.h create mode 100644 src/fsfw/cfdp/pdu/AckPduDeserializer.cpp create mode 100644 src/fsfw/cfdp/pdu/AckPduDeserializer.h create mode 100644 src/fsfw/cfdp/pdu/AckPduSerializer.cpp create mode 100644 src/fsfw/cfdp/pdu/AckPduSerializer.h create mode 100644 src/fsfw/cfdp/pdu/CMakeLists.txt create mode 100644 src/fsfw/cfdp/pdu/EofInfo.cpp create mode 100644 src/fsfw/cfdp/pdu/EofInfo.h create mode 100644 src/fsfw/cfdp/pdu/EofPduDeserializer.cpp create mode 100644 src/fsfw/cfdp/pdu/EofPduDeserializer.h create mode 100644 src/fsfw/cfdp/pdu/EofPduSerializer.cpp create mode 100644 src/fsfw/cfdp/pdu/EofPduSerializer.h create mode 100644 src/fsfw/cfdp/pdu/FileDataDeserializer.cpp create mode 100644 src/fsfw/cfdp/pdu/FileDataDeserializer.h create mode 100644 src/fsfw/cfdp/pdu/FileDataInfo.cpp create mode 100644 src/fsfw/cfdp/pdu/FileDataInfo.h create mode 100644 src/fsfw/cfdp/pdu/FileDataSerializer.cpp create mode 100644 src/fsfw/cfdp/pdu/FileDataSerializer.h create mode 100644 src/fsfw/cfdp/pdu/FileDirectiveDeserializer.cpp create mode 100644 src/fsfw/cfdp/pdu/FileDirectiveDeserializer.h create mode 100644 src/fsfw/cfdp/pdu/FileDirectiveSerializer.cpp create mode 100644 src/fsfw/cfdp/pdu/FileDirectiveSerializer.h create mode 100644 src/fsfw/cfdp/pdu/FinishedInfo.cpp create mode 100644 src/fsfw/cfdp/pdu/FinishedInfo.h create mode 100644 src/fsfw/cfdp/pdu/FinishedPduDeserializer.cpp create mode 100644 src/fsfw/cfdp/pdu/FinishedPduDeserializer.h create mode 100644 src/fsfw/cfdp/pdu/FinishedPduSerializer.cpp create mode 100644 src/fsfw/cfdp/pdu/FinishedPduSerializer.h create mode 100644 src/fsfw/cfdp/pdu/HeaderDeserializer.cpp create mode 100644 src/fsfw/cfdp/pdu/HeaderDeserializer.h create mode 100644 src/fsfw/cfdp/pdu/HeaderSerializer.cpp create mode 100644 src/fsfw/cfdp/pdu/HeaderSerializer.h create mode 100644 src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.cpp create mode 100644 src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.h create mode 100644 src/fsfw/cfdp/pdu/KeepAlivePduSerializer.cpp create mode 100644 src/fsfw/cfdp/pdu/KeepAlivePduSerializer.h create mode 100644 src/fsfw/cfdp/pdu/MetadataInfo.cpp create mode 100644 src/fsfw/cfdp/pdu/MetadataInfo.h create mode 100644 src/fsfw/cfdp/pdu/MetadataPduDeserializer.cpp create mode 100644 src/fsfw/cfdp/pdu/MetadataPduDeserializer.h create mode 100644 src/fsfw/cfdp/pdu/MetadataPduSerializer.cpp create mode 100644 src/fsfw/cfdp/pdu/MetadataPduSerializer.h create mode 100644 src/fsfw/cfdp/pdu/NakInfo.cpp create mode 100644 src/fsfw/cfdp/pdu/NakInfo.h create mode 100644 src/fsfw/cfdp/pdu/NakPduDeserializer.cpp create mode 100644 src/fsfw/cfdp/pdu/NakPduDeserializer.h create mode 100644 src/fsfw/cfdp/pdu/NakPduSerializer.cpp create mode 100644 src/fsfw/cfdp/pdu/NakPduSerializer.h create mode 100644 src/fsfw/cfdp/pdu/PduConfig.cpp create mode 100644 src/fsfw/cfdp/pdu/PduConfig.h create mode 100644 src/fsfw/cfdp/pdu/PduHeaderIF.h create mode 100644 src/fsfw/cfdp/pdu/PromptPduDeserializer.cpp create mode 100644 src/fsfw/cfdp/pdu/PromptPduDeserializer.h create mode 100644 src/fsfw/cfdp/pdu/PromptPduSerializer.cpp create mode 100644 src/fsfw/cfdp/pdu/PromptPduSerializer.h create mode 100644 src/fsfw/cfdp/pdu/VarLenField.cpp create mode 100644 src/fsfw/cfdp/pdu/VarLenField.h create mode 100644 src/fsfw/cfdp/tlv/CMakeLists.txt create mode 100644 src/fsfw/cfdp/tlv/EntityIdTlv.cpp create mode 100644 src/fsfw/cfdp/tlv/EntityIdTlv.h create mode 100644 src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.cpp create mode 100644 src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.h create mode 100644 src/fsfw/cfdp/tlv/FilestoreRequestTlv.cpp create mode 100644 src/fsfw/cfdp/tlv/FilestoreRequestTlv.h create mode 100644 src/fsfw/cfdp/tlv/FilestoreResponseTlv.cpp create mode 100644 src/fsfw/cfdp/tlv/FilestoreResponseTlv.h create mode 100644 src/fsfw/cfdp/tlv/FilestoreTlvBase.h create mode 100644 src/fsfw/cfdp/tlv/FlowLabelTlv.cpp create mode 100644 src/fsfw/cfdp/tlv/FlowLabelTlv.h create mode 100644 src/fsfw/cfdp/tlv/Lv.cpp create mode 100644 src/fsfw/cfdp/tlv/Lv.h create mode 100644 src/fsfw/cfdp/tlv/MessageToUserTlv.cpp create mode 100644 src/fsfw/cfdp/tlv/MessageToUserTlv.h create mode 100644 src/fsfw/cfdp/tlv/Tlv.cpp create mode 100644 src/fsfw/cfdp/tlv/Tlv.h create mode 100644 src/fsfw/cfdp/tlv/TlvIF.h create mode 100644 src/fsfw/tcdistribution/CFDPDistributor.cpp create mode 100644 src/fsfw/tcdistribution/CFDPDistributor.h create mode 100644 src/fsfw/tcdistribution/CFDPDistributorIF.h create mode 100644 src/fsfw/tcdistribution/TcPacketCheckCFDP.cpp create mode 100644 src/fsfw/tcdistribution/TcPacketCheckCFDP.h create mode 100644 src/fsfw/tcdistribution/TcPacketCheckIF.h rename src/fsfw/tcdistribution/{TcPacketCheck.cpp => TcPacketCheckPUS.cpp} (65%) rename src/fsfw/tcdistribution/{TcPacketCheck.h => TcPacketCheckPUS.h} (73%) create mode 100644 src/fsfw/tmtcpacket/RedirectableDataPointerIF.h create mode 100644 src/fsfw/tmtcpacket/cfdp/CFDPPacket.cpp create mode 100644 src/fsfw/tmtcpacket/cfdp/CFDPPacket.h create mode 100644 src/fsfw/tmtcpacket/cfdp/CFDPPacketStored.cpp create mode 100644 src/fsfw/tmtcpacket/cfdp/CFDPPacketStored.h create mode 100644 src/fsfw/tmtcpacket/cfdp/CMakeLists.txt rename src/fsfw/tmtcpacket/pus/tc/{TcPacketBase.cpp => TcPacketPusBase.cpp} (65%) rename src/fsfw/tmtcpacket/pus/tc/{TcPacketBase.h => TcPacketPusBase.h} (93%) create mode 100644 tests/src/fsfw_tests/unit/cfdp/CMakeLists.txt create mode 100644 tests/src/fsfw_tests/unit/cfdp/testAckPdu.cpp create mode 100644 tests/src/fsfw_tests/unit/cfdp/testCfdp.cpp create mode 100644 tests/src/fsfw_tests/unit/cfdp/testEofPdu.cpp create mode 100644 tests/src/fsfw_tests/unit/cfdp/testFileData.cpp create mode 100644 tests/src/fsfw_tests/unit/cfdp/testFinishedPdu.cpp create mode 100644 tests/src/fsfw_tests/unit/cfdp/testKeepAlivePdu.cpp create mode 100644 tests/src/fsfw_tests/unit/cfdp/testMetadataPdu.cpp create mode 100644 tests/src/fsfw_tests/unit/cfdp/testNakPdu.cpp create mode 100644 tests/src/fsfw_tests/unit/cfdp/testPromptPdu.cpp create mode 100644 tests/src/fsfw_tests/unit/cfdp/testTlvsLvs.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e78e8929..bd65cfe1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -189,13 +189,13 @@ if(FSFW_BUILD_UNITTESTS) "--exclude-unreachable-branches" ) set(COVERAGE_EXCLUDES - "/c/msys64/mingw64/*" + "/c/msys64/mingw64/*" "*/fsfw_hal/*" ) elseif(UNIX) set(COVERAGE_EXCLUDES "/usr/include/*" "/usr/bin/*" "Catch2/*" "/usr/local/include/*" "*/fsfw_tests/*" - "*/catch2-src/*" + "*/catch2-src/*" "*/fsfw_hal/*" ) endif() diff --git a/README.md b/README.md index 312bc077..a6f52ca0 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ You can use the following commands inside the `fsfw` folder to set up the build ```sh mkdir build-Unittest && cd build-Unittest -cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host .. +cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug .. ``` You can also use `-DFSFW_OSAL=linux` on Linux systems. diff --git a/misc/defaultcfg/fsfwconfig/devices/logicalAddresses.h b/misc/defaultcfg/fsfwconfig/devices/logicalAddresses.h index 53edcd54..8f263e9a 100644 --- a/misc/defaultcfg/fsfwconfig/devices/logicalAddresses.h +++ b/misc/defaultcfg/fsfwconfig/devices/logicalAddresses.h @@ -10,7 +10,7 @@ */ namespace addresses { /* Logical addresses have uint32_t datatype */ - enum logicalAddresses: address_t { + enum LogAddr: address_t { }; } diff --git a/src/fsfw/CMakeLists.txt b/src/fsfw/CMakeLists.txt index 7c665e28..12c673ed 100644 --- a/src/fsfw/CMakeLists.txt +++ b/src/fsfw/CMakeLists.txt @@ -1,6 +1,7 @@ # Core add_subdirectory(action) +add_subdirectory(cfdp) add_subdirectory(container) add_subdirectory(controller) add_subdirectory(datapool) diff --git a/src/fsfw/FSFW.h.in b/src/fsfw/FSFW.h.in index 7e52b646..d4a8f3ba 100644 --- a/src/fsfw/FSFW.h.in +++ b/src/fsfw/FSFW.h.in @@ -42,6 +42,10 @@ #define FSFW_USE_PUS_C_TELECOMMANDS 1 #endif +#ifndef FSFW_TCP_RECV_WIRETAPPING_ENABLED +#define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0 +#endif + // FSFW HAL defines // Can be used for low-level debugging of the SPI bus diff --git a/src/fsfw/cfdp/CFDPHandler.cpp b/src/fsfw/cfdp/CFDPHandler.cpp new file mode 100644 index 00000000..79712bf2 --- /dev/null +++ b/src/fsfw/cfdp/CFDPHandler.cpp @@ -0,0 +1,60 @@ +#include "fsfw/ipc/CommandMessage.h" +#include "fsfw/storagemanager/storeAddress.h" +#include "fsfw/cfdp/CFDPHandler.h" +#include "fsfw/cfdp/CFDPMessage.h" + +#include "fsfw/tmtcservices/AcceptsTelemetryIF.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/objectmanager/ObjectManager.h" + +object_id_t CFDPHandler::packetSource = 0; +object_id_t CFDPHandler::packetDestination = 0; + +CFDPHandler::CFDPHandler(object_id_t setObjectId, CFDPDistributor* dist) : SystemObject(setObjectId) { + requestQueue = QueueFactory::instance()->createMessageQueue(CFDP_HANDLER_MAX_RECEPTION); + distributor = dist; +} + +CFDPHandler::~CFDPHandler() {} + +ReturnValue_t CFDPHandler::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != RETURN_OK) { + return result; + } + this->distributor->registerHandler(this); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CFDPHandler::handleRequest(store_address_t storeId) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::debug << "CFDPHandler::handleRequest" << std::endl; +#else + sif::printDebug("CFDPHandler::handleRequest\n"); +#endif /* !FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif + + //TODO read out packet from store using storeId + + return RETURN_OK; +} + +ReturnValue_t CFDPHandler::performOperation(uint8_t opCode) { + ReturnValue_t status = RETURN_OK; + CommandMessage currentMessage; + for (status = this->requestQueue->receiveMessage(¤tMessage); status == RETURN_OK; + status = this->requestQueue->receiveMessage(¤tMessage)) { + store_address_t storeId = CFDPMessage::getStoreId(¤tMessage); + this->handleRequest(storeId); + } + return RETURN_OK; +} + +uint16_t CFDPHandler::getIdentifier() { + return 0; +} + +MessageQueueId_t CFDPHandler::getRequestQueue() { + return this->requestQueue->getId(); +} diff --git a/src/fsfw/cfdp/CFDPHandler.h b/src/fsfw/cfdp/CFDPHandler.h new file mode 100644 index 00000000..2f11eee3 --- /dev/null +++ b/src/fsfw/cfdp/CFDPHandler.h @@ -0,0 +1,62 @@ +#ifndef FSFW_CFDP_CFDPHANDLER_H_ +#define FSFW_CFDP_CFDPHANDLER_H_ + +#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/tcdistribution/CFDPDistributor.h" + +#include "fsfw/ipc/MessageQueueIF.h" + +namespace Factory{ +void setStaticFrameworkObjectIds(); +} + +class CFDPHandler : + public ExecutableObjectIF, + public AcceptsTelecommandsIF, + public SystemObject, + public HasReturnvaluesIF { + friend void (Factory::setStaticFrameworkObjectIds)(); +public: + CFDPHandler(object_id_t setObjectId, CFDPDistributor* distributor); + /** + * The destructor is empty. + */ + virtual ~CFDPHandler(); + + virtual ReturnValue_t handleRequest(store_address_t storeId); + + virtual ReturnValue_t initialize() override; + virtual uint16_t getIdentifier() override; + MessageQueueId_t getRequestQueue() override; + ReturnValue_t performOperation(uint8_t opCode) override; + protected: + /** + * This is a complete instance of the telecommand reception queue + * of the class. It is initialized on construction of the class. + */ + MessageQueueIF* requestQueue = nullptr; + + CFDPDistributor* distributor = nullptr; + + /** + * The current CFDP packet to be processed. + * It is deleted after handleRequest was executed. + */ + CFDPPacketStored currentPacket; + + static object_id_t packetSource; + + static object_id_t packetDestination; + private: + /** + * This constant sets the maximum number of packets accepted per call. + * Remember that one packet must be completely handled in one + * #handleRequest call. + */ + static const uint8_t CFDP_HANDLER_MAX_RECEPTION = 100; +}; + +#endif /* FSFW_CFDP_CFDPHANDLER_H_ */ diff --git a/src/fsfw/cfdp/CFDPMessage.cpp b/src/fsfw/cfdp/CFDPMessage.cpp new file mode 100644 index 00000000..c75b6b2c --- /dev/null +++ b/src/fsfw/cfdp/CFDPMessage.cpp @@ -0,0 +1,21 @@ +#include "CFDPMessage.h" + +CFDPMessage::CFDPMessage() { +} + +CFDPMessage::~CFDPMessage() { +} + +void CFDPMessage::setCommand(CommandMessage *message, + store_address_t cfdpPacket) { + message->setParameter(cfdpPacket.raw); +} + +store_address_t CFDPMessage::getStoreId(const CommandMessage *message) { + store_address_t storeAddressCFDPPacket; + storeAddressCFDPPacket = message->getParameter(); + return storeAddressCFDPPacket; +} + +void CFDPMessage::clear(CommandMessage *message) { +} diff --git a/src/fsfw/cfdp/CFDPMessage.h b/src/fsfw/cfdp/CFDPMessage.h new file mode 100644 index 00000000..5b321975 --- /dev/null +++ b/src/fsfw/cfdp/CFDPMessage.h @@ -0,0 +1,23 @@ +#ifndef FSFW_CFDP_CFDPMESSAGE_H_ +#define FSFW_CFDP_CFDPMESSAGE_H_ + +#include "fsfw/ipc/CommandMessage.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/storagemanager/StorageManagerIF.h" + +class CFDPMessage { +private: + CFDPMessage(); +public: + static const uint8_t MESSAGE_ID = messagetypes::CFDP; + + virtual ~CFDPMessage(); + static void setCommand(CommandMessage* message, + store_address_t cfdpPacket); + + static store_address_t getStoreId(const CommandMessage* message); + + static void clear(CommandMessage* message); +}; + +#endif /* FSFW_CFDP_CFDPMESSAGE_H_ */ diff --git a/src/fsfw/cfdp/CMakeLists.txt b/src/fsfw/cfdp/CMakeLists.txt new file mode 100644 index 00000000..908dc32a --- /dev/null +++ b/src/fsfw/cfdp/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + CFDPHandler.cpp + CFDPMessage.cpp +) + +add_subdirectory(pdu) +add_subdirectory(tlv) diff --git a/src/fsfw/cfdp/FileSize.h b/src/fsfw/cfdp/FileSize.h new file mode 100644 index 00000000..3997d5a4 --- /dev/null +++ b/src/fsfw/cfdp/FileSize.h @@ -0,0 +1,83 @@ +#ifndef FSFW_SRC_FSFW_CFDP_FILESIZE_H_ +#define FSFW_SRC_FSFW_CFDP_FILESIZE_H_ + +#include "fsfw/serialize/SerializeAdapter.h" +#include "fsfw/serialize/SerializeIF.h" + +namespace cfdp { + +struct FileSize: public SerializeIF { +public: + FileSize(): largeFile(false) {}; + + FileSize(uint64_t fileSize, bool isLarge = false) { + setFileSize(fileSize, isLarge); + }; + + ReturnValue_t serialize(bool isLarge, uint8_t **buffer, size_t *size,size_t maxSize, + Endianness streamEndianness) { + this->largeFile = isLarge; + return serialize(buffer, size, maxSize, streamEndianness); + } + + ReturnValue_t serialize(uint8_t **buffer, size_t *size,size_t maxSize, + Endianness streamEndianness) const override { + if(not largeFile) { + uint32_t fileSizeTyped = fileSize; + return SerializeAdapter::serialize(&fileSizeTyped, buffer, size, maxSize, + streamEndianness); + + } + return SerializeAdapter::serialize(&fileSize, buffer, size, maxSize, streamEndianness); + } + + size_t getSerializedSize() const override { + if (largeFile) { + return 8; + } else { + return 4; + } + } + + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override { + if(largeFile) { + return SerializeAdapter::deSerialize(&size, buffer, size, streamEndianness); + } else { + uint32_t sizeTmp = 0; + ReturnValue_t result = SerializeAdapter::deSerialize(&sizeTmp, buffer, size, + streamEndianness); + if(result == HasReturnvaluesIF::RETURN_OK) { + fileSize = sizeTmp; + } + return result; + } + } + + ReturnValue_t setFileSize(uint64_t fileSize, bool largeFile) { + if (not largeFile and fileSize > UINT32_MAX) { + // TODO: emit warning here + return HasReturnvaluesIF::RETURN_FAILED; + } + this->fileSize = fileSize; + this->largeFile = largeFile; + return HasReturnvaluesIF::RETURN_OK; + } + + bool isLargeFile() const { + return largeFile; + } + uint64_t getSize(bool* largeFile = nullptr) const { + if(largeFile != nullptr) { + *largeFile = this->largeFile; + } + return fileSize; + } +private: + uint64_t fileSize = 0; + bool largeFile = false; +}; + +} + +#endif /* FSFW_SRC_FSFW_CFDP_FILESIZE_H_ */ diff --git a/src/fsfw/cfdp/definitions.h b/src/fsfw/cfdp/definitions.h new file mode 100644 index 00000000..ffcbca97 --- /dev/null +++ b/src/fsfw/cfdp/definitions.h @@ -0,0 +1,153 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_DEFINITIONS_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_DEFINITIONS_H_ + +#include +#include +#include +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/returnvalues/FwClassIds.h" + +namespace cfdp { + +static constexpr uint8_t VERSION_BITS = 0b00100000; + +static constexpr uint8_t CFDP_CLASS_ID = CLASS_ID::CFDP; + +static constexpr ReturnValue_t INVALID_TLV_TYPE = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 1); +static constexpr ReturnValue_t INVALID_DIRECTIVE_FIELDS = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 2); +static constexpr ReturnValue_t INVALID_PDU_DATAFIELD_LEN = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 3); +static constexpr ReturnValue_t INVALID_ACK_DIRECTIVE_FIELDS = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 4); +//! Can not parse options. This can also occur because there are options +//! available but the user did not pass a valid options array +static constexpr ReturnValue_t METADATA_CANT_PARSE_OPTIONS = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 5); +static constexpr ReturnValue_t NAK_CANT_PARSE_OPTIONS = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 6); +static constexpr ReturnValue_t FINISHED_CANT_PARSE_FS_RESPONSES = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 6); +static constexpr ReturnValue_t FILESTORE_REQUIRES_SECOND_FILE = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 8); +//! Can not parse filestore response because user did not pass a valid instance +//! or remaining size is invalid +static constexpr ReturnValue_t FILESTORE_RESPONSE_CANT_PARSE_FS_MESSAGE = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 9); + +//! Checksum types according to the SANA Checksum Types registry +//! https://sanaregistry.org/r/checksum_identifiers/ +enum ChecksumType { + // Modular legacy checksum + MODULAR = 0, + CRC_32_PROXIMITY_1 = 1, + CRC_32C = 2, + CRC_32 = 3, + NULL_CHECKSUM = 15 +}; + +enum PduType: bool { + FILE_DIRECTIVE = 0, + FILE_DATA = 1 +}; + +enum TransmissionModes: bool { + ACKNOWLEDGED = 0, + UNACKNOWLEDGED = 1 +}; + +enum SegmentMetadataFlag: bool { + NOT_PRESENT = 0, + PRESENT = 1 +}; + +enum Direction: bool { + TOWARDS_RECEIVER = 0, + TOWARDS_SENDER = 1 +}; + +enum SegmentationControl: bool { + NO_RECORD_BOUNDARIES_PRESERVATION = 0, + RECORD_BOUNDARIES_PRESERVATION = 1 +}; + +enum WidthInBytes: uint8_t { + // Only those are supported for now + ONE_BYTE = 1, + TWO_BYTES = 2, + FOUR_BYTES = 4, +}; + +enum FileDirectives: uint8_t { + INVALID_DIRECTIVE = 0x0f, + EOF_DIRECTIVE = 0x04, + FINISH = 0x05, + ACK = 0x06, + METADATA = 0x07, + NAK = 0x08, + PROMPT = 0x09, + KEEP_ALIVE = 0x0c +}; + +enum ConditionCode: uint8_t { + NO_CONDITION_FIELD = 0xff, + NO_ERROR = 0b0000, + POSITIVE_ACK_LIMIT_REACHED = 0b0001, + KEEP_ALIVE_LIMIT_REACHED = 0b0010, + INVALID_TRANSMISSION_MODE = 0b0011, + FILESTORE_REJECTION = 0b0100, + FILE_CHECKSUM_FAILURE = 0b0101, + FILE_SIZE_ERROR = 0b0110, + NAK_LIMIT_REACHED = 0b0111, + INACTIVITY_DETECTED = 0b1000, + CHECK_LIMIT_REACHED = 0b1010, + UNSUPPORTED_CHECKSUM_TYPE = 0b1011, + SUSPEND_REQUEST_RECEIVED = 0b1110, + CANCEL_REQUEST_RECEIVED = 0b1111 +}; + +enum AckTransactionStatus { + UNDEFINED = 0b00, + ACTIVE = 0b01, + TERMINATED = 0b10, + UNRECOGNIZED = 0b11 +}; + +enum FinishedDeliveryCode { + DATA_COMPLETE = 0, + DATA_INCOMPLETE = 1 +}; + +enum FinishedFileStatus { + DISCARDED_DELIBERATELY = 0, + DISCARDED_FILESTORE_REJECTION = 1, + RETAINED_IN_FILESTORE = 2, + FILE_STATUS_UNREPORTED = 3 +}; + +enum PromptResponseRequired: bool { + PROMPT_NAK = 0, + PROMPT_KEEP_ALIVE = 1 +}; + +enum TlvTypes: uint8_t { + FILESTORE_REQUEST = 0x00, + FILESTORE_RESPONSE = 0x01, + MSG_TO_USER = 0x02, + FAULT_HANDLER = 0x04, + FLOW_LABEL = 0x05, + ENTITY_ID = 0x06, + INVALID_TLV = 0xff, +}; + +enum RecordContinuationState { + NO_START_NO_END = 0b00, + CONTAINS_START_NO_END = 0b01, + CONTAINS_END_NO_START = 0b10, + CONTAINS_START_AND_END = 0b11 +}; + +} + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_DEFINITIONS_H_ */ diff --git a/src/fsfw/cfdp/pdu/AckInfo.cpp b/src/fsfw/cfdp/pdu/AckInfo.cpp new file mode 100644 index 00000000..4095e8bf --- /dev/null +++ b/src/fsfw/cfdp/pdu/AckInfo.cpp @@ -0,0 +1,52 @@ +#include "AckInfo.h" + +AckInfo::AckInfo(cfdp::FileDirectives ackedDirective, cfdp::ConditionCode ackedConditionCode, + cfdp::AckTransactionStatus transactionStatus, uint8_t directiveSubtypeCode): + ackedDirective(ackedDirective), ackedConditionCode(ackedConditionCode), + transactionStatus(transactionStatus), directiveSubtypeCode(directiveSubtypeCode) { + if (ackedDirective == cfdp::FileDirectives::FINISH) { + this->directiveSubtypeCode = 0b0001; + } else { + this->directiveSubtypeCode = 0b0000; + } +} + +cfdp::ConditionCode AckInfo::getAckedConditionCode() const { + return ackedConditionCode; +} + +void AckInfo::setAckedConditionCode(cfdp::ConditionCode ackedConditionCode) { + this->ackedConditionCode = ackedConditionCode; + if (ackedDirective == cfdp::FileDirectives::FINISH) { + this->directiveSubtypeCode = 0b0001; + } else { + this->directiveSubtypeCode = 0b0000; + } +} + +cfdp::FileDirectives AckInfo::getAckedDirective() const { + return ackedDirective; +} + +void AckInfo::setAckedDirective(cfdp::FileDirectives ackedDirective) { + this->ackedDirective = ackedDirective; +} + +uint8_t AckInfo::getDirectiveSubtypeCode() const { + return directiveSubtypeCode; +} + +void AckInfo::setDirectiveSubtypeCode(uint8_t directiveSubtypeCode) { + this->directiveSubtypeCode = directiveSubtypeCode; +} + +cfdp::AckTransactionStatus AckInfo::getTransactionStatus() const { + return transactionStatus; +} + +AckInfo::AckInfo() { +} + +void AckInfo::setTransactionStatus(cfdp::AckTransactionStatus transactionStatus) { + this->transactionStatus = transactionStatus; +} diff --git a/src/fsfw/cfdp/pdu/AckInfo.h b/src/fsfw/cfdp/pdu/AckInfo.h new file mode 100644 index 00000000..2d54c535 --- /dev/null +++ b/src/fsfw/cfdp/pdu/AckInfo.h @@ -0,0 +1,33 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_ACKINFO_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_ACKINFO_H_ + +#include "../definitions.h" + +class AckInfo { +public: + AckInfo(); + AckInfo(cfdp::FileDirectives ackedDirective, cfdp::ConditionCode ackedConditionCode, + cfdp::AckTransactionStatus transactionStatus, uint8_t directiveSubtypeCode = 0); + + cfdp::ConditionCode getAckedConditionCode() const; + void setAckedConditionCode(cfdp::ConditionCode ackedConditionCode); + + cfdp::FileDirectives getAckedDirective() const; + void setAckedDirective(cfdp::FileDirectives ackedDirective); + + uint8_t getDirectiveSubtypeCode() const; + void setDirectiveSubtypeCode(uint8_t directiveSubtypeCode); + + cfdp::AckTransactionStatus getTransactionStatus() const; + void setTransactionStatus(cfdp::AckTransactionStatus transactionStatus); + +private: + cfdp::FileDirectives ackedDirective = cfdp::FileDirectives::INVALID_DIRECTIVE; + cfdp::ConditionCode ackedConditionCode = cfdp::ConditionCode::NO_CONDITION_FIELD; + cfdp::AckTransactionStatus transactionStatus = cfdp::AckTransactionStatus::UNDEFINED; + uint8_t directiveSubtypeCode = 0; +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_ACKINFO_H_ */ diff --git a/src/fsfw/cfdp/pdu/AckPduDeserializer.cpp b/src/fsfw/cfdp/pdu/AckPduDeserializer.cpp new file mode 100644 index 00000000..b4f59a7a --- /dev/null +++ b/src/fsfw/cfdp/pdu/AckPduDeserializer.cpp @@ -0,0 +1,38 @@ +#include "AckPduDeserializer.h" + +AckPduDeserializer::AckPduDeserializer(const uint8_t *pduBuf, size_t maxSize, AckInfo& info): + FileDirectiveDeserializer(pduBuf, maxSize), info(info) { +} + +ReturnValue_t AckPduDeserializer::parseData() { + ReturnValue_t result = FileDirectiveDeserializer::parseData(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); + if (currentIdx + 2 > this->maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + if(not checkAndSetCodes(rawPtr[currentIdx], rawPtr[currentIdx + 1])) { + return cfdp::INVALID_ACK_DIRECTIVE_FIELDS; + } + return HasReturnvaluesIF::RETURN_OK; +} + +bool AckPduDeserializer::checkAndSetCodes(uint8_t firstByte, uint8_t secondByte) { + uint8_t ackedDirective = static_cast(firstByte >> 4); + + if(ackedDirective != cfdp::FileDirectives::EOF_DIRECTIVE and + ackedDirective != cfdp::FileDirectives::FINISH) { + return false; + } + this->info.setAckedDirective(static_cast(ackedDirective)); + uint8_t directiveSubtypeCode = firstByte & 0x0f; + if(directiveSubtypeCode != 0b0000 and directiveSubtypeCode != 0b0001) { + return false; + } + this->info.setDirectiveSubtypeCode(directiveSubtypeCode); + this->info.setAckedConditionCode(static_cast(secondByte >> 4)); + this->info.setTransactionStatus(static_cast(secondByte & 0x0f)); + return true; +} diff --git a/src/fsfw/cfdp/pdu/AckPduDeserializer.h b/src/fsfw/cfdp/pdu/AckPduDeserializer.h new file mode 100644 index 00000000..31f09c92 --- /dev/null +++ b/src/fsfw/cfdp/pdu/AckPduDeserializer.h @@ -0,0 +1,26 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_ACKPDUDESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_ACKPDUDESERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" +#include "AckInfo.h" + +class AckPduDeserializer: public FileDirectiveDeserializer { +public: + AckPduDeserializer(const uint8_t* pduBuf, size_t maxSize, AckInfo& info); + + /** + * + * @return + * - cfdp::INVALID_DIRECTIVE_FIELDS: Invalid fields + */ + ReturnValue_t parseData(); + +private: + bool checkAndSetCodes(uint8_t rawAckedByte, uint8_t rawAckedConditionCode); + AckInfo& info; + +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_ACKPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/AckPduSerializer.cpp b/src/fsfw/cfdp/pdu/AckPduSerializer.cpp new file mode 100644 index 00000000..56fe8b33 --- /dev/null +++ b/src/fsfw/cfdp/pdu/AckPduSerializer.cpp @@ -0,0 +1,38 @@ +#include "AckPduSerializer.h" + +AckPduSerializer::AckPduSerializer(AckInfo& ackInfo, PduConfig &pduConf): + FileDirectiveSerializer(pduConf, cfdp::FileDirectives::ACK, 2), + ackInfo(ackInfo) { +} + +size_t AckPduSerializer::getSerializedSize() const { + return FileDirectiveSerializer::getWholePduSize(); +} + +ReturnValue_t AckPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = FileDirectiveSerializer::serialize(buffer, size, maxSize, + streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + cfdp::FileDirectives ackedDirective = ackInfo.getAckedDirective(); + uint8_t directiveSubtypeCode = ackInfo.getDirectiveSubtypeCode(); + cfdp::ConditionCode ackedConditionCode = ackInfo.getAckedConditionCode(); + cfdp::AckTransactionStatus transactionStatus = ackInfo.getTransactionStatus(); + if(ackedDirective != cfdp::FileDirectives::FINISH and + ackedDirective != cfdp::FileDirectives::EOF_DIRECTIVE) { + // TODO: better returncode + return HasReturnvaluesIF::RETURN_FAILED; + } + if(*size + 2 > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = ackedDirective << 4 | directiveSubtypeCode; + *buffer += 1; + *size += 1; + **buffer = ackedConditionCode << 4 | transactionStatus; + *buffer += 1; + *size += 1; + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/src/fsfw/cfdp/pdu/AckPduSerializer.h b/src/fsfw/cfdp/pdu/AckPduSerializer.h new file mode 100644 index 00000000..de478c69 --- /dev/null +++ b/src/fsfw/cfdp/pdu/AckPduSerializer.h @@ -0,0 +1,30 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_ + +#include "AckInfo.h" +#include "FileDirectiveDeserializer.h" +#include "FileDirectiveSerializer.h" + +class AckPduSerializer: public FileDirectiveSerializer { +public: + /** + * @brief Serializer to pack ACK PDUs + * @details + * Please note that only Finished PDUs and EOF are acknowledged. + * @param ackedDirective + * @param ackedConditionCode + * @param transactionStatus + * @param pduConf + */ + AckPduSerializer(AckInfo& ackInfo, PduConfig& pduConf); + + size_t getSerializedSize() const override; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; + +private: + AckInfo& ackInfo; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/CMakeLists.txt b/src/fsfw/cfdp/pdu/CMakeLists.txt new file mode 100644 index 00000000..931db306 --- /dev/null +++ b/src/fsfw/cfdp/pdu/CMakeLists.txt @@ -0,0 +1,32 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + PduConfig.cpp + VarLenField.cpp + HeaderSerializer.cpp + HeaderDeserializer.cpp + FileDirectiveDeserializer.cpp + FileDirectiveSerializer.cpp + + AckInfo.cpp + AckPduSerializer.cpp + AckPduDeserializer.cpp + EofInfo.cpp + EofPduSerializer.cpp + EofPduDeserializer.cpp + NakInfo.cpp + NakPduSerializer.cpp + NakPduDeserializer.cpp + FinishedInfo.cpp + FinishedPduSerializer.cpp + FinishedPduDeserializer.cpp + MetadataInfo.cpp + MetadataPduSerializer.cpp + MetadataPduDeserializer.cpp + KeepAlivePduSerializer.cpp + KeepAlivePduDeserializer.cpp + PromptPduSerializer.cpp + PromptPduDeserializer.cpp + + FileDataSerializer.cpp + FileDataDeserializer.cpp + FileDataInfo.cpp +) \ No newline at end of file diff --git a/src/fsfw/cfdp/pdu/EofInfo.cpp b/src/fsfw/cfdp/pdu/EofInfo.cpp new file mode 100644 index 00000000..f7c41dbe --- /dev/null +++ b/src/fsfw/cfdp/pdu/EofInfo.cpp @@ -0,0 +1,58 @@ +#include "EofInfo.h" + +EofInfo::EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::FileSize fileSize, + EntityIdTlv* faultLoc): conditionCode(conditionCode), checksum(checksum), + fileSize(fileSize), faultLoc(faultLoc) { +} + +EofInfo::EofInfo(EntityIdTlv *faultLoc): conditionCode(cfdp::ConditionCode::NO_CONDITION_FIELD), + checksum(0), fileSize(0), faultLoc(faultLoc) { +} + +uint32_t EofInfo::getChecksum() const { + return checksum; +} + +cfdp::ConditionCode EofInfo::getConditionCode() const { + return conditionCode; +} + +EntityIdTlv* EofInfo::getFaultLoc() const { + return faultLoc; +} + +cfdp::FileSize& EofInfo::getFileSize() { + return fileSize; +} + +void EofInfo::setChecksum(uint32_t checksum) { + this->checksum = checksum; +} + +void EofInfo::setConditionCode(cfdp::ConditionCode conditionCode) { + this->conditionCode = conditionCode; +} + +void EofInfo::setFaultLoc(EntityIdTlv *faultLoc) { + this->faultLoc = faultLoc; +} + +size_t EofInfo::getSerializedSize(bool fssLarge) { + // Condition code + spare + 4 byte checksum + size_t size = 5; + if(fssLarge) { + size += 8; + } else { + size += 4; + } + // Do not account for fault location if the condition code is NO_ERROR. We assume that + // a serializer will not serialize the fault location here. + if(getFaultLoc() != nullptr and getConditionCode() != cfdp::ConditionCode::NO_ERROR) { + size+= faultLoc->getSerializedSize(); + } + return size; +} + +ReturnValue_t EofInfo::setFileSize(size_t fileSize, bool isLarge) { + return this->fileSize.setFileSize(fileSize, isLarge); +} diff --git a/src/fsfw/cfdp/pdu/EofInfo.h b/src/fsfw/cfdp/pdu/EofInfo.h new file mode 100644 index 00000000..33feb4fd --- /dev/null +++ b/src/fsfw/cfdp/pdu/EofInfo.h @@ -0,0 +1,33 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_ + +#include "fsfw/cfdp/tlv/EntityIdTlv.h" +#include "../definitions.h" +#include "../FileSize.h" + +struct EofInfo { +public: + EofInfo(EntityIdTlv* faultLoc = nullptr); + EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::FileSize fileSize, + EntityIdTlv* faultLoc = nullptr); + + size_t getSerializedSize(bool fssLarge = false); + + uint32_t getChecksum() const; + cfdp::ConditionCode getConditionCode() const; + + EntityIdTlv* getFaultLoc() const; + cfdp::FileSize& getFileSize(); + void setChecksum(uint32_t checksum); + void setConditionCode(cfdp::ConditionCode conditionCode); + void setFaultLoc(EntityIdTlv *faultLoc); + ReturnValue_t setFileSize(size_t size, bool isLarge); +private: + + cfdp::ConditionCode conditionCode; + uint32_t checksum; + cfdp::FileSize fileSize; + EntityIdTlv* faultLoc = nullptr; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_ */ diff --git a/src/fsfw/cfdp/pdu/EofPduDeserializer.cpp b/src/fsfw/cfdp/pdu/EofPduDeserializer.cpp new file mode 100644 index 00000000..e5f607bf --- /dev/null +++ b/src/fsfw/cfdp/pdu/EofPduDeserializer.cpp @@ -0,0 +1,68 @@ +#include "EofPduDeserializer.h" +#include "fsfw/FSFW.h" +#include "fsfw/serviceinterface.h" + +EofPduDeserializer::EofPduDeserializer(const uint8_t *pduBuf, size_t maxSize, EofInfo& eofInfo): + FileDirectiveDeserializer(pduBuf, maxSize), info(eofInfo) { +} + +ReturnValue_t EofPduDeserializer::parseData() { + ReturnValue_t result = FileDirectiveDeserializer::parseData(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + const uint8_t* bufPtr = rawPtr; + size_t expectedFileFieldLen = 4; + if(this->getLargeFileFlag()) { + expectedFileFieldLen = 8; + } + size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); + size_t deserLen = maxSize; + if(maxSize < currentIdx + 5 + expectedFileFieldLen) { + return SerializeIF::STREAM_TOO_SHORT; + } + + bufPtr += currentIdx; + deserLen -= currentIdx; + info.setConditionCode(static_cast(*bufPtr >> 4)); + bufPtr += 1; + deserLen -= 1; + uint32_t checksum = 0; + auto endianness = getEndianness(); + result = SerializeAdapter::deSerialize(&checksum, &bufPtr, &deserLen, endianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + info.setChecksum(checksum); + if(this->getLargeFileFlag()) { + uint64_t fileSizeValue = 0; + result = SerializeAdapter::deSerialize(&fileSizeValue, &bufPtr, &deserLen, endianness); + info.setFileSize(fileSizeValue, true); + } + else { + uint32_t fileSizeValue = 0; + result = SerializeAdapter::deSerialize(&fileSizeValue, &bufPtr, &deserLen, endianness); + info.setFileSize(fileSizeValue, false); + } + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(info.getConditionCode() != cfdp::ConditionCode::NO_ERROR) { + EntityIdTlv* tlvPtr = info.getFaultLoc(); + if(tlvPtr == nullptr) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "EofPduDeserializer::parseData: Ca not deserialize fault location," + " given TLV pointer invalid" << std::endl; +#else + sif::printWarning("EofPduDeserializer::parseData: Ca not deserialize fault location," + " given TLV pointer invalid"); +#endif +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + return HasReturnvaluesIF::RETURN_FAILED; + } + result = tlvPtr->deSerialize(&bufPtr, &deserLen, endianness); + } + return result; +} diff --git a/src/fsfw/cfdp/pdu/EofPduDeserializer.h b/src/fsfw/cfdp/pdu/EofPduDeserializer.h new file mode 100644 index 00000000..fea5f03f --- /dev/null +++ b/src/fsfw/cfdp/pdu/EofPduDeserializer.h @@ -0,0 +1,18 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" +#include "EofInfo.h" + +class EofPduDeserializer: public FileDirectiveDeserializer { +public: + EofPduDeserializer(const uint8_t* pduBuf, size_t maxSize, EofInfo& eofInfo); + + virtual ReturnValue_t parseData() override; +private: + EofInfo& info; +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/EofPduSerializer.cpp b/src/fsfw/cfdp/pdu/EofPduSerializer.cpp new file mode 100644 index 00000000..81bd98f1 --- /dev/null +++ b/src/fsfw/cfdp/pdu/EofPduSerializer.cpp @@ -0,0 +1,46 @@ +#include "fsfw/FSFW.h" +#include "fsfw/serviceinterface.h" +#include "EofPduSerializer.h" + +EofPduSerializer::EofPduSerializer(PduConfig &conf, EofInfo& info): + FileDirectiveSerializer(conf, cfdp::FileDirectives::EOF_DIRECTIVE, 9), info(info) { + setDirectiveDataFieldLen(info.getSerializedSize(getLargeFileFlag())); +} + +size_t EofPduSerializer::getSerializedSize() const { + return FileDirectiveSerializer::getWholePduSize(); +} + +ReturnValue_t EofPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = FileDirectiveSerializer::serialize(buffer, size, maxSize, + streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(*size + 1 > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = info.getConditionCode() << 4; + *buffer += 1; + *size += 1; + uint32_t checksum = info.getChecksum(); + result = SerializeAdapter::serialize(&checksum, buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(info.getFileSize().isLargeFile()) { + uint64_t fileSizeValue = info.getFileSize().getSize(); + result = SerializeAdapter::serialize(&fileSizeValue, buffer, size, + maxSize, streamEndianness); + } + else { + uint32_t fileSizeValue = info.getFileSize().getSize(); + result = SerializeAdapter::serialize(&fileSizeValue, buffer, size, + maxSize, streamEndianness); + } + if(info.getFaultLoc() != nullptr and info.getConditionCode() != cfdp::ConditionCode::NO_ERROR) { + result = info.getFaultLoc()->serialize(buffer, size, maxSize, streamEndianness); + } + return result; +} diff --git a/src/fsfw/cfdp/pdu/EofPduSerializer.h b/src/fsfw/cfdp/pdu/EofPduSerializer.h new file mode 100644 index 00000000..cdc9b0f1 --- /dev/null +++ b/src/fsfw/cfdp/pdu/EofPduSerializer.h @@ -0,0 +1,22 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFPDUSERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_EOFPDUSERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" +#include "fsfw/cfdp/tlv/EntityIdTlv.h" +#include "EofInfo.h" + +class EofPduSerializer: public FileDirectiveSerializer { +public: + EofPduSerializer(PduConfig &conf, EofInfo& info); + + size_t getSerializedSize() const override; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; +private: + EofInfo& info; +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_EOFPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FileDataDeserializer.cpp b/src/fsfw/cfdp/pdu/FileDataDeserializer.cpp new file mode 100644 index 00000000..80106edf --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDataDeserializer.cpp @@ -0,0 +1,52 @@ +#include "FileDataDeserializer.h" + +FileDataDeserializer::FileDataDeserializer(const uint8_t *pduBuf, size_t maxSize, + FileDataInfo& info): + HeaderDeserializer(pduBuf, maxSize), info(info) { +} + +ReturnValue_t FileDataDeserializer::parseData() { + ReturnValue_t result = HeaderDeserializer::parseData(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t currentIdx = HeaderDeserializer::getHeaderSize(); + const uint8_t* buf = rawPtr + currentIdx; + size_t remSize = HeaderDeserializer::getWholePduSize() - currentIdx; + if (remSize < 1) { + return SerializeIF::STREAM_TOO_SHORT; + } + if(hasSegmentMetadataFlag()) { + info.setSegmentMetadataFlag(true); + info.setRecordContinuationState(static_cast( + (*buf >> 6) & 0b11)); + size_t segmentMetadataLen = *buf & 0b00111111; + info.setSegmentMetadataLen(segmentMetadataLen); + if(remSize < segmentMetadataLen + 1) { + return SerializeIF::STREAM_TOO_SHORT; + } + if(segmentMetadataLen > 0) { + buf += 1; + remSize -= 1; + info.setSegmentMetadata(buf); + buf += segmentMetadataLen; + remSize -= segmentMetadataLen; + } + } + result = info.getOffset().deSerialize(&buf, &remSize, this->getEndianness()); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(remSize > 0) { + info.setFileData(buf, remSize); + } + return HasReturnvaluesIF::RETURN_OK; +} + +SerializeIF::Endianness FileDataDeserializer::getEndianness() const { + return endianness; +} + +void FileDataDeserializer::setEndianness(SerializeIF::Endianness endianness) { + this->endianness = endianness; +} diff --git a/src/fsfw/cfdp/pdu/FileDataDeserializer.h b/src/fsfw/cfdp/pdu/FileDataDeserializer.h new file mode 100644 index 00000000..13532d95 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDataDeserializer.h @@ -0,0 +1,22 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDATADESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_FILEDATADESERIALIZER_H_ + +#include "FileDataInfo.h" +#include "HeaderDeserializer.h" +#include "../definitions.h" + +class FileDataDeserializer: public HeaderDeserializer { +public: + FileDataDeserializer(const uint8_t* pduBuf, size_t maxSize, FileDataInfo& info); + + ReturnValue_t parseData(); + SerializeIF::Endianness getEndianness() const; + void setEndianness(SerializeIF::Endianness endianness = SerializeIF::Endianness::NETWORK); + +private: + + SerializeIF::Endianness endianness = SerializeIF::Endianness::NETWORK; + FileDataInfo& info; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_FILEDATADESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FileDataInfo.cpp b/src/fsfw/cfdp/pdu/FileDataInfo.cpp new file mode 100644 index 00000000..1698f5e0 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDataInfo.cpp @@ -0,0 +1,104 @@ +#include "FileDataInfo.h" + +FileDataInfo::FileDataInfo(cfdp::FileSize &offset, const uint8_t *fileData, size_t fileSize): + offset(offset), fileData(fileData), fileSize(fileSize) { +} + +FileDataInfo::FileDataInfo(cfdp::FileSize &offset): offset(offset) { +} + +void FileDataInfo::setSegmentMetadataFlag(bool enable) { + if(enable) { + segmentMetadataFlag = cfdp::SegmentMetadataFlag::PRESENT; + } else { + segmentMetadataFlag = cfdp::SegmentMetadataFlag::NOT_PRESENT; + } +} + +size_t FileDataInfo::getSerializedSize(bool largeFile) const { + size_t sz = 0; + if(segmentMetadataFlag == cfdp::SegmentMetadataFlag::PRESENT) { + sz += 1 + segmentMetadataLen; + } + if(largeFile) { + sz += 8; + } else { + sz += 4; + } + sz += fileSize; + return sz; +} + +cfdp::SegmentMetadataFlag FileDataInfo::getSegmentMetadataFlag() const { + return this->segmentMetadataFlag; +} + +bool FileDataInfo::hasSegmentMetadata() const { + if(segmentMetadataFlag == cfdp::SegmentMetadataFlag::PRESENT) { + return true; + } + return false; +} + +cfdp::RecordContinuationState FileDataInfo::getRecordContinuationState() const { + return this->recContState; +} + +size_t FileDataInfo::getSegmentMetadataLen() const { + return segmentMetadataLen; +} + +ReturnValue_t FileDataInfo::addSegmentMetadataInfo(cfdp::RecordContinuationState recContState, + const uint8_t* segmentMetadata, size_t segmentMetadataLen) { + this->segmentMetadataFlag = cfdp::SegmentMetadataFlag::PRESENT; + this->recContState = recContState; + if(segmentMetadataLen > 63) { + return HasReturnvaluesIF::RETURN_FAILED; + } + this->segmentMetadata = segmentMetadata; + this->segmentMetadataLen = segmentMetadataLen; + return HasReturnvaluesIF::RETURN_OK; +} + +const uint8_t* FileDataInfo::getFileData(size_t *fileSize) const { + if(fileSize != nullptr) { + *fileSize = this->fileSize; + } + return fileData; +} + +const uint8_t* FileDataInfo::getSegmentMetadata(size_t *segmentMetadataLen) { + if(segmentMetadataLen != nullptr) { + *segmentMetadataLen = this->segmentMetadataLen; + } + return segmentMetadata; +} + +cfdp::FileSize& FileDataInfo::getOffset() { + return offset; +} + +void FileDataInfo::setRecordContinuationState(cfdp::RecordContinuationState recContState) { + this->recContState = recContState; +} + +void FileDataInfo::setSegmentMetadataLen(size_t len) { + this->segmentMetadataLen = len; +} + +void FileDataInfo::setSegmentMetadata(const uint8_t *ptr) { + this->segmentMetadata = ptr; +} + +void FileDataInfo::setFileData(const uint8_t *fileData, size_t fileSize) { + this->fileData = fileData; + this->fileSize = fileSize; +} + +cfdp::SegmentationControl FileDataInfo::getSegmentationControl() const { + return segCtrl; +} + +void FileDataInfo::setSegmentationControl(cfdp::SegmentationControl segCtrl) { + this->segCtrl = segCtrl; +} diff --git a/src/fsfw/cfdp/pdu/FileDataInfo.h b/src/fsfw/cfdp/pdu/FileDataInfo.h new file mode 100644 index 00000000..1fcc6ff0 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDataInfo.h @@ -0,0 +1,45 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_ + +#include +#include + +class FileDataInfo { +public: + FileDataInfo(cfdp::FileSize& offset); + FileDataInfo(cfdp::FileSize& offset, const uint8_t* fileData, size_t fileSize); + + size_t getSerializedSize(bool largeFile = false) const; + + cfdp::FileSize& getOffset(); + const uint8_t* getFileData(size_t* fileSize = nullptr) const; + void setFileData(const uint8_t* fileData, size_t fileSize); + + cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const; + cfdp::SegmentationControl getSegmentationControl() const; + cfdp::RecordContinuationState getRecordContinuationState() const; + void setRecordContinuationState(cfdp::RecordContinuationState recContState); + void setSegmentationControl(cfdp::SegmentationControl segCtrl); + + size_t getSegmentMetadataLen() const; + void setSegmentMetadataLen(size_t len); + void setSegmentMetadata(const uint8_t* ptr); + bool hasSegmentMetadata() const; + void setSegmentMetadataFlag(bool enable); + ReturnValue_t addSegmentMetadataInfo(cfdp::RecordContinuationState recContState, + const uint8_t* segmentMetadata, size_t segmentMetadataLen); + const uint8_t* getSegmentMetadata(size_t* segmentMetadataLen = nullptr); + +private: + cfdp::SegmentMetadataFlag segmentMetadataFlag = cfdp::SegmentMetadataFlag::NOT_PRESENT; + cfdp::SegmentationControl segCtrl = + cfdp::SegmentationControl::NO_RECORD_BOUNDARIES_PRESERVATION; + cfdp::FileSize& offset; + const uint8_t* fileData = nullptr; + size_t fileSize = 0; + cfdp::RecordContinuationState recContState = cfdp::RecordContinuationState::NO_START_NO_END; + size_t segmentMetadataLen = 0; + const uint8_t* segmentMetadata = nullptr; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_ */ diff --git a/src/fsfw/cfdp/pdu/FileDataSerializer.cpp b/src/fsfw/cfdp/pdu/FileDataSerializer.cpp new file mode 100644 index 00000000..4488e368 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDataSerializer.cpp @@ -0,0 +1,54 @@ +#include "FileDataSerializer.h" +#include + +FileDataSerializer::FileDataSerializer(PduConfig& conf, FileDataInfo& info): + HeaderSerializer(conf, cfdp::PduType::FILE_DATA, 0, info.getSegmentMetadataFlag()), + info(info) { + update(); +} + +void FileDataSerializer::update() { + this->setSegmentMetadataFlag(info.getSegmentMetadataFlag()); + this->setSegmentationControl(info.getSegmentationControl()); + setPduDataFieldLen(info.getSerializedSize(this->getLargeFileFlag())); +} + +ReturnValue_t FileDataSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = HeaderSerializer::serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(*size + this->getSerializedSize() > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + const uint8_t* readOnlyPtr = nullptr; + if (this->hasSegmentMetadataFlag()) { + size_t segmentMetadataLen = info.getSegmentMetadataLen(); + **buffer = info.getRecordContinuationState() << 6 | segmentMetadataLen; + *buffer += 1; + *size += 1; + readOnlyPtr = info.getSegmentMetadata(); + std::memcpy(*buffer, readOnlyPtr, segmentMetadataLen); + *buffer += segmentMetadataLen; + *size += segmentMetadataLen; + } + cfdp::FileSize& offset = info.getOffset(); + result = offset.serialize(this->getLargeFileFlag(), buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t fileSize = 0; + readOnlyPtr = info.getFileData(&fileSize); + if(*size + fileSize > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + std::memcpy(*buffer, readOnlyPtr, fileSize); + *buffer += fileSize; + *size += fileSize; + return HasReturnvaluesIF::RETURN_OK; +} + +size_t FileDataSerializer::getSerializedSize() const { + return HeaderSerializer::getSerializedSize() + info.getSerializedSize(this->getLargeFileFlag()); +} diff --git a/src/fsfw/cfdp/pdu/FileDataSerializer.h b/src/fsfw/cfdp/pdu/FileDataSerializer.h new file mode 100644 index 00000000..b0153528 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDataSerializer.h @@ -0,0 +1,23 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDATASERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_FILEDATASERIALIZER_H_ + +#include "FileDataInfo.h" +#include "../definitions.h" +#include "HeaderSerializer.h" + +class FileDataSerializer: public HeaderSerializer { +public: + FileDataSerializer(PduConfig& conf, FileDataInfo& info); + + void update(); + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; + + size_t getSerializedSize() const override; + +private: + FileDataInfo& info; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_FILEDATADESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FileDirectiveDeserializer.cpp b/src/fsfw/cfdp/pdu/FileDirectiveDeserializer.cpp new file mode 100644 index 00000000..b348c5bd --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDirectiveDeserializer.cpp @@ -0,0 +1,55 @@ +#include "FileDirectiveDeserializer.h" + +FileDirectiveDeserializer::FileDirectiveDeserializer(const uint8_t *pduBuf, size_t maxSize): + HeaderDeserializer(pduBuf, maxSize) { +} + +cfdp::FileDirectives FileDirectiveDeserializer::getFileDirective() const { + return fileDirective; +} + +ReturnValue_t FileDirectiveDeserializer::parseData() { + ReturnValue_t result = HeaderDeserializer::parseData(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(this->getPduDataFieldLen() < 1) { + return cfdp::INVALID_PDU_DATAFIELD_LEN; + } + if(FileDirectiveDeserializer::getWholePduSize() > maxSize) { + return SerializeIF::STREAM_TOO_SHORT; + } + size_t currentIdx = HeaderDeserializer::getHeaderSize(); + if(not checkFileDirective(rawPtr[currentIdx])) { + return cfdp::INVALID_DIRECTIVE_FIELDS; + } + setFileDirective(static_cast(rawPtr[currentIdx])); + return HasReturnvaluesIF::RETURN_OK; +} + +size_t FileDirectiveDeserializer::getHeaderSize() const { + // return size of header plus the directive byte + return HeaderDeserializer::getHeaderSize() + 1; +} + +bool FileDirectiveDeserializer::checkFileDirective(uint8_t rawByte) { + if(rawByte < cfdp::FileDirectives::EOF_DIRECTIVE or + (rawByte > cfdp::FileDirectives::PROMPT and + rawByte != cfdp::FileDirectives::KEEP_ALIVE)) { + // Invalid directive field. TODO: Custom returnvalue + return false; + } + return true; +} + +void FileDirectiveDeserializer::setFileDirective(cfdp::FileDirectives fileDirective) { + this->fileDirective = fileDirective; +} + +void FileDirectiveDeserializer::setEndianness(SerializeIF::Endianness endianness) { + this->endianness = endianness; +} + +SerializeIF::Endianness FileDirectiveDeserializer::getEndianness() const { + return endianness; +} diff --git a/src/fsfw/cfdp/pdu/FileDirectiveDeserializer.h b/src/fsfw/cfdp/pdu/FileDirectiveDeserializer.h new file mode 100644 index 00000000..257fb5c0 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDirectiveDeserializer.h @@ -0,0 +1,41 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVEDESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVEDESERIALIZER_H_ + +#include "../definitions.h" +#include "fsfw/cfdp/pdu/HeaderDeserializer.h" + +/** + * @brief This class is used to deserialize a PDU file directive header from raw memory. + * @details + * Base class for other file directives. + * This is a zero-copy implementation and #parseData needs to be called to ensure the data is + * valid. + */ +class FileDirectiveDeserializer: public HeaderDeserializer { +public: + FileDirectiveDeserializer(const uint8_t* pduBuf, size_t maxSize); + + /** + * This needs to be called before accessing the PDU fields to avoid segmentation faults. + * @return + */ + virtual ReturnValue_t parseData(); + size_t getHeaderSize() const; + + cfdp::FileDirectives getFileDirective() const; + + void setEndianness(SerializeIF::Endianness endianness); + SerializeIF::Endianness getEndianness() const; + +protected: + bool checkFileDirective(uint8_t rawByte); + +private: + void setFileDirective(cfdp::FileDirectives fileDirective); + cfdp::FileDirectives fileDirective = cfdp::FileDirectives::INVALID_DIRECTIVE; + SerializeIF::Endianness endianness = SerializeIF::Endianness::NETWORK; +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVEDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FileDirectiveSerializer.cpp b/src/fsfw/cfdp/pdu/FileDirectiveSerializer.cpp new file mode 100644 index 00000000..89600d1d --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDirectiveSerializer.cpp @@ -0,0 +1,39 @@ +#include "FileDirectiveSerializer.h" + + +FileDirectiveSerializer::FileDirectiveSerializer(PduConfig &pduConf, + cfdp::FileDirectives directiveCode, size_t directiveParamFieldLen): + HeaderSerializer(pduConf, cfdp::PduType::FILE_DIRECTIVE, directiveParamFieldLen + 1), + directiveCode(directiveCode) { +} + +size_t FileDirectiveSerializer::getSerializedSize() const { + return HeaderSerializer::getSerializedSize() + 1; +} + +ReturnValue_t FileDirectiveSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + if(buffer == nullptr or size == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(FileDirectiveSerializer::getWholePduSize() > maxSize) { + return BUFFER_TOO_SHORT; + } + ReturnValue_t result = HeaderSerializer::serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + if(*size >= maxSize) { + return BUFFER_TOO_SHORT; + } + **buffer = directiveCode; + *buffer += 1; + *size += 1; + return HasReturnvaluesIF::RETURN_OK; +} + +void FileDirectiveSerializer::setDirectiveDataFieldLen(size_t len) { + // Set length of data field plus 1 byte for the directive octet + HeaderSerializer::setPduDataFieldLen(len + 1); +} diff --git a/src/fsfw/cfdp/pdu/FileDirectiveSerializer.h b/src/fsfw/cfdp/pdu/FileDirectiveSerializer.h new file mode 100644 index 00000000..75a3582d --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDirectiveSerializer.h @@ -0,0 +1,28 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVESERIALIZER_H_ + +#include "fsfw/cfdp/pdu/HeaderSerializer.h" + +class FileDirectiveSerializer: public HeaderSerializer { +public: + FileDirectiveSerializer(PduConfig& pduConf, cfdp::FileDirectives directiveCode, + size_t directiveParamFieldLen); + + /** + * This only returns the size of the PDU header + 1 for the directive code octet. + * Use FileDirectiveSerializer::getWholePduSize to get the full packet length, assuming + * the length fields was set correctly + * @return + */ + size_t getSerializedSize() const override; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; + + void setDirectiveDataFieldLen(size_t len); +private: + cfdp::FileDirectives directiveCode = cfdp::FileDirectives::INVALID_DIRECTIVE; + +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FinishedInfo.cpp b/src/fsfw/cfdp/pdu/FinishedInfo.cpp new file mode 100644 index 00000000..e6b7e9b4 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FinishedInfo.cpp @@ -0,0 +1,111 @@ +#include "FinishedInfo.h" + +FinishedInfo::FinishedInfo() { +} + + +FinishedInfo::FinishedInfo(cfdp::ConditionCode conditionCode, + cfdp::FinishedDeliveryCode deliveryCode, cfdp::FinishedFileStatus fileStatus): + conditionCode(conditionCode), deliveryCode(deliveryCode), fileStatus(fileStatus) { +} + +size_t FinishedInfo::getSerializedSize() const { + size_t size = 1; + if(hasFsResponses()) { + for(size_t idx = 0; idx < fsResponsesLen; idx++) { + size += fsResponses[idx]->getSerializedSize(); + } + } + if(this->faultLocation != nullptr) { + size += faultLocation->getSerializedSize(); + } + return size; +} + +bool FinishedInfo::hasFsResponses() const { + if(fsResponses != nullptr and fsResponsesLen > 0) { + return true; + } + return false; +} +bool FinishedInfo::canHoldFsResponses() const { + if(fsResponses != nullptr and fsResponsesMaxLen > 0) { + return true; + } + return false; +} + + +ReturnValue_t FinishedInfo::setFilestoreResponsesArray(FilestoreResponseTlv** fsResponses, + size_t* fsResponsesLen, const size_t* maxFsResponsesLen) { + this->fsResponses = fsResponses; + if(fsResponsesLen != nullptr) { + this->fsResponsesLen = *fsResponsesLen; + if(this->fsResponsesMaxLen < *fsResponsesLen) { + this->fsResponsesMaxLen = this->fsResponsesLen; + } + } + if(maxFsResponsesLen != nullptr) { + this->fsResponsesMaxLen = *maxFsResponsesLen; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FinishedInfo::getFilestoreResonses(FilestoreResponseTlv ***fsResponses, + size_t *fsResponsesLen, size_t* fsResponsesMaxLen) { + if(fsResponses == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + *fsResponses = this->fsResponses; + if(fsResponsesLen != nullptr) { + *fsResponsesLen = this->fsResponsesLen; + } + if(fsResponsesMaxLen != nullptr) { + *fsResponsesMaxLen = this->fsResponsesMaxLen; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void FinishedInfo::setFaultLocation(EntityIdTlv *faultLocation) { + this->faultLocation = faultLocation; +} + +ReturnValue_t FinishedInfo::getFaultLocation(EntityIdTlv** faultLocation) { + if(this->faultLocation == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + *faultLocation = this->faultLocation; + return HasReturnvaluesIF::RETURN_OK; +} + +cfdp::ConditionCode FinishedInfo::getConditionCode() const { + return conditionCode; +} + +void FinishedInfo::setConditionCode(cfdp::ConditionCode conditionCode) { + this->conditionCode = conditionCode; +} + +cfdp::FinishedDeliveryCode FinishedInfo::getDeliveryCode() const { + return deliveryCode; +} + +void FinishedInfo::setDeliveryCode(cfdp::FinishedDeliveryCode deliveryCode) { + this->deliveryCode = deliveryCode; +} + +cfdp::FinishedFileStatus FinishedInfo::getFileStatus() const { + return fileStatus; +} + +void FinishedInfo::setFilestoreResponsesArrayLen(size_t fsResponsesLen) { + this->fsResponsesLen = fsResponsesLen; +} + +size_t FinishedInfo::getFsResponsesLen() const { + return fsResponsesLen; +} + +void FinishedInfo::setFileStatus(cfdp::FinishedFileStatus fileStatus) { + this->fileStatus = fileStatus; +} diff --git a/src/fsfw/cfdp/pdu/FinishedInfo.h b/src/fsfw/cfdp/pdu/FinishedInfo.h new file mode 100644 index 00000000..18552df5 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FinishedInfo.h @@ -0,0 +1,45 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_FINISHINFO_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_FINISHINFO_H_ + +#include "fsfw/cfdp/tlv/EntityIdTlv.h" +#include "fsfw/cfdp/tlv/FilestoreResponseTlv.h" +#include "../definitions.h" + +class FinishedInfo { +public: + FinishedInfo(); + FinishedInfo(cfdp::ConditionCode conditionCode, cfdp::FinishedDeliveryCode deliveryCode, + cfdp::FinishedFileStatus fileStatus); + + size_t getSerializedSize() const; + + bool hasFsResponses() const; + bool canHoldFsResponses() const; + + ReturnValue_t setFilestoreResponsesArray(FilestoreResponseTlv** fsResponses, + size_t* fsResponsesLen, const size_t* maxFsResponseLen); + void setFaultLocation(EntityIdTlv* entityId); + + ReturnValue_t getFilestoreResonses(FilestoreResponseTlv ***fsResponses, + size_t *fsResponsesLen, size_t* fsResponsesMaxLen); + size_t getFsResponsesLen() const; + void setFilestoreResponsesArrayLen(size_t fsResponsesLen); + ReturnValue_t getFaultLocation(EntityIdTlv** entityId); + cfdp::ConditionCode getConditionCode() const; + void setConditionCode(cfdp::ConditionCode conditionCode); + cfdp::FinishedDeliveryCode getDeliveryCode() const; + void setDeliveryCode(cfdp::FinishedDeliveryCode deliveryCode); + cfdp::FinishedFileStatus getFileStatus() const; + void setFileStatus(cfdp::FinishedFileStatus fileStatus); + +private: + cfdp::ConditionCode conditionCode = cfdp::ConditionCode::NO_CONDITION_FIELD; + cfdp::FinishedDeliveryCode deliveryCode = cfdp::FinishedDeliveryCode::DATA_COMPLETE; + cfdp::FinishedFileStatus fileStatus = cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY; + FilestoreResponseTlv** fsResponses = nullptr; + size_t fsResponsesLen = 0; + size_t fsResponsesMaxLen = 0; + EntityIdTlv* faultLocation = nullptr; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_FINISHINFO_H_ */ diff --git a/src/fsfw/cfdp/pdu/FinishedPduDeserializer.cpp b/src/fsfw/cfdp/pdu/FinishedPduDeserializer.cpp new file mode 100644 index 00000000..55528650 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FinishedPduDeserializer.cpp @@ -0,0 +1,90 @@ +#include "FinishedPduDeserializer.h" + +FinishPduDeserializer::FinishPduDeserializer(const uint8_t *pduBuf, size_t maxSize, + FinishedInfo &info): FileDirectiveDeserializer(pduBuf, maxSize), finishedInfo(info) { +} + +ReturnValue_t FinishPduDeserializer::parseData() { + ReturnValue_t result = FileDirectiveDeserializer::parseData(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); + const uint8_t* buf = rawPtr + currentIdx; + size_t remSize = FileDirectiveDeserializer::getWholePduSize() - currentIdx; + if (remSize < 1) { + return SerializeIF::STREAM_TOO_SHORT; + } + uint8_t firstByte = *buf; + cfdp::ConditionCode condCode = static_cast((firstByte >> 4) & 0x0f); + finishedInfo.setConditionCode(condCode); + finishedInfo.setDeliveryCode(static_cast(firstByte >> 2 & 0b1)); + finishedInfo.setFileStatus(static_cast(firstByte & 0b11)); + buf += 1; + remSize -= 1; + currentIdx += 1; + if(remSize > 0) { + result = parseTlvs(remSize, currentIdx, buf, condCode); + } + return result; +} + +FinishedInfo& FinishPduDeserializer::getInfo() { + return finishedInfo; +} + +ReturnValue_t FinishPduDeserializer::parseTlvs(size_t remLen, size_t currentIdx, + const uint8_t* buf, cfdp::ConditionCode conditionCode) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + size_t fsResponsesIdx = 0; + auto endianness = getEndianness(); + FilestoreResponseTlv** fsResponseArray = nullptr; + size_t fsResponseMaxArrayLen = 0; + EntityIdTlv* faultLocation = nullptr; + cfdp::TlvTypes nextTlv = cfdp::TlvTypes::INVALID_TLV; + while(remLen > 0) { + // Simply forward parse the TLV type. Every TLV type except the last one must be a Filestore + // Response TLV, and even the last one can be a Filestore Response TLV if the fault + // location is omitted + if (currentIdx + 2 > maxSize) { + return SerializeIF::STREAM_TOO_SHORT; + } + nextTlv = static_cast(*buf); + if (nextTlv == cfdp::TlvTypes::FILESTORE_RESPONSE) { + if(fsResponseArray == nullptr) { + if(not finishedInfo.canHoldFsResponses()) { + return cfdp::FINISHED_CANT_PARSE_FS_RESPONSES; + } + result = finishedInfo.getFilestoreResonses(&fsResponseArray, nullptr, + &fsResponseMaxArrayLen); + } + if(fsResponsesIdx == fsResponseMaxArrayLen) { + return cfdp::FINISHED_CANT_PARSE_FS_RESPONSES; + } + result = fsResponseArray[fsResponsesIdx]->deSerialize(&buf, &remLen, endianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + fsResponsesIdx += 1; + } else if(nextTlv == cfdp::TlvTypes::ENTITY_ID) { + // This needs to be the last TLV and it should not be here if the condition code + // is "No Error" or "Unsupported Checksum Type" + if(conditionCode == cfdp::ConditionCode::NO_ERROR or + conditionCode == cfdp::ConditionCode::UNSUPPORTED_CHECKSUM_TYPE) { + return cfdp::INVALID_TLV_TYPE; + } + result = finishedInfo.getFaultLocation(&faultLocation); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = faultLocation->deSerialize(&buf, &remLen, endianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } else { + return cfdp::INVALID_TLV_TYPE; + } + } + finishedInfo.setFilestoreResponsesArrayLen(fsResponsesIdx); + return result; +} diff --git a/src/fsfw/cfdp/pdu/FinishedPduDeserializer.h b/src/fsfw/cfdp/pdu/FinishedPduDeserializer.h new file mode 100644 index 00000000..dcbc23bd --- /dev/null +++ b/src/fsfw/cfdp/pdu/FinishedPduDeserializer.h @@ -0,0 +1,21 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_FINISHEDPDUDESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_FINISHEDPDUDESERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FinishedInfo.h" +#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" + +class FinishPduDeserializer: public FileDirectiveDeserializer { +public: + FinishPduDeserializer(const uint8_t *pduBuf, size_t maxSize, FinishedInfo& info); + + ReturnValue_t parseData() override; + + FinishedInfo& getInfo(); +private: + FinishedInfo& finishedInfo; + + ReturnValue_t parseTlvs(size_t remLen, size_t currentIdx, const uint8_t* buf, + cfdp::ConditionCode conditionCode); +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_FINISHEDPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FinishedPduSerializer.cpp b/src/fsfw/cfdp/pdu/FinishedPduSerializer.cpp new file mode 100644 index 00000000..98112ce2 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FinishedPduSerializer.cpp @@ -0,0 +1,47 @@ +#include "FinishedPduSerializer.h" + +FinishPduSerializer::FinishPduSerializer(PduConfig &conf, FinishedInfo &finishInfo): + FileDirectiveSerializer(conf, cfdp::FileDirectives::FINISH, 0), finishInfo(finishInfo) { + updateDirectiveFieldLen(); +} + +size_t FinishPduSerializer::getSerializedSize() const { + return FinishPduSerializer::getWholePduSize(); +} + +void FinishPduSerializer::updateDirectiveFieldLen() { + setDirectiveDataFieldLen(finishInfo.getSerializedSize()); +} + +ReturnValue_t FinishPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = FileDirectiveSerializer::serialize(buffer, size, maxSize, + streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(*size + 1 >= maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = finishInfo.getConditionCode() << 4 | finishInfo.getDeliveryCode() << 2 | + finishInfo.getFileStatus(); + *size += 1; + *buffer += 1; + + if(finishInfo.hasFsResponses()) { + FilestoreResponseTlv** fsResponsesArray = nullptr; + size_t fsResponsesArrayLen = 0; + finishInfo.getFilestoreResonses(&fsResponsesArray, &fsResponsesArrayLen, nullptr); + for(size_t idx = 0; idx < fsResponsesArrayLen; idx++) { + result = fsResponsesArray[idx]->serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + } + EntityIdTlv* entityId = nullptr; + if(finishInfo.getFaultLocation(&entityId) == HasReturnvaluesIF::RETURN_OK) { + result = entityId->serialize(buffer, size, maxSize, streamEndianness); + } + return result; +} diff --git a/src/fsfw/cfdp/pdu/FinishedPduSerializer.h b/src/fsfw/cfdp/pdu/FinishedPduSerializer.h new file mode 100644 index 00000000..cfb067a5 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FinishedPduSerializer.h @@ -0,0 +1,22 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_FINISHEDPDUSERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_FINISHEDPDUSERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" +#include "fsfw/cfdp/pdu/FileDataSerializer.h" +#include "FinishedInfo.h" + +class FinishPduSerializer: public FileDirectiveSerializer { +public: + FinishPduSerializer(PduConfig& pduConf, FinishedInfo& finishInfo); + + void updateDirectiveFieldLen(); + + size_t getSerializedSize() const override; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; +private: + FinishedInfo& finishInfo; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_FINISHEDPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/HeaderDeserializer.cpp b/src/fsfw/cfdp/pdu/HeaderDeserializer.cpp new file mode 100644 index 00000000..39994eb5 --- /dev/null +++ b/src/fsfw/cfdp/pdu/HeaderDeserializer.cpp @@ -0,0 +1,136 @@ +#include +#include "HeaderDeserializer.h" +#include + +HeaderDeserializer::HeaderDeserializer(const uint8_t *pduBuf, size_t maxSize): + rawPtr(pduBuf), maxSize(maxSize) { +} + +ReturnValue_t HeaderDeserializer::parseData() { + if (maxSize < 7) { + return SerializeIF::STREAM_TOO_SHORT; + } + return setData(const_cast(rawPtr), maxSize); +} + +ReturnValue_t HeaderDeserializer::setData(uint8_t *dataPtr, size_t maxSize, + void* args) { + if(dataPtr == nullptr) { + // Allowed for now + this->fixedHeader = nullptr; + return HasReturnvaluesIF::RETURN_OK; + } + this->fixedHeader = reinterpret_cast(const_cast(dataPtr)); + sourceIdRaw = static_cast(&fixedHeader->variableFieldsStart); + cfdp::WidthInBytes widthEntityIds = getLenEntityIds(); + cfdp::WidthInBytes widthSeqNum = getLenSeqNum(); + seqNumRaw = static_cast(sourceIdRaw) + static_cast(widthEntityIds); + destIdRaw = static_cast(seqNumRaw) + static_cast(widthSeqNum); + this->maxSize = maxSize; + return HasReturnvaluesIF::RETURN_OK; +} + +size_t HeaderDeserializer::getHeaderSize() const { + if(fixedHeader != nullptr) { + return getLenEntityIds() * 2 + getLenSeqNum() + 4; + } + return 0; +} + +size_t HeaderDeserializer::getPduDataFieldLen() const { + uint16_t pduFiedlLen = (fixedHeader->pduDataFieldLenH << 8) | fixedHeader->pduDataFieldLenL; + return pduFiedlLen; +} + +size_t HeaderDeserializer::getWholePduSize() const { + return getPduDataFieldLen() + getHeaderSize(); +} + +cfdp::PduType HeaderDeserializer::getPduType() const { + return static_cast((fixedHeader->firstByte >> 4) & 0x01); +} + +cfdp::Direction HeaderDeserializer::getDirection() const { + return static_cast((fixedHeader->firstByte >> 3) & 0x01); +} + +cfdp::TransmissionModes HeaderDeserializer::getTransmissionMode() const { + return static_cast((fixedHeader->firstByte >> 2) & 0x01); +} + +bool HeaderDeserializer::getCrcFlag() const { + return (fixedHeader->firstByte >> 1) & 0x01; +} + +bool HeaderDeserializer::getLargeFileFlag() const { + return fixedHeader->firstByte & 0x01; +} + +cfdp::SegmentationControl HeaderDeserializer::getSegmentationControl() const { + return static_cast((fixedHeader->fourthByte >> 7) & 0x01); +} + +cfdp::WidthInBytes HeaderDeserializer::getLenEntityIds() const { + return static_cast((fixedHeader->fourthByte >> 4) & 0x07); +} + +cfdp::WidthInBytes HeaderDeserializer::getLenSeqNum() const { + return static_cast(fixedHeader->fourthByte & 0x07); +} + +cfdp::SegmentMetadataFlag HeaderDeserializer::getSegmentMetadataFlag() const { + return static_cast((fixedHeader->fourthByte >> 3) & 0x01); +} + +void HeaderDeserializer::getSourceId(cfdp::EntityId &sourceId) const { + assignVarLenField(dynamic_cast(&sourceId), getLenEntityIds(), + this->sourceIdRaw); +} + +void HeaderDeserializer::getDestId(cfdp::EntityId &destId) const { + assignVarLenField(dynamic_cast(&destId), getLenEntityIds(), + this->destIdRaw); +} + +void HeaderDeserializer::getTransactionSeqNum(cfdp::TransactionSeqNum &seqNum) const { + assignVarLenField(dynamic_cast(&seqNum), getLenSeqNum(), + this->seqNumRaw); +} + +void HeaderDeserializer::assignVarLenField(cfdp::VarLenField* field, cfdp::WidthInBytes width, + void *sourcePtr) const { + switch(width) { + case(cfdp::WidthInBytes::ONE_BYTE): { + uint8_t* fieldTyped = static_cast(sourcePtr); + field->setValue(width, *fieldTyped); + break; + } + case(cfdp::WidthInBytes::TWO_BYTES): { + uint16_t fieldTyped = 0; + size_t deserSize = 0; + SerializeAdapter::deSerialize(&fieldTyped, static_cast(sourcePtr), &deserSize, + SerializeIF::Endianness::NETWORK); + field->setValue(width, fieldTyped); + break; + } + case(cfdp::WidthInBytes::FOUR_BYTES): { + uint32_t fieldTyped = 0; + size_t deserSize = 0; + SerializeAdapter::deSerialize(&fieldTyped, static_cast(sourcePtr), &deserSize, + SerializeIF::Endianness::NETWORK); + field->setValue(width, fieldTyped); + break; + } + } +} + +size_t HeaderDeserializer::getMaxSize() const { + return maxSize; +} + +bool HeaderDeserializer::hasSegmentMetadataFlag() const { + if(this->getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT) { + return true; + } + return false; +} diff --git a/src/fsfw/cfdp/pdu/HeaderDeserializer.h b/src/fsfw/cfdp/pdu/HeaderDeserializer.h new file mode 100644 index 00000000..d44d538f --- /dev/null +++ b/src/fsfw/cfdp/pdu/HeaderDeserializer.h @@ -0,0 +1,93 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_HEADERDESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_HEADERDESERIALIZER_H_ + +#include "PduConfig.h" +#include "PduHeaderIF.h" +#include "fsfw/serialize/SerializeIF.h" +#include "fsfw/tmtcpacket/RedirectableDataPointerIF.h" +#include +#include + +struct PduHeaderFixedStruct { + uint8_t firstByte; + uint8_t pduDataFieldLenH; + uint8_t pduDataFieldLenL; + uint8_t fourthByte; + uint8_t variableFieldsStart; +}; + +/** + * @brief This class is used to deserialize a PDU header from raw memory. + * @details + * This is a zero-copy implementation and #parseData needs to be called to ensure the data is + * valid. + */ +class HeaderDeserializer: + public RedirectableDataPointerIF, + public PduHeaderIF { +public: + /** + * Initialize a PDU header from raw data. This is a zero-copy implementation and #parseData + * needs to be called to ensure the data is valid + * @param pduBuf + * @param maxSize + */ + HeaderDeserializer(const uint8_t* pduBuf, size_t maxSize); + + /** + * This needs to be called before accessing the PDU fields to avoid segmentation faults. + * @return + * - RETURN_OK on parse success + * - RETURN_FAILED Invalid raw data + * - SerializeIF::BUFFER_TOO_SHORT if buffer is shorter than expected + */ + virtual ReturnValue_t parseData(); + size_t getHeaderSize() const; + + size_t getPduDataFieldLen() const override; + size_t getWholePduSize() const override; + + cfdp::PduType getPduType() const override; + cfdp::Direction getDirection() const override; + cfdp::TransmissionModes getTransmissionMode() const override; + bool getCrcFlag() const override; + bool getLargeFileFlag() const override; + cfdp::SegmentationControl getSegmentationControl() const override; + cfdp::WidthInBytes getLenEntityIds() const override; + cfdp::WidthInBytes getLenSeqNum() const override; + cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const override; + bool hasSegmentMetadataFlag() const override; + + void getSourceId(cfdp::EntityId& sourceId) const override; + void getDestId(cfdp::EntityId& destId) const override; + void getTransactionSeqNum(cfdp::TransactionSeqNum& seqNum) const override; + + ReturnValue_t deserResult = HasReturnvaluesIF::RETURN_OK; + + /** + * Can also be used to reset the pointer to a nullptr, but the getter functions will not + * perform nullptr checks! + * @param dataPtr + * @param maxSize + * @param args + * @return + */ + ReturnValue_t setData(uint8_t* dataPtr, size_t maxSize, + void* args = nullptr) override; + + size_t getMaxSize() const; +protected: + PduHeaderFixedStruct* fixedHeader = nullptr; + const uint8_t* rawPtr = nullptr; + size_t maxSize = 0; + +private: + + void assignVarLenField(cfdp::VarLenField* field, cfdp::WidthInBytes width, + void* sourcePtr) const; + void* sourceIdRaw = nullptr; + void* seqNumRaw = nullptr; + void* destIdRaw = nullptr; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_HEADERDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/HeaderSerializer.cpp b/src/fsfw/cfdp/pdu/HeaderSerializer.cpp new file mode 100644 index 00000000..a5163b29 --- /dev/null +++ b/src/fsfw/cfdp/pdu/HeaderSerializer.cpp @@ -0,0 +1,135 @@ +#include "HeaderSerializer.h" +#include "HeaderDeserializer.h" + +HeaderSerializer::HeaderSerializer(PduConfig& pduConf, cfdp::PduType pduType, + size_t initPduDataFieldLen, cfdp::SegmentMetadataFlag segmentMetadataFlag, + cfdp::SegmentationControl segCtrl): + pduType(pduType), segmentMetadataFlag(segmentMetadataFlag), segmentationCtrl(segCtrl), + pduDataFieldLen(initPduDataFieldLen), pduConf(pduConf) { +} + +ReturnValue_t HeaderSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + if(buffer == nullptr or size == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(maxSize < this->getSerializedSize()) { + return BUFFER_TOO_SHORT; + } + **buffer = cfdp::VERSION_BITS | this->pduType << 4 | pduConf.direction << 3 | + pduConf.mode << 2 | pduConf.crcFlag << 1 | pduConf.largeFile; + *buffer += 1; + **buffer = (pduDataFieldLen & 0xff00) >> 8; + *buffer += 1; + **buffer = pduDataFieldLen & 0x00ff; + *buffer += 1; + **buffer = segmentationCtrl << 7 | pduConf.sourceId.getWidth() << 4 | + segmentMetadataFlag << 3 | pduConf.seqNum.getWidth(); + *buffer += 1; + *size += 4; + ReturnValue_t result = pduConf.sourceId.serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = pduConf.seqNum.serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = pduConf.destId.serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + return HasReturnvaluesIF::RETURN_OK; +} + +size_t HeaderSerializer::getSerializedSize() const { + size_t shit = pduConf.seqNum.getWidth() + pduConf.sourceId.getWidth() * 2 + 4; + return shit; +} + +ReturnValue_t HeaderSerializer::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + // We could implement this, but I prefer dedicated classes + return HasReturnvaluesIF::RETURN_FAILED; +} + +size_t HeaderSerializer::getWholePduSize() const { + // Return size of header plus the PDU data field length + return pduDataFieldLen + HeaderSerializer::getSerializedSize(); +} + +size_t HeaderSerializer::getPduDataFieldLen() const { + return pduDataFieldLen; +} + +void HeaderSerializer::setPduDataFieldLen(size_t pduDataFieldLen) { + this->pduDataFieldLen = pduDataFieldLen; +} + +void HeaderSerializer::setPduType(cfdp::PduType pduType) { + this->pduType = pduType; +} + +void HeaderSerializer::setSegmentMetadataFlag(cfdp::SegmentMetadataFlag segmentMetadataFlag) { + this->segmentMetadataFlag = segmentMetadataFlag; +} + +cfdp::PduType HeaderSerializer::getPduType() const { + return pduType; +} + +cfdp::Direction HeaderSerializer::getDirection() const { + return pduConf.direction; +} + +cfdp::TransmissionModes HeaderSerializer::getTransmissionMode() const { + return pduConf.mode; +} + +bool HeaderSerializer::getCrcFlag() const { + return pduConf.crcFlag; +} + +bool HeaderSerializer::getLargeFileFlag() const { + return pduConf.largeFile; +} + +cfdp::SegmentationControl HeaderSerializer::getSegmentationControl() const { + return segmentationCtrl; +} + +cfdp::WidthInBytes HeaderSerializer::getLenEntityIds() const { + return pduConf.sourceId.getWidth(); +} + +cfdp::WidthInBytes HeaderSerializer::getLenSeqNum() const { + return pduConf.seqNum.getWidth(); +} + +cfdp::SegmentMetadataFlag HeaderSerializer::getSegmentMetadataFlag() const { + return segmentMetadataFlag; +} + +void HeaderSerializer::getSourceId(cfdp::EntityId &sourceId) const { + sourceId = pduConf.sourceId; +} + +void HeaderSerializer::getDestId(cfdp::EntityId &destId) const { + destId = pduConf.destId; +} + +void HeaderSerializer::setSegmentationControl(cfdp::SegmentationControl segmentationControl) { + this->segmentationCtrl = segmentationControl; +} + +void HeaderSerializer::getTransactionSeqNum(cfdp::TransactionSeqNum &seqNum) const { + seqNum = pduConf.seqNum; +} + +bool HeaderSerializer::hasSegmentMetadataFlag() const { + if(this->segmentMetadataFlag == cfdp::SegmentMetadataFlag::PRESENT) { + return true; + } + return false; +} diff --git a/src/fsfw/cfdp/pdu/HeaderSerializer.h b/src/fsfw/cfdp/pdu/HeaderSerializer.h new file mode 100644 index 00000000..61e9d74a --- /dev/null +++ b/src/fsfw/cfdp/pdu/HeaderSerializer.h @@ -0,0 +1,64 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_HEADERSERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_HEADERSERIALIZER_H_ + +#include "PduHeaderIF.h" +#include "fsfw/serialize/SerializeIF.h" +#include "../definitions.h" +#include "PduConfig.h" + +class HeaderSerializer: public SerializeIF, public PduHeaderIF { +public: + + HeaderSerializer(PduConfig& pduConf, cfdp::PduType pduType, + size_t initPduDataFieldLen, + cfdp::SegmentMetadataFlag segmentMetadataFlag = cfdp::SegmentMetadataFlag::NOT_PRESENT, + cfdp::SegmentationControl segCtrl = + cfdp::SegmentationControl::NO_RECORD_BOUNDARIES_PRESERVATION); + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; + + /** + * This only returns the length of the serialized hader. + * Use #getWholePduSize to get the length of the full packet, assuming that the PDU + * data field length was not properly. + * @return + */ + size_t getSerializedSize() const override; + + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + void setPduDataFieldLen(size_t pduDataFieldLen); + void setPduType(cfdp::PduType pduType); + void setSegmentMetadataFlag(cfdp::SegmentMetadataFlag); + + size_t getPduDataFieldLen() const override; + size_t getWholePduSize() const override; + + cfdp::PduType getPduType() const override; + cfdp::Direction getDirection() const override; + cfdp::TransmissionModes getTransmissionMode() const override; + bool getCrcFlag() const override; + bool getLargeFileFlag() const override; + cfdp::SegmentationControl getSegmentationControl() const override; + cfdp::WidthInBytes getLenEntityIds() const override; + cfdp::WidthInBytes getLenSeqNum() const override; + cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const override; + bool hasSegmentMetadataFlag() const; + void setSegmentationControl(cfdp::SegmentationControl); + + void getSourceId(cfdp::EntityId& sourceId) const override; + void getDestId(cfdp::EntityId& destId) const override; + void getTransactionSeqNum(cfdp::TransactionSeqNum& seqNum) const override; +private: + cfdp::PduType pduType; + cfdp::SegmentMetadataFlag segmentMetadataFlag; + cfdp::SegmentationControl segmentationCtrl; + size_t pduDataFieldLen; + + PduConfig& pduConf; +}; + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_HEADERSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.cpp b/src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.cpp new file mode 100644 index 00000000..f8778224 --- /dev/null +++ b/src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.cpp @@ -0,0 +1,20 @@ +#include "KeepAlivePduDeserializer.h" + +KeepAlivePduDeserializer::KeepAlivePduDeserializer(const uint8_t *pduBuf, size_t maxSize, + cfdp::FileSize &progress): FileDirectiveDeserializer(pduBuf, maxSize), progress(progress) { +} + +ReturnValue_t KeepAlivePduDeserializer::parseData() { + ReturnValue_t result = FileDirectiveDeserializer::parseData(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); + size_t remLen = FileDirectiveDeserializer::getWholePduSize() - currentIdx; + const uint8_t* buffer = rawPtr + currentIdx; + return progress.deSerialize(&buffer, &remLen, getEndianness()); +} + +cfdp::FileSize& KeepAlivePduDeserializer::getProgress() { + return progress; +} diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.h b/src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.h new file mode 100644 index 00000000..a7016166 --- /dev/null +++ b/src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.h @@ -0,0 +1,18 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_KEEPALIVEPDUDESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_KEEPALIVEPDUDESERIALIZER_H_ + +#include "fsfw/cfdp/FileSize.h" +#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" + +class KeepAlivePduDeserializer: public FileDirectiveDeserializer { +public: + KeepAlivePduDeserializer(const uint8_t *pduBuf, size_t maxSize, cfdp::FileSize& progress); + + ReturnValue_t parseData() override; + + cfdp::FileSize& getProgress(); +private: + cfdp::FileSize& progress; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_KEEPALIVEPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduSerializer.cpp b/src/fsfw/cfdp/pdu/KeepAlivePduSerializer.cpp new file mode 100644 index 00000000..7882562b --- /dev/null +++ b/src/fsfw/cfdp/pdu/KeepAlivePduSerializer.cpp @@ -0,0 +1,26 @@ +#include "KeepAlivePduSerializer.h" + +KeepAlivePduSerializer::KeepAlivePduSerializer(PduConfig &conf, cfdp::FileSize& progress): + FileDirectiveSerializer(conf, cfdp::FileDirectives::KEEP_ALIVE, 4), progress(progress) { + updateDirectiveFieldLen(); +} + +size_t KeepAlivePduSerializer::getSerializedSize() const { + return FileDirectiveSerializer::getWholePduSize(); +} + +void KeepAlivePduSerializer::updateDirectiveFieldLen() { + if(this->getLargeFileFlag()) { + this->setDirectiveDataFieldLen(8); + } +} + +ReturnValue_t KeepAlivePduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = FileDirectiveSerializer::serialize(buffer, size, maxSize, + streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return progress.serialize(this->getLargeFileFlag(), buffer, size, maxSize, streamEndianness); +} diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduSerializer.h b/src/fsfw/cfdp/pdu/KeepAlivePduSerializer.h new file mode 100644 index 00000000..57882d3f --- /dev/null +++ b/src/fsfw/cfdp/pdu/KeepAlivePduSerializer.h @@ -0,0 +1,21 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ + +#include "fsfw/cfdp/FileSize.h" +#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" + +class KeepAlivePduSerializer: public FileDirectiveSerializer { +public: + KeepAlivePduSerializer(PduConfig& conf, cfdp::FileSize& progress); + + void updateDirectiveFieldLen(); + + size_t getSerializedSize() const override; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; +private: + cfdp::FileSize& progress; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/MetadataInfo.cpp b/src/fsfw/cfdp/pdu/MetadataInfo.cpp new file mode 100644 index 00000000..04e0d6d1 --- /dev/null +++ b/src/fsfw/cfdp/pdu/MetadataInfo.cpp @@ -0,0 +1,115 @@ +#include "MetadataInfo.h" + +MetadataInfo::MetadataInfo(bool closureRequested, cfdp::ChecksumType checksumType, + cfdp::FileSize& fileSize, cfdp::Lv& sourceFileName, cfdp::Lv& destFileName): + closureRequested(closureRequested), checksumType(checksumType), fileSize(fileSize), + sourceFileName(sourceFileName), destFileName(destFileName) { +} + +void MetadataInfo::setOptionsArray(cfdp::Tlv** optionsArray, size_t* optionsLen, + size_t* maxOptionsLen) { + this->optionsArray = optionsArray; + if(maxOptionsLen != nullptr) { + this->maxOptionsLen = *maxOptionsLen; + } + if(optionsLen != nullptr) { + this->optionsLen = *optionsLen; + } +} + +cfdp::ChecksumType MetadataInfo::getChecksumType() const { + return checksumType; +} + +void MetadataInfo::setChecksumType(cfdp::ChecksumType checksumType) { + this->checksumType = checksumType; +} + +bool MetadataInfo::isClosureRequested() const { + return closureRequested; +} + +void MetadataInfo::setClosureRequested(bool closureRequested) { + this->closureRequested = closureRequested; +} + +cfdp::Lv& MetadataInfo::getDestFileName() { + return destFileName; +} + +cfdp::FileSize& MetadataInfo::getFileSize() { + return fileSize; +} + +ReturnValue_t MetadataInfo::getOptions(cfdp::Tlv*** optionsArray, size_t *optionsLen, + size_t* maxOptsLen) { + if(optionsArray == nullptr or this->optionsArray == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + *optionsArray = this->optionsArray; + if(optionsLen != nullptr) { + *optionsLen = this->optionsLen; + } + if(maxOptsLen != nullptr) { + *maxOptsLen = this->maxOptionsLen; + } + return HasReturnvaluesIF::RETURN_OK; +} + +bool MetadataInfo::hasOptions() const { + if (optionsArray != nullptr and optionsLen > 0) { + return true; + } + return false; +} + +bool MetadataInfo::canHoldOptions() const { + if (optionsArray != nullptr and maxOptionsLen > 0) { + return true; + } + return false; +} + +size_t MetadataInfo::getSerializedSize(bool fssLarge) { + // 1 byte + minimal FSS 4 bytes + size_t size = 5; + if(fssLarge) { + size += 4; + } + size += sourceFileName.getSerializedSize(); + size += destFileName.getSerializedSize(); + if(hasOptions()) { + for(size_t idx = 0; idx < optionsLen; idx++) { + size += optionsArray[idx]->getSerializedSize(); + } + } + return size; +} + +void MetadataInfo::setDestFileName(cfdp::Lv &destFileName) { + this->destFileName = destFileName; +} + +void MetadataInfo::setSourceFileName(cfdp::Lv &sourceFileName) { + this->sourceFileName = sourceFileName; +} + +size_t MetadataInfo::getMaxOptionsLen() const { + return maxOptionsLen; +} + +void MetadataInfo::setMaxOptionsLen(size_t maxOptionsLen) { + this->maxOptionsLen = maxOptionsLen; +} + +size_t MetadataInfo::getOptionsLen() const { + return optionsLen; +} + +void MetadataInfo::setOptionsLen(size_t optionsLen) { + this->optionsLen = optionsLen; +} + +cfdp::Lv& MetadataInfo::getSourceFileName() { + return sourceFileName; +} diff --git a/src/fsfw/cfdp/pdu/MetadataInfo.h b/src/fsfw/cfdp/pdu/MetadataInfo.h new file mode 100644 index 00000000..c5a9a0ef --- /dev/null +++ b/src/fsfw/cfdp/pdu/MetadataInfo.h @@ -0,0 +1,49 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ + +#include "fsfw/cfdp/tlv/Tlv.h" +#include "fsfw/cfdp/tlv/Lv.h" +#include "fsfw/cfdp/FileSize.h" +#include "fsfw/cfdp/definitions.h" + +class MetadataInfo { +public: + MetadataInfo(bool closureRequested, cfdp::ChecksumType checksumType, cfdp::FileSize& fileSize, + cfdp::Lv& sourceFileName, cfdp::Lv& destFileName); + + size_t getSerializedSize(bool fssLarge = false); + + void setOptionsArray(cfdp::Tlv** optionsArray, size_t* optionsLen, size_t* maxOptionsLen); + cfdp::ChecksumType getChecksumType() const; + void setChecksumType(cfdp::ChecksumType checksumType); + bool isClosureRequested() const; + void setClosureRequested(bool closureRequested = false); + + void setDestFileName(cfdp::Lv& destFileName); + void setSourceFileName(cfdp::Lv& sourceFileName); + + cfdp::Lv& getDestFileName(); + cfdp::Lv& getSourceFileName(); + cfdp::FileSize& getFileSize(); + + bool hasOptions() const; + bool canHoldOptions() const; + ReturnValue_t getOptions(cfdp::Tlv*** optionsArray, size_t* optionsLen, size_t* maxOptsLen); + void setOptionsLen(size_t optionsLen); + size_t getOptionsLen() const; + void setMaxOptionsLen(size_t maxOptionsLen); + size_t getMaxOptionsLen() const; + +private: + bool closureRequested = false; + cfdp::ChecksumType checksumType; + cfdp::FileSize& fileSize; + cfdp::Lv& sourceFileName; + cfdp::Lv& destFileName; + + cfdp::Tlv** optionsArray = nullptr; + size_t optionsLen = 0; + size_t maxOptionsLen = 0; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ */ diff --git a/src/fsfw/cfdp/pdu/MetadataPduDeserializer.cpp b/src/fsfw/cfdp/pdu/MetadataPduDeserializer.cpp new file mode 100644 index 00000000..ccfaf2c9 --- /dev/null +++ b/src/fsfw/cfdp/pdu/MetadataPduDeserializer.cpp @@ -0,0 +1,58 @@ +#include "MetadataPduDeserializer.h" + +MetadataPduDeserializer::MetadataPduDeserializer(const uint8_t *pduBuf, size_t maxSize, + MetadataInfo &info): FileDirectiveDeserializer(pduBuf, maxSize), info(info) { +} + +ReturnValue_t MetadataPduDeserializer::parseData() { + ReturnValue_t result = FileDirectiveDeserializer::parseData(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); + const uint8_t* buf = rawPtr + currentIdx; + size_t remSize = FileDirectiveDeserializer::getWholePduSize() - currentIdx; + if (remSize < 1) { + return SerializeIF::STREAM_TOO_SHORT; + } + info.setClosureRequested((*buf >> 6) & 0x01); + info.setChecksumType(static_cast(*buf & 0x0f)); + remSize -= 1; + buf += 1; + auto endianness = getEndianness(); + result = info.getFileSize().deSerialize(&buf, &remSize, endianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = info.getSourceFileName().deSerialize(&buf, &remSize, endianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = info.getDestFileName().deSerialize(&buf, &remSize, endianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + info.setOptionsLen(0); + if (remSize > 0) { + if(not info.canHoldOptions()) { + return cfdp::METADATA_CANT_PARSE_OPTIONS; + } + cfdp::Tlv** optionsArray = nullptr; + size_t optsMaxLen = 0; + size_t optsIdx = 0; + info.getOptions(&optionsArray, nullptr, &optsMaxLen); + while(remSize > 0) { + if(optsIdx > optsMaxLen) { + return cfdp::METADATA_CANT_PARSE_OPTIONS; + } + result = optionsArray[optsIdx]->deSerialize(&buf, &remSize, endianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + optsIdx++; + } + info.setOptionsLen(optsIdx); + } + return result; +} diff --git a/src/fsfw/cfdp/pdu/MetadataPduDeserializer.h b/src/fsfw/cfdp/pdu/MetadataPduDeserializer.h new file mode 100644 index 00000000..a3b343b4 --- /dev/null +++ b/src/fsfw/cfdp/pdu/MetadataPduDeserializer.h @@ -0,0 +1,18 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_METADATAPDUDESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_METADATAPDUDESERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" +#include "fsfw/cfdp/pdu/MetadataInfo.h" + +class MetadataPduDeserializer: public FileDirectiveDeserializer { +public: + MetadataPduDeserializer(const uint8_t* pduBuf, size_t maxSize, MetadataInfo& info); + + ReturnValue_t parseData() override; +private: + MetadataInfo& info; +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_METADATAPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/MetadataPduSerializer.cpp b/src/fsfw/cfdp/pdu/MetadataPduSerializer.cpp new file mode 100644 index 00000000..1d2d67c2 --- /dev/null +++ b/src/fsfw/cfdp/pdu/MetadataPduSerializer.cpp @@ -0,0 +1,54 @@ +#include "MetadataPduSerializer.h" + +MetadataPduSerializer::MetadataPduSerializer(PduConfig &conf, MetadataInfo &info): + FileDirectiveSerializer(conf, cfdp::FileDirectives::METADATA, 5), info(info) { + updateDirectiveFieldLen(); +} + +void MetadataPduSerializer::updateDirectiveFieldLen() { + setDirectiveDataFieldLen(info.getSerializedSize(getLargeFileFlag())); +} + +size_t MetadataPduSerializer::getSerializedSize() const { + return FileDirectiveSerializer::getWholePduSize(); +} + +ReturnValue_t MetadataPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = FileDirectiveSerializer::serialize(buffer, size, maxSize, + streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(*size + 1 >= maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = info.isClosureRequested() << 6 | info.getChecksumType(); + *buffer += 1; + *size += 1; + result = info.getFileSize().serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = info.getSourceFileName().serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = info.getDestFileName().serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + if(info.hasOptions()) { + cfdp::Tlv** optsArray = nullptr; + size_t optsLen = 0; + info.getOptions(&optsArray, &optsLen, nullptr); + for(size_t idx = 0; idx < optsLen; idx++) { + result = optsArray[idx]->serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + } + return result; +} diff --git a/src/fsfw/cfdp/pdu/MetadataPduSerializer.h b/src/fsfw/cfdp/pdu/MetadataPduSerializer.h new file mode 100644 index 00000000..6cbead49 --- /dev/null +++ b/src/fsfw/cfdp/pdu/MetadataPduSerializer.h @@ -0,0 +1,23 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_METADATAPDUSERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_METADATAPDUSERIALIZER_H_ + +#include "fsfw/cfdp/pdu/MetadataInfo.h" +#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" + +class MetadataPduSerializer: public FileDirectiveSerializer { +public: + MetadataPduSerializer(PduConfig &conf, MetadataInfo& info); + + void updateDirectiveFieldLen(); + + size_t getSerializedSize() const override; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; +private: + MetadataInfo& info; +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_METADATAPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/NakInfo.cpp b/src/fsfw/cfdp/pdu/NakInfo.cpp new file mode 100644 index 00000000..d11aabc1 --- /dev/null +++ b/src/fsfw/cfdp/pdu/NakInfo.cpp @@ -0,0 +1,83 @@ +#include "NakInfo.h" + +NakInfo::NakInfo(cfdp::FileSize startOfScope, cfdp::FileSize endOfScope): + startOfScope(startOfScope), endOfScope(endOfScope) { +} + +size_t NakInfo::getSerializedSize(bool fssLarge) { + size_t size = 8; + if(fssLarge) { + size += 8; + } + if(hasSegmentRequests()) { + if(fssLarge) { + size += segmentRequestsLen * 16; + } else { + size += segmentRequestsLen * 8; + } + } + return size; +} + +bool NakInfo::hasSegmentRequests() const { + if(this->segmentRequests != nullptr and segmentRequestsLen > 0) { + return true; + } + return false; +} + +bool NakInfo::canHoldSegmentRequests() const { + if(this->segmentRequests != nullptr and maxSegmentRequestsLen > 0) { + return true; + } + return false; +} + +bool NakInfo::getSegmentRequests(SegmentRequest **segmentRequestPtr, + size_t *segmentRequestLen, size_t* maxSegmentRequestsLen) { + if(this->segmentRequests != nullptr) { + *segmentRequestPtr = this->segmentRequests; + } + if(segmentRequestLen != nullptr) { + *segmentRequestLen = this->segmentRequestsLen; + } + if(maxSegmentRequestsLen != nullptr) { + *maxSegmentRequestsLen = this->maxSegmentRequestsLen; + } + return true; +} + +void NakInfo::setSegmentRequests(SegmentRequest *segmentRequests, size_t* segmentRequestLen, + size_t* maxSegmentRequestLen) { + this->segmentRequests = segmentRequests; + if(segmentRequestLen != nullptr) { + this->segmentRequestsLen = *segmentRequestLen; + } + if(maxSegmentRequestLen != nullptr) { + this->maxSegmentRequestsLen = *maxSegmentRequestLen; + } +} + +cfdp::FileSize& NakInfo::getStartOfScope() { + return startOfScope; +} + +cfdp::FileSize& NakInfo::getEndOfScope() { + return endOfScope; +} + +size_t NakInfo::getSegmentRequestsLen() const { + return segmentRequestsLen; +} + +size_t NakInfo::getSegmentRequestsMaxLen() const { + return maxSegmentRequestsLen; +} + +void NakInfo::setSegmentRequestLen(size_t readLen) { + this->segmentRequestsLen = readLen; +} + +void NakInfo::setMaxSegmentRequestLen(size_t maxSize) { + this->maxSegmentRequestsLen = maxSize; +} diff --git a/src/fsfw/cfdp/pdu/NakInfo.h b/src/fsfw/cfdp/pdu/NakInfo.h new file mode 100644 index 00000000..839484be --- /dev/null +++ b/src/fsfw/cfdp/pdu/NakInfo.h @@ -0,0 +1,40 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_NAKINFO_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_NAKINFO_H_ + +#include "fsfw/cfdp/FileSize.h" +#include + +class NakInfo { +public: + using SegmentRequest = std::pair; + + NakInfo(cfdp::FileSize startOfScope, cfdp::FileSize endOfScope); + + void setSegmentRequests(SegmentRequest* segmentRequests, size_t* segmentRequestLen, + size_t* maxSegmentRequestLen); + + size_t getSerializedSize(bool fssLarge = false); + + cfdp::FileSize& getStartOfScope(); + cfdp::FileSize& getEndOfScope(); + + bool hasSegmentRequests() const; + bool canHoldSegmentRequests() const; + void setMaxSegmentRequestLen(size_t maxSize); + bool getSegmentRequests(SegmentRequest** segmentRequestPtr, size_t* segmentRequestLen, + size_t* maxSegmentRequestsLen); + size_t getSegmentRequestsLen() const; + size_t getSegmentRequestsMaxLen() const; + + //! This functions is more relevant for deserializers + void setSegmentRequestLen(size_t readLen); + +private: + cfdp::FileSize startOfScope; + cfdp::FileSize endOfScope; + SegmentRequest* segmentRequests = nullptr; + size_t segmentRequestsLen = 0; + size_t maxSegmentRequestsLen = 0; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_NAKINFO_H_ */ diff --git a/src/fsfw/cfdp/pdu/NakPduDeserializer.cpp b/src/fsfw/cfdp/pdu/NakPduDeserializer.cpp new file mode 100644 index 00000000..b2d02322 --- /dev/null +++ b/src/fsfw/cfdp/pdu/NakPduDeserializer.cpp @@ -0,0 +1,58 @@ +#include "NakPduDeserializer.h" + +NakPduDeserializer::NakPduDeserializer(const uint8_t *pduBuf, size_t maxSize, NakInfo &info): + FileDirectiveDeserializer(pduBuf, maxSize), nakInfo(info) { +} + +ReturnValue_t NakPduDeserializer::parseData() { + ReturnValue_t result = FileDirectiveDeserializer::parseData(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); + const uint8_t* buffer = rawPtr + currentIdx; + size_t remSize = FileDirectiveDeserializer::getWholePduSize() - currentIdx; + if (remSize < 1) { + return SerializeIF::STREAM_TOO_SHORT; + } + result = nakInfo.getStartOfScope().deSerialize(&buffer, &remSize, + SerializeIF::Endianness::NETWORK); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = nakInfo.getEndOfScope().deSerialize(&buffer, &remSize, + SerializeIF::Endianness::NETWORK); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + nakInfo.setSegmentRequestLen(0); + if(remSize > 0) { + if(not nakInfo.canHoldSegmentRequests()) { + return cfdp::NAK_CANT_PARSE_OPTIONS; + } + NakInfo::SegmentRequest* segReqs = nullptr; + size_t maxSegReqs = 0; + nakInfo.getSegmentRequests(&segReqs, nullptr, &maxSegReqs); + if(segReqs != nullptr) { + size_t idx = 0; + while(remSize > 0) { + if(idx == maxSegReqs) { + return cfdp::NAK_CANT_PARSE_OPTIONS; + } + result = segReqs[idx].first.deSerialize(&buffer, &remSize, + SerializeIF::Endianness::NETWORK); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = segReqs[idx].second.deSerialize(&buffer, &remSize, + SerializeIF::Endianness::NETWORK); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + idx++; + } + nakInfo.setSegmentRequestLen(idx); + } + } + return result; +} diff --git a/src/fsfw/cfdp/pdu/NakPduDeserializer.h b/src/fsfw/cfdp/pdu/NakPduDeserializer.h new file mode 100644 index 00000000..81726610 --- /dev/null +++ b/src/fsfw/cfdp/pdu/NakPduDeserializer.h @@ -0,0 +1,22 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_NAKPDUDESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_NAKPDUDESERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" +#include "fsfw/cfdp/pdu/NakInfo.h" + +class NakPduDeserializer: public FileDirectiveDeserializer { +public: + NakPduDeserializer(const uint8_t* pduBuf, size_t maxSize, NakInfo& info); + + /** + * This needs to be called before accessing the PDU fields to avoid segmentation faults. + * @return + */ + virtual ReturnValue_t parseData() override; +private: + NakInfo& nakInfo; +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_NAKPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/NakPduSerializer.cpp b/src/fsfw/cfdp/pdu/NakPduSerializer.cpp new file mode 100644 index 00000000..9afb80cb --- /dev/null +++ b/src/fsfw/cfdp/pdu/NakPduSerializer.cpp @@ -0,0 +1,49 @@ +#include "NakPduSerializer.h" + +NakPduSerializer::NakPduSerializer(PduConfig& pduConf, NakInfo& nakInfo): + FileDirectiveSerializer(pduConf, cfdp::FileDirectives::NAK, 0), nakInfo(nakInfo) { + updateDirectiveFieldLen(); +} + +void NakPduSerializer::updateDirectiveFieldLen() { + this->setDirectiveDataFieldLen(nakInfo.getSerializedSize(getLargeFileFlag())); +} + +size_t NakPduSerializer::getSerializedSize() const { + return FileDirectiveSerializer::getWholePduSize(); +} + +ReturnValue_t NakPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = FileDirectiveSerializer::serialize(buffer, size, maxSize, + streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = nakInfo.getStartOfScope().serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = nakInfo.getEndOfScope().serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(nakInfo.hasSegmentRequests()) { + NakInfo::SegmentRequest *segmentRequests = nullptr; + size_t segmentRequestLen = 0; + nakInfo.getSegmentRequests(&segmentRequests, &segmentRequestLen, nullptr); + for(size_t idx = 0; idx < segmentRequestLen; idx++) { + result = segmentRequests[idx].first.serialize(buffer, size, maxSize, + streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = segmentRequests[idx].second.serialize(buffer, size, maxSize, + streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + } + return result; +} diff --git a/src/fsfw/cfdp/pdu/NakPduSerializer.h b/src/fsfw/cfdp/pdu/NakPduSerializer.h new file mode 100644 index 00000000..556f0037 --- /dev/null +++ b/src/fsfw/cfdp/pdu/NakPduSerializer.h @@ -0,0 +1,41 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_NAKPDUSERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_NAKPDUSERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" +#include "fsfw/cfdp/definitions.h" +#include "fsfw/cfdp/FileSize.h" +#include "NakInfo.h" + +#include + +class NakPduSerializer: public FileDirectiveSerializer { +public: + + /** + * + * @param PduConf + * @param startOfScope + * @param endOfScope + * @param [in] segmentRequests Pointer to the start of a list of segment requests + * @param segmentRequestLen Length of the segment request list to be serialized + */ + NakPduSerializer(PduConfig& PduConf, NakInfo& nakInfo); + + size_t getSerializedSize() const override; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; + + /** + * If you change the info struct, you might need to update the directive field length + * manually + */ + void updateDirectiveFieldLen(); +private: + NakInfo& nakInfo; + +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_NAKPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/PduConfig.cpp b/src/fsfw/cfdp/pdu/PduConfig.cpp new file mode 100644 index 00000000..acf02f5b --- /dev/null +++ b/src/fsfw/cfdp/pdu/PduConfig.cpp @@ -0,0 +1,8 @@ +#include "PduConfig.h" + +PduConfig::PduConfig(cfdp::TransmissionModes mode, cfdp::TransactionSeqNum seqNum, + cfdp::EntityId sourceId, cfdp::EntityId destId, bool crcFlag, + bool largeFile, cfdp::Direction direction): + mode(mode), seqNum(seqNum), sourceId(sourceId), destId(destId), + crcFlag(crcFlag), largeFile(largeFile), direction(direction) { +} diff --git a/src/fsfw/cfdp/pdu/PduConfig.h b/src/fsfw/cfdp/pdu/PduConfig.h new file mode 100644 index 00000000..79d14a2e --- /dev/null +++ b/src/fsfw/cfdp/pdu/PduConfig.h @@ -0,0 +1,36 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_PDUCONFIG_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_PDUCONFIG_H_ + +#include "VarLenField.h" + +namespace cfdp { + +struct EntityId: public VarLenField { +public: + EntityId(): VarLenField() {} + EntityId(cfdp::WidthInBytes width, size_t entityId): VarLenField(width, entityId) {} +}; + +struct TransactionSeqNum: public VarLenField { +public: + TransactionSeqNum(): VarLenField() {} + TransactionSeqNum(cfdp::WidthInBytes width, size_t seqNum): VarLenField(width, seqNum) {} +}; + +} + +class PduConfig { +public: + PduConfig(cfdp::TransmissionModes mode, cfdp::TransactionSeqNum seqNum, + cfdp::EntityId sourceId, cfdp::EntityId destId, bool crcFlag = false, + bool largeFile = false, cfdp::Direction direction = cfdp::Direction::TOWARDS_RECEIVER); + cfdp::TransmissionModes mode; + cfdp::TransactionSeqNum seqNum; + cfdp::EntityId sourceId; + cfdp::EntityId destId; + bool crcFlag; + bool largeFile; + cfdp::Direction direction; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_PDUCONFIG_H_ */ diff --git a/src/fsfw/cfdp/pdu/PduHeaderIF.h b/src/fsfw/cfdp/pdu/PduHeaderIF.h new file mode 100644 index 00000000..0ea8b4fe --- /dev/null +++ b/src/fsfw/cfdp/pdu/PduHeaderIF.h @@ -0,0 +1,37 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_PDUHEADERIF_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_PDUHEADERIF_H_ + +#include "PduConfig.h" +#include "../definitions.h" +#include + +/** + * @brief Generic interface to access all fields of a PDU header + * @details + * See CCSDS 727.0-B-5 pp.75 for more information about these fields + */ +class PduHeaderIF { +public: + virtual~ PduHeaderIF() {}; + + virtual size_t getWholePduSize() const = 0; + virtual size_t getPduDataFieldLen() const = 0; + virtual cfdp::PduType getPduType() const = 0; + virtual cfdp::Direction getDirection() const = 0; + virtual cfdp::TransmissionModes getTransmissionMode() const = 0; + virtual bool getCrcFlag() const = 0; + virtual bool getLargeFileFlag() const = 0; + virtual cfdp::SegmentationControl getSegmentationControl() const = 0; + virtual cfdp::WidthInBytes getLenEntityIds() const = 0; + virtual cfdp::WidthInBytes getLenSeqNum() const = 0; + virtual cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const = 0; + virtual bool hasSegmentMetadataFlag() const = 0; + virtual void getSourceId(cfdp::EntityId& sourceId) const = 0; + virtual void getDestId(cfdp::EntityId& destId) const = 0; + virtual void getTransactionSeqNum(cfdp::TransactionSeqNum& seqNum) const = 0; +private: +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_PDUHEADERIF_H_ */ diff --git a/src/fsfw/cfdp/pdu/PromptPduDeserializer.cpp b/src/fsfw/cfdp/pdu/PromptPduDeserializer.cpp new file mode 100644 index 00000000..abff805e --- /dev/null +++ b/src/fsfw/cfdp/pdu/PromptPduDeserializer.cpp @@ -0,0 +1,22 @@ +#include "PromptPduDeserializer.h" + +PromptPduDeserializer::PromptPduDeserializer(const uint8_t *pduBuf, size_t maxSize): + FileDirectiveDeserializer(pduBuf, maxSize) { +} + +cfdp::PromptResponseRequired PromptPduDeserializer::getPromptResponseRequired() const { + return responseRequired; +} + +ReturnValue_t PromptPduDeserializer::parseData() { + ReturnValue_t result = FileDirectiveDeserializer::parseData(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); + if (FileDirectiveDeserializer::getWholePduSize() - currentIdx < 1) { + return SerializeIF::STREAM_TOO_SHORT; + } + responseRequired = static_cast((rawPtr[currentIdx] >> 7) & 0x01); + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/src/fsfw/cfdp/pdu/PromptPduDeserializer.h b/src/fsfw/cfdp/pdu/PromptPduDeserializer.h new file mode 100644 index 00000000..97762243 --- /dev/null +++ b/src/fsfw/cfdp/pdu/PromptPduDeserializer.h @@ -0,0 +1,18 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_PROMPTPDUDESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_PROMPTPDUDESERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" + +class PromptPduDeserializer: public FileDirectiveDeserializer { +public: + PromptPduDeserializer(const uint8_t *pduBuf, size_t maxSize); + + cfdp::PromptResponseRequired getPromptResponseRequired() const; + ReturnValue_t parseData() override; +private: + cfdp::PromptResponseRequired responseRequired = cfdp::PromptResponseRequired::PROMPT_NAK; +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_PROMPTPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/PromptPduSerializer.cpp b/src/fsfw/cfdp/pdu/PromptPduSerializer.cpp new file mode 100644 index 00000000..599f8072 --- /dev/null +++ b/src/fsfw/cfdp/pdu/PromptPduSerializer.cpp @@ -0,0 +1,27 @@ +#include "PromptPduSerializer.h" + +PromptPduSerializer::PromptPduSerializer(PduConfig &conf, + cfdp::PromptResponseRequired responseRequired): + FileDirectiveSerializer(conf, cfdp::FileDirectives::PROMPT, 1), + responseRequired(responseRequired) { +} + +size_t PromptPduSerializer::getSerializedSize() const { + return FileDirectiveSerializer::getWholePduSize(); +} + +ReturnValue_t PromptPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = FileDirectiveSerializer::serialize(buffer, size, maxSize, + streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(*size + 1 > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = this->responseRequired << 7; + *buffer += 1; + *size += 1; + return result; +} diff --git a/src/fsfw/cfdp/pdu/PromptPduSerializer.h b/src/fsfw/cfdp/pdu/PromptPduSerializer.h new file mode 100644 index 00000000..79945fd7 --- /dev/null +++ b/src/fsfw/cfdp/pdu/PromptPduSerializer.h @@ -0,0 +1,18 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_PROMPTPDUSERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_PROMPTPDUSERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" + +class PromptPduSerializer: public FileDirectiveSerializer { +public: + PromptPduSerializer(PduConfig& conf, cfdp::PromptResponseRequired responseRequired); + + size_t getSerializedSize() const override; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; +private: + cfdp::PromptResponseRequired responseRequired; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_PROMPTPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/VarLenField.cpp b/src/fsfw/cfdp/pdu/VarLenField.cpp new file mode 100644 index 00000000..ac2410c8 --- /dev/null +++ b/src/fsfw/cfdp/pdu/VarLenField.cpp @@ -0,0 +1,127 @@ +#include "VarLenField.h" +#include "fsfw/FSFW.h" +#include "fsfw/serviceinterface.h" +#include "fsfw/serialize/SerializeAdapter.h" + +cfdp::VarLenField::VarLenField(cfdp::WidthInBytes width, size_t value): VarLenField() { + ReturnValue_t result = this->setValue(width, value); + if(result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_DISABLE_PRINTOUT == 0 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "cfdp::VarLenField: Setting value failed" << std::endl; +#else + sif::printWarning("cfdp::VarLenField: Setting value failed\n"); +#endif +#endif + } +} + +cfdp::VarLenField::VarLenField(): width(cfdp::WidthInBytes::ONE_BYTE) { + value.oneByte = 0; +} + +cfdp::WidthInBytes cfdp::VarLenField::getWidth() const { + return width; +} + +ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_t value) { + switch(widthInBytes) { + case(cfdp::WidthInBytes::ONE_BYTE): { + if(value > UINT8_MAX) { + return HasReturnvaluesIF::RETURN_FAILED; + } + this->value.oneByte = value; + break; + } + case(cfdp::WidthInBytes::TWO_BYTES): { + if(value > UINT16_MAX) { + return HasReturnvaluesIF::RETURN_FAILED; + } + this->value.twoBytes = value; + break; + } + case(cfdp::WidthInBytes::FOUR_BYTES): { + if(value > UINT32_MAX) { + return HasReturnvaluesIF::RETURN_FAILED; + } + this->value.fourBytes = value; + break; + } + default: { + break; + } + } + this->width = widthInBytes; + return HasReturnvaluesIF::RETURN_OK; +} + +size_t cfdp::VarLenField::getValue() const { + switch(width) { + case(cfdp::WidthInBytes::ONE_BYTE): { + return value.oneByte; + } + case(cfdp::WidthInBytes::TWO_BYTES): { + return value.twoBytes; + } + case(cfdp::WidthInBytes::FOUR_BYTES): { + return value.fourBytes; + } + } + return 0; +} + +ReturnValue_t cfdp::VarLenField::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + switch(width) { + case(cfdp::WidthInBytes::ONE_BYTE): { + if (*size + 1 > maxSize) { + return BUFFER_TOO_SHORT; + } + **buffer = value.oneByte; + *size += 1; + *buffer += 1; + return HasReturnvaluesIF::RETURN_OK; + } + case(cfdp::WidthInBytes::TWO_BYTES): { + return SerializeAdapter::serialize(&value.twoBytes, buffer, size, maxSize, + streamEndianness); + } + case(cfdp::WidthInBytes::FOUR_BYTES): { + return SerializeAdapter::serialize(&value.fourBytes, buffer, size, maxSize, + streamEndianness); + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } +} + +size_t cfdp::VarLenField::getSerializedSize() const { + return width; +} + +ReturnValue_t cfdp::VarLenField::deSerialize(cfdp::WidthInBytes width, const uint8_t **buffer, + size_t *size, Endianness streamEndianness) { + this->width = width; + return deSerialize(buffer, size, streamEndianness); +} + +ReturnValue_t cfdp::VarLenField::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + switch(width) { + case(cfdp::WidthInBytes::ONE_BYTE): { + value.oneByte = **buffer; + *size += 1; + return HasReturnvaluesIF::RETURN_OK; + } + case(cfdp::WidthInBytes::TWO_BYTES): { + return SerializeAdapter::deSerialize(&value.twoBytes, buffer, size, streamEndianness); + } + case(cfdp::WidthInBytes::FOUR_BYTES): { + return SerializeAdapter::deSerialize(&value.fourBytes, buffer, size, streamEndianness); + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } +} diff --git a/src/fsfw/cfdp/pdu/VarLenField.h b/src/fsfw/cfdp/pdu/VarLenField.h new file mode 100644 index 00000000..01bcfaed --- /dev/null +++ b/src/fsfw/cfdp/pdu/VarLenField.h @@ -0,0 +1,45 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_VARLENFIELD_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_VARLENFIELD_H_ + +#include "../definitions.h" +#include "fsfw/serialize/SerializeIF.h" +#include +#include + +namespace cfdp { + +class VarLenField: public SerializeIF { +public: + union LengthFieldLen { + uint8_t oneByte; + uint16_t twoBytes; + uint32_t fourBytes; + uint64_t eightBytes; + }; + + VarLenField(); + VarLenField(cfdp::WidthInBytes width, size_t value); + + ReturnValue_t setValue(cfdp::WidthInBytes, size_t value); + + ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const override; + + size_t getSerializedSize() const override; + + ReturnValue_t deSerialize(cfdp::WidthInBytes width, const uint8_t **buffer, size_t *size, + Endianness streamEndianness); + + cfdp::WidthInBytes getWidth() const; + size_t getValue() const; +private: + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + cfdp::WidthInBytes width; + LengthFieldLen value; +}; + +} + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_VARLENFIELD_H_ */ diff --git a/src/fsfw/cfdp/tlv/CMakeLists.txt b/src/fsfw/cfdp/tlv/CMakeLists.txt new file mode 100644 index 00000000..24459cf8 --- /dev/null +++ b/src/fsfw/cfdp/tlv/CMakeLists.txt @@ -0,0 +1,10 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + EntityIdTlv.cpp + FilestoreRequestTlv.cpp + FilestoreResponseTlv.cpp + Lv.cpp + Tlv.cpp + FlowLabelTlv.cpp + MessageToUserTlv.cpp + FaultHandlerOverrideTlv.cpp +) \ No newline at end of file diff --git a/src/fsfw/cfdp/tlv/EntityIdTlv.cpp b/src/fsfw/cfdp/tlv/EntityIdTlv.cpp new file mode 100644 index 00000000..98b1094e --- /dev/null +++ b/src/fsfw/cfdp/tlv/EntityIdTlv.cpp @@ -0,0 +1,68 @@ +#include "EntityIdTlv.h" +#include + +EntityIdTlv::EntityIdTlv(cfdp::EntityId& entityId): entityId(entityId) { +} + +EntityIdTlv::~EntityIdTlv() { +} + +ReturnValue_t EntityIdTlv::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + if(maxSize < this->getSerializedSize()) { + return BUFFER_TOO_SHORT; + } + **buffer = cfdp::TlvTypes::ENTITY_ID; + *size += 1; + *buffer += 1; + size_t serLen = entityId.getSerializedSize(); + **buffer = serLen; + *size += 1; + *buffer += 1; + return entityId.serialize(buffer, size, maxSize, streamEndianness); +} + +size_t EntityIdTlv::getSerializedSize() const { + return getLengthField() + 1; +} + +ReturnValue_t EntityIdTlv::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + if(*size < 3) { + return STREAM_TOO_SHORT; + } + cfdp::TlvTypes type = static_cast(**buffer); + if(type != cfdp::TlvTypes::ENTITY_ID) { + return cfdp::INVALID_TLV_TYPE; + } + *buffer += 1; + *size -= 1; + + cfdp::WidthInBytes width = static_cast(**buffer); + if (*size < static_cast(1 + width)) { + return STREAM_TOO_SHORT; + } + *buffer += 1; + *size -= 1; + + return entityId.deSerialize(width, buffer, size, streamEndianness); +} + +ReturnValue_t EntityIdTlv::deSerialize(cfdp::Tlv &tlv, Endianness endianness) { + const uint8_t* ptr = tlv.getValue() + 2; + size_t remSz = tlv.getSerializedSize() - 2; + cfdp::WidthInBytes width = static_cast(remSz); + return entityId.deSerialize(width, &ptr, &remSz, endianness); +} + +uint8_t EntityIdTlv::getLengthField() const { + return 1 + entityId.getSerializedSize(); +} + +cfdp::TlvTypes EntityIdTlv::getType() const { + return cfdp::TlvTypes::ENTITY_ID; +} + +cfdp::EntityId& EntityIdTlv::getEntityId() { + return entityId; +} diff --git a/src/fsfw/cfdp/tlv/EntityIdTlv.h b/src/fsfw/cfdp/tlv/EntityIdTlv.h new file mode 100644 index 00000000..5860ce05 --- /dev/null +++ b/src/fsfw/cfdp/tlv/EntityIdTlv.h @@ -0,0 +1,39 @@ +#ifndef FSFW_SRC_FSFW_CFDP_ENTITYIDTLV_H_ +#define FSFW_SRC_FSFW_CFDP_ENTITYIDTLV_H_ + +#include "fsfw/cfdp/tlv/Tlv.h" +#include "fsfw/cfdp/pdu/PduConfig.h" +#include "TlvIF.h" + +class EntityIdTlv: public TlvIF { +public: + EntityIdTlv(cfdp::EntityId& entityId); + virtual~ EntityIdTlv(); + + ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override; + + size_t getSerializedSize() const override; + + /** + * Deserialize an entity ID from a raw TLV object + * @param tlv + * @param endianness + * @return + */ + ReturnValue_t deSerialize(cfdp::Tlv& tlv, Endianness endianness); + + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + uint8_t getLengthField() const override; + cfdp::TlvTypes getType() const override; + + cfdp::EntityId& getEntityId(); +private: + cfdp::EntityId& entityId; +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_ENTITYIDTLV_H_ */ diff --git a/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.cpp b/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.cpp new file mode 100644 index 00000000..f5ef9311 --- /dev/null +++ b/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.cpp @@ -0,0 +1,64 @@ +#include "FaultHandlerOverrideTlv.h" + +FaultHandlerOverrideTlv::FaultHandlerOverrideTlv(cfdp::ConditionCode conditionCode, + cfdp::FaultHandlerCode handlerCode): + conditionCode(conditionCode), handlerCode(handlerCode) { +} + +FaultHandlerOverrideTlv::FaultHandlerOverrideTlv() { +} + +uint8_t FaultHandlerOverrideTlv::getLengthField() const { + return 1; +} + + +ReturnValue_t FaultHandlerOverrideTlv::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + if((maxSize < 3) or ((*size + 3) > maxSize)) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = getType(); + *size += 1; + *buffer += 1; + **buffer = getLengthField(); + *size += 1; + *buffer += 1; + **buffer = this->conditionCode << 4 | this->handlerCode; + *buffer += 1; + *size += 1; + return HasReturnvaluesIF::RETURN_OK; +} + +size_t FaultHandlerOverrideTlv::getSerializedSize() const { + return getLengthField() + 2; +} + +ReturnValue_t FaultHandlerOverrideTlv::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + if(*size < 3) { + return SerializeIF::STREAM_TOO_SHORT; + } + auto detectedType = static_cast(**buffer); + if(detectedType != cfdp::TlvTypes::FAULT_HANDLER) { + return cfdp::INVALID_TLV_TYPE; + } + *buffer += 1; + *size -= 1; + size_t detectedSize = **buffer; + if(detectedSize != getLengthField()) { + return HasReturnvaluesIF::RETURN_FAILED; + } + *buffer += 1; + *size += 1; + this->conditionCode = static_cast((**buffer >> 4) & 0x0f); + this->handlerCode = static_cast(**buffer & 0x0f); + *buffer += 1; + *size += 1; + return HasReturnvaluesIF::RETURN_OK; +} + + +cfdp::TlvTypes FaultHandlerOverrideTlv::getType() const { + return cfdp::TlvTypes::FAULT_HANDLER; +} diff --git a/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.h b/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.h new file mode 100644 index 00000000..7014ae0e --- /dev/null +++ b/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.h @@ -0,0 +1,39 @@ +#ifndef FSFW_SRC_FSFW_CFDP_TLV_FAULTHANDLEROVERRIDETLV_H_ +#define FSFW_SRC_FSFW_CFDP_TLV_FAULTHANDLEROVERRIDETLV_H_ + +#include "TlvIF.h" + +namespace cfdp { + +enum FaultHandlerCode { + RESERVED = 0b0000, + NOTICE_OF_CANCELLATION = 0b0001, + NOTICE_OF_SUSPENSION = 0b0010, + IGNORE_ERROR = 0b0011, + ABANDON_TRANSACTION = 0b0100 +}; + +} + +class FaultHandlerOverrideTlv: public TlvIF { +public: + + FaultHandlerOverrideTlv(); + FaultHandlerOverrideTlv(cfdp::ConditionCode conditionCode, cfdp::FaultHandlerCode handlerCode); + + ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override; + + size_t getSerializedSize() const override; + + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + uint8_t getLengthField() const override; + cfdp::TlvTypes getType() const override; + +private: + cfdp::ConditionCode conditionCode = cfdp::ConditionCode::NO_CONDITION_FIELD; + cfdp::FaultHandlerCode handlerCode = cfdp::FaultHandlerCode::RESERVED; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_TLV_FAULTHANDLEROVERRIDETLV_H_ */ diff --git a/src/fsfw/cfdp/tlv/FilestoreRequestTlv.cpp b/src/fsfw/cfdp/tlv/FilestoreRequestTlv.cpp new file mode 100644 index 00000000..044c4e9a --- /dev/null +++ b/src/fsfw/cfdp/tlv/FilestoreRequestTlv.cpp @@ -0,0 +1,83 @@ +#include "fsfw/cfdp/tlv/FilestoreRequestTlv.h" +#include "fsfw/FSFW.h" + +FilestoreRequestTlv::FilestoreRequestTlv(cfdp::FilestoreActionCode actionCode, + cfdp::Lv& firstFileName): FilestoreTlvBase(actionCode, firstFileName) { +} + +FilestoreRequestTlv::FilestoreRequestTlv(cfdp::Lv &firstFileName): + FilestoreTlvBase(cfdp::FilestoreActionCode::INVALID, firstFileName) { +} + +void FilestoreRequestTlv::setSecondFileName(cfdp::Lv *secondFileName) { + this->secondFileName = secondFileName; +} + +ReturnValue_t FilestoreRequestTlv::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = commonSerialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = firstFileName.serialize(buffer, size, maxSize, + streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(requiresSecondFileName()) { + if(secondFileName == nullptr) { + secondFileNameMissing(); + return cfdp::FILESTORE_REQUIRES_SECOND_FILE; + } + secondFileName->serialize(buffer, size, maxSize, streamEndianness); + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FilestoreRequestTlv::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + ReturnValue_t result = commonDeserialize(buffer, size, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return deSerializeFromValue(buffer, size, streamEndianness); +} + +ReturnValue_t FilestoreRequestTlv::deSerialize(cfdp::Tlv &tlv, + SerializeIF::Endianness endianness) { + const uint8_t* ptr = tlv.getValue(); + size_t remSz = tlv.getSerializedSize(); + + return deSerializeFromValue(&ptr, &remSz, endianness); +} + +uint8_t FilestoreRequestTlv::getLengthField() const { + size_t secondFileNameLen = 0; + if(secondFileName != nullptr and requiresSecondFileName()) { + secondFileNameLen = secondFileName->getSerializedSize(); + } + return 1 + firstFileName.getSerializedSize() + secondFileNameLen; +} + +ReturnValue_t FilestoreRequestTlv::deSerializeFromValue(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + this->actionCode = static_cast((**buffer >> 4) & 0x0f); + *buffer += 1; + *size -= 1; + ReturnValue_t result = firstFileName.deSerialize(buffer, size, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(requiresSecondFileName()) { + if(secondFileName == nullptr) { + secondFileNameMissing(); + return HasReturnvaluesIF::RETURN_FAILED; + } + result = secondFileName->deSerialize(buffer, size, streamEndianness); + } + return result; +} + +cfdp::TlvTypes FilestoreRequestTlv::getType() const { + return cfdp::TlvTypes::FILESTORE_REQUEST; +} diff --git a/src/fsfw/cfdp/tlv/FilestoreRequestTlv.h b/src/fsfw/cfdp/tlv/FilestoreRequestTlv.h new file mode 100644 index 00000000..d4cedbb2 --- /dev/null +++ b/src/fsfw/cfdp/tlv/FilestoreRequestTlv.h @@ -0,0 +1,45 @@ +#ifndef FSFW_SRC_FSFW_CFDP_FILESTOREREQUESTTLV_H_ +#define FSFW_SRC_FSFW_CFDP_FILESTOREREQUESTTLV_H_ + +#include "fsfw/cfdp/tlv/FilestoreTlvBase.h" +#include "fsfw/cfdp/tlv/Tlv.h" +#include "TlvIF.h" +#include "Lv.h" +#include "../definitions.h" + +class FilestoreRequestTlv: + public cfdp::FilestoreTlvBase { +public: + FilestoreRequestTlv(cfdp::FilestoreActionCode actionCode, cfdp::Lv& firstFileName); + + FilestoreRequestTlv(cfdp::Lv& firstFileName); + + void setSecondFileName(cfdp::Lv* secondFileName); + + ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override; + + /** + * Deserialize a FS request from a raw TLV object + * @param tlv + * @param endianness + * @return + */ + ReturnValue_t deSerialize(cfdp::Tlv& tlv, Endianness endianness); + + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + uint8_t getLengthField() const override; + cfdp::TlvTypes getType() const override; + +private: + cfdp::Lv* secondFileName = nullptr; + + ReturnValue_t deSerializeFromValue(const uint8_t **buffer, size_t *size, + Endianness streamEndianness); +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_FILESTOREREQUESTTLV_H_ */ diff --git a/src/fsfw/cfdp/tlv/FilestoreResponseTlv.cpp b/src/fsfw/cfdp/tlv/FilestoreResponseTlv.cpp new file mode 100644 index 00000000..ec57579a --- /dev/null +++ b/src/fsfw/cfdp/tlv/FilestoreResponseTlv.cpp @@ -0,0 +1,124 @@ +#include "FilestoreResponseTlv.h" + +FilestoreResponseTlv::FilestoreResponseTlv(cfdp::FilestoreActionCode actionCode, uint8_t statusCode, + cfdp::Lv& firstFileName, cfdp::Lv* fsMsg): FilestoreTlvBase(actionCode, firstFileName), + statusCode(statusCode), filestoreMsg(fsMsg) { +} + +FilestoreResponseTlv::FilestoreResponseTlv(cfdp::Lv &firstFileName, cfdp::Lv* fsMsg): + FilestoreTlvBase(firstFileName), statusCode(0), filestoreMsg(fsMsg) { +} + +uint8_t FilestoreResponseTlv::getLengthField() const { + size_t optFieldsLen = 0; + if(secondFileName != nullptr) { + optFieldsLen += secondFileName->getSerializedSize(); + } + if(filestoreMsg != nullptr) { + optFieldsLen += filestoreMsg->getSerializedSize(); + } else { + optFieldsLen += 1; + } + return 1 + firstFileName.getSerializedSize() + optFieldsLen; +} + +void FilestoreResponseTlv::setSecondFileName(cfdp::Lv *secondFileName) { + this->secondFileName = secondFileName; +} + +void FilestoreResponseTlv::setFilestoreMessage(cfdp::Lv *filestoreMsg) { + this->filestoreMsg = filestoreMsg; +} + +ReturnValue_t FilestoreResponseTlv::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = commonSerialize(buffer, size, maxSize, streamEndianness, + true, this->statusCode); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = firstFileName.serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(requiresSecondFileName()) { + if(secondFileName == nullptr) { + secondFileNameMissing(); + return cfdp::FILESTORE_REQUIRES_SECOND_FILE; + } + } + if(filestoreMsg != nullptr) { + result = filestoreMsg->serialize(buffer, size, maxSize, streamEndianness); + } + else { + if(*size == maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = 0; + *buffer += 1; + *size +=1; + } + return result; +} + +ReturnValue_t FilestoreResponseTlv::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + ReturnValue_t result = commonDeserialize(buffer, size, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return deSerializeFromValue(buffer, size, streamEndianness); +} + +ReturnValue_t FilestoreResponseTlv::deSerializeFromValue(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + + // The common function above checks whether at least one byte is remaining + this->actionCode = static_cast((**buffer >> 4) & 0x0f); + this->statusCode = **buffer & 0x0f; + *buffer += 1; + *size -= 1; + ReturnValue_t result = firstFileName.deSerialize(buffer, size, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(requiresSecondFileName()) { + if(secondFileName == nullptr) { + return cfdp::FILESTORE_REQUIRES_SECOND_FILE; + } + result = secondFileName->deSerialize(buffer, size, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + // If the filestore message is not empty, the deserialization is only considered successfully + // if the filestore message can be parsed. Also, if data follows after the FS response, + // the FS msg needs to be set as well. + if(*size == 0 or (*size > 1 and filestoreMsg == nullptr)) { + // Filestore message missing or can't parse it + return cfdp::FILESTORE_RESPONSE_CANT_PARSE_FS_MESSAGE; + } + if(filestoreMsg == nullptr) { + *size -= 1; + *buffer += 1; + // Ignore empty filestore message + return HasReturnvaluesIF::RETURN_OK; + } + return filestoreMsg->deSerialize(buffer, size, streamEndianness); +} + +ReturnValue_t FilestoreResponseTlv::deSerialize(const cfdp::Tlv &tlv, Endianness endianness) { + const uint8_t* ptr = tlv.getValue(); + size_t remSz = tlv.getSerializedSize(); + + return deSerializeFromValue(&ptr, &remSz, endianness); +} + +uint8_t FilestoreResponseTlv::getStatusCode() const { + return statusCode; +} + + +cfdp::TlvTypes FilestoreResponseTlv::getType() const { + return cfdp::TlvTypes::FILESTORE_RESPONSE; +} diff --git a/src/fsfw/cfdp/tlv/FilestoreResponseTlv.h b/src/fsfw/cfdp/tlv/FilestoreResponseTlv.h new file mode 100644 index 00000000..1159fdca --- /dev/null +++ b/src/fsfw/cfdp/tlv/FilestoreResponseTlv.h @@ -0,0 +1,50 @@ +#ifndef FSFW_SRC_FSFW_CFDP_FILESTORERESPONSETLV_H_ +#define FSFW_SRC_FSFW_CFDP_FILESTORERESPONSETLV_H_ + +#include "fsfw/cfdp/tlv/FilestoreTlvBase.h" +#include "fsfw/cfdp/tlv/Tlv.h" +#include "TlvIF.h" +#include "Lv.h" + +class FilestoreResponseTlv: + public cfdp::FilestoreTlvBase { +public: + + FilestoreResponseTlv(cfdp::Lv& firstFileName, cfdp::Lv* fsMsg); + + FilestoreResponseTlv(cfdp::FilestoreActionCode actionCode, uint8_t statusCode, + cfdp::Lv& firstFileName, cfdp::Lv* fsMsg); + + uint8_t getStatusCode() const; + void setSecondFileName(cfdp::Lv* secondFileName); + void setFilestoreMessage(cfdp::Lv* filestoreMsg); + + ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override; + + /** + * Deserialize a filestore response from a raw TLV object + * @param tlv + * @param endianness + * @return + */ + ReturnValue_t deSerialize(const cfdp::Tlv& tlv, Endianness endianness); + + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + uint8_t getLengthField() const override; + cfdp::TlvTypes getType() const override; + +private: + uint8_t statusCode; + cfdp::Lv* secondFileName = nullptr; + cfdp::Lv* filestoreMsg = nullptr; + + ReturnValue_t deSerializeFromValue(const uint8_t **buffer, size_t *size, + Endianness streamEndianness); +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_FILESTORERESPONSETLV_H_ */ diff --git a/src/fsfw/cfdp/tlv/FilestoreTlvBase.h b/src/fsfw/cfdp/tlv/FilestoreTlvBase.h new file mode 100644 index 00000000..f81b8807 --- /dev/null +++ b/src/fsfw/cfdp/tlv/FilestoreTlvBase.h @@ -0,0 +1,176 @@ +#ifndef FSFW_SRC_FSFW_CFDP_FILESTOREREQUESTBASE_H_ +#define FSFW_SRC_FSFW_CFDP_FILESTOREREQUESTBASE_H_ + +#include +#include +#include +#include +#include +#include +#include + +namespace cfdp { + +enum FilestoreActionCode { + CREATE_FILE = 0b0000, + DELETE_FILE = 0b0001, + // Second file name present + RENAME_FILE = 0b0010, + // Second file name present + APPEND_FILE = 0b0011, + // Second file name present + REPLACE_FILE = 0b0100, + CREATE_DIRECTORY = 0b0101, + REMOVE_DIRECTORY = 0b0110, + // Delete file if present + DENY_FILE = 0b0111, + // Remove directory if present + DNEY_DIRECTORY = 0b1000, + INVALID = 0b1111 +}; + +// FSR = Filestore Response +static constexpr uint8_t FSR_SUCCESS = 0b0000; +static constexpr uint8_t FSR_NOT_PERFORMED = 0b1111; + +static constexpr uint8_t FSR_CREATE_NOT_ALLOWED = 0b0001; + +static constexpr uint8_t FSR_DEL_FILE_NOT_EXISTS = 0b0001; +static constexpr uint8_t FSR_DEL_NOT_ALLOWED = 0b0010; + +static constexpr uint8_t FSR_RENAME_OLD_FILE_NOT_EXISTS = 0b0001; +static constexpr uint8_t FSR_RENAME_NEW_FILE_ALREADY_EXISTS = 0b0010; +static constexpr uint8_t FSR_RENAME_NOT_ALLOWED = 0b0011; + +static constexpr uint8_t FSR_APPEND_FILE_1_NOT_EXISTS = 0b0001; +static constexpr uint8_t FSR_APPEND_FILE_2_NOT_EXISTS = 0b0010; +static constexpr uint8_t FSR_APPEND_NOT_ALLOWED = 0b0011; + +static constexpr uint8_t FSR_REPLACE_FILE_1_NOT_EXISTS = 0b0001; +static constexpr uint8_t FSR_REPLACE_FILE_2_NOT_EXISTS = 0b0010; +static constexpr uint8_t FSR_REPLACE_REPLACE_NOT_ALLOWED = 0b0011; + +static constexpr uint8_t FSR_CREATE_DIR_NOT_POSSIBLE = 0b0001; + +static constexpr uint8_t FSR_DELDIR_NOT_EXISTS = 0b0001; +static constexpr uint8_t FSR_DELDIR_NOT_ALLOWED = 0b0010; + +static constexpr uint8_t FSR_DENY_FILE_NOT_ALLOWED = 0b0010; + +static constexpr uint8_t FSR_DENY_DIR_NOT_ALLOWED = 0b0010; + +class FilestoreTlvBase: public TlvIF { +public: + + FilestoreTlvBase(cfdp::Lv& firstFileName): firstFileName(firstFileName) {}; + FilestoreTlvBase(FilestoreActionCode actionCode, cfdp::Lv& firstFileName): + actionCode(actionCode), firstFileName(firstFileName) {}; + + ReturnValue_t commonSerialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness, + bool isResponse = false, uint8_t responseStatusCode = 0) const { + if(buffer == nullptr or size == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(maxSize < 3) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = getType(); + *buffer += 1; + *size += 1; + **buffer = getLengthField(); + *buffer += 1; + *size += 1; + **buffer = this->actionCode << 4; + if(isResponse) { + **buffer |= responseStatusCode; + } + *buffer += 1; + *size += 1; + return HasReturnvaluesIF::RETURN_OK; + } + + ReturnValue_t commonDeserialize(const uint8_t **buffer, size_t *size, + SerializeIF::Endianness streamEndianness) { + if(buffer == nullptr or size == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(*size < 3) { + return SerializeIF::STREAM_TOO_SHORT; + } + cfdp::TlvTypes type = static_cast(**buffer); + if(type != getType()) { + return cfdp::INVALID_TLV_TYPE; + } + *size -= 1; + *buffer += 1; + + size_t remainingLength = **buffer; + *size -= 1; + *buffer += 1; + if(remainingLength == 0) { + return SerializeIF::STREAM_TOO_SHORT; + } + return HasReturnvaluesIF::RETURN_OK; + } + + bool requiresSecondFileName() const { + using namespace cfdp; + if(actionCode == FilestoreActionCode::RENAME_FILE or + actionCode == FilestoreActionCode::APPEND_FILE or + actionCode == FilestoreActionCode::REPLACE_FILE) { + return true; + } + return false; + } + + void secondFileNameMissing() const { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "FilestoreRequestTlv::deSerialize: Second file name required" + " but TLV pointer not set" << std::endl; +#else + sif::printWarning("FilestoreRequestTlv::deSerialize: Second file name required" + " but TLV pointer not set\n"); +#endif +#endif + } + + FilestoreActionCode getActionCode() const { + return actionCode; + } + + void setActionCode(FilestoreActionCode actionCode) { + this->actionCode = actionCode; + } + + cfdp::Lv& getFirstFileName() { + return firstFileName; + } + + ReturnValue_t convertToTlv(cfdp::Tlv& tlv, uint8_t *buffer, size_t maxSize, + Endianness streamEndianness) { + size_t serSize = 0; + uint8_t* valueStart = buffer + 2; + ReturnValue_t result = this->serialize(&buffer, &serSize, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + tlv.setValue(valueStart, serSize - 2); + tlv.setType(getType()); + return result; + } + + size_t getSerializedSize() const override { + return getLengthField() + 2; + } +protected: + FilestoreActionCode actionCode = FilestoreActionCode::INVALID; + cfdp::Lv& firstFileName; +}; + +} + + + +#endif /* FSFW_SRC_FSFW_CFDP_FILESTOREREQUESTBASE_H_ */ diff --git a/src/fsfw/cfdp/tlv/FlowLabelTlv.cpp b/src/fsfw/cfdp/tlv/FlowLabelTlv.cpp new file mode 100644 index 00000000..c5835414 --- /dev/null +++ b/src/fsfw/cfdp/tlv/FlowLabelTlv.cpp @@ -0,0 +1,5 @@ +#include "FlowLabelTlv.h" + +FlowLabelTlv::FlowLabelTlv(uint8_t* value, size_t size): + Tlv(cfdp::TlvTypes::FLOW_LABEL, value, size) { +} diff --git a/src/fsfw/cfdp/tlv/FlowLabelTlv.h b/src/fsfw/cfdp/tlv/FlowLabelTlv.h new file mode 100644 index 00000000..3375c361 --- /dev/null +++ b/src/fsfw/cfdp/tlv/FlowLabelTlv.h @@ -0,0 +1,13 @@ +#ifndef FSFW_SRC_FSFW_CFDP_TLV_FLOWLABELTLV_H_ +#define FSFW_SRC_FSFW_CFDP_TLV_FLOWLABELTLV_H_ + +#include "Tlv.h" + +class FlowLabelTlv: public cfdp::Tlv { +public: + FlowLabelTlv(uint8_t* value, size_t size); +private: + +}; + +#endif /* FSFW_SRC_FSFW_CFDP_TLV_FLOWLABELTLV_H_ */ diff --git a/src/fsfw/cfdp/tlv/Lv.cpp b/src/fsfw/cfdp/tlv/Lv.cpp new file mode 100644 index 00000000..fa3b99e7 --- /dev/null +++ b/src/fsfw/cfdp/tlv/Lv.cpp @@ -0,0 +1,88 @@ +#include "Lv.h" + +cfdp::Lv::Lv(const uint8_t *value, size_t size): value(value, size, true) { + if(size > 0) { + zeroLen = false; + } +} + +cfdp::Lv::Lv(): value(static_cast(nullptr), 0, true) { +} + +cfdp::Lv::Lv(const Lv& other): + value(other.value.getConstBuffer(), other.value.getSerializedSize() - 1, true) { + if(other.value.getSerializedSize() - 1 > 0) { + zeroLen = false; + } +} + +cfdp::Lv& cfdp::Lv::operator =(const Lv& other) { + size_t otherSize = 0; + uint8_t* value = const_cast(other.getValue(&otherSize)); + if (value == nullptr or otherSize == 0) { + this->zeroLen = true; + } + this->value.setBuffer(value, otherSize); + return *this; +} + + +ReturnValue_t cfdp::Lv::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + if(maxSize < 1) { + return BUFFER_TOO_SHORT; + } + if(buffer == nullptr or size == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(zeroLen) { + **buffer = 0; + *size += 1; + *buffer += 1; + return HasReturnvaluesIF::RETURN_OK; + } + return value.serialize(buffer, size, maxSize, streamEndianness); +} + +size_t cfdp::Lv::getSerializedSize() const { + if(zeroLen) { + return 1; + } + else if(value.getConstBuffer() == nullptr) { + return 0; + } + return value.getSerializedSize(); +} + +ReturnValue_t cfdp::Lv::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + if(buffer == nullptr or size == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(*size < 1) { + return SerializeIF::STREAM_TOO_SHORT; + } + size_t lengthField = **buffer; + if(lengthField == 0) { + zeroLen = true; + *buffer += 1; + *size -= 1; + return HasReturnvaluesIF::RETURN_OK; + } else if(*size < lengthField + 1) { + return SerializeIF::STREAM_TOO_SHORT; + } + zeroLen = false; + // Zero-copy implementation + value.setBuffer(const_cast(*buffer + 1), lengthField); + *buffer += 1 + lengthField; + *size -= 1 + lengthField; + return HasReturnvaluesIF::RETURN_OK; +} + +const uint8_t* cfdp::Lv::getValue(size_t* size) const { + if(size != nullptr) { + // Length without length field + *size = value.getSerializedSize() - 1; + } + return value.getConstBuffer(); +} diff --git a/src/fsfw/cfdp/tlv/Lv.h b/src/fsfw/cfdp/tlv/Lv.h new file mode 100644 index 00000000..46d47819 --- /dev/null +++ b/src/fsfw/cfdp/tlv/Lv.h @@ -0,0 +1,53 @@ +#ifndef FSFW_SRC_FSFW_CFDP_LV_H_ +#define FSFW_SRC_FSFW_CFDP_LV_H_ + +#include "fsfw/serialize/SerialBufferAdapter.h" + +namespace cfdp { + +/** + * @brief Length-Value field implementation + * @details + * Thin abstraction layer around a serial buffer adapter + */ +class Lv: public SerializeIF { +public: + Lv(const uint8_t* value, size_t size); + Lv(); + + // Delete copy ctor and assingment ctor for now because this class contains a reference to + // data + Lv (const Lv&); + Lv& operator= (const Lv&); + + ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override; + + size_t getSerializedSize() const override; + + /** + * @brief Deserialize a LV field from a raw buffer + * @param buffer Raw buffer including the size field + * @param size + * @param streamEndianness + * @return + */ + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + /** + * Get value field and its size. + * @param size Optionally retrieve size. Size will be the size of the actual value field + * without the length field of the LV + * @return + */ + const uint8_t* getValue(size_t* size) const; +private: + + bool zeroLen = true; + SerialBufferAdapter value; +}; + +} + +#endif /* FSFW_SRC_FSFW_CFDP_LV_H_ */ diff --git a/src/fsfw/cfdp/tlv/MessageToUserTlv.cpp b/src/fsfw/cfdp/tlv/MessageToUserTlv.cpp new file mode 100644 index 00000000..f776f5ef --- /dev/null +++ b/src/fsfw/cfdp/tlv/MessageToUserTlv.cpp @@ -0,0 +1,8 @@ +#include "MessageToUserTlv.h" + +MessageToUserTlv::MessageToUserTlv(uint8_t *value, size_t size): + Tlv(cfdp::TlvTypes::MSG_TO_USER, value, size) { +} + +MessageToUserTlv::MessageToUserTlv(): Tlv() { +} diff --git a/src/fsfw/cfdp/tlv/MessageToUserTlv.h b/src/fsfw/cfdp/tlv/MessageToUserTlv.h new file mode 100644 index 00000000..7bbe3a40 --- /dev/null +++ b/src/fsfw/cfdp/tlv/MessageToUserTlv.h @@ -0,0 +1,13 @@ +#ifndef FSFW_SRC_FSFW_CFDP_TLV_MESSAGETOUSERTLV_H_ +#define FSFW_SRC_FSFW_CFDP_TLV_MESSAGETOUSERTLV_H_ + +#include "Tlv.h" + +class MessageToUserTlv: public cfdp::Tlv { +public: + MessageToUserTlv(); + MessageToUserTlv(uint8_t* value, size_t size); +private: +}; + +#endif /* FSFW_SRC_FSFW_CFDP_TLV_MESSAGETOUSERTLV_H_ */ diff --git a/src/fsfw/cfdp/tlv/Tlv.cpp b/src/fsfw/cfdp/tlv/Tlv.cpp new file mode 100644 index 00000000..71aa512d --- /dev/null +++ b/src/fsfw/cfdp/tlv/Tlv.cpp @@ -0,0 +1,114 @@ +#include "Tlv.h" + +cfdp::Tlv::Tlv(TlvTypes type, const uint8_t *value, size_t size): type(type), + value(value, size, true) { + if(size > 0) { + zeroLen = false; + } +} + +cfdp::Tlv::Tlv(): value(static_cast(nullptr), 0, true) { +} + +ReturnValue_t cfdp::Tlv::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + if(buffer == nullptr or size == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(*size + 2 > maxSize) { + return BUFFER_TOO_SHORT; + } + if(type == TlvTypes::INVALID_TLV) { + return INVALID_TLV_TYPE; + } + **buffer = type; + *size += 1; + *buffer += 1; + + if(zeroLen) { + **buffer = 0; + *size += 1; + *buffer += 1; + return HasReturnvaluesIF::RETURN_OK; + } + if(value.getConstBuffer() == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return value.serialize(buffer, size, maxSize, streamEndianness); +} + +size_t cfdp::Tlv::getSerializedSize() const { + if(zeroLen) { + return 2; + } + else if (value.getConstBuffer() == nullptr) { + return 0; + } + return value.getSerializedSize() + 1; +} + +ReturnValue_t cfdp::Tlv::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + if(buffer == nullptr or size == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(*size < 2) { + return STREAM_TOO_SHORT; + } + + uint8_t rawType = **buffer; + if(not checkType(rawType)) { + return INVALID_TLV_TYPE; + } + + type = static_cast(rawType); + *buffer += 1; + *size -= 1; + + size_t lengthField = **buffer; + if(lengthField == 0) { + zeroLen = true; + *buffer += 1; + *size -= 1; + return HasReturnvaluesIF::RETURN_OK; + } + if(lengthField + 1 > *size) { + return SerializeIF::STREAM_TOO_SHORT; + } + zeroLen = false; + // Zero-copy implementation + value.setBuffer(const_cast(*buffer + 1), lengthField); + *buffer += 1 + lengthField; + *size -= 1 + lengthField; + return HasReturnvaluesIF::RETURN_OK; +} + +const uint8_t* cfdp::Tlv::getValue() const { + return value.getConstBuffer(); +} + +cfdp::TlvTypes cfdp::Tlv::getType() const { + return type; +} + +bool cfdp::Tlv::checkType(uint8_t rawType) { + if (rawType != 0x03 and rawType <= 6) { + return true; + } + return false; +} + +void cfdp::Tlv::setValue(uint8_t *value, size_t len) { + if(len > 0) { + zeroLen = false; + } + this->value.setBuffer(value, len); +} + +uint8_t cfdp::Tlv::getLengthField() const { + return this->value.getSerializedSize() - 1; +} + +void cfdp::Tlv::setType(TlvTypes type) { + this->type = type; +} diff --git a/src/fsfw/cfdp/tlv/Tlv.h b/src/fsfw/cfdp/tlv/Tlv.h new file mode 100644 index 00000000..65c6ca09 --- /dev/null +++ b/src/fsfw/cfdp/tlv/Tlv.h @@ -0,0 +1,64 @@ +#ifndef FSFW_SRC_FSFW_CFDP_TLV_H_ +#define FSFW_SRC_FSFW_CFDP_TLV_H_ + +#include "TlvIF.h" +#include "fsfw/serialize/SerialBufferAdapter.h" + +namespace cfdp { + +/** + * @brief Type-Length-Value field implementation + * @details + * Thin abstraction layer around a serial buffer adapter + */ +class Tlv: public TlvIF { +public: + Tlv(TlvTypes type, const uint8_t *value, size_t size); + Tlv(); + + /** + * Serialize a TLV into a given buffer + * @param buffer + * @param size + * @param maxSize + * @param streamEndianness + * @return + * - RETURN_OK on success + * - INVALID_TLV_TYPE + * - SerializeIF returncode on wrong serialization parameters + */ + virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override; + + virtual size_t getSerializedSize() const override; + + /** + * @brief Deserialize a LV field from a raw buffer. Zero-copy implementation + * @param buffer Raw buffer including the size field + * @param size + * @param streamEndianness + * - RETURN_OK on success + * - INVALID_TLV_TYPE + * - SerializeIF returncode on wrong deserialization parameters + */ + virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + + void setValue(uint8_t *value, size_t len); + + const uint8_t* getValue() const; + void setType(TlvTypes type); + TlvTypes getType() const override; + uint8_t getLengthField() const override; +private: + bool checkType(uint8_t rawType); + + bool zeroLen = true; + TlvTypes type = TlvTypes::INVALID_TLV; + SerialBufferAdapter value; +}; + +} + +#endif /* FSFW_SRC_FSFW_CFDP_TLV_H_ */ diff --git a/src/fsfw/cfdp/tlv/TlvIF.h b/src/fsfw/cfdp/tlv/TlvIF.h new file mode 100644 index 00000000..885e7814 --- /dev/null +++ b/src/fsfw/cfdp/tlv/TlvIF.h @@ -0,0 +1,16 @@ +#ifndef FSFW_SRC_FSFW_CFDP_TLVIF_H_ +#define FSFW_SRC_FSFW_CFDP_TLVIF_H_ + +#include "../definitions.h" + +class TlvIF: public SerializeIF { +public: + virtual~ TlvIF() {}; + + virtual uint8_t getLengthField() const = 0; + virtual cfdp::TlvTypes getType() const = 0; +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_TLVIF_H_ */ diff --git a/src/fsfw/controller/ExtendedControllerBase.h b/src/fsfw/controller/ExtendedControllerBase.h index 4172e03e..abd48637 100644 --- a/src/fsfw/controller/ExtendedControllerBase.h +++ b/src/fsfw/controller/ExtendedControllerBase.h @@ -8,11 +8,10 @@ #include "fsfw/datapoollocal/LocalDataPoolManager.h" /** - * @brief Extendes the basic ControllerBase with the common components - * HasActionsIF for commandability and HasLocalDataPoolIF to keep - * a pool of local data pool variables. + * @brief Extends the basic ControllerBase with commonly used components * @details - * Default implementations required for the interfaces will be empty and have + * HasActionsIF for commandability and HasLocalDataPoolIF to keep a pool of local data pool + * variables. Default implementations required for the interfaces will be empty and have * to be implemented by child class. */ class ExtendedControllerBase: public ControllerBase, diff --git a/src/fsfw/devicehandlers/AssemblyBase.h b/src/fsfw/devicehandlers/AssemblyBase.h index 6cac81b4..7d54f14d 100644 --- a/src/fsfw/devicehandlers/AssemblyBase.h +++ b/src/fsfw/devicehandlers/AssemblyBase.h @@ -7,7 +7,7 @@ /** * @brief Base class to implement reconfiguration and failure handling for - * redundant devices by monitoring their modes health states. + * redundant devices by monitoring their modes and health states. * @details * Documentation: Dissertation Baetz p.156, 157. * diff --git a/src/fsfw/devicehandlers/DeviceCommunicationIF.h b/src/fsfw/devicehandlers/DeviceCommunicationIF.h index e0b473d3..527e4700 100644 --- a/src/fsfw/devicehandlers/DeviceCommunicationIF.h +++ b/src/fsfw/devicehandlers/DeviceCommunicationIF.h @@ -85,9 +85,10 @@ public: * Called by DHB in the GET_WRITE doGetWrite(). * Get send confirmation that the data in sendMessage() was sent successfully. * @param cookie - * @return - @c RETURN_OK if data was sent successfull - * - Everything else triggers falure event with - * returnvalue as parameter 1 + * @return + * - @c RETURN_OK if data was sent successfully but a reply is expected + * - NO_REPLY_EXPECTED if data was sent successfully and no reply is expected + * - Everything else to indicate failure */ virtual ReturnValue_t getSendSuccess(CookieIF *cookie) = 0; diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index b182b611..da609eed 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -78,15 +78,16 @@ class StorageManagerIF; * * @ingroup devices */ -class DeviceHandlerBase: public DeviceHandlerIF, -public HasReturnvaluesIF, -public ExecutableObjectIF, -public SystemObject, -public HasModesIF, -public HasHealthIF, -public HasActionsIF, -public ReceivesParameterMessagesIF, -public HasLocalDataPoolIF { +class DeviceHandlerBase: + public DeviceHandlerIF, + public HasReturnvaluesIF, + public ExecutableObjectIF, + public SystemObject, + public HasModesIF, + public HasHealthIF, + public HasActionsIF, + public ReceivesParameterMessagesIF, + public HasLocalDataPoolIF { friend void (Factory::setStaticFrameworkObjectIds)(); public: /** @@ -334,8 +335,7 @@ protected: * - @c RETURN_OK to send command after #rawPacket and #rawPacketLen * have been set. * - @c HasActionsIF::EXECUTION_COMPLETE to generate a finish reply immediately. This can - * be used if no reply is expected. Otherwise, the developer can call #actionHelper.finish - * to finish the command handling. + * be used if no reply is expected * - Anything else triggers an event with the return code as a parameter as well as a * step reply failed with the return code */ diff --git a/src/fsfw/devicehandlers/DeviceHandlerIF.h b/src/fsfw/devicehandlers/DeviceHandlerIF.h index 1933c571..1fc57c42 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerIF.h +++ b/src/fsfw/devicehandlers/DeviceHandlerIF.h @@ -120,7 +120,8 @@ public: static const ReturnValue_t WRONG_MODE_FOR_COMMAND = MAKE_RETURN_CODE(0xA5); static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(0xA6); static const ReturnValue_t BUSY = MAKE_RETURN_CODE(0xA7); - static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8); //!< Used to indicate that this is a command-only command. + //!< Used to indicate that this is a command-only command. + static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8); static const ReturnValue_t NON_OP_TEMPERATURE = MAKE_RETURN_CODE(0xA9); static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xAA); diff --git a/src/fsfw/ipc/FwMessageTypes.h b/src/fsfw/ipc/FwMessageTypes.h index 8b49c122..22fe9d0d 100644 --- a/src/fsfw/ipc/FwMessageTypes.h +++ b/src/fsfw/ipc/FwMessageTypes.h @@ -9,6 +9,7 @@ enum FsfwMessageTypes { HEALTH_COMMAND, MODE_SEQUENCE, ACTION, + CFDP, TM_STORE, DEVICE_HANDLER_COMMAND, MONITORING, diff --git a/src/fsfw/objectmanager/frameworkObjects.h b/src/fsfw/objectmanager/frameworkObjects.h index 36010807..ff7d9341 100644 --- a/src/fsfw/objectmanager/frameworkObjects.h +++ b/src/fsfw/objectmanager/frameworkObjects.h @@ -19,6 +19,9 @@ enum framework_objects: object_id_t { PUS_SERVICE_200_MODE_MGMT = 0x53000200, PUS_SERVICE_201_HEALTH = 0x53000201, + /* CFDP Distributer */ + CFDP_PACKET_DISTRIBUTOR = 0x53001000, + //Generic IDs for IPC, modes, health, events HEALTH_TABLE = 0x53010000, // MODE_STORE = 0x53010100, diff --git a/src/fsfw/osal/linux/CMakeLists.txt b/src/fsfw/osal/linux/CMakeLists.txt index 41800764..63206cb2 100644 --- a/src/fsfw/osal/linux/CMakeLists.txt +++ b/src/fsfw/osal/linux/CMakeLists.txt @@ -15,6 +15,7 @@ target_sources(${LIB_FSFW_NAME} TaskFactory.cpp tcpipHelpers.cpp unixUtility.cpp + CommandExecutor.cpp ) find_package(Threads REQUIRED) diff --git a/src/fsfw/osal/linux/MessageQueue.cpp b/src/fsfw/osal/linux/MessageQueue.cpp index b068c04f..d028f9f7 100644 --- a/src/fsfw/osal/linux/MessageQueue.cpp +++ b/src/fsfw/osal/linux/MessageQueue.cpp @@ -285,10 +285,10 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EBADF"); #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "mq_send to: " << sendTo << " sent from " - << sentFrom << "failed" << std::endl; + sif::warning << "mq_send to " << sendTo << " sent from " + << sentFrom << " failed" << std::endl; #else - sif::printWarning("mq_send to: %d sent from %d failed\n", sendTo, sentFrom); + sif::printWarning("mq_send to %d sent from %d failed\n", sendTo, sentFrom); #endif return DESTINATION_INVALID; } diff --git a/src/fsfw/returnvalues/FwClassIds.h b/src/fsfw/returnvalues/FwClassIds.h index 9fa0c9ae..96f96660 100644 --- a/src/fsfw/returnvalues/FwClassIds.h +++ b/src/fsfw/returnvalues/FwClassIds.h @@ -60,6 +60,7 @@ enum: uint8_t { HAS_ACTIONS_IF, //HF DEVICE_COMMUNICATION_IF, //DC BSP, //BSP + CFDP, //CFDP TIME_STAMPER_IF, //TSI SGP4PROPAGATOR_CLASS, //SGP4 MUTEX_IF, //MUX diff --git a/src/fsfw/serialize/SerialBufferAdapter.cpp b/src/fsfw/serialize/SerialBufferAdapter.cpp index 4f03658a..6db17d5e 100644 --- a/src/fsfw/serialize/SerialBufferAdapter.cpp +++ b/src/fsfw/serialize/SerialBufferAdapter.cpp @@ -105,7 +105,7 @@ uint8_t * SerialBufferAdapter::getBuffer() { } template -const uint8_t * SerialBufferAdapter::getConstBuffer() { +const uint8_t * SerialBufferAdapter::getConstBuffer() const { if(constBuffer == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "SerialBufferAdapter::getConstBuffer:" diff --git a/src/fsfw/serialize/SerialBufferAdapter.h b/src/fsfw/serialize/SerialBufferAdapter.h index 6c79cd03..48f5ce53 100644 --- a/src/fsfw/serialize/SerialBufferAdapter.h +++ b/src/fsfw/serialize/SerialBufferAdapter.h @@ -66,7 +66,7 @@ public: Endianness streamEndianness) override; uint8_t * getBuffer(); - const uint8_t * getConstBuffer(); + const uint8_t * getConstBuffer() const; void setBuffer(uint8_t* buffer, count_t bufferLength); private: bool serializeLength = false; diff --git a/src/fsfw/subsystem/SubsystemBase.h b/src/fsfw/subsystem/SubsystemBase.h index 6b2e9b5f..a1de077d 100644 --- a/src/fsfw/subsystem/SubsystemBase.h +++ b/src/fsfw/subsystem/SubsystemBase.h @@ -62,7 +62,8 @@ protected: struct ChildInfo { MessageQueueId_t commandQueue; Mode_t mode; - Submode_t submode;bool healthChanged; + Submode_t submode; + bool healthChanged; }; Mode_t mode; diff --git a/src/fsfw/tcdistribution/CCSDSDistributor.cpp b/src/fsfw/tcdistribution/CCSDSDistributor.cpp index ffceaecc..a040a5df 100644 --- a/src/fsfw/tcdistribution/CCSDSDistributor.cpp +++ b/src/fsfw/tcdistribution/CCSDSDistributor.cpp @@ -7,8 +7,8 @@ #define CCSDS_DISTRIBUTOR_DEBUGGING 0 CCSDSDistributor::CCSDSDistributor(uint16_t setDefaultApid, - object_id_t setObjectId): - TcDistributor(setObjectId), defaultApid( setDefaultApid ) { + object_id_t setObjectId): + TcDistributor(setObjectId), defaultApid( setDefaultApid ) { } CCSDSDistributor::~CCSDSDistributor() {} @@ -16,97 +16,97 @@ CCSDSDistributor::~CCSDSDistributor() {} TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() { #if CCSDS_DISTRIBUTOR_DEBUGGING == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "CCSDSDistributor::selectDestination received: " << - this->currentMessage.getStorageId().poolIndex << ", " << - this->currentMessage.getStorageId().packetIndex << std::endl; + sif::debug << "CCSDSDistributor::selectDestination received: " << + this->currentMessage.getStorageId().poolIndex << ", " << + this->currentMessage.getStorageId().packetIndex << std::endl; #else - sif::printDebug("CCSDSDistributor::selectDestination received: %d, %d\n", - currentMessage.getStorageId().poolIndex, currentMessage.getStorageId().packetIndex); + sif::printDebug("CCSDSDistributor::selectDestination received: %d, %d\n", + currentMessage.getStorageId().poolIndex, currentMessage.getStorageId().packetIndex); #endif #endif - const uint8_t* packet = nullptr; - size_t size = 0; - ReturnValue_t result = this->tcStore->getData(currentMessage.getStorageId(), - &packet, &size ); - if(result != HasReturnvaluesIF::RETURN_OK) { + const uint8_t* packet = nullptr; + size_t size = 0; + ReturnValue_t result = this->tcStore->getData(currentMessage.getStorageId(), + &packet, &size ); + if(result != HasReturnvaluesIF::RETURN_OK) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "CCSDSDistributor::selectDestination: Getting data from" - " store failed!" << std::endl; + sif::error << "CCSDSDistributor::selectDestination: Getting data from" + " store failed!" << std::endl; #else - sif::printError("CCSDSDistributor::selectDestination: Getting data from" + sif::printError("CCSDSDistributor::selectDestination: Getting data from" " store failed!\n"); #endif #endif - } - SpacePacketBase currentPacket(packet); + } + SpacePacketBase currentPacket(packet); #if FSFW_CPP_OSTREAM_ENABLED == 1 && CCSDS_DISTRIBUTOR_DEBUGGING == 1 - sif::info << "CCSDSDistributor::selectDestination has packet with APID " << std::hex << - currentPacket.getAPID() << std::dec << std::endl; + sif::info << "CCSDSDistributor::selectDestination has packet with APID " << std::hex << + currentPacket.getAPID() << std::dec << std::endl; #endif - TcMqMapIter position = this->queueMap.find(currentPacket.getAPID()); - if ( position != this->queueMap.end() ) { - return position; - } else { - //The APID was not found. Forward packet to main SW-APID anyway to - // create acceptance failure report. - return this->queueMap.find( this->defaultApid ); - } + TcMqMapIter position = this->queueMap.find(currentPacket.getAPID()); + if ( position != this->queueMap.end() ) { + return position; + } else { + //The APID was not found. Forward packet to main SW-APID anyway to + // create acceptance failure report. + return this->queueMap.find( this->defaultApid ); + } } MessageQueueId_t CCSDSDistributor::getRequestQueue() { - return tcQueue->getId(); + return tcQueue->getId(); } ReturnValue_t CCSDSDistributor::registerApplication( - AcceptsTelecommandsIF* application) { - ReturnValue_t returnValue = RETURN_OK; - auto insertPair = this->queueMap.emplace(application->getIdentifier(), - application->getRequestQueue()); - if(not insertPair.second) { - returnValue = RETURN_FAILED; - } - return returnValue; + AcceptsTelecommandsIF* application) { + ReturnValue_t returnValue = RETURN_OK; + auto insertPair = this->queueMap.emplace(application->getIdentifier(), + application->getRequestQueue()); + if(not insertPair.second) { + returnValue = RETURN_FAILED; + } + return returnValue; } ReturnValue_t CCSDSDistributor::registerApplication(uint16_t apid, - MessageQueueId_t id) { - ReturnValue_t returnValue = RETURN_OK; - auto insertPair = this->queueMap.emplace(apid, id); - if(not insertPair.second) { - returnValue = RETURN_FAILED; - } - return returnValue; + MessageQueueId_t id) { + ReturnValue_t returnValue = RETURN_OK; + auto insertPair = this->queueMap.emplace(apid, id); + if(not insertPair.second) { + returnValue = RETURN_FAILED; + } + return returnValue; } uint16_t CCSDSDistributor::getIdentifier() { - return 0; + return 0; } ReturnValue_t CCSDSDistributor::initialize() { - ReturnValue_t status = this->TcDistributor::initialize(); - this->tcStore = ObjectManager::instance()->get( objects::TC_STORE ); - if (this->tcStore == nullptr) { + ReturnValue_t status = this->TcDistributor::initialize(); + this->tcStore = ObjectManager::instance()->get( objects::TC_STORE ); + if (this->tcStore == nullptr) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "CCSDSDistributor::initialize: Could not initialize" - " TC store!" << std::endl; + sif::error << "CCSDSDistributor::initialize: Could not initialize" + " TC store!" << std::endl; #else - sif::printError("CCSDSDistributor::initialize: Could not initialize" + sif::printError("CCSDSDistributor::initialize: Could not initialize" " TC store!\n"); #endif #endif - status = RETURN_FAILED; - } - return status; + status = RETURN_FAILED; + } + return status; } ReturnValue_t CCSDSDistributor::callbackAfterSending( - ReturnValue_t queueStatus) { - if (queueStatus != RETURN_OK) { - tcStore->deleteData(currentMessage.getStorageId()); - } - return RETURN_OK; + ReturnValue_t queueStatus) { + if (queueStatus != RETURN_OK) { + tcStore->deleteData(currentMessage.getStorageId()); + } + return RETURN_OK; } diff --git a/src/fsfw/tcdistribution/CCSDSDistributor.h b/src/fsfw/tcdistribution/CCSDSDistributor.h index e8d54c9c..f8995bc5 100644 --- a/src/fsfw/tcdistribution/CCSDSDistributor.h +++ b/src/fsfw/tcdistribution/CCSDSDistributor.h @@ -15,56 +15,57 @@ * The Secondary Header (with Service/Subservice) is ignored. * @ingroup tc_distribution */ -class CCSDSDistributor : public TcDistributor, - public CCSDSDistributorIF, - public AcceptsTelecommandsIF { +class CCSDSDistributor: + public TcDistributor, + public CCSDSDistributorIF, + public AcceptsTelecommandsIF { public: - /** - * @brief The constructor sets the default APID and calls the - * TcDistributor ctor with a certain object id. - * @details - * @c tcStore is set in the @c initialize method. - * @param setDefaultApid The default APID, where packets with unknown - * destination are sent to. - */ - CCSDSDistributor(uint16_t setDefaultApid, object_id_t setObjectId); - /** - * The destructor is empty. - */ - virtual ~CCSDSDistributor(); + /** + * @brief The constructor sets the default APID and calls the + * TcDistributor ctor with a certain object id. + * @details + * @c tcStore is set in the @c initialize method. + * @param setDefaultApid The default APID, where packets with unknown + * destination are sent to. + */ + CCSDSDistributor(uint16_t setDefaultApid, object_id_t setObjectId); + /** + * The destructor is empty. + */ + virtual ~CCSDSDistributor(); - MessageQueueId_t getRequestQueue() override; - ReturnValue_t registerApplication( uint16_t apid, - MessageQueueId_t id) override; - ReturnValue_t registerApplication( - AcceptsTelecommandsIF* application) override; - uint16_t getIdentifier() override; - ReturnValue_t initialize() override; + MessageQueueId_t getRequestQueue() override; + ReturnValue_t registerApplication( uint16_t apid, + MessageQueueId_t id) override; + ReturnValue_t registerApplication( + AcceptsTelecommandsIF* application) override; + uint16_t getIdentifier() override; + ReturnValue_t initialize() override; protected: - /** - * This implementation checks if an application with fitting APID has - * registered and forwards the packet to the according message queue. - * If the packet is not found, it returns the queue to @c defaultApid, - * where a Acceptance Failure message should be generated. - * @return Iterator to map entry of found APID or iterator to default APID. - */ - TcMqMapIter selectDestination() override; + /** + * This implementation checks if an application with fitting APID has + * registered and forwards the packet to the according message queue. + * If the packet is not found, it returns the queue to @c defaultApid, + * where a Acceptance Failure message should be generated. + * @return Iterator to map entry of found APID or iterator to default APID. + */ + TcMqMapIter selectDestination() override; /** * The callback here handles the generation of acceptance * success/failure messages. */ ReturnValue_t callbackAfterSending( ReturnValue_t queueStatus ) override; - /** - * The default APID, where packets with unknown APID are sent to. - */ - uint16_t defaultApid; - /** - * A reference to the TC storage must be maintained, as this class handles - * pure Space Packets and there exists no SpacePacketStored class. - */ - StorageManagerIF* tcStore = nullptr; + /** + * The default APID, where packets with unknown APID are sent to. + */ + uint16_t defaultApid; + /** + * A reference to the TC storage must be maintained, as this class handles + * pure Space Packets and there exists no SpacePacketStored class. + */ + StorageManagerIF* tcStore = nullptr; }; diff --git a/src/fsfw/tcdistribution/CCSDSDistributorIF.h b/src/fsfw/tcdistribution/CCSDSDistributorIF.h index 6334a35a..4e4c2a5b 100644 --- a/src/fsfw/tcdistribution/CCSDSDistributorIF.h +++ b/src/fsfw/tcdistribution/CCSDSDistributorIF.h @@ -13,31 +13,30 @@ */ class CCSDSDistributorIF { public: - /** - * With this call, a class implementing the CCSDSApplicationIF can register - * at the distributor. - * @param application A pointer to the Application to register. - * @return - @c RETURN_OK on success, - * - @c RETURN_FAILED on failure. - */ - virtual ReturnValue_t registerApplication( - AcceptsTelecommandsIF* application) = 0; - /** - * With this call, other Applications can register to the CCSDS distributor. - * This is done by passing an APID and a MessageQueueId to the method. - * @param apid The APID to register. - * @param id The MessageQueueId of the message queue to send the - * TC Packets to. - * @return - @c RETURN_OK on success, - * - @c RETURN_FAILED on failure. - */ - virtual ReturnValue_t registerApplication( uint16_t apid, - MessageQueueId_t id) = 0; - /** - * The empty virtual destructor. - */ - virtual ~CCSDSDistributorIF() { - } + /** + * With this call, a class implementing the CCSDSApplicationIF can register + * at the distributor. + * @param application A pointer to the Application to register. + * @return - @c RETURN_OK on success, + * - @c RETURN_FAILED on failure. + */ + virtual ReturnValue_t registerApplication( + AcceptsTelecommandsIF* application) = 0; + /** + * With this call, other Applications can register to the CCSDS distributor. + * This is done by passing an APID and a MessageQueueId to the method. + * @param apid The APID to register. + * @param id The MessageQueueId of the message queue to send the + * TC Packets to. + * @return - @c RETURN_OK on success, + * - @c RETURN_FAILED on failure. + */ + virtual ReturnValue_t registerApplication( uint16_t apid, + MessageQueueId_t id) = 0; + /** + * The empty virtual destructor. + */ + virtual ~CCSDSDistributorIF() {} }; diff --git a/src/fsfw/tcdistribution/CFDPDistributor.cpp b/src/fsfw/tcdistribution/CFDPDistributor.cpp new file mode 100644 index 00000000..f28a2998 --- /dev/null +++ b/src/fsfw/tcdistribution/CFDPDistributor.cpp @@ -0,0 +1,147 @@ +#include "fsfw/tcdistribution/CCSDSDistributorIF.h" +#include "fsfw/tcdistribution/CFDPDistributor.h" + +#include "fsfw/tmtcpacket/cfdp/CFDPPacketStored.h" + +#include "fsfw/objectmanager/ObjectManager.h" + +#ifndef FSFW_CFDP_DISTRIBUTOR_DEBUGGING +#define FSFW_CFDP_DISTRIBUTOR_DEBUGGING 1 +#endif + +CFDPDistributor::CFDPDistributor(uint16_t setApid, object_id_t setObjectId, + object_id_t setPacketSource): + TcDistributor(setObjectId), apid(setApid), checker(setApid), + tcStatus(RETURN_FAILED), packetSource(setPacketSource) { +} + +CFDPDistributor::~CFDPDistributor() {} + +CFDPDistributor::TcMqMapIter CFDPDistributor::selectDestination() { +#if FSFW_CFDP_DISTRIBUTOR_DEBUGGING == 1 + store_address_t storeId = this->currentMessage.getStorageId(); +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::debug << "CFDPDistributor::handlePacket received: " << storeId.poolIndex << ", " << + storeId.packetIndex << std::endl; +#else + sif::printDebug("CFDPDistributor::handlePacket received: %d, %d\n", storeId.poolIndex, + storeId.packetIndex); +#endif +#endif + TcMqMapIter queueMapIt = this->queueMap.end(); + if(this->currentPacket == nullptr) { + return queueMapIt; + } + this->currentPacket->setStoreAddress(this->currentMessage.getStorageId()); + if (currentPacket->getWholeData() != nullptr) { + tcStatus = checker.checkPacket(currentPacket); + if(tcStatus != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::debug << "CFDPDistributor::handlePacket: Packet format invalid, code " << + static_cast(tcStatus) << std::endl; +#else + sif::printDebug("CFDPDistributor::handlePacket: Packet format invalid, code %d\n", + static_cast(tcStatus)); +#endif +#endif + } + queueMapIt = this->queueMap.find(0); + } + else { + tcStatus = PACKET_LOST; + } + + if (queueMapIt == this->queueMap.end()) { + tcStatus = DESTINATION_NOT_FOUND; +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::debug << "CFDPDistributor::handlePacket: Destination not found" << std::endl; +#else + sif::printDebug("CFDPDistributor::handlePacket: Destination not found\n"); +#endif /* !FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif + } + + if (tcStatus != RETURN_OK) { + return this->queueMap.end(); + } + else { + return queueMapIt; + } + +} + + +ReturnValue_t CFDPDistributor::registerHandler(AcceptsTelecommandsIF* handler) { + uint16_t handlerId = handler->getIdentifier(); //should be 0, because CFDPHandler does not set a set a service-ID +#if FSFW_CFDP_DISTRIBUTOR_DEBUGGING == 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "CFDPDistributor::registerHandler: Handler ID: " << static_cast(handlerId) << std::endl; +#else + sif::printInfo("CFDPDistributor::registerHandler: Handler ID: %d\n", static_cast(handlerId)); +#endif +#endif + MessageQueueId_t queue = handler->getRequestQueue(); + auto returnPair = queueMap.emplace(handlerId, queue); + if (not returnPair.second) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "CFDPDistributor::registerHandler: Service ID already" + " exists in map" << std::endl; +#else + sif::printError("CFDPDistributor::registerHandler: Service ID already exists in map\n"); +#endif +#endif + return SERVICE_ID_ALREADY_EXISTS; + } + return HasReturnvaluesIF::RETURN_OK; +} + +MessageQueueId_t CFDPDistributor::getRequestQueue() { + return tcQueue->getId(); +} + +//ReturnValue_t CFDPDistributor::callbackAfterSending(ReturnValue_t queueStatus) { +// if (queueStatus != RETURN_OK) { +// tcStatus = queueStatus; +// } +// if (tcStatus != RETURN_OK) { +// this->verifyChannel.sendFailureReport(tc_verification::ACCEPTANCE_FAILURE, +// currentPacket, tcStatus); +// // A failed packet is deleted immediately after reporting, +// // otherwise it will block memory. +// currentPacket->deletePacket(); +// return RETURN_FAILED; +// } else { +// this->verifyChannel.sendSuccessReport(tc_verification::ACCEPTANCE_SUCCESS, +// currentPacket); +// return RETURN_OK; +// } +//} + +uint16_t CFDPDistributor::getIdentifier() { + return this->apid; +} + +ReturnValue_t CFDPDistributor::initialize() { + currentPacket = new CFDPPacketStored(); + if(currentPacket == nullptr) { + // Should not happen, memory allocation failed! + return ObjectManagerIF::CHILD_INIT_FAILED; + } + + CCSDSDistributorIF* ccsdsDistributor = ObjectManager::instance()->get( + packetSource); + if (ccsdsDistributor == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "CFDPDistributor::initialize: Packet source invalid" << std::endl; + sif::error << " Make sure it exists and implements CCSDSDistributorIF!" << std::endl; +#else + sif::printError("CFDPDistributor::initialize: Packet source invalid\n"); + sif::printError("Make sure it exists and implements CCSDSDistributorIF\n"); +#endif + return RETURN_FAILED; + } + return ccsdsDistributor->registerApplication(this); +} diff --git a/src/fsfw/tcdistribution/CFDPDistributor.h b/src/fsfw/tcdistribution/CFDPDistributor.h new file mode 100644 index 00000000..5c7513b3 --- /dev/null +++ b/src/fsfw/tcdistribution/CFDPDistributor.h @@ -0,0 +1,72 @@ +#ifndef FSFW_TCDISTRIBUTION_CFDPDISTRIBUTOR_H_ +#define FSFW_TCDISTRIBUTION_CFDPDISTRIBUTOR_H_ + +#include +#include "CFDPDistributorIF.h" +#include "TcDistributor.h" +#include "../tmtcpacket/cfdp/CFDPPacketStored.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../tmtcservices/AcceptsTelecommandsIF.h" +#include "../tmtcservices/VerificationReporter.h" + +/** + * This class accepts CFDP Telecommands and forwards them to Application + * services. + * @ingroup tc_distribution + */ +class CFDPDistributor: + public TcDistributor, + public CFDPDistributorIF, + public AcceptsTelecommandsIF { +public: + /** + * The ctor passes @c set_apid to the checker class and calls the + * TcDistribution ctor with a certain object id. + * @param setApid The APID of this receiving Application. + * @param setObjectId Object ID of the distributor itself + * @param setPacketSource Object ID of the source of TC packets. + * Must implement CCSDSDistributorIF. + */ + CFDPDistributor(uint16_t setApid, object_id_t setObjectId, + object_id_t setPacketSource); + /** + * The destructor is empty. + */ + virtual ~CFDPDistributor(); + ReturnValue_t registerHandler(AcceptsTelecommandsIF* handler) override; + MessageQueueId_t getRequestQueue() override; + ReturnValue_t initialize() override; + uint16_t getIdentifier() override; + +protected: + uint16_t apid; + /** + * The currently handled packet is stored here. + */ + CFDPPacketStored* currentPacket = nullptr; + TcPacketCheckCFDP checker; + /** + * With this variable, the current check status is stored to generate + * acceptance messages later. + */ + ReturnValue_t tcStatus; + + const object_id_t packetSource; + + /** + * This method reads the packet service, checks if such a service is + * registered and forwards the packet to the destination. + * It also initiates the formal packet check and sending of verification + * messages. + * @return Iterator to map entry of found service id + * or iterator to @c map.end(). + */ + TcMqMapIter selectDestination() override; + /** + * The callback here handles the generation of acceptance + * success/failure messages. + */ + //ReturnValue_t callbackAfterSending(ReturnValue_t queueStatus) override; +}; + +#endif /* FSFW_TCDISTRIBUTION_CFDPDISTRIBUTOR_H_ */ diff --git a/src/fsfw/tcdistribution/CFDPDistributorIF.h b/src/fsfw/tcdistribution/CFDPDistributorIF.h new file mode 100644 index 00000000..f1c85772 --- /dev/null +++ b/src/fsfw/tcdistribution/CFDPDistributorIF.h @@ -0,0 +1,27 @@ +#ifndef FSFW_TCDISTRIBUTION_CFDPDISTRIBUTORIF_H_ +#define FSFW_TCDISTRIBUTION_CFDPDISTRIBUTORIF_H_ + +#include "../tmtcservices/AcceptsTelecommandsIF.h" +#include "../ipc/MessageQueueSenderIF.h" + +/** + * This interface allows CFDP Services to register themselves at a CFDP Distributor. + * @ingroup tc_distribution + */ +class CFDPDistributorIF { +public: + /** + * The empty virtual destructor. + */ + virtual ~CFDPDistributorIF() { + } + /** + * With this method, Handlers can register themselves at the CFDP Distributor. + * @param handler A pointer to the registering Handler. + * @return - @c RETURN_OK on success, + * - @c RETURN_FAILED on failure. + */ + virtual ReturnValue_t registerHandler(AcceptsTelecommandsIF* handler) = 0; +}; + +#endif /* FSFW_TCDISTRIBUTION_CFDPDISTRIBUTORIF_H_ */ diff --git a/src/fsfw/tcdistribution/CMakeLists.txt b/src/fsfw/tcdistribution/CMakeLists.txt index 6f237076..7118c38c 100644 --- a/src/fsfw/tcdistribution/CMakeLists.txt +++ b/src/fsfw/tcdistribution/CMakeLists.txt @@ -2,5 +2,8 @@ target_sources(${LIB_FSFW_NAME} PRIVATE CCSDSDistributor.cpp PUSDistributor.cpp TcDistributor.cpp - TcPacketCheck.cpp + TcPacketCheckPUS.cpp + TcPacketCheckCFDP.cpp + CFDPDistributor.cpp ) + diff --git a/src/fsfw/tcdistribution/PUSDistributor.cpp b/src/fsfw/tcdistribution/PUSDistributor.cpp index adab58c8..aafd1244 100644 --- a/src/fsfw/tcdistribution/PUSDistributor.cpp +++ b/src/fsfw/tcdistribution/PUSDistributor.cpp @@ -24,25 +24,25 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() { if(this->currentPacket == nullptr) { return queueMapIt; } - this->currentPacket->setStoreAddress(this->currentMessage.getStorageId()); + this->currentPacket->setStoreAddress(this->currentMessage.getStorageId(), currentPacket); if (currentPacket->getWholeData() != nullptr) { tcStatus = checker.checkPacket(currentPacket); if(tcStatus != HasReturnvaluesIF::RETURN_OK) { #if FSFW_VERBOSE_LEVEL >= 1 const char* keyword = "unnamed error"; - if(tcStatus == TcPacketCheck::INCORRECT_CHECKSUM) { + if(tcStatus == TcPacketCheckPUS::INCORRECT_CHECKSUM) { keyword = "checksum"; } - else if(tcStatus == TcPacketCheck::INCORRECT_PRIMARY_HEADER) { + else if(tcStatus == TcPacketCheckPUS::INCORRECT_PRIMARY_HEADER) { keyword = "incorrect primary header"; } - else if(tcStatus == TcPacketCheck::ILLEGAL_APID) { + else if(tcStatus == TcPacketCheckPUS::ILLEGAL_APID) { keyword = "illegal APID"; } - else if(tcStatus == TcPacketCheck::INCORRECT_SECONDARY_HEADER) { + else if(tcStatus == TcPacketCheckPUS::INCORRECT_SECONDARY_HEADER) { keyword = "incorrect secondary header"; } - else if(tcStatus == TcPacketCheck::INCOMPLETE_PACKET) { + else if(tcStatus == TcPacketCheckPUS::INCOMPLETE_PACKET) { keyword = "incomplete packet"; } #if FSFW_CPP_OSTREAM_ENABLED == 1 diff --git a/src/fsfw/tcdistribution/PUSDistributor.h b/src/fsfw/tcdistribution/PUSDistributor.h index 53a996ca..b010125c 100644 --- a/src/fsfw/tcdistribution/PUSDistributor.h +++ b/src/fsfw/tcdistribution/PUSDistributor.h @@ -3,7 +3,7 @@ #include "PUSDistributorIF.h" #include "TcDistributor.h" -#include "TcPacketCheck.h" +#include "TcPacketCheckPUS.h" #include "fsfw/tmtcpacket/pus/tc.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h" @@ -17,65 +17,65 @@ * @ingroup tc_distribution */ class PUSDistributor: public TcDistributor, - public PUSDistributorIF, - public AcceptsTelecommandsIF { +public PUSDistributorIF, +public AcceptsTelecommandsIF { public: - /** - * The ctor passes @c set_apid to the checker class and calls the - * TcDistribution ctor with a certain object id. - * @param setApid The APID of this receiving Application. - * @param setObjectId Object ID of the distributor itself - * @param setPacketSource Object ID of the source of TC packets. - * Must implement CCSDSDistributorIF. - */ - PUSDistributor(uint16_t setApid, object_id_t setObjectId, - object_id_t setPacketSource); - /** - * The destructor is empty. - */ - virtual ~PUSDistributor(); - ReturnValue_t registerService(AcceptsTelecommandsIF* service) override; - MessageQueueId_t getRequestQueue() override; - ReturnValue_t initialize() override; - uint16_t getIdentifier() override; + /** + * The ctor passes @c set_apid to the checker class and calls the + * TcDistribution ctor with a certain object id. + * @param setApid The APID of this receiving Application. + * @param setObjectId Object ID of the distributor itself + * @param setPacketSource Object ID of the source of TC packets. + * Must implement CCSDSDistributorIF. + */ + PUSDistributor(uint16_t setApid, object_id_t setObjectId, + object_id_t setPacketSource); + /** + * The destructor is empty. + */ + virtual ~PUSDistributor(); + ReturnValue_t registerService(AcceptsTelecommandsIF* service) override; + MessageQueueId_t getRequestQueue() override; + ReturnValue_t initialize() override; + uint16_t getIdentifier() override; protected: - /** - * This attribute contains the class, that performs a formal packet check. - */ - TcPacketCheck checker; - /** - * With this class, verification messages are sent to the - * TC Verification service. - */ - VerificationReporter verifyChannel; - /** - * The currently handled packet is stored here. - */ - TcPacketStoredPus* currentPacket = nullptr; + /** + * This attribute contains the class, that performs a formal packet check. + */ + TcPacketCheckPUS checker; + /** + * With this class, verification messages are sent to the + * TC Verification service. + */ + VerificationReporter verifyChannel; + /** + * The currently handled packet is stored here. + */ + TcPacketStoredPus* currentPacket = nullptr; - /** - * With this variable, the current check status is stored to generate - * acceptance messages later. - */ - ReturnValue_t tcStatus; + /** + * With this variable, the current check status is stored to generate + * acceptance messages later. + */ + ReturnValue_t tcStatus; - const object_id_t packetSource; + const object_id_t packetSource; - /** - * This method reads the packet service, checks if such a service is - * registered and forwards the packet to the destination. - * It also initiates the formal packet check and sending of verification - * messages. - * @return Iterator to map entry of found service id - * or iterator to @c map.end(). - */ - TcMqMapIter selectDestination() override; - /** - * The callback here handles the generation of acceptance - * success/failure messages. - */ - ReturnValue_t callbackAfterSending(ReturnValue_t queueStatus) override; + /** + * This method reads the packet service, checks if such a service is + * registered and forwards the packet to the destination. + * It also initiates the formal packet check and sending of verification + * messages. + * @return Iterator to map entry of found service id + * or iterator to @c map.end(). + */ + TcMqMapIter selectDestination() override; + /** + * The callback here handles the generation of acceptance + * success/failure messages. + */ + ReturnValue_t callbackAfterSending(ReturnValue_t queueStatus) override; }; #endif /* FSFW_TCDISTRIBUTION_PUSDISTRIBUTOR_H_ */ diff --git a/src/fsfw/tcdistribution/PUSDistributorIF.h b/src/fsfw/tcdistribution/PUSDistributorIF.h index 0125c08f..e4a66758 100644 --- a/src/fsfw/tcdistribution/PUSDistributorIF.h +++ b/src/fsfw/tcdistribution/PUSDistributorIF.h @@ -10,18 +10,18 @@ */ class PUSDistributorIF { public: - /** - * The empty virtual destructor. - */ - virtual ~PUSDistributorIF() { - } -/** - * With this method, Services can register themselves at the PUS Distributor. - * @param service A pointer to the registering Service. - * @return - @c RETURN_OK on success, - * - @c RETURN_FAILED on failure. - */ - virtual ReturnValue_t registerService( AcceptsTelecommandsIF* service ) = 0; + /** + * The empty virtual destructor. + */ + virtual ~PUSDistributorIF() { + } + /** + * With this method, Services can register themselves at the PUS Distributor. + * @param service A pointer to the registering Service. + * @return - @c RETURN_OK on success, + * - @c RETURN_FAILED on failure. + */ + virtual ReturnValue_t registerService( AcceptsTelecommandsIF* service ) = 0; }; #endif /* FSFW_TCDISTRIBUTION_PUSDISTRIBUTORIF_H_ */ diff --git a/src/fsfw/tcdistribution/TcPacketCheckCFDP.cpp b/src/fsfw/tcdistribution/TcPacketCheckCFDP.cpp new file mode 100644 index 00000000..43e5511b --- /dev/null +++ b/src/fsfw/tcdistribution/TcPacketCheckCFDP.cpp @@ -0,0 +1,13 @@ +#include "fsfw/tcdistribution/TcPacketCheckCFDP.h" +#include "fsfw/tmtcpacket/cfdp/CFDPPacketStored.h" + +TcPacketCheckCFDP::TcPacketCheckCFDP(uint16_t setApid): apid(setApid) { +} + +ReturnValue_t TcPacketCheckCFDP::checkPacket(SpacePacketBase* currentPacket) { + return RETURN_OK; +} + +uint16_t TcPacketCheckCFDP::getApid() const { + return apid; +} diff --git a/src/fsfw/tcdistribution/TcPacketCheckCFDP.h b/src/fsfw/tcdistribution/TcPacketCheckCFDP.h new file mode 100644 index 00000000..8205fe4b --- /dev/null +++ b/src/fsfw/tcdistribution/TcPacketCheckCFDP.h @@ -0,0 +1,35 @@ +#ifndef FSFW_TCDISTRIBUTION_TCPACKETCHECKCFDP_H_ +#define FSFW_TCDISTRIBUTION_TCPACKETCHECKCFDP_H_ + +#include "TcPacketCheckIF.h" + +#include "fsfw/FSFW.h" + +class CFDPPacketStored; + +/** + * This class performs a formal packet check for incoming CFDP Packets. + * @ingroup tc_distribution + */ +class TcPacketCheckCFDP : + public TcPacketCheckIF, + public HasReturnvaluesIF { +protected: + /** + * The packet id each correct packet should have. + * It is composed of the APID and some static fields. + */ + uint16_t apid; +public: + /** + * The constructor only sets the APID attribute. + * @param set_apid The APID to set. + */ + TcPacketCheckCFDP(uint16_t setApid); + + ReturnValue_t checkPacket(SpacePacketBase* currentPacket) override; + + uint16_t getApid() const; +}; + +#endif /* FSFW_TCDISTRIBUTION_TCPACKETCHECKCFDP_H_ */ diff --git a/src/fsfw/tcdistribution/TcPacketCheckIF.h b/src/fsfw/tcdistribution/TcPacketCheckIF.h new file mode 100644 index 00000000..ac1dfef9 --- /dev/null +++ b/src/fsfw/tcdistribution/TcPacketCheckIF.h @@ -0,0 +1,31 @@ +#ifndef FSFW_TCDISTRIBUTION_TCPACKETCHECKIF_H_ +#define FSFW_TCDISTRIBUTION_TCPACKETCHECKIF_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" + +class SpacePacketBase; + +/** + * This interface is used by PacketCheckers for PUS packets and CFDP packets . + * @ingroup tc_distribution + */ +class TcPacketCheckIF { +public: + /** + * The empty virtual destructor. + */ + virtual ~TcPacketCheckIF() { + } + + /** + * This is the actual method to formally check a certain Packet. + * The packet's Application Data can not be checked here. + * @param current_packet The packet to check + * @return - @c RETURN_OK on success. + * - @c INCORRECT_CHECKSUM if checksum is invalid. + * - @c ILLEGAL_APID if APID does not match. + */ + virtual ReturnValue_t checkPacket(SpacePacketBase* currentPacket) = 0; +}; + +#endif /* FSFW_TCDISTRIBUTION_TCPACKETCHECKIF_H_ */ diff --git a/src/fsfw/tcdistribution/TcPacketCheck.cpp b/src/fsfw/tcdistribution/TcPacketCheckPUS.cpp similarity index 65% rename from src/fsfw/tcdistribution/TcPacketCheck.cpp rename to src/fsfw/tcdistribution/TcPacketCheckPUS.cpp index 44501c58..d106a455 100644 --- a/src/fsfw/tcdistribution/TcPacketCheck.cpp +++ b/src/fsfw/tcdistribution/TcPacketCheckPUS.cpp @@ -1,18 +1,20 @@ -#include "fsfw/tcdistribution/TcPacketCheck.h" +#include "fsfw/tcdistribution/TcPacketCheckPUS.h" #include "fsfw/globalfunctions/CRC.h" -#include "fsfw/tmtcpacket/pus/tc/TcPacketBase.h" +#include "fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.h" +#include "fsfw/tmtcpacket/pus/tc/TcPacketPusBase.h" #include "fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h" #include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/storagemanager/StorageManagerIF.h" #include "fsfw/tmtcservices/VerificationCodes.h" -TcPacketCheck::TcPacketCheck(uint16_t setApid): apid(setApid) { +TcPacketCheckPUS::TcPacketCheckPUS(uint16_t setApid): apid(setApid) { } -ReturnValue_t TcPacketCheck::checkPacket(TcPacketStoredBase* currentPacket) { - TcPacketBase* tcPacketBase = currentPacket->getPacketBase(); - if(tcPacketBase == nullptr) { +ReturnValue_t TcPacketCheckPUS::checkPacket(SpacePacketBase* currentPacket) { + TcPacketStoredBase* storedPacket = dynamic_cast(currentPacket); + TcPacketPusBase* tcPacketBase = dynamic_cast(currentPacket); + if(tcPacketBase == nullptr or storedPacket == nullptr) { return RETURN_FAILED; } uint16_t calculated_crc = CRC::crc16ccitt(tcPacketBase->getWholeData(), @@ -29,7 +31,7 @@ ReturnValue_t TcPacketCheck::checkPacket(TcPacketStoredBase* currentPacket) { if (tcPacketBase->getAPID() != this->apid) return ILLEGAL_APID; - if (not currentPacket->isSizeCorrect()) { + if (not storedPacket->isSizeCorrect()) { return INCOMPLETE_PACKET; } @@ -41,6 +43,6 @@ ReturnValue_t TcPacketCheck::checkPacket(TcPacketStoredBase* currentPacket) { return RETURN_OK; } -uint16_t TcPacketCheck::getApid() const { +uint16_t TcPacketCheckPUS::getApid() const { return apid; } diff --git a/src/fsfw/tcdistribution/TcPacketCheck.h b/src/fsfw/tcdistribution/TcPacketCheckPUS.h similarity index 73% rename from src/fsfw/tcdistribution/TcPacketCheck.h rename to src/fsfw/tcdistribution/TcPacketCheckPUS.h index 519943c7..ae4c7789 100644 --- a/src/fsfw/tcdistribution/TcPacketCheck.h +++ b/src/fsfw/tcdistribution/TcPacketCheckPUS.h @@ -1,5 +1,7 @@ -#ifndef FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_ -#define FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_ +#ifndef FSFW_TCDISTRIBUTION_TCPACKETCHECKPUS_H_ +#define FSFW_TCDISTRIBUTION_TCPACKETCHECKPUS_H_ + +#include "TcPacketCheckIF.h" #include "fsfw/FSFW.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h" @@ -12,7 +14,9 @@ class TcPacketStoredBase; * Currently, it only checks if the APID and CRC are correct. * @ingroup tc_distribution */ -class TcPacketCheck : public HasReturnvaluesIF { +class TcPacketCheckPUS : + public TcPacketCheckIF, + public HasReturnvaluesIF { protected: /** * Describes the version number a packet must have to pass. @@ -49,18 +53,11 @@ public: * The constructor only sets the APID attribute. * @param set_apid The APID to set. */ - TcPacketCheck(uint16_t setApid); - /** - * This is the actual method to formally check a certain Telecommand Packet. - * The packet's Application Data can not be checked here. - * @param current_packet The packt to check - * @return - @c RETURN_OK on success. - * - @c INCORRECT_CHECKSUM if checksum is invalid. - * - @c ILLEGAL_APID if APID does not match. - */ - ReturnValue_t checkPacket(TcPacketStoredBase* currentPacket); + TcPacketCheckPUS(uint16_t setApid); + + ReturnValue_t checkPacket(SpacePacketBase* currentPacket) override; uint16_t getApid() const; }; -#endif /* FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_ */ +#endif /* FSFW_TCDISTRIBUTION_TCPACKETCHECKPUS_H_ */ diff --git a/src/fsfw/tmtcpacket/CMakeLists.txt b/src/fsfw/tmtcpacket/CMakeLists.txt index fdc884ec..e1deaba9 100644 --- a/src/fsfw/tmtcpacket/CMakeLists.txt +++ b/src/fsfw/tmtcpacket/CMakeLists.txt @@ -3,5 +3,6 @@ target_sources(${LIB_FSFW_NAME} PRIVATE SpacePacketBase.cpp ) +add_subdirectory(cfdp) add_subdirectory(packetmatcher) add_subdirectory(pus) \ No newline at end of file diff --git a/src/fsfw/tmtcpacket/RedirectableDataPointerIF.h b/src/fsfw/tmtcpacket/RedirectableDataPointerIF.h new file mode 100644 index 00000000..63a760ec --- /dev/null +++ b/src/fsfw/tmtcpacket/RedirectableDataPointerIF.h @@ -0,0 +1,34 @@ +#ifndef TMTCPACKET_PUS_TC_SETTABLEDATAPOINTERIF_H_ +#define TMTCPACKET_PUS_TC_SETTABLEDATAPOINTERIF_H_ + +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include + +/** + * @brief This interface can be used for classes which store a reference to data. It allows + * the implementing class to redirect the data it refers too. + */ +class RedirectableDataPointerIF { +public: + virtual ~RedirectableDataPointerIF() {}; + + /** + * Redirect the data pointer, but allow an implementation to change the data. + * The default implementation also sets a read-only pointer where applicable. + * @param dataPtr + * @param maxSize Maximum allowed size in buffer which holds the data. Can be used for size + * checks if a struct is cast directly onto the data pointer to ensure that the buffer is + * large enough + * @param args Any additional user arguments required to set the data pointer + * @return + * - RETURN_OK if the pointer was set successfully + * - RETURN_FAILED on general error of if the maximum size is too small + */ + virtual ReturnValue_t setData(uint8_t* dataPtr, size_t maxSize, void* args = nullptr) = 0; + +private: +}; + + + +#endif /* FSFW_SRC_FSFW_TMTCPACKET_PUS_TC_SETTABLEDATAPOINTERIF_H_ */ diff --git a/src/fsfw/tmtcpacket/SpacePacket.cpp b/src/fsfw/tmtcpacket/SpacePacket.cpp index cbf82e0d..5284eb5c 100644 --- a/src/fsfw/tmtcpacket/SpacePacket.cpp +++ b/src/fsfw/tmtcpacket/SpacePacket.cpp @@ -5,23 +5,23 @@ SpacePacket::SpacePacket(uint16_t packetDataLength, bool isTelecommand, uint16_t apid, uint16_t sequenceCount): SpacePacketBase( (uint8_t*)&this->localData ) { - initSpacePacketHeader(isTelecommand, false, apid, sequenceCount); - this->setPacketSequenceCount(sequenceCount); - if ( packetDataLength <= sizeof(this->localData.fields.buffer) ) { - this->setPacketDataLength(packetDataLength); - } else { - this->setPacketDataLength( sizeof(this->localData.fields.buffer) ); - } + initSpacePacketHeader(isTelecommand, false, apid, sequenceCount); + this->setPacketSequenceCount(sequenceCount); + if ( packetDataLength <= sizeof(this->localData.fields.buffer) ) { + this->setPacketDataLength(packetDataLength); + } else { + this->setPacketDataLength( sizeof(this->localData.fields.buffer) ); + } } SpacePacket::~SpacePacket( void ) { } bool SpacePacket::addWholeData( const uint8_t* p_Data, uint32_t packet_size ) { - if ( packet_size <= sizeof(this->data) ) { - memcpy( &this->localData.byteStream, p_Data, packet_size ); - return true; - } else { - return false; - } + if ( packet_size <= sizeof(this->data) ) { + memcpy( &this->localData.byteStream, p_Data, packet_size ); + return true; + } else { + return false; + } } diff --git a/src/fsfw/tmtcpacket/SpacePacket.h b/src/fsfw/tmtcpacket/SpacePacket.h index a092712c..d9e51f35 100644 --- a/src/fsfw/tmtcpacket/SpacePacket.h +++ b/src/fsfw/tmtcpacket/SpacePacket.h @@ -26,7 +26,7 @@ public: * @param sequenceCount ets the packet's Source Sequence Count field. */ SpacePacket(uint16_t packetDataLength, bool isTelecommand = false, - uint16_t apid = APID_IDLE_PACKET, uint16_t sequenceCount = 0); + uint16_t apid = APID_IDLE_PACKET, uint16_t sequenceCount = 0); /** * The class's default destructor. */ diff --git a/src/fsfw/tmtcpacket/SpacePacketBase.cpp b/src/fsfw/tmtcpacket/SpacePacketBase.cpp index 16883d7f..58f4feea 100644 --- a/src/fsfw/tmtcpacket/SpacePacketBase.cpp +++ b/src/fsfw/tmtcpacket/SpacePacketBase.cpp @@ -110,10 +110,6 @@ uint8_t* SpacePacketBase::getWholeData() { return (uint8_t*)this->data; } -void SpacePacketBase::setData( const uint8_t* p_Data ) { - this->data = (SpacePacketPointer*)p_Data; -} - uint32_t SpacePacketBase::getApidAndSequenceCount() const { return (getAPID() << 16) + getPacketSequenceCount(); } @@ -121,3 +117,11 @@ uint32_t SpacePacketBase::getApidAndSequenceCount() const { uint8_t* SpacePacketBase::getPacketData() { return &(data->packet_data); } + +ReturnValue_t SpacePacketBase::setData(uint8_t *pData, size_t maxSize, void *args) { + if(maxSize < 6) { + return HasReturnvaluesIF::RETURN_FAILED; + } + this->data = reinterpret_cast(const_cast(pData)); + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/src/fsfw/tmtcpacket/SpacePacketBase.h b/src/fsfw/tmtcpacket/SpacePacketBase.h index 1ebc484f..dfc808e3 100644 --- a/src/fsfw/tmtcpacket/SpacePacketBase.h +++ b/src/fsfw/tmtcpacket/SpacePacketBase.h @@ -1,6 +1,7 @@ #ifndef FSFW_TMTCPACKET_SPACEPACKETBASE_H_ #define FSFW_TMTCPACKET_SPACEPACKETBASE_H_ +#include #include "ccsds_header.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h" @@ -37,7 +38,7 @@ struct SpacePacketPointer { * the most significant bit (from left). * @ingroup tmtcpackets */ -class SpacePacketBase { +class SpacePacketBase: virtual public RedirectableDataPointerIF { protected: /** * A pointer to a structure which defines the data structure of @@ -70,8 +71,7 @@ public: */ virtual ~SpacePacketBase(); - //CCSDS Methods - + //CCSDS Methods: /** * Getter for the packet version number field. * @return Returns the highest three bit of the packet in one byte. @@ -163,7 +163,7 @@ public: */ void setPacketDataLength( uint16_t setLength ); - // Helper methods + //Helper methods: /** * This method returns a raw uint8_t pointer to the packet. * @return A \c uint8_t pointer to the first byte of the CCSDS primary header. @@ -171,12 +171,14 @@ public: virtual uint8_t* getWholeData( void ); uint8_t* getPacketData(); + /** * With this method, the packet data pointer can be redirected to another * location. * @param p_Data A pointer to another raw Space Packet. */ - virtual void setData( const uint8_t* p_Data ); + virtual ReturnValue_t setData(uint8_t* p_Data , size_t maxSize, + void* args = nullptr) override; /** * This method returns the full raw packet size. * @return The full size of the packet in bytes. diff --git a/src/fsfw/tmtcpacket/cfdp/CFDPPacket.cpp b/src/fsfw/tmtcpacket/cfdp/CFDPPacket.cpp new file mode 100644 index 00000000..6172201e --- /dev/null +++ b/src/fsfw/tmtcpacket/cfdp/CFDPPacket.cpp @@ -0,0 +1,20 @@ +#include "fsfw/tmtcpacket/cfdp/CFDPPacket.h" + +#include "fsfw/globalfunctions/CRC.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/serviceinterface/ServiceInterface.h" + +#include + +CFDPPacket::CFDPPacket(const uint8_t* setData): SpacePacketBase(setData) {} + +CFDPPacket::~CFDPPacket() {} + +void CFDPPacket::print() { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "CFDPPacket::print:" << std::endl; +#else + sif::printInfo("CFDPPacket::print:\n"); +#endif + arrayprinter::print(getWholeData(), getFullSize()); +} diff --git a/src/fsfw/tmtcpacket/cfdp/CFDPPacket.h b/src/fsfw/tmtcpacket/cfdp/CFDPPacket.h new file mode 100644 index 00000000..f288a8ae --- /dev/null +++ b/src/fsfw/tmtcpacket/cfdp/CFDPPacket.h @@ -0,0 +1,27 @@ +#ifndef FSFW_INC_FSFW_TMTCPACKET_CFDP_CFDPPACKET_H_ +#define FSFW_INC_FSFW_TMTCPACKET_CFDP_CFDPPACKET_H_ + +#include "fsfw/tmtcpacket/SpacePacketBase.h" + +class CFDPPacket : public SpacePacketBase { +public: + /** + * This is the default constructor. + * It sets its internal data pointer to the address passed and also + * forwards the data pointer to the parent SpacePacketBase class. + * @param setData The position where the packet data lies. + */ + CFDPPacket( const uint8_t* setData ); + /** + * This is the empty default destructor. + */ + virtual ~CFDPPacket(); + + /** + * This is a debugging helper method that prints the whole packet content + * to the screen. + */ + void print(); +}; + +#endif /* FSFW_INC_FSFW_TMTCPACKET_CFDP_CFDPPACKET_H_ */ diff --git a/src/fsfw/tmtcpacket/cfdp/CFDPPacketStored.cpp b/src/fsfw/tmtcpacket/cfdp/CFDPPacketStored.cpp new file mode 100644 index 00000000..568d8981 --- /dev/null +++ b/src/fsfw/tmtcpacket/cfdp/CFDPPacketStored.cpp @@ -0,0 +1,97 @@ +#include "fsfw/tmtcpacket/cfdp/CFDPPacketStored.h" +#include "fsfw/objectmanager/ObjectManager.h" + +StorageManagerIF* CFDPPacketStored::store = nullptr; + +CFDPPacketStored::CFDPPacketStored(): CFDPPacket(nullptr) { +} + +CFDPPacketStored::CFDPPacketStored(store_address_t setAddress): CFDPPacket(nullptr) { + this->setStoreAddress(setAddress); +} + +CFDPPacketStored::CFDPPacketStored(const uint8_t* data, size_t size): CFDPPacket(data) { + if (this->getFullSize() != size) { + return; + } + if (this->checkAndSetStore()) { + ReturnValue_t status = store->addData(&storeAddress, data, size); + if (status != HasReturnvaluesIF::RETURN_OK) { + this->setData(nullptr, -1); + } + const uint8_t* storePtr = nullptr; + // Repoint base data pointer to the data in the store. + store->getData(storeAddress, &storePtr, &size); + this->setData(const_cast(storePtr), size); + } +} + +ReturnValue_t CFDPPacketStored::deletePacket() { + ReturnValue_t result = this->store->deleteData(this->storeAddress); + this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + // To circumvent size checks + this->setData(nullptr, -1); + return result; +} + +//CFDPPacket* CFDPPacketStored::getPacketBase() { +// return this; +//} +void CFDPPacketStored::setStoreAddress(store_address_t setAddress) { + this->storeAddress = setAddress; + const uint8_t* tempData = nullptr; + size_t tempSize; + ReturnValue_t status = StorageManagerIF::RETURN_FAILED; + if (this->checkAndSetStore()) { + status = this->store->getData(this->storeAddress, &tempData, &tempSize); + } + if (status == StorageManagerIF::RETURN_OK) { + this->setData(const_cast(tempData), tempSize); + } else { + // To circumvent size checks + this->setData(nullptr, -1); + this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + } +} + +store_address_t CFDPPacketStored::getStoreAddress() { + return this->storeAddress; +} + +CFDPPacketStored::~CFDPPacketStored() { +} + +ReturnValue_t CFDPPacketStored::getData(const uint8_t **dataPtr, size_t *dataSize) { + return HasReturnvaluesIF::RETURN_OK; +} + +//ReturnValue_t CFDPPacketStored::setData(const uint8_t *data) { +// return HasReturnvaluesIF::RETURN_OK; +//} + +bool CFDPPacketStored::checkAndSetStore() { + if (this->store == nullptr) { + this->store = ObjectManager::instance()->get(objects::TC_STORE); + if (this->store == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "CFDPPacketStored::CFDPPacketStored: TC Store not found!" + << std::endl; +#endif + return false; + } + } + return true; +} + +bool CFDPPacketStored::isSizeCorrect() { + const uint8_t* temp_data = nullptr; + size_t temp_size; + ReturnValue_t status = this->store->getData(this->storeAddress, &temp_data, + &temp_size); + if (status == StorageManagerIF::RETURN_OK) { + if (this->getFullSize() == temp_size) { + return true; + } + } + return false; +} diff --git a/src/fsfw/tmtcpacket/cfdp/CFDPPacketStored.h b/src/fsfw/tmtcpacket/cfdp/CFDPPacketStored.h new file mode 100644 index 00000000..2c03439b --- /dev/null +++ b/src/fsfw/tmtcpacket/cfdp/CFDPPacketStored.h @@ -0,0 +1,67 @@ +#ifndef FSFW_INC_FSFW_TMTCPACKET_CFDP_CFDPPACKETSTORED_H_ +#define FSFW_INC_FSFW_TMTCPACKET_CFDP_CFDPPACKETSTORED_H_ + +#include "../pus/tc/TcPacketStoredBase.h" +#include "CFDPPacket.h" + +class CFDPPacketStored: + public CFDPPacket, + public TcPacketStoredBase { +public: + /** + * Create stored packet with existing data. + * @param data + * @param size + */ + CFDPPacketStored(const uint8_t* data, size_t size); + /** + * Create stored packet from existing packet in store + * @param setAddress + */ + CFDPPacketStored(store_address_t setAddress); + CFDPPacketStored(); + + virtual ~CFDPPacketStored(); + + /** + * Getter function for the raw data. + * @param dataPtr [out] Pointer to the data pointer to set + * @param dataSize [out] Address of size to set. + * @return -@c RETURN_OK if data was retrieved successfully. + */ + ReturnValue_t getData(const uint8_t ** dataPtr, size_t* dataSize); + + void setStoreAddress(store_address_t setAddress); + + store_address_t getStoreAddress(); + + ReturnValue_t deletePacket(); + +private: + + bool isSizeCorrect(); +protected: + /** + * This is a pointer to the store all instances of the class use. + * If the store is not yet set (i.e. @c store is NULL), every constructor + * call tries to set it and throws an error message in case of failures. + * The default store is objects::TC_STORE. + */ + static StorageManagerIF* store; + /** + * The address where the packet data of the object instance is stored. + */ + store_address_t storeAddress; + /** + * A helper method to check if a store is assigned to the class. + * If not, the method tries to retrieve the store from the global + * ObjectManager. + * @return @li @c true if the store is linked or could be created. + * @li @c false otherwise. + */ + bool checkAndSetStore(); +}; + + + +#endif /* FSFW_INC_FSFW_TMTCPACKET_CFDP_CFDPPACKETSTORED_H_ */ diff --git a/src/fsfw/tmtcpacket/cfdp/CMakeLists.txt b/src/fsfw/tmtcpacket/cfdp/CMakeLists.txt new file mode 100644 index 00000000..0b7ab18a --- /dev/null +++ b/src/fsfw/tmtcpacket/cfdp/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + CFDPPacket.cpp + CFDPPacketStored.cpp +) diff --git a/src/fsfw/tmtcpacket/pus/tc/CMakeLists.txt b/src/fsfw/tmtcpacket/pus/tc/CMakeLists.txt index 723b7943..dc611263 100644 --- a/src/fsfw/tmtcpacket/pus/tc/CMakeLists.txt +++ b/src/fsfw/tmtcpacket/pus/tc/CMakeLists.txt @@ -1,5 +1,5 @@ target_sources(${LIB_FSFW_NAME} PRIVATE - TcPacketBase.cpp + TcPacketPusBase.cpp TcPacketPus.cpp TcPacketStoredBase.cpp TcPacketStoredPus.cpp diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp b/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp index 2b97b0d2..dc1eb4bf 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp @@ -3,7 +3,7 @@ #include -TcPacketPus::TcPacketPus(const uint8_t *setData): TcPacketBase(setData) { +TcPacketPus::TcPacketPus(const uint8_t *setData): TcPacketPusBase(setData) { tcData = reinterpret_cast(const_cast(setData)); } @@ -59,13 +59,6 @@ void TcPacketPus::setErrorControl() { (&tcData->appData)[size + 1] = (crc) & 0X00FF; // CRCL } -void TcPacketPus::setData(const uint8_t* pData) { - SpacePacketBase::setData(pData); - // This function is const-correct, but it was decided to keep the pointer non-const - // for convenience. Therefore, cast aways constness here and then cast to packet type. - tcData = reinterpret_cast(const_cast(pData)); -} - uint8_t TcPacketPus::getSecondaryHeaderFlag() const { #if FSFW_USE_PUS_C_TELECOMMANDS == 1 // Does not exist for PUS C @@ -93,5 +86,20 @@ uint16_t TcPacketPus::getSourceId() const { size_t TcPacketPus::calculateFullPacketLength(size_t appDataLen) const { return sizeof(CCSDSPrimaryHeader) + sizeof(PUSTcDataFieldHeader) + - appDataLen + TcPacketBase::CRC_SIZE; + appDataLen + TcPacketPusBase::CRC_SIZE; } + +ReturnValue_t TcPacketPus::setData(uint8_t *dataPtr, size_t maxSize, void *args) { + ReturnValue_t result = SpacePacketBase::setData(dataPtr, maxSize); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(maxSize < sizeof(TcPacketPointer)) { + return HasReturnvaluesIF::RETURN_FAILED; + } + // This function is const-correct, but it was decided to keep the pointer non-const + // for convenience. Therefore, cast away constness here and then cast to packet type. + tcData = reinterpret_cast(const_cast(dataPtr)); + return HasReturnvaluesIF::RETURN_OK; +} + diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h index 1bacc3a7..1b0facaf 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h @@ -4,7 +4,7 @@ #include "fsfw/FSFW.h" #include "../definitions.h" #include "fsfw/tmtcpacket/ccsds_header.h" -#include "TcPacketBase.h" +#include "TcPacketPusBase.h" #include @@ -38,7 +38,7 @@ struct TcPacketPointer { }; -class TcPacketPus: public TcPacketBase { +class TcPacketPus: public TcPacketPusBase { public: static const uint16_t TC_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) + sizeof(PUSTcDataFieldHeader) + 2); @@ -65,7 +65,8 @@ public: protected: - void setData(const uint8_t* pData) override; + ReturnValue_t setData(uint8_t* dataPtr, size_t maxSize, + void* args = nullptr) override; /** * Initializes the Tc Packet header. diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketBase.cpp b/src/fsfw/tmtcpacket/pus/tc/TcPacketPusBase.cpp similarity index 65% rename from src/fsfw/tmtcpacket/pus/tc/TcPacketBase.cpp rename to src/fsfw/tmtcpacket/pus/tc/TcPacketPusBase.cpp index 0c7a4183..1a8850b1 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketBase.cpp +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketPusBase.cpp @@ -1,4 +1,4 @@ -#include "fsfw/tmtcpacket/pus/tc/TcPacketBase.h" +#include "TcPacketPusBase.h" #include "fsfw/globalfunctions/CRC.h" #include "fsfw/globalfunctions/arrayprinter.h" @@ -6,11 +6,11 @@ #include -TcPacketBase::TcPacketBase(const uint8_t* setData): SpacePacketBase(setData) {} +TcPacketPusBase::TcPacketPusBase(const uint8_t* setData): SpacePacketBase(setData) {} -TcPacketBase::~TcPacketBase() {} +TcPacketPusBase::~TcPacketPusBase() {} -void TcPacketBase::print() { +void TcPacketPusBase::print() { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TcPacketBase::print:" << std::endl; #else diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketBase.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketPusBase.h similarity index 93% rename from src/fsfw/tmtcpacket/pus/tc/TcPacketBase.h rename to src/fsfw/tmtcpacket/pus/tc/TcPacketPusBase.h index 14356c8c..b65ca0fb 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketBase.h +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketPusBase.h @@ -1,6 +1,7 @@ #ifndef TMTCPACKET_PUS_TCPACKETBASE_H_ #define TMTCPACKET_PUS_TCPACKETBASE_H_ +#include #include "fsfw/tmtcpacket/SpacePacketBase.h" #include @@ -15,7 +16,8 @@ * check can be performed by making use of the getWholeData method. * @ingroup tmtcpackets */ -class TcPacketBase : public SpacePacketBase { +class TcPacketPusBase : public SpacePacketBase, + virtual public RedirectableDataPointerIF { friend class TcPacketStoredBase; public: @@ -41,11 +43,11 @@ public: * forwards the data pointer to the parent SpacePacketBase class. * @param setData The position where the packet data lies. */ - TcPacketBase( const uint8_t* setData ); + TcPacketPusBase( const uint8_t* setData ); /** * This is the empty default destructor. */ - virtual ~TcPacketBase(); + virtual ~TcPacketPusBase(); /** * This command returns the CCSDS Secondary Header Flag. @@ -133,6 +135,7 @@ public: * to the screen. */ void print(); + protected: /** @@ -143,7 +146,8 @@ protected: * * @param p_data A pointer to another PUS Telecommand Packet. */ - void setData( const uint8_t* pData ) = 0; + virtual ReturnValue_t setData(uint8_t* pData, size_t maxSize, + void* args = nullptr) override = 0; }; diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.cpp b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.cpp index 98ce1725..35bfdfeb 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.cpp +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.cpp @@ -46,7 +46,8 @@ bool TcPacketStoredBase::checkAndSetStore() { return true; } -void TcPacketStoredBase::setStoreAddress(store_address_t setAddress) { +void TcPacketStoredBase::setStoreAddress(store_address_t setAddress, + RedirectableDataPointerIF* packet) { this->storeAddress = setAddress; const uint8_t* tempData = nullptr; size_t tempSize; @@ -54,15 +55,12 @@ void TcPacketStoredBase::setStoreAddress(store_address_t setAddress) { if (this->checkAndSetStore()) { status = this->store->getData(this->storeAddress, &tempData, &tempSize); } - TcPacketBase* tcPacketBase = this->getPacketBase(); - if(tcPacketBase == nullptr) { - return; - } + if (status == StorageManagerIF::RETURN_OK) { - tcPacketBase->setData(tempData); + packet->setData(const_cast(tempData), tempSize); } else { - tcPacketBase->setData(nullptr); + packet->setData(nullptr, -1); this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; } } diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h index 1e1681f6..045d40d8 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h @@ -2,16 +2,10 @@ #define TMTCPACKET_PUS_TCPACKETSTORED_H_ #include "TcPacketStoredIF.h" -#include "../../../storagemanager/StorageManagerIF.h" +#include "fsfw/storagemanager/StorageManagerIF.h" /** - * This class generates a ECSS PUS Telecommand packet within a given - * intermediate storage. - * As most packets are passed between tasks with the help of a storage - * anyway, it seems logical to create a Packet-In-Storage access class - * which saves the user almost all storage handling operation. - * Packets can both be newly created with the class and be "linked" to - * packets in a store with the help of a storeAddress. + * Base class for telecommand packets like CFDP or PUS packets. * @ingroup tmtcpackets */ class TcPacketStoredBase: public TcPacketStoredIF { @@ -44,7 +38,7 @@ public: */ ReturnValue_t getData(const uint8_t ** dataPtr, size_t* dataSize) override; - void setStoreAddress(store_address_t setAddress) override; + void setStoreAddress(store_address_t setAddress, RedirectableDataPointerIF* packet) override; store_address_t getStoreAddress() override; /** diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredIF.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredIF.h index 3d356725..4beafedc 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredIF.h +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredIF.h @@ -1,9 +1,10 @@ #ifndef FSFW_TMTCPACKET_PUS_TCPACKETSTOREDIF_H_ #define FSFW_TMTCPACKET_PUS_TCPACKETSTOREDIF_H_ -#include "TcPacketBase.h" -#include "../../../storagemanager/storeAddress.h" -#include "../../../returnvalues/HasReturnvaluesIF.h" +#include +#include "TcPacketPusBase.h" +#include "fsfw/storagemanager/storeAddress.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" class TcPacketStoredIF { public: @@ -14,7 +15,7 @@ public: * if the packet is a class member and used for more than one packet. * @param setAddress The new packet id to link to. */ - virtual void setStoreAddress(store_address_t setAddress) = 0; + virtual void setStoreAddress(store_address_t setAddress, RedirectableDataPointerIF* packet) = 0; virtual store_address_t getStoreAddress() = 0; @@ -25,12 +26,6 @@ public: * @return -@c RETURN_OK if data was retrieved successfully. */ virtual ReturnValue_t getData(const uint8_t ** dataPtr, size_t* dataSize) = 0; - - /** - * Get packet base pointer which can be used to get access to PUS packet fields - * @return - */ - virtual TcPacketBase* getPacketBase() = 0; }; diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp index 7f8f4ac8..f1ad13e1 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp @@ -22,7 +22,7 @@ TcPacketStoredPus::TcPacketStoredPus(uint16_t apid, uint8_t service, #endif return; } - this->setData(pData); + this->setData(pData, TC_PACKET_MIN_SIZE + size); #if FSFW_USE_PUS_C_TELECOMMANDS == 1 pus::PusVersion pusVersion = pus::PusVersion::PUS_C_VERSION; #else @@ -39,7 +39,7 @@ TcPacketStoredPus::TcPacketStoredPus(): TcPacketStoredBase(), TcPacketPus(nullpt } TcPacketStoredPus::TcPacketStoredPus(store_address_t setAddress): TcPacketPus(nullptr) { - TcPacketStoredBase::setStoreAddress(setAddress); + TcPacketStoredBase::setStoreAddress(setAddress, this); } TcPacketStoredPus::TcPacketStoredPus(const uint8_t* data, size_t size): TcPacketPus(data) { @@ -49,23 +49,24 @@ TcPacketStoredPus::TcPacketStoredPus(const uint8_t* data, size_t size): TcPacket if (this->checkAndSetStore()) { ReturnValue_t status = store->addData(&storeAddress, data, size); if (status != HasReturnvaluesIF::RETURN_OK) { - this->setData(nullptr); + this->setData(nullptr, size); } const uint8_t* storePtr = nullptr; // Repoint base data pointer to the data in the store. store->getData(storeAddress, &storePtr, &size); - this->setData(storePtr); + this->setData(const_cast(storePtr), size); } } ReturnValue_t TcPacketStoredPus::deletePacket() { ReturnValue_t result = this->store->deleteData(this->storeAddress); this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - this->setData(nullptr); + // To circumvent size checks + this->setData(nullptr, -1); return result; } -TcPacketBase* TcPacketStoredPus::getPacketBase() { +TcPacketPusBase* TcPacketStoredPus::getPacketBase() { return this; } diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.h index 8b318733..f0434b33 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.h +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.h @@ -26,7 +26,7 @@ public: */ TcPacketStoredPus(uint16_t apid, uint8_t service, uint8_t subservice, uint8_t sequence_count = 0, const uint8_t* data = nullptr, - size_t size = 0, uint8_t ack = TcPacketBase::ACK_ALL); + size_t size = 0, uint8_t ack = TcPacketPusBase::ACK_ALL); /** * Create stored packet with existing data. * @param data @@ -41,7 +41,7 @@ public: TcPacketStoredPus(); ReturnValue_t deletePacket() override; - TcPacketBase* getPacketBase() override; + TcPacketPusBase* getPacketBase(); private: diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp index ccf5a8ac..933a6b4c 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp @@ -36,9 +36,13 @@ uint16_t TmPacketPusA::getSourceDataSize() { - CRC_SIZE + 1; } -void TmPacketPusA::setData(const uint8_t* p_Data) { - SpacePacketBase::setData(p_Data); - tmData = (TmPacketPointerPusA*) p_Data; +ReturnValue_t TmPacketPusA::setData(uint8_t* p_Data, size_t maxSize, void* args) { + ReturnValue_t result = SpacePacketBase::setData(p_Data, maxSize); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + tmData = reinterpret_cast(const_cast(p_Data)); + return HasReturnvaluesIF::RETURN_OK; } diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h index 3856c779..9bb01890 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h @@ -110,7 +110,8 @@ protected: * * @param p_data A pointer to another PUS Telemetry Packet. */ - void setData( const uint8_t* pData ); + ReturnValue_t setData(uint8_t* pData, size_t maxSize, + void* args = nullptr) override; /** * In case data was filled manually (almost never the case). diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp index 003d565e..f33a896a 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp @@ -35,9 +35,16 @@ uint16_t TmPacketPusC::getSourceDataSize() { return getPacketDataLength() - sizeof(tmData->dataField) - CRC_SIZE + 1; } -void TmPacketPusC::setData(const uint8_t* p_Data) { - SpacePacketBase::setData(p_Data); - tmData = (TmPacketPointerPusC*) p_Data; +ReturnValue_t TmPacketPusC::setData(uint8_t* p_Data, size_t maxSize, void* args) { + ReturnValue_t result = SpacePacketBase::setData(p_Data, maxSize); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(maxSize < sizeof(TmPacketPointerPusC)) { + return HasReturnvaluesIF::RETURN_OK; + } + tmData = reinterpret_cast(const_cast(p_Data)); + return HasReturnvaluesIF::RETURN_OK; } diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h index 3a9be132..b3780183 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h @@ -110,9 +110,9 @@ protected: * This call overwrites the parent's setData method to set both its * @c tc_data pointer and the parent's @c data pointer. * - * @param p_data A pointer to another PUS Telemetry Packet. + * @param pData A pointer to another PUS Telemetry Packet. */ - void setData( const uint8_t* pData ); + ReturnValue_t setData(uint8_t* pData, size_t maxSize, void* args = nullptr) override; /** * In case data was filled manually (almost never the case). diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.cpp index 523fb619..f2cc5a67 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.cpp @@ -27,7 +27,7 @@ store_address_t TmPacketStoredBase::getStoreAddress() { void TmPacketStoredBase::deletePacket() { store->deleteData(storeAddress); storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - setDataPointer(nullptr); + setData(nullptr, -1); } void TmPacketStoredBase::setStoreAddress(store_address_t setAddress) { @@ -39,9 +39,9 @@ void TmPacketStoredBase::setStoreAddress(store_address_t setAddress) { } ReturnValue_t status = store->getData(storeAddress, &tempData, &tempSize); if (status == StorageManagerIF::RETURN_OK) { - setDataPointer(tempData); + setData(const_cast(tempData), tempSize); } else { - setDataPointer(nullptr); + setData(nullptr, -1); storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; } } diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.h index 91ca2f93..372b1e63 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.h @@ -21,7 +21,7 @@ * packets in a store with the help of a storeAddress. * @ingroup tmtcpackets */ -class TmPacketStoredBase { +class TmPacketStoredBase: virtual public RedirectableDataPointerIF { public: /** * This is a default constructor which does not set the data pointer. @@ -33,7 +33,6 @@ public: virtual ~TmPacketStoredBase(); virtual uint8_t* getAllTmData() = 0; - virtual void setDataPointer(const uint8_t* newPointer) = 0; /** * This is a getter for the current store address of the packet. diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp index 4ffacce4..b4b396b5 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp @@ -26,7 +26,7 @@ TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service, handleStoreFailure("A", returnValue, sizeToReserve); return; } - setData(pData); + setData(pData, sizeToReserve); initializeTmPacket(apid, service, subservice, packetSubcounter); memcpy(getSourceData(), headerData, headerSize); memcpy(getSourceData() + headerSize, data, size); @@ -56,7 +56,7 @@ TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service, handleStoreFailure("A", returnValue, sizeToReserve); return; } - setData(pData); + setData(pData, sizeToReserve); initializeTmPacket(apid, service, subservice, packetSubcounter); uint8_t *putDataHere = getSourceData(); size_t size = 0; @@ -75,6 +75,6 @@ uint8_t* TmPacketStoredPusA::getAllTmData() { return getWholeData(); } -void TmPacketStoredPusA::setDataPointer(const uint8_t *newPointer) { - setData(newPointer); +ReturnValue_t TmPacketStoredPusA::setData(uint8_t *newPointer, size_t maxSize, void* args) { + return TmPacketPusA::setData(newPointer, maxSize); } diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.h index 6a338cd5..6fa80949 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.h @@ -57,7 +57,17 @@ public: SerializeIF* header = nullptr); uint8_t* getAllTmData() override; - void setDataPointer(const uint8_t* newPointer) override; + +private: + + /** + * Implementation required by base class + * @param newPointer + * @param maxSize + * @param args + * @return + */ + ReturnValue_t setData(uint8_t* newPointer, size_t maxSize, void* args = nullptr) override; }; diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp index ee574299..8d7dd9eb 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp @@ -27,7 +27,7 @@ TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service, handleStoreFailure("C", returnValue, sizeToReserve); return; } - setData(pData); + setData(pData, sizeToReserve); initializeTmPacket(apid, service, subservice, packetSubcounter, destinationId, timeRefField); memcpy(getSourceData(), headerData, headerSize); memcpy(getSourceData() + headerSize, data, size); @@ -56,7 +56,7 @@ TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service, handleStoreFailure("C", returnValue, sizeToReserve); return; } - setData(pData); + TmPacketPusC::setData(pData, sizeToReserve); initializeTmPacket(apid, service, subservice, packetSubcounter, destinationId, timeRefField); uint8_t *putDataHere = getSourceData(); size_t size = 0; @@ -76,6 +76,7 @@ uint8_t* TmPacketStoredPusC::getAllTmData() { return getWholeData(); } -void TmPacketStoredPusC::setDataPointer(const uint8_t *newPointer) { - setData(newPointer); +ReturnValue_t TmPacketStoredPusC::setData(uint8_t *newPointer, size_t maxSize, + void* args) { + return TmPacketPusC::setData(newPointer, maxSize); } diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.h index 35c66083..cbf62b1b 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.h @@ -59,7 +59,17 @@ public: SerializeIF* header = nullptr, uint16_t destinationId = 0, uint8_t timeRefField = 0); uint8_t* getAllTmData() override; - void setDataPointer(const uint8_t* newPointer) override; + +private: + + /** + * Implementation required by base class + * @param newPointer + * @param maxSize + * @param args + * @return + */ + ReturnValue_t setData(uint8_t* newPointer, size_t maxSize, void* args = nullptr) override; }; diff --git a/src/fsfw/tmtcservices/CommandingServiceBase.cpp b/src/fsfw/tmtcservices/CommandingServiceBase.cpp index 10805b47..00fed415 100644 --- a/src/fsfw/tmtcservices/CommandingServiceBase.cpp +++ b/src/fsfw/tmtcservices/CommandingServiceBase.cpp @@ -13,300 +13,300 @@ object_id_t CommandingServiceBase::defaultPacketSource = objects::NO_OBJECT; object_id_t CommandingServiceBase::defaultPacketDestination = objects::NO_OBJECT; CommandingServiceBase::CommandingServiceBase(object_id_t setObjectId, - uint16_t apid, uint8_t service, uint8_t numberOfParallelCommands, - uint16_t commandTimeoutSeconds, size_t queueDepth) : - SystemObject(setObjectId), apid(apid), service(service), - timeoutSeconds(commandTimeoutSeconds), - commandMap(numberOfParallelCommands) { - commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth); - requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth); + uint16_t apid, uint8_t service, uint8_t numberOfParallelCommands, + uint16_t commandTimeoutSeconds, size_t queueDepth) : + SystemObject(setObjectId), apid(apid), service(service), + timeoutSeconds(commandTimeoutSeconds), + commandMap(numberOfParallelCommands) { + commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth); + requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth); } void CommandingServiceBase::setPacketSource(object_id_t packetSource) { - this->packetSource = packetSource; + this->packetSource = packetSource; } void CommandingServiceBase::setPacketDestination( - object_id_t packetDestination) { - this->packetDestination = packetDestination; + object_id_t packetDestination) { + this->packetDestination = packetDestination; } CommandingServiceBase::~CommandingServiceBase() { - QueueFactory::instance()->deleteMessageQueue(commandQueue); - QueueFactory::instance()->deleteMessageQueue(requestQueue); + QueueFactory::instance()->deleteMessageQueue(commandQueue); + QueueFactory::instance()->deleteMessageQueue(requestQueue); } ReturnValue_t CommandingServiceBase::performOperation(uint8_t opCode) { - handleCommandQueue(); - handleRequestQueue(); - checkTimeout(); - doPeriodicOperation(); - return RETURN_OK; + handleCommandQueue(); + handleRequestQueue(); + checkTimeout(); + doPeriodicOperation(); + return RETURN_OK; } uint16_t CommandingServiceBase::getIdentifier() { - return service; + return service; } MessageQueueId_t CommandingServiceBase::getRequestQueue() { - return requestQueue->getId(); + return requestQueue->getId(); } ReturnValue_t CommandingServiceBase::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + ReturnValue_t result = SystemObject::initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - if(packetDestination == objects::NO_OBJECT) { - packetDestination = defaultPacketDestination; - } - AcceptsTelemetryIF* packetForwarding = - ObjectManager::instance()->get(packetDestination); + if(packetDestination == objects::NO_OBJECT) { + packetDestination = defaultPacketDestination; + } + AcceptsTelemetryIF* packetForwarding = + ObjectManager::instance()->get(packetDestination); - if(packetSource == objects::NO_OBJECT) { - packetSource = defaultPacketSource; - } - PUSDistributorIF* distributor = ObjectManager::instance()->get( - packetSource); + if(packetSource == objects::NO_OBJECT) { + packetSource = defaultPacketSource; + } + PUSDistributorIF* distributor = ObjectManager::instance()->get( + packetSource); - if (packetForwarding == nullptr or distributor == nullptr) { + if (packetForwarding == nullptr or distributor == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "CommandingServiceBase::intialize: Packet source or " - "packet destination invalid!" << std::endl; + sif::error << "CommandingServiceBase::intialize: Packet source or " + "packet destination invalid!" << std::endl; #endif - return ObjectManagerIF::CHILD_INIT_FAILED; - } + return ObjectManagerIF::CHILD_INIT_FAILED; + } - distributor->registerService(this); - requestQueue->setDefaultDestination( - packetForwarding->getReportReceptionQueue()); + distributor->registerService(this); + requestQueue->setDefaultDestination( + packetForwarding->getReportReceptionQueue()); - IPCStore = ObjectManager::instance()->get(objects::IPC_STORE); - TCStore = ObjectManager::instance()->get(objects::TC_STORE); + IPCStore = ObjectManager::instance()->get(objects::IPC_STORE); + TCStore = ObjectManager::instance()->get(objects::TC_STORE); - if (IPCStore == nullptr or TCStore == nullptr) { + if (IPCStore == nullptr or TCStore == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "CommandingServiceBase::intialize: IPC store or TC store " - "not initialized yet!" << std::endl; + sif::error << "CommandingServiceBase::intialize: IPC store or TC store " + "not initialized yet!" << std::endl; #endif - return ObjectManagerIF::CHILD_INIT_FAILED; - } + return ObjectManagerIF::CHILD_INIT_FAILED; + } - return RETURN_OK; + return RETURN_OK; } void CommandingServiceBase::handleCommandQueue() { - CommandMessage reply; - ReturnValue_t result = RETURN_FAILED; - while(true) { - result = commandQueue->receiveMessage(&reply); - if (result == HasReturnvaluesIF::RETURN_OK) { - handleCommandMessage(&reply); - continue; - } - else if(result == MessageQueueIF::EMPTY) { - break; - } - else { + CommandMessage reply; + ReturnValue_t result = RETURN_FAILED; + while(true) { + result = commandQueue->receiveMessage(&reply); + if (result == HasReturnvaluesIF::RETURN_OK) { + handleCommandMessage(&reply); + continue; + } + else if(result == MessageQueueIF::EMPTY) { + break; + } + else { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "CommandingServiceBase::handleCommandQueue: Receiving message failed" - "with code" << result << std::endl; + sif::warning << "CommandingServiceBase::handleCommandQueue: Receiving message failed" + "with code" << result << std::endl; #else - sif::printWarning("CommandingServiceBase::handleCommandQueue: Receiving message " - "failed with code %d\n", result); + sif::printWarning("CommandingServiceBase::handleCommandQueue: Receiving message " + "failed with code %d\n", result); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */ - break; - } - } + break; + } + } } void CommandingServiceBase::handleCommandMessage(CommandMessage* reply) { - bool isStep = false; - CommandMessage nextCommand; - CommandMapIter iter = commandMap.find(reply->getSender()); + bool isStep = false; + CommandMessage nextCommand; + CommandMapIter iter = commandMap.find(reply->getSender()); - // handle unrequested reply first - if (reply->getSender() == MessageQueueIF::NO_QUEUE or - iter == commandMap.end()) { - handleUnrequestedReply(reply); - return; - } - nextCommand.setCommand(CommandMessage::CMD_NONE); + // handle unrequested reply first + if (reply->getSender() == MessageQueueIF::NO_QUEUE or + iter == commandMap.end()) { + handleUnrequestedReply(reply); + return; + } + nextCommand.setCommand(CommandMessage::CMD_NONE); - // Implemented by child class, specifies what to do with reply. - ReturnValue_t result = handleReply(reply, iter->second.command, &iter->second.state, - &nextCommand, iter->second.objectId, &isStep); + // Implemented by child class, specifies what to do with reply. + ReturnValue_t result = handleReply(reply, iter->second.command, &iter->second.state, + &nextCommand, iter->second.objectId, &isStep); - /* If the child implementation does not implement special handling for - * rejected replies (RETURN_FAILED or INVALID_REPLY is returned), a - * failure verification will be generated with the reason as the - * return code and the initial command as failure parameter 1 */ - if((reply->getCommand() == CommandMessage::REPLY_REJECTED) and - (result == RETURN_FAILED or result == INVALID_REPLY)) { - result = reply->getReplyRejectedReason(); - failureParameter1 = iter->second.command; - } + /* If the child implementation does not implement special handling for + * rejected replies (RETURN_FAILED or INVALID_REPLY is returned), a + * failure verification will be generated with the reason as the + * return code and the initial command as failure parameter 1 */ + if((reply->getCommand() == CommandMessage::REPLY_REJECTED) and + (result == RETURN_FAILED or result == INVALID_REPLY)) { + result = reply->getReplyRejectedReason(); + failureParameter1 = iter->second.command; + } - switch (result) { - case EXECUTION_COMPLETE: - case RETURN_OK: - case NO_STEP_MESSAGE: - // handle result of reply handler implemented by developer. - handleReplyHandlerResult(result, iter, &nextCommand, reply, isStep); - break; - case INVALID_REPLY: - //might be just an unrequested reply at a bad moment - handleUnrequestedReply(reply); - break; - default: - if (isStep) { - verificationReporter.sendFailureReport( - tc_verification::PROGRESS_FAILURE, iter->second.tcInfo.ackFlags, - iter->second.tcInfo.tcPacketId, iter->second.tcInfo.tcSequenceControl, - result, ++iter->second.step, failureParameter1, - failureParameter2); - } else { - verificationReporter.sendFailureReport( - tc_verification::COMPLETION_FAILURE, iter->second.tcInfo.ackFlags, - iter->second.tcInfo.tcPacketId, iter->second.tcInfo.tcSequenceControl, - result, 0, failureParameter1, failureParameter2); - } - failureParameter1 = 0; - failureParameter2 = 0; - checkAndExecuteFifo(iter); - break; - } + switch (result) { + case EXECUTION_COMPLETE: + case RETURN_OK: + case NO_STEP_MESSAGE: + // handle result of reply handler implemented by developer. + handleReplyHandlerResult(result, iter, &nextCommand, reply, isStep); + break; + case INVALID_REPLY: + //might be just an unrequested reply at a bad moment + handleUnrequestedReply(reply); + break; + default: + if (isStep) { + verificationReporter.sendFailureReport( + tc_verification::PROGRESS_FAILURE, iter->second.tcInfo.ackFlags, + iter->second.tcInfo.tcPacketId, iter->second.tcInfo.tcSequenceControl, + result, ++iter->second.step, failureParameter1, + failureParameter2); + } else { + verificationReporter.sendFailureReport( + tc_verification::COMPLETION_FAILURE, iter->second.tcInfo.ackFlags, + iter->second.tcInfo.tcPacketId, iter->second.tcInfo.tcSequenceControl, + result, 0, failureParameter1, failureParameter2); + } + failureParameter1 = 0; + failureParameter2 = 0; + checkAndExecuteFifo(iter); + break; + } } void CommandingServiceBase::handleReplyHandlerResult(ReturnValue_t result, - CommandMapIter iter, CommandMessage* nextCommand, - CommandMessage* reply, bool& isStep) { - iter->second.command = nextCommand->getCommand(); + CommandMapIter iter, CommandMessage* nextCommand, + CommandMessage* reply, bool& isStep) { + iter->second.command = nextCommand->getCommand(); - // In case a new command is to be sent immediately, this is performed here. - // If no new command is sent, only analyse reply result by initializing - // sendResult as RETURN_OK - ReturnValue_t sendResult = RETURN_OK; - if (nextCommand->getCommand() != CommandMessage::CMD_NONE) { - sendResult = commandQueue->sendMessage(reply->getSender(), - nextCommand); - } + // In case a new command is to be sent immediately, this is performed here. + // If no new command is sent, only analyse reply result by initializing + // sendResult as RETURN_OK + ReturnValue_t sendResult = RETURN_OK; + if (nextCommand->getCommand() != CommandMessage::CMD_NONE) { + sendResult = commandQueue->sendMessage(reply->getSender(), + nextCommand); + } - if (sendResult == RETURN_OK) { - if (isStep and result != NO_STEP_MESSAGE) { - verificationReporter.sendSuccessReport( - tc_verification::PROGRESS_SUCCESS, - iter->second.tcInfo.ackFlags, iter->second.tcInfo.tcPacketId, - iter->second.tcInfo.tcSequenceControl, ++iter->second.step); - } - else { - verificationReporter.sendSuccessReport( - tc_verification::COMPLETION_SUCCESS, - iter->second.tcInfo.ackFlags, iter->second.tcInfo.tcPacketId, - iter->second.tcInfo.tcSequenceControl, 0); - checkAndExecuteFifo(iter); - } - } - else { - if (isStep) { - nextCommand->clearCommandMessage(); - verificationReporter.sendFailureReport( - tc_verification::PROGRESS_FAILURE, iter->second.tcInfo.ackFlags, - iter->second.tcInfo.tcPacketId, - iter->second.tcInfo.tcSequenceControl, sendResult, - ++iter->second.step, failureParameter1, failureParameter2); - } else { - nextCommand->clearCommandMessage(); - verificationReporter.sendFailureReport( - tc_verification::COMPLETION_FAILURE, - iter->second.tcInfo.ackFlags, iter->second.tcInfo.tcPacketId, - iter->second.tcInfo.tcSequenceControl, sendResult, 0, - failureParameter1, failureParameter2); - } - failureParameter1 = 0; - failureParameter2 = 0; - checkAndExecuteFifo(iter); - } + if (sendResult == RETURN_OK) { + if (isStep and result != NO_STEP_MESSAGE) { + verificationReporter.sendSuccessReport( + tc_verification::PROGRESS_SUCCESS, + iter->second.tcInfo.ackFlags, iter->second.tcInfo.tcPacketId, + iter->second.tcInfo.tcSequenceControl, ++iter->second.step); + } + else { + verificationReporter.sendSuccessReport( + tc_verification::COMPLETION_SUCCESS, + iter->second.tcInfo.ackFlags, iter->second.tcInfo.tcPacketId, + iter->second.tcInfo.tcSequenceControl, 0); + checkAndExecuteFifo(iter); + } + } + else { + if (isStep) { + nextCommand->clearCommandMessage(); + verificationReporter.sendFailureReport( + tc_verification::PROGRESS_FAILURE, iter->second.tcInfo.ackFlags, + iter->second.tcInfo.tcPacketId, + iter->second.tcInfo.tcSequenceControl, sendResult, + ++iter->second.step, failureParameter1, failureParameter2); + } else { + nextCommand->clearCommandMessage(); + verificationReporter.sendFailureReport( + tc_verification::COMPLETION_FAILURE, + iter->second.tcInfo.ackFlags, iter->second.tcInfo.tcPacketId, + iter->second.tcInfo.tcSequenceControl, sendResult, 0, + failureParameter1, failureParameter2); + } + failureParameter1 = 0; + failureParameter2 = 0; + checkAndExecuteFifo(iter); + } } void CommandingServiceBase::handleRequestQueue() { - TmTcMessage message; - ReturnValue_t result; - store_address_t address; - TcPacketStoredPus packet; - MessageQueueId_t queue; - object_id_t objectId; - for (result = requestQueue->receiveMessage(&message); result == RETURN_OK; - result = requestQueue->receiveMessage(&message)) { - address = message.getStorageId(); - packet.setStoreAddress(address); + TmTcMessage message; + ReturnValue_t result; + store_address_t address; + TcPacketStoredPus packet; + MessageQueueId_t queue; + object_id_t objectId; + for (result = requestQueue->receiveMessage(&message); result == RETURN_OK; + result = requestQueue->receiveMessage(&message)) { + address = message.getStorageId(); + packet.setStoreAddress(address, &packet); - if ((packet.getSubService() == 0) - or (isValidSubservice(packet.getSubService()) != RETURN_OK)) { - rejectPacket(tc_verification::START_FAILURE, &packet, INVALID_SUBSERVICE); - continue; - } + if ((packet.getSubService() == 0) + or (isValidSubservice(packet.getSubService()) != RETURN_OK)) { + rejectPacket(tc_verification::START_FAILURE, &packet, INVALID_SUBSERVICE); + continue; + } - result = getMessageQueueAndObject(packet.getSubService(), - packet.getApplicationData(), packet.getApplicationDataSize(), - &queue, &objectId); - if (result != HasReturnvaluesIF::RETURN_OK) { - rejectPacket(tc_verification::START_FAILURE, &packet, result); - continue; - } + result = getMessageQueueAndObject(packet.getSubService(), + packet.getApplicationData(), packet.getApplicationDataSize(), + &queue, &objectId); + if (result != HasReturnvaluesIF::RETURN_OK) { + rejectPacket(tc_verification::START_FAILURE, &packet, result); + continue; + } - //Is a command already active for the target object? - CommandMapIter iter; - iter = commandMap.find(queue); + //Is a command already active for the target object? + CommandMapIter iter; + iter = commandMap.find(queue); - if (iter != commandMap.end()) { - result = iter->second.fifo.insert(address); - if (result != RETURN_OK) { - rejectPacket(tc_verification::START_FAILURE, &packet, OBJECT_BUSY); - } - } else { - CommandInfo newInfo; //Info will be set by startExecution if neccessary - newInfo.objectId = objectId; - result = commandMap.insert(queue, newInfo, &iter); - if (result != RETURN_OK) { - rejectPacket(tc_verification::START_FAILURE, &packet, BUSY); - } else { - startExecution(&packet, iter); - } - } + if (iter != commandMap.end()) { + result = iter->second.fifo.insert(address); + if (result != RETURN_OK) { + rejectPacket(tc_verification::START_FAILURE, &packet, OBJECT_BUSY); + } + } else { + CommandInfo newInfo; //Info will be set by startExecution if neccessary + newInfo.objectId = objectId; + result = commandMap.insert(queue, newInfo, &iter); + if (result != RETURN_OK) { + rejectPacket(tc_verification::START_FAILURE, &packet, BUSY); + } else { + startExecution(&packet, iter); + } + } - } + } } ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, - const uint8_t* data, size_t dataLen, const uint8_t* headerData, - size_t headerSize) { + const uint8_t* data, size_t dataLen, const uint8_t* headerData, + size_t headerSize) { #if FSFW_USE_PUS_C_TELEMETRY == 0 - TmPacketStoredPusA tmPacketStored(this->apid, this->service, subservice, - this->tmPacketCounter, data, dataLen, headerData, headerSize); + TmPacketStoredPusA tmPacketStored(this->apid, this->service, subservice, + this->tmPacketCounter, data, dataLen, headerData, headerSize); #else - TmPacketStoredPusC tmPacketStored(this->apid, this->service, subservice, + TmPacketStoredPusC tmPacketStored(this->apid, this->service, subservice, this->tmPacketCounter, data, dataLen, headerData, headerSize); #endif - ReturnValue_t result = tmPacketStored.sendPacket( - requestQueue->getDefaultDestination(), requestQueue->getId()); - if (result == HasReturnvaluesIF::RETURN_OK) { - this->tmPacketCounter++; - } - return result; + ReturnValue_t result = tmPacketStored.sendPacket( + requestQueue->getDefaultDestination(), requestQueue->getId()); + if (result == HasReturnvaluesIF::RETURN_OK) { + this->tmPacketCounter++; + } + return result; } @@ -316,7 +316,7 @@ ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, uint8_t* pBuffer = buffer; size_t size = 0; SerializeAdapter::serialize(&objectId, &pBuffer, &size, - sizeof(object_id_t), SerializeIF::Endianness::BIG); + sizeof(object_id_t), SerializeIF::Endianness::BIG); #if FSFW_USE_PUS_C_TELEMETRY == 0 TmPacketStoredPusA tmPacketStored(this->apid, this->service, subservice, this->tmPacketCounter, data, dataLen, buffer, size); @@ -351,95 +351,96 @@ ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, } -void CommandingServiceBase::startExecution(TcPacketStoredBase *storedPacket, +void CommandingServiceBase::startExecution(TcPacketStoredPus* storedPacket, CommandMapIter iter) { ReturnValue_t result = RETURN_OK; CommandMessage command; - TcPacketBase* tcPacketBase = storedPacket->getPacketBase(); - if(tcPacketBase == nullptr) { + //TcPacketPusBase* tcPacketBase = storedPacket->getPacketBase(); + if(storedPacket == nullptr) { return; } - iter->second.subservice = tcPacketBase->getSubService(); + iter->second.subservice = storedPacket->getSubService(); result = prepareCommand(&command, iter->second.subservice, - tcPacketBase->getApplicationData(), - tcPacketBase->getApplicationDataSize(), &iter->second.state, + storedPacket->getApplicationData(), + storedPacket->getApplicationDataSize(), &iter->second.state, iter->second.objectId); ReturnValue_t sendResult = RETURN_OK; - switch (result) { - case RETURN_OK: - if (command.getCommand() != CommandMessage::CMD_NONE) { - sendResult = commandQueue->sendMessage(iter.value->first, - &command); - } - if (sendResult == RETURN_OK) { - Clock::getUptime(&iter->second.uptimeOfStart); - iter->second.step = 0; - iter->second.subservice = tcPacketBase->getSubService(); - iter->second.command = command.getCommand(); - iter->second.tcInfo.ackFlags = tcPacketBase->getAcknowledgeFlags(); - iter->second.tcInfo.tcPacketId = tcPacketBase->getPacketId(); - iter->second.tcInfo.tcSequenceControl = - tcPacketBase->getPacketSequenceControl(); - acceptPacket(tc_verification::START_SUCCESS, storedPacket); - } else { - command.clearCommandMessage(); - rejectPacket(tc_verification::START_FAILURE, storedPacket, sendResult); - checkAndExecuteFifo(iter); - } - break; - case EXECUTION_COMPLETE: - if (command.getCommand() != CommandMessage::CMD_NONE) { - //Fire-and-forget command. - sendResult = commandQueue->sendMessage(iter.value->first, - &command); - } - if (sendResult == RETURN_OK) { - verificationReporter.sendSuccessReport(tc_verification::START_SUCCESS, - storedPacket->getPacketBase()); - acceptPacket(tc_verification::COMPLETION_SUCCESS, storedPacket); - checkAndExecuteFifo(iter); - } else { - command.clearCommandMessage(); - rejectPacket(tc_verification::START_FAILURE, storedPacket, sendResult); - checkAndExecuteFifo(iter); - } - break; - default: - rejectPacket(tc_verification::START_FAILURE, storedPacket, result); - checkAndExecuteFifo(iter); - break; - } + switch (result) { + case RETURN_OK: + if (command.getCommand() != CommandMessage::CMD_NONE) { + sendResult = commandQueue->sendMessage(iter.value->first, + &command); + } + if (sendResult == RETURN_OK) { + Clock::getUptime(&iter->second.uptimeOfStart); + iter->second.step = 0; + iter->second.subservice = storedPacket->getSubService(); + iter->second.command = command.getCommand(); + iter->second.tcInfo.ackFlags = storedPacket->getAcknowledgeFlags(); + iter->second.tcInfo.tcPacketId = storedPacket->getPacketId(); + iter->second.tcInfo.tcSequenceControl = + storedPacket->getPacketSequenceControl(); + acceptPacket(tc_verification::START_SUCCESS, storedPacket); + } else { + command.clearCommandMessage(); + rejectPacket(tc_verification::START_FAILURE, storedPacket, sendResult); + checkAndExecuteFifo(iter); + } + break; + case EXECUTION_COMPLETE: + if (command.getCommand() != CommandMessage::CMD_NONE) { + //Fire-and-forget command. + sendResult = commandQueue->sendMessage(iter.value->first, + &command); + } + if (sendResult == RETURN_OK) { + verificationReporter.sendSuccessReport(tc_verification::START_SUCCESS, + storedPacket->getPacketBase()); + acceptPacket(tc_verification::COMPLETION_SUCCESS, storedPacket); + checkAndExecuteFifo(iter); + } else { + command.clearCommandMessage(); + rejectPacket(tc_verification::START_FAILURE, storedPacket, sendResult); + checkAndExecuteFifo(iter); + } + break; + default: + rejectPacket(tc_verification::START_FAILURE, storedPacket, result); + checkAndExecuteFifo(iter); + break; + } } void CommandingServiceBase::rejectPacket(uint8_t reportId, - TcPacketStoredBase* packet, ReturnValue_t errorCode) { - verificationReporter.sendFailureReport(reportId, packet->getPacketBase(), errorCode); - packet->deletePacket(); + TcPacketStoredPus* packet, ReturnValue_t errorCode) { + verificationReporter.sendFailureReport(reportId, dynamic_cast(packet), + errorCode); + packet->deletePacket(); } void CommandingServiceBase::acceptPacket(uint8_t reportId, - TcPacketStoredBase* packet) { - verificationReporter.sendSuccessReport(reportId, packet->getPacketBase()); - packet->deletePacket(); + TcPacketStoredPus* packet) { + verificationReporter.sendSuccessReport(reportId, dynamic_cast(packet)); + packet->deletePacket(); } void CommandingServiceBase::checkAndExecuteFifo(CommandMapIter& iter) { - store_address_t address; - if (iter->second.fifo.retrieve(&address) != RETURN_OK) { - commandMap.erase(&iter); - } else { - TcPacketStoredPus newPacket(address); - startExecution(&newPacket, iter); - } + store_address_t address; + if (iter->second.fifo.retrieve(&address) != RETURN_OK) { + commandMap.erase(&iter); + } else { + TcPacketStoredPus newPacket(address); + startExecution(&newPacket, iter); + } } void CommandingServiceBase::handleUnrequestedReply(CommandMessage* reply) { - reply->clearCommandMessage(); + reply->clearCommandMessage(); } @@ -447,22 +448,22 @@ inline void CommandingServiceBase::doPeriodicOperation() { } MessageQueueId_t CommandingServiceBase::getCommandQueue() { - return commandQueue->getId(); + return commandQueue->getId(); } void CommandingServiceBase::checkTimeout() { - uint32_t uptime; - Clock::getUptime(&uptime); - CommandMapIter iter; - for (iter = commandMap.begin(); iter != commandMap.end(); ++iter) { - if ((iter->second.uptimeOfStart + (timeoutSeconds * 1000)) < uptime) { - verificationReporter.sendFailureReport( - tc_verification::COMPLETION_FAILURE, iter->second.tcInfo.ackFlags, - iter->second.tcInfo.tcPacketId, iter->second.tcInfo.tcSequenceControl, - TIMEOUT); - checkAndExecuteFifo(iter); - } - } + uint32_t uptime; + Clock::getUptime(&uptime); + CommandMapIter iter; + for (iter = commandMap.begin(); iter != commandMap.end(); ++iter) { + if ((iter->second.uptimeOfStart + (timeoutSeconds * 1000)) < uptime) { + verificationReporter.sendFailureReport( + tc_verification::COMPLETION_FAILURE, iter->second.tcInfo.ackFlags, + iter->second.tcInfo.tcPacketId, iter->second.tcInfo.tcSequenceControl, + TIMEOUT); + checkAndExecuteFifo(iter); + } + } } void CommandingServiceBase::setTaskIF(PeriodicTaskIF* task_) { diff --git a/src/fsfw/tmtcservices/CommandingServiceBase.h b/src/fsfw/tmtcservices/CommandingServiceBase.h index b6709693..d9b1b5ef 100644 --- a/src/fsfw/tmtcservices/CommandingServiceBase.h +++ b/src/fsfw/tmtcservices/CommandingServiceBase.h @@ -14,8 +14,8 @@ #include "fsfw/container/FIFO.h" #include "fsfw/serialize/SerializeIF.h" -class TcPacketStored; class TcPacketStoredBase; +class TcPacketStoredPus; namespace Factory{ void setStaticFrameworkObjectIds(); @@ -36,333 +36,333 @@ void setStaticFrameworkObjectIds(); * @ingroup pus_services */ class CommandingServiceBase: public SystemObject, - public AcceptsTelecommandsIF, - public ExecutableObjectIF, - public HasReturnvaluesIF { - friend void (Factory::setStaticFrameworkObjectIds)(); +public AcceptsTelecommandsIF, +public ExecutableObjectIF, +public HasReturnvaluesIF { + friend void (Factory::setStaticFrameworkObjectIds)(); public: - // We could make this configurable via preprocessor and the FSFWConfig file. - static constexpr uint8_t COMMAND_INFO_FIFO_DEPTH = - fsfwconfig::FSFW_CSB_FIFO_DEPTH; + // We could make this configurable via preprocessor and the FSFWConfig file. + static constexpr uint8_t COMMAND_INFO_FIFO_DEPTH = + fsfwconfig::FSFW_CSB_FIFO_DEPTH; - static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_SERVICE_BASE; + static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_SERVICE_BASE; - static const ReturnValue_t EXECUTION_COMPLETE = MAKE_RETURN_CODE(1); - static const ReturnValue_t NO_STEP_MESSAGE = MAKE_RETURN_CODE(2); - static const ReturnValue_t OBJECT_BUSY = MAKE_RETURN_CODE(3); - static const ReturnValue_t BUSY = MAKE_RETURN_CODE(4); - static const ReturnValue_t INVALID_TC = MAKE_RETURN_CODE(5); - static const ReturnValue_t INVALID_OBJECT = MAKE_RETURN_CODE(6); - static const ReturnValue_t INVALID_REPLY = MAKE_RETURN_CODE(7); + static const ReturnValue_t EXECUTION_COMPLETE = MAKE_RETURN_CODE(1); + static const ReturnValue_t NO_STEP_MESSAGE = MAKE_RETURN_CODE(2); + static const ReturnValue_t OBJECT_BUSY = MAKE_RETURN_CODE(3); + static const ReturnValue_t BUSY = MAKE_RETURN_CODE(4); + static const ReturnValue_t INVALID_TC = MAKE_RETURN_CODE(5); + static const ReturnValue_t INVALID_OBJECT = MAKE_RETURN_CODE(6); + static const ReturnValue_t INVALID_REPLY = MAKE_RETURN_CODE(7); - /** - * Class constructor. Initializes two important MessageQueues: - * commandQueue for command reception and requestQueue for device reception - * @param setObjectId - * @param apid - * @param service - * @param numberOfParallelCommands - * @param commandTimeout_seconds - * @param setPacketSource - * @param setPacketDestination - * @param queueDepth - */ - CommandingServiceBase(object_id_t setObjectId, uint16_t apid, - uint8_t service, uint8_t numberOfParallelCommands, - uint16_t commandTimeoutSeconds, size_t queueDepth = 20); - virtual ~CommandingServiceBase(); + /** + * Class constructor. Initializes two important MessageQueues: + * commandQueue for command reception and requestQueue for device reception + * @param setObjectId + * @param apid + * @param service + * @param numberOfParallelCommands + * @param commandTimeout_seconds + * @param setPacketSource + * @param setPacketDestination + * @param queueDepth + */ + CommandingServiceBase(object_id_t setObjectId, uint16_t apid, + uint8_t service, uint8_t numberOfParallelCommands, + uint16_t commandTimeoutSeconds, size_t queueDepth = 20); + virtual ~CommandingServiceBase(); - /** - * This setter can be used to set the packet source individually instead - * of using the default static framework ID set in the factory. - * This should be called at object initialization and not during run-time! - * @param packetSource - */ - void setPacketSource(object_id_t packetSource); - /** - * This setter can be used to set the packet destination individually - * instead of using the default static framework ID set in the factory. - * This should be called at object initialization and not during run-time! - * @param packetDestination - */ - void setPacketDestination(object_id_t packetDestination); + /** + * This setter can be used to set the packet source individually instead + * of using the default static framework ID set in the factory. + * This should be called at object initialization and not during run-time! + * @param packetSource + */ + void setPacketSource(object_id_t packetSource); + /** + * This setter can be used to set the packet destination individually + * instead of using the default static framework ID set in the factory. + * This should be called at object initialization and not during run-time! + * @param packetDestination + */ + void setPacketDestination(object_id_t packetDestination); - /*** - * This is the periodically called function. - * Handle request queue for external commands. - * Handle command Queue for internal commands. - * @param opCode is unused here at the moment - * @return RETURN_OK - */ - virtual ReturnValue_t performOperation(uint8_t opCode) override; + /*** + * This is the periodically called function. + * Handle request queue for external commands. + * Handle command Queue for internal commands. + * @param opCode is unused here at the moment + * @return RETURN_OK + */ + virtual ReturnValue_t performOperation(uint8_t opCode) override; - virtual uint16_t getIdentifier(); + virtual uint16_t getIdentifier(); - /** - * Returns the requestQueue MessageQueueId_t - * - * The requestQueue is the queue for external commands (TC) - * - * @return requestQueue messageQueueId_t - */ - virtual MessageQueueId_t getRequestQueue(); + /** + * Returns the requestQueue MessageQueueId_t + * + * The requestQueue is the queue for external commands (TC) + * + * @return requestQueue messageQueueId_t + */ + virtual MessageQueueId_t getRequestQueue(); - /** - * Returns the commandQueue MessageQueueId_t - * - * Remember the CommandQueue is the queue for internal communication - * @return commandQueue messageQueueId_t - */ - virtual MessageQueueId_t getCommandQueue(); + /** + * Returns the commandQueue MessageQueueId_t + * + * Remember the CommandQueue is the queue for internal communication + * @return commandQueue messageQueueId_t + */ + virtual MessageQueueId_t getCommandQueue(); - virtual ReturnValue_t initialize() override; + virtual ReturnValue_t initialize() override; - /** - * Implementation of ExecutableObjectIF function - * - * Used to setup the reference of the task, that executes this component - * @param task Pointer to the taskIF of this task - */ - virtual void setTaskIF(PeriodicTaskIF* task) override; + /** + * Implementation of ExecutableObjectIF function + * + * Used to setup the reference of the task, that executes this component + * @param task Pointer to the taskIF of this task + */ + virtual void setTaskIF(PeriodicTaskIF* task) override; protected: - /** - * Check the target subservice - * @param subservice[in] - * @return - * -@c RETURN_OK Subservice valid, continue message handling + /** + * Check the target subservice + * @param subservice[in] + * @return + * -@c RETURN_OK Subservice valid, continue message handling * -@c INVALID_SUBSERVICE if service is not known, rejects packet. - */ - virtual ReturnValue_t isValidSubservice(uint8_t subservice) = 0; + */ + virtual ReturnValue_t isValidSubservice(uint8_t subservice) = 0; - /** - * Once a TC Request is valid, the existence of the destination and its - * target interface is checked and retrieved. The target message queue ID - * can then be acquired by using the target interface. - * @param subservice - * @param tcData Application Data of TC Packet - * @param tcDataLen - * @param id MessageQueue ID is stored here - * @param objectId Object ID is extracted and stored here - * @return - * - @c RETURN_OK Cotinue message handling - * - @c RETURN_FAILED Reject the packet and generates a start failure - * verification - */ - virtual ReturnValue_t getMessageQueueAndObject(uint8_t subservice, - const uint8_t *tcData, size_t tcDataLen, MessageQueueId_t *id, - object_id_t *objectId) = 0; + /** + * Once a TC Request is valid, the existence of the destination and its + * target interface is checked and retrieved. The target message queue ID + * can then be acquired by using the target interface. + * @param subservice + * @param tcData Application Data of TC Packet + * @param tcDataLen + * @param id MessageQueue ID is stored here + * @param objectId Object ID is extracted and stored here + * @return + * - @c RETURN_OK Cotinue message handling + * - @c RETURN_FAILED Reject the packet and generates a start failure + * verification + */ + virtual ReturnValue_t getMessageQueueAndObject(uint8_t subservice, + const uint8_t *tcData, size_t tcDataLen, MessageQueueId_t *id, + object_id_t *objectId) = 0; - /** - * After the Message Queue and Object ID are determined, the command is - * prepared by using an implementation specific CommandMessage type - * which is sent to the target object. It contains all necessary information - * for the device to execute telecommands. - * @param message [out] message which can be set and is sent to the object - * @param subservice Subservice of the current communication - * @param tcData Application data of command - * @param tcDataLen Application data length - * @param state [out/in] Setable state of the communication. - * communication - * @param objectId Target object ID - * @return - * - @c RETURN_OK to generate a verification start message - * - @c EXECUTION_COMPELTE Fire-and-forget command. Generate a completion - * verification message. - * - @c Anything else rejects the packets and generates a start failure - * verification. - */ - virtual ReturnValue_t prepareCommand(CommandMessage* message, - uint8_t subservice, const uint8_t *tcData, size_t tcDataLen, - uint32_t *state, object_id_t objectId) = 0; + /** + * After the Message Queue and Object ID are determined, the command is + * prepared by using an implementation specific CommandMessage type + * which is sent to the target object. It contains all necessary information + * for the device to execute telecommands. + * @param message [out] message which can be set and is sent to the object + * @param subservice Subservice of the current communication + * @param tcData Application data of command + * @param tcDataLen Application data length + * @param state [out/in] Setable state of the communication. + * communication + * @param objectId Target object ID + * @return + * - @c RETURN_OK to generate a verification start message + * - @c EXECUTION_COMPELTE Fire-and-forget command. Generate a completion + * verification message. + * - @c Anything else rejects the packets and generates a start failure + * verification. + */ + virtual ReturnValue_t prepareCommand(CommandMessage* message, + uint8_t subservice, const uint8_t *tcData, size_t tcDataLen, + uint32_t *state, object_id_t objectId) = 0; - /** - * This function is implemented by child services to specify how replies - * to a command from another software component are handled. - * @param reply - * This is the reply in form of a generic read-only command message. - * @param previousCommand - * Command_t of related command - * @param state [out/in] - * Additional parameter which can be used to pass state information. - * State of the communication - * @param optionalNextCommand [out] - * An optional next command which can be set in this function - * @param objectId Source object ID - * @param isStep Flag value to mark steps of command execution - * @return - * - @c RETURN_OK, @c EXECUTION_COMPLETE or @c NO_STEP_MESSAGE to - * generate TC verification success - * - @c INVALID_REPLY Calls handleUnrequestedReply - * - Anything else triggers a TC verification failure. If RETURN_FAILED or - * INVALID_REPLY is returned and the command ID is - * CommandMessage::REPLY_REJECTED, a failure verification message with - * the reason as the error parameter and the initial command as - * failure parameter 1 is generated. - */ - virtual ReturnValue_t handleReply(const CommandMessage* reply, - Command_t previousCommand, uint32_t *state, - CommandMessage* optionalNextCommand, object_id_t objectId, - bool *isStep) = 0; + /** + * This function is implemented by child services to specify how replies + * to a command from another software component are handled. + * @param reply + * This is the reply in form of a generic read-only command message. + * @param previousCommand + * Command_t of related command + * @param state [out/in] + * Additional parameter which can be used to pass state information. + * State of the communication + * @param optionalNextCommand [out] + * An optional next command which can be set in this function + * @param objectId Source object ID + * @param isStep Flag value to mark steps of command execution + * @return + * - @c RETURN_OK, @c EXECUTION_COMPLETE or @c NO_STEP_MESSAGE to + * generate TC verification success + * - @c INVALID_REPLY Calls handleUnrequestedReply + * - Anything else triggers a TC verification failure. If RETURN_FAILED or + * INVALID_REPLY is returned and the command ID is + * CommandMessage::REPLY_REJECTED, a failure verification message with + * the reason as the error parameter and the initial command as + * failure parameter 1 is generated. + */ + virtual ReturnValue_t handleReply(const CommandMessage* reply, + Command_t previousCommand, uint32_t *state, + CommandMessage* optionalNextCommand, object_id_t objectId, + bool *isStep) = 0; - /** - * This function can be overidden to handle unrequested reply, - * when the reply sender ID is unknown or is not found is the command map. - * The default implementation will clear the command message and all - * its contents. - * @param reply - * Reply which is non-const so the default implementation can clear the - * message. - */ - virtual void handleUnrequestedReply(CommandMessage* reply); + /** + * This function can be overidden to handle unrequested reply, + * when the reply sender ID is unknown or is not found is the command map. + * The default implementation will clear the command message and all + * its contents. + * @param reply + * Reply which is non-const so the default implementation can clear the + * message. + */ + virtual void handleUnrequestedReply(CommandMessage* reply); - virtual void doPeriodicOperation(); + virtual void doPeriodicOperation(); - struct CommandInfo: public SerializeIF{ - struct tcInfo { - uint8_t ackFlags; - uint16_t tcPacketId; - uint16_t tcSequenceControl; - } tcInfo; - uint32_t uptimeOfStart; - uint8_t step; - uint8_t subservice; - uint32_t state; - Command_t command; - object_id_t objectId; - FIFO fifo; + struct CommandInfo: public SerializeIF{ + struct tcInfo { + uint8_t ackFlags; + uint16_t tcPacketId; + uint16_t tcSequenceControl; + } tcInfo; + uint32_t uptimeOfStart; + uint8_t step; + uint8_t subservice; + uint32_t state; + Command_t command; + object_id_t objectId; + FIFO fifo; - virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, - size_t maxSize, Endianness streamEndianness) const override{ - return HasReturnvaluesIF::RETURN_FAILED; - }; + virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override{ + return HasReturnvaluesIF::RETURN_FAILED; + }; - virtual size_t getSerializedSize() const override { - return 0; - }; + virtual size_t getSerializedSize() const override { + return 0; + }; - virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) override { - return HasReturnvaluesIF::RETURN_FAILED; - }; - }; + virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override { + return HasReturnvaluesIF::RETURN_FAILED; + }; + }; - using CommandMapIter = FixedMap::Iterator; + using CommandMapIter = FixedMap::Iterator; - const uint16_t apid; + const uint16_t apid; - const uint8_t service; + const uint8_t service; - const uint16_t timeoutSeconds; + const uint16_t timeoutSeconds; - uint8_t tmPacketCounter = 0; + uint8_t tmPacketCounter = 0; - StorageManagerIF *IPCStore = nullptr; + StorageManagerIF *IPCStore = nullptr; - StorageManagerIF *TCStore = nullptr; + StorageManagerIF *TCStore = nullptr; - MessageQueueIF* commandQueue = nullptr; + MessageQueueIF* commandQueue = nullptr; - MessageQueueIF* requestQueue = nullptr; + MessageQueueIF* requestQueue = nullptr; - VerificationReporter verificationReporter; + VerificationReporter verificationReporter; - FixedMap commandMap; + FixedMap commandMap; - /* May be set be children to return a more precise failure condition. */ - uint32_t failureParameter1 = 0; - uint32_t failureParameter2 = 0; + /* May be set be children to return a more precise failure condition. */ + uint32_t failureParameter1 = 0; + uint32_t failureParameter2 = 0; - static object_id_t defaultPacketSource; - object_id_t packetSource = objects::NO_OBJECT; - static object_id_t defaultPacketDestination; - object_id_t packetDestination = objects::NO_OBJECT; + static object_id_t defaultPacketSource; + object_id_t packetSource = objects::NO_OBJECT; + static object_id_t defaultPacketDestination; + object_id_t packetDestination = objects::NO_OBJECT; - /** - * Pointer to the task which executes this component, - * is invalid before setTaskIF was called. - */ - PeriodicTaskIF* executingTask = nullptr; + /** + * Pointer to the task which executes this component, + * is invalid before setTaskIF was called. + */ + PeriodicTaskIF* executingTask = nullptr; - /** - * @brief Send TM data from pointer to data. - * If a header is supplied it is added before data - * @param subservice Number of subservice - * @param data Pointer to the data in the Packet - * @param dataLen Lenght of data in the Packet - * @param headerData HeaderData will be placed before data - * @param headerSize Size of HeaderData - */ - ReturnValue_t sendTmPacket(uint8_t subservice, const uint8_t *data, - size_t dataLen, const uint8_t* headerData = nullptr, - size_t headerSize = 0); + /** + * @brief Send TM data from pointer to data. + * If a header is supplied it is added before data + * @param subservice Number of subservice + * @param data Pointer to the data in the Packet + * @param dataLen Lenght of data in the Packet + * @param headerData HeaderData will be placed before data + * @param headerSize Size of HeaderData + */ + ReturnValue_t sendTmPacket(uint8_t subservice, const uint8_t *data, + size_t dataLen, const uint8_t* headerData = nullptr, + size_t headerSize = 0); - /** - * @brief To send TM packets of objects that still need to be serialized - * and consist of an object ID with appended data. - * @param subservice Number of subservice - * @param objectId ObjectId is placed before data - * @param data Data to append to the packet - * @param dataLen Length of Data - */ - ReturnValue_t sendTmPacket(uint8_t subservice, object_id_t objectId, - const uint8_t *data, size_t dataLen); + /** + * @brief To send TM packets of objects that still need to be serialized + * and consist of an object ID with appended data. + * @param subservice Number of subservice + * @param objectId ObjectId is placed before data + * @param data Data to append to the packet + * @param dataLen Length of Data + */ + ReturnValue_t sendTmPacket(uint8_t subservice, object_id_t objectId, + const uint8_t *data, size_t dataLen); - /** - * @brief To send packets which are contained inside a class implementing - * SerializeIF. - * @param subservice Number of subservice - * @param content This is a pointer to the serialized packet - * @param header Serialize IF header which will be placed before content - */ - ReturnValue_t sendTmPacket(uint8_t subservice, SerializeIF* content, - SerializeIF* header = nullptr); + /** + * @brief To send packets which are contained inside a class implementing + * SerializeIF. + * @param subservice Number of subservice + * @param content This is a pointer to the serialized packet + * @param header Serialize IF header which will be placed before content + */ + ReturnValue_t sendTmPacket(uint8_t subservice, SerializeIF* content, + SerializeIF* header = nullptr); - void checkAndExecuteFifo(CommandMapIter& iter); + void checkAndExecuteFifo(CommandMapIter& iter); -private: - /** - * This method handles internal execution of a command, - * once it has been started by @sa{startExecution()} in the request - * queue handler. - * It handles replies generated by the devices and relayed by the specific - * service implementation. This means that it determines further course of - * action depending on the return values specified in the service - * implementation. - * This includes the generation of TC verification messages. Note that - * the static framework object ID @c VerificationReporter::messageReceiver - * needs to be set. - * - TM[1,5] Step Successs - * - TM[1,6] Step Failure - * - TM[1,7] Completion Success - * - TM[1,8] Completion Failure - */ - void handleCommandQueue(); + private: + /** + * This method handles internal execution of a command, + * once it has been started by @sa{startExecution()} in the request + * queue handler. + * It handles replies generated by the devices and relayed by the specific + * service implementation. This means that it determines further course of + * action depending on the return values specified in the service + * implementation. + * This includes the generation of TC verification messages. Note that + * the static framework object ID @c VerificationReporter::messageReceiver + * needs to be set. + * - TM[1,5] Step Successs + * - TM[1,6] Step Failure + * - TM[1,7] Completion Success + * - TM[1,8] Completion Failure + */ + void handleCommandQueue(); - /** - * @brief Handler function for request queue - * @details - * Sequence of request queue handling: - * isValidSubservice -> getMessageQueueAndObject -> startExecution - * Generates a Start Success Reports TM[1,3] in subfunction - * @sa{startExecution()} or a Start Failure Report TM[1,4] by using the - * TC Verification Service. - */ - void handleRequestQueue(); + /** + * @brief Handler function for request queue + * @details + * Sequence of request queue handling: + * isValidSubservice -> getMessageQueueAndObject -> startExecution + * Generates a Start Success Reports TM[1,3] in subfunction + * @sa{startExecution()} or a Start Failure Report TM[1,4] by using the + * TC Verification Service. + */ + void handleRequestQueue(); - void rejectPacket(uint8_t reportId, TcPacketStoredBase* packet, - ReturnValue_t errorCode); + void rejectPacket(uint8_t reportId, TcPacketStoredPus* packet, + ReturnValue_t errorCode); - void acceptPacket(uint8_t reportId, TcPacketStoredBase* packet); + void acceptPacket(uint8_t reportId, TcPacketStoredPus* packet); - void startExecution(TcPacketStoredBase *storedPacket, CommandMapIter iter); + void startExecution(TcPacketStoredPus* storedPacket, CommandMapIter iter); - void handleCommandMessage(CommandMessage* reply); - void handleReplyHandlerResult(ReturnValue_t result, CommandMapIter iter, - CommandMessage* nextCommand, CommandMessage* reply, bool& isStep); + void handleCommandMessage(CommandMessage* reply); + void handleReplyHandlerResult(ReturnValue_t result, CommandMapIter iter, + CommandMessage* nextCommand, CommandMessage* reply, bool& isStep); - void checkTimeout(); + void checkTimeout(); }; #endif /* FSFW_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ */ diff --git a/src/fsfw/tmtcservices/PusServiceBase.cpp b/src/fsfw/tmtcservices/PusServiceBase.cpp index 866e0844..191acd9c 100644 --- a/src/fsfw/tmtcservices/PusServiceBase.cpp +++ b/src/fsfw/tmtcservices/PusServiceBase.cpp @@ -12,28 +12,28 @@ object_id_t PusServiceBase::packetSource = 0; object_id_t PusServiceBase::packetDestination = 0; PusServiceBase::PusServiceBase(object_id_t setObjectId, uint16_t setApid, - uint8_t setServiceId) : - SystemObject(setObjectId), apid(setApid), serviceId(setServiceId) { - requestQueue = QueueFactory::instance()-> - createMessageQueue(PUS_SERVICE_MAX_RECEPTION); + uint8_t setServiceId): + SystemObject(setObjectId), apid(setApid), serviceId(setServiceId) { + requestQueue = QueueFactory::instance()-> + createMessageQueue(PUS_SERVICE_MAX_RECEPTION); } PusServiceBase::~PusServiceBase() { - QueueFactory::instance()->deleteMessageQueue(requestQueue); + QueueFactory::instance()->deleteMessageQueue(requestQueue); } ReturnValue_t PusServiceBase::performOperation(uint8_t opCode) { - handleRequestQueue(); - ReturnValue_t result = this->performService(); - if (result != RETURN_OK) { + handleRequestQueue(); + ReturnValue_t result = this->performService(); + if (result != RETURN_OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PusService " << (uint16_t) this->serviceId - << ": performService returned with " << (int16_t) result - << std::endl; + sif::error << "PusService " << (uint16_t) this->serviceId + << ": performService returned with " << (int16_t) result + << std::endl; #endif - return RETURN_FAILED; - } - return RETURN_OK; + return RETURN_FAILED; + } + return RETURN_OK; } void PusServiceBase::setTaskIF(PeriodicTaskIF* taskHandle) { @@ -41,88 +41,88 @@ void PusServiceBase::setTaskIF(PeriodicTaskIF* taskHandle) { } void PusServiceBase::handleRequestQueue() { - TmTcMessage message; - ReturnValue_t result = RETURN_FAILED; - for (uint8_t count = 0; count < PUS_SERVICE_MAX_RECEPTION; count++) { - ReturnValue_t status = this->requestQueue->receiveMessage(&message); -// if(status != MessageQueueIF::EMPTY) { + TmTcMessage message; + ReturnValue_t result = RETURN_FAILED; + for (uint8_t count = 0; count < PUS_SERVICE_MAX_RECEPTION; count++) { + ReturnValue_t status = this->requestQueue->receiveMessage(&message); + // if(status != MessageQueueIF::EMPTY) { #if FSFW_CPP_OSTREAM_ENABLED == 1 -// sif::debug << "PusServiceBase::performOperation: Receiving from " -// << "MQ ID: " << std::hex << "0x" << std::setw(8) -// << std::setfill('0') << this->requestQueue->getId() -// << std::dec << " returned: " << status << std::setfill(' ') -// << std::endl; + // sif::debug << "PusServiceBase::performOperation: Receiving from " + // << "MQ ID: " << std::hex << "0x" << std::setw(8) + // << std::setfill('0') << this->requestQueue->getId() + // << std::dec << " returned: " << status << std::setfill(' ') + // << std::endl; #endif -// } + // } - if (status == RETURN_OK) { - this->currentPacket.setStoreAddress(message.getStorageId()); - //info << "Service " << (uint16_t) this->serviceId << - // ": new packet!" << std::endl; + if (status == RETURN_OK) { + this->currentPacket.setStoreAddress(message.getStorageId(), ¤tPacket); + //info << "Service " << (uint16_t) this->serviceId << + // ": new packet!" << std::endl; - result = this->handleRequest(currentPacket.getSubService()); + result = this->handleRequest(currentPacket.getSubService()); - // debug << "Service " << (uint16_t)this->serviceId << - // ": handleRequest returned: " << (int)return_code << std::endl; - if (result == RETURN_OK) { - this->verifyReporter.sendSuccessReport( - tc_verification::COMPLETION_SUCCESS, &this->currentPacket); - } - else { - this->verifyReporter.sendFailureReport( - tc_verification::COMPLETION_FAILURE, &this->currentPacket, - result, 0, errorParameter1, errorParameter2); - } - this->currentPacket.deletePacket(); - errorParameter1 = 0; - errorParameter2 = 0; - } - else if (status == MessageQueueIF::EMPTY) { - status = RETURN_OK; - // debug << "PusService " << (uint16_t)this->serviceId << - // ": no new packet." << std::endl; - break; - } - else { + // debug << "Service " << (uint16_t)this->serviceId << + // ": handleRequest returned: " << (int)return_code << std::endl; + if (result == RETURN_OK) { + this->verifyReporter.sendSuccessReport( + tc_verification::COMPLETION_SUCCESS, &this->currentPacket); + } + else { + this->verifyReporter.sendFailureReport( + tc_verification::COMPLETION_FAILURE, &this->currentPacket, + result, 0, errorParameter1, errorParameter2); + } + this->currentPacket.deletePacket(); + errorParameter1 = 0; + errorParameter2 = 0; + } + else if (status == MessageQueueIF::EMPTY) { + status = RETURN_OK; + // debug << "PusService " << (uint16_t)this->serviceId << + // ": no new packet." << std::endl; + break; + } + else { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PusServiceBase::performOperation: Service " - << this->serviceId << ": Error receiving packet. Code: " - << std::hex << status << std::dec << std::endl; + sif::error << "PusServiceBase::performOperation: Service " + << this->serviceId << ": Error receiving packet. Code: " + << std::hex << status << std::dec << std::endl; #endif - } - } + } + } } uint16_t PusServiceBase::getIdentifier() { - return this->serviceId; + return this->serviceId; } MessageQueueId_t PusServiceBase::getRequestQueue() { - return this->requestQueue->getId(); + return this->requestQueue->getId(); } ReturnValue_t PusServiceBase::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != RETURN_OK) { - return result; - } - AcceptsTelemetryIF* destService = ObjectManager::instance()->get( - packetDestination); - PUSDistributorIF* distributor = ObjectManager::instance()->get( - packetSource); - if (destService == nullptr or distributor == nullptr) { + ReturnValue_t result = SystemObject::initialize(); + if (result != RETURN_OK) { + return result; + } + AcceptsTelemetryIF* destService = ObjectManager::instance()->get( + packetDestination); + PUSDistributorIF* distributor = ObjectManager::instance()->get( + packetSource); + if (destService == nullptr or distributor == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PusServiceBase::PusServiceBase: Service " - << this->serviceId << ": Configuration error. Make sure " - << "packetSource and packetDestination are defined correctly" - << std::endl; + sif::error << "PusServiceBase::PusServiceBase: Service " + << this->serviceId << ": Configuration error. Make sure " + << "packetSource and packetDestination are defined correctly" + << std::endl; #endif - return ObjectManagerIF::CHILD_INIT_FAILED; - } - this->requestQueue->setDefaultDestination( - destService->getReportReceptionQueue()); - distributor->registerService(this); - return HasReturnvaluesIF::RETURN_OK; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + this->requestQueue->setDefaultDestination( + destService->getReportReceptionQueue()); + distributor->registerService(this); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t PusServiceBase::initializeAfterTaskCreation() { diff --git a/src/fsfw/tmtcservices/PusServiceBase.h b/src/fsfw/tmtcservices/PusServiceBase.h index ea4147fe..ec338331 100644 --- a/src/fsfw/tmtcservices/PusServiceBase.h +++ b/src/fsfw/tmtcservices/PusServiceBase.h @@ -35,126 +35,126 @@ void setStaticFrameworkObjectIds(); * @ingroup pus_services */ class PusServiceBase : public ExecutableObjectIF, - public AcceptsTelecommandsIF, - public SystemObject, - public HasReturnvaluesIF { - friend void (Factory::setStaticFrameworkObjectIds)(); +public AcceptsTelecommandsIF, +public SystemObject, +public HasReturnvaluesIF { + friend void (Factory::setStaticFrameworkObjectIds)(); public: - /** - * @brief The passed values are set, but inter-object initialization is - * done in the initialize method. - * @param setObjectId - * The system object identifier of this Service instance. - * @param setApid - * The APID the Service is instantiated for. - * @param setServiceId - * The Service Identifier as specified in ECSS PUS. - */ - PusServiceBase( object_id_t setObjectId, uint16_t setApid, - uint8_t setServiceId); - /** - * The destructor is empty. - */ - virtual ~PusServiceBase(); - /** - * @brief The handleRequest method shall handle any kind of Telecommand - * Request immediately. - * @details - * Implemetations can take the Telecommand in currentPacket and perform - * any kind of operation. - * They may send additional "Start Success (1,3)" messages with the - * verifyReporter, but Completion Success or Failure Reports are generated - * automatically after execution of this method. - * - * If a Telecommand can not be executed within one call cycle, - * this Base class is not the right parent. - * - * The child class may add additional error information by setting - * #errorParameters which aren attached to the generated verification - * message. - * - * Subservice checking should be implemented in this method. - * - * @return The returned status_code is directly taken as main error code - * in the Verification Report. - * On success, RETURN_OK shall be returned. - */ - virtual ReturnValue_t handleRequest(uint8_t subservice) = 0; - /** - * In performService, implementations can handle periodic, - * non-TC-triggered activities. - * The performService method is always called. - * @return Currently, everything other that RETURN_OK only triggers - * diagnostic output. - */ - virtual ReturnValue_t performService() = 0; - /** - * This method implements the typical activity of a simple PUS Service. - * It checks for new requests, and, if found, calls handleRequest, sends - * completion verification messages and deletes - * the TC requests afterwards. - * performService is always executed afterwards. - * @return @c RETURN_OK if the periodic performService was successful. - * @c RETURN_FAILED else. - */ - ReturnValue_t performOperation(uint8_t opCode) override; - virtual uint16_t getIdentifier() override; - MessageQueueId_t getRequestQueue() override; - virtual ReturnValue_t initialize() override; + /** + * @brief The passed values are set, but inter-object initialization is + * done in the initialize method. + * @param setObjectId + * The system object identifier of this Service instance. + * @param setApid + * The APID the Service is instantiated for. + * @param setServiceId + * The Service Identifier as specified in ECSS PUS. + */ + PusServiceBase( object_id_t setObjectId, uint16_t setApid, + uint8_t setServiceId); + /** + * The destructor is empty. + */ + virtual ~PusServiceBase(); + /** + * @brief The handleRequest method shall handle any kind of Telecommand + * Request immediately. + * @details + * Implemetations can take the Telecommand in currentPacket and perform + * any kind of operation. + * They may send additional "Start Success (1,3)" messages with the + * verifyReporter, but Completion Success or Failure Reports are generated + * automatically after execution of this method. + * + * If a Telecommand can not be executed within one call cycle, + * this Base class is not the right parent. + * + * The child class may add additional error information by setting + * #errorParameters which aren attached to the generated verification + * message. + * + * Subservice checking should be implemented in this method. + * + * @return The returned status_code is directly taken as main error code + * in the Verification Report. + * On success, RETURN_OK shall be returned. + */ + virtual ReturnValue_t handleRequest(uint8_t subservice) = 0; + /** + * In performService, implementations can handle periodic, + * non-TC-triggered activities. + * The performService method is always called. + * @return Currently, everything other that RETURN_OK only triggers + * diagnostic output. + */ + virtual ReturnValue_t performService() = 0; + /** + * This method implements the typical activity of a simple PUS Service. + * It checks for new requests, and, if found, calls handleRequest, sends + * completion verification messages and deletes + * the TC requests afterwards. + * performService is always executed afterwards. + * @return @c RETURN_OK if the periodic performService was successful. + * @c RETURN_FAILED else. + */ + ReturnValue_t performOperation(uint8_t opCode) override; + virtual uint16_t getIdentifier() override; + MessageQueueId_t getRequestQueue() override; + virtual ReturnValue_t initialize() override; - virtual void setTaskIF(PeriodicTaskIF* taskHandle) override; - virtual ReturnValue_t initializeAfterTaskCreation() override; + virtual void setTaskIF(PeriodicTaskIF* taskHandle) override; + virtual ReturnValue_t initializeAfterTaskCreation() override; protected: - /** - * @brief Handle to the underlying task - * @details - * Will be set by setTaskIF(), which is called on task creation. - */ - PeriodicTaskIF* taskHandle = nullptr; - /** - * The APID of this instance of the Service. - */ - uint16_t apid; - /** - * The Service Identifier. - */ - uint8_t serviceId; - /** - * One of two error parameters for additional error information. - */ - uint32_t errorParameter1 = 0; - /** - * One of two error parameters for additional error information. - */ - uint32_t errorParameter2 = 0; - /** - * This is a complete instance of the telecommand reception queue - * of the class. It is initialized on construction of the class. - */ - MessageQueueIF* requestQueue = nullptr; - /** - * An instance of the VerificationReporter class, that simplifies - * sending any kind of verification message to the TC Verification Service. - */ - VerificationReporter verifyReporter; - /** - * The current Telecommand to be processed. - * It is deleted after handleRequest was executed. - */ - TcPacketStoredPus currentPacket; + /** + * @brief Handle to the underlying task + * @details + * Will be set by setTaskIF(), which is called on task creation. + */ + PeriodicTaskIF* taskHandle = nullptr; + /** + * The APID of this instance of the Service. + */ + uint16_t apid; + /** + * The Service Identifier. + */ + uint8_t serviceId; + /** + * One of two error parameters for additional error information. + */ + uint32_t errorParameter1 = 0; + /** + * One of two error parameters for additional error information. + */ + uint32_t errorParameter2 = 0; + /** + * This is a complete instance of the telecommand reception queue + * of the class. It is initialized on construction of the class. + */ + MessageQueueIF* requestQueue = nullptr; + /** + * An instance of the VerificationReporter class, that simplifies + * sending any kind of verification message to the TC Verification Service. + */ + VerificationReporter verifyReporter; + /** + * The current Telecommand to be processed. + * It is deleted after handleRequest was executed. + */ + TcPacketStoredPus currentPacket; - static object_id_t packetSource; + static object_id_t packetSource; - static object_id_t packetDestination; + static object_id_t packetDestination; private: - /** - * This constant sets the maximum number of packets accepted per call. - * Remember that one packet must be completely handled in one - * #handleRequest call. - */ - static const uint8_t PUS_SERVICE_MAX_RECEPTION = 10; + /** + * This constant sets the maximum number of packets accepted per call. + * Remember that one packet must be completely handled in one + * #handleRequest call. + */ + static const uint8_t PUS_SERVICE_MAX_RECEPTION = 10; - void handleRequestQueue(); + void handleRequestQueue(); }; #endif /* FSFW_TMTCSERVICES_PUSSERVICEBASE_H_ */ diff --git a/src/fsfw/tmtcservices/PusVerificationReport.h b/src/fsfw/tmtcservices/PusVerificationReport.h index c22ba535..bc9793d9 100644 --- a/src/fsfw/tmtcservices/PusVerificationReport.h +++ b/src/fsfw/tmtcservices/PusVerificationReport.h @@ -4,7 +4,7 @@ #include "VerificationCodes.h" #include "fsfw/ipc/MessageQueueMessage.h" -#include "fsfw/tmtcpacket/pus/tc/TcPacketBase.h" +#include "fsfw/tmtcpacket/pus/tc/TcPacketPusBase.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h" class PusVerificationMessage: public MessageQueueMessage { diff --git a/src/fsfw/tmtcservices/VerificationReporter.cpp b/src/fsfw/tmtcservices/VerificationReporter.cpp index 2b371d1e..b885cccf 100644 --- a/src/fsfw/tmtcservices/VerificationReporter.cpp +++ b/src/fsfw/tmtcservices/VerificationReporter.cpp @@ -17,7 +17,7 @@ VerificationReporter::VerificationReporter() : VerificationReporter::~VerificationReporter() {} void VerificationReporter::sendSuccessReport(uint8_t set_report_id, - TcPacketBase* currentPacket, uint8_t set_step) { + TcPacketPusBase* currentPacket, uint8_t set_step) { if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); } @@ -59,7 +59,7 @@ void VerificationReporter::sendSuccessReport(uint8_t set_report_id, } void VerificationReporter::sendFailureReport(uint8_t report_id, - TcPacketBase* currentPacket, ReturnValue_t error_code, uint8_t step, + TcPacketPusBase* currentPacket, ReturnValue_t error_code, uint8_t step, uint32_t parameter1, uint32_t parameter2) { if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); diff --git a/src/fsfw/tmtcservices/VerificationReporter.h b/src/fsfw/tmtcservices/VerificationReporter.h index 4a64d3df..d57cc791 100644 --- a/src/fsfw/tmtcservices/VerificationReporter.h +++ b/src/fsfw/tmtcservices/VerificationReporter.h @@ -25,13 +25,13 @@ public: VerificationReporter(); virtual ~VerificationReporter(); - void sendSuccessReport( uint8_t set_report_id, TcPacketBase* current_packet, + void sendSuccessReport( uint8_t set_report_id, TcPacketPusBase* current_packet, uint8_t set_step = 0 ); void sendSuccessReport(uint8_t set_report_id, uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, uint8_t set_step = 0); - void sendFailureReport( uint8_t report_id, TcPacketBase* current_packet, + void sendFailureReport( uint8_t report_id, TcPacketPusBase* current_packet, ReturnValue_t error_code = 0, uint8_t step = 0, uint32_t parameter1 = 0, uint32_t parameter2 = 0 ); diff --git a/tests/src/fsfw_tests/unit/CMakeLists.txt b/tests/src/fsfw_tests/unit/CMakeLists.txt index 164e3bde..ce0d313c 100644 --- a/tests/src/fsfw_tests/unit/CMakeLists.txt +++ b/tests/src/fsfw_tests/unit/CMakeLists.txt @@ -21,3 +21,4 @@ add_subdirectory(storagemanager) add_subdirectory(globalfunctions) add_subdirectory(timemanager) add_subdirectory(tmtcpacket) +add_subdirectory(cfdp) diff --git a/tests/src/fsfw_tests/unit/cfdp/CMakeLists.txt b/tests/src/fsfw_tests/unit/cfdp/CMakeLists.txt new file mode 100644 index 00000000..8e18cd3b --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/CMakeLists.txt @@ -0,0 +1,12 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE + testCfdp.cpp + testTlvsLvs.cpp + testAckPdu.cpp + testEofPdu.cpp + testNakPdu.cpp + testFinishedPdu.cpp + testPromptPdu.cpp + testKeepAlivePdu.cpp + testMetadataPdu.cpp + testFileData.cpp +) diff --git a/tests/src/fsfw_tests/unit/cfdp/testAckPdu.cpp b/tests/src/fsfw_tests/unit/cfdp/testAckPdu.cpp new file mode 100644 index 00000000..70576543 --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testAckPdu.cpp @@ -0,0 +1,101 @@ +#include + +#include "fsfw/cfdp/pdu/AckPduDeserializer.h" +#include "fsfw/cfdp/pdu/AckPduSerializer.h" +#include "fsfw/globalfunctions/arrayprinter.h" + +#include + +TEST_CASE( "ACK PDU" , "[AckPdu]") { + + using namespace cfdp; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::array buf = {}; + uint8_t* bufptr = buf.data(); + size_t maxsz = buf.size(); + size_t sz = 0; + auto seqNum = TransactionSeqNum(WidthInBytes::TWO_BYTES, 15); + auto sourceId = EntityId(WidthInBytes::TWO_BYTES, 1); + auto destId = EntityId(WidthInBytes::TWO_BYTES, 2); + auto pduConf = PduConfig(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); + AckInfo ackInfo(FileDirectives::EOF_DIRECTIVE, ConditionCode::NO_ERROR, AckTransactionStatus::ACTIVE); + auto ackSerializer = AckPduSerializer(ackInfo, pduConf); + result = ackSerializer.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + SECTION("Serialize") { + REQUIRE(buf.data()[sz - 3] == cfdp::FileDirectives::ACK); + REQUIRE((buf.data()[sz - 2] >> 4) == FileDirectives::EOF_DIRECTIVE); + REQUIRE((buf.data()[sz - 2] & 0x0f) == 0); + REQUIRE(buf.data()[sz - 1] == AckTransactionStatus::ACTIVE); + ackInfo.setAckedDirective(FileDirectives::FINISH); + ackInfo.setAckedConditionCode(ConditionCode::FILESTORE_REJECTION); + ackInfo.setTransactionStatus(AckTransactionStatus::TERMINATED); + auto ackSerializer2 = AckPduSerializer(ackInfo, pduConf); + bufptr = buf.data(); + sz = 0; + result = ackSerializer2.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(buf.data()[sz - 3] == cfdp::FileDirectives::ACK); + REQUIRE((buf.data()[sz - 2] >> 4) == FileDirectives::FINISH); + REQUIRE((buf.data()[sz - 2] & 0x0f) == 0b0001); + REQUIRE((buf.data()[sz - 1] >> 4) == ConditionCode::FILESTORE_REJECTION); + REQUIRE((buf.data()[sz - 1] & 0b11) == AckTransactionStatus::TERMINATED); + + bufptr = buf.data(); + sz = 0; + ackInfo.setAckedDirective(FileDirectives::KEEP_ALIVE); + auto ackSerializer3 = AckPduSerializer(ackInfo, pduConf); + result = ackSerializer3.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK); + // Invalid file directive + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + + ackInfo.setAckedDirective(FileDirectives::FINISH); + // buffer too small + result = ackSerializer.serialize(&bufptr, &sz, 8, SerializeIF::Endianness::NETWORK); + REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT); + } + + SECTION("Deserialize") { + AckInfo ackInfo; + auto reader = AckPduDeserializer(buf.data(), sz, ackInfo); + result = reader.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(ackInfo.getAckedDirective() == FileDirectives::EOF_DIRECTIVE); + REQUIRE(ackInfo.getAckedConditionCode() == ConditionCode::NO_ERROR); + REQUIRE(ackInfo.getDirectiveSubtypeCode() == 0); + REQUIRE(ackInfo.getTransactionStatus() == AckTransactionStatus::ACTIVE); + + AckInfo newInfo = AckInfo(FileDirectives::FINISH, + ConditionCode::FILESTORE_REJECTION, AckTransactionStatus::TERMINATED); + auto ackSerializer2 = AckPduSerializer(newInfo, pduConf); + bufptr = buf.data(); + sz = 0; + result = ackSerializer2.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + auto reader2 = AckPduDeserializer(buf.data(), sz, ackInfo); + result = reader2.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(ackInfo.getAckedDirective() == FileDirectives::FINISH); + REQUIRE(ackInfo.getAckedConditionCode() == ConditionCode::FILESTORE_REJECTION); + REQUIRE(ackInfo.getDirectiveSubtypeCode() == 0b0001); + REQUIRE(ackInfo.getTransactionStatus() == AckTransactionStatus::TERMINATED); + + uint8_t prevVal = buf[sz - 2]; + buf[sz - 2] = FileDirectives::INVALID_DIRECTIVE << 4; + result = reader2.parseData(); + REQUIRE(result == cfdp::INVALID_ACK_DIRECTIVE_FIELDS); + buf[sz - 2] = FileDirectives::FINISH << 4 | 0b1111; + result = reader2.parseData(); + REQUIRE(result == cfdp::INVALID_ACK_DIRECTIVE_FIELDS); + buf[sz - 2] = prevVal; + buf[sz - 3] = cfdp::FileDirectives::INVALID_DIRECTIVE; + result = reader2.parseData(); + REQUIRE(result == cfdp::INVALID_DIRECTIVE_FIELDS); + buf[sz - 3] = cfdp::FileDirectives::ACK; + auto maxSizeTooSmall = AckPduDeserializer(buf.data(), sz - 2, ackInfo); + result = maxSizeTooSmall.parseData(); + REQUIRE(result == SerializeIF::STREAM_TOO_SHORT); + } +} diff --git a/tests/src/fsfw_tests/unit/cfdp/testCfdp.cpp b/tests/src/fsfw_tests/unit/cfdp/testCfdp.cpp new file mode 100644 index 00000000..7db3800d --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testCfdp.cpp @@ -0,0 +1,372 @@ +#include +#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" +#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" +#include "fsfw/cfdp/pdu/HeaderDeserializer.h" +#include "fsfw_tests/unit/CatchDefinitions.h" +#include "fsfw/cfdp/FileSize.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/cfdp/pdu/HeaderSerializer.h" +#include "fsfw/serialize/SerializeAdapter.h" + +#include +#include + +TEST_CASE( "CFDP Base" , "[CfdpBase]") { + using namespace cfdp; + std::array serBuf; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + cfdp::TransactionSeqNum seqNum = TransactionSeqNum(cfdp::WidthInBytes::ONE_BYTE, 2); + cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 0); + cfdp::EntityId destId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 1); + PduConfig pduConf = PduConfig(cfdp::TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, + destId, false); + uint8_t* serTarget = serBuf.data(); + const uint8_t* deserTarget = serTarget; + size_t serSize = 0; + + SECTION("Header Serialization") { + auto headerSerializer = HeaderSerializer(pduConf, cfdp::PduType::FILE_DIRECTIVE, 0); + const uint8_t** dummyPtr = nullptr; + ReturnValue_t deserResult = headerSerializer.deSerialize(dummyPtr, &serSize, + SerializeIF::Endianness::NETWORK); + REQUIRE(deserResult == retval::CATCH_FAILED); + deserResult = headerSerializer.serialize(nullptr, &serSize, serBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(deserResult == retval::CATCH_FAILED); + REQUIRE(seqNum.getSerializedSize() == 1); + + REQUIRE(headerSerializer.getPduDataFieldLen() == 0); + REQUIRE(headerSerializer.getSerializedSize() == 7); + REQUIRE(headerSerializer.getWholePduSize() == 7); + REQUIRE(headerSerializer.getCrcFlag() == false); + REQUIRE(headerSerializer.getDirection() == cfdp::Direction::TOWARDS_RECEIVER); + REQUIRE(headerSerializer.getLargeFileFlag() == false); + REQUIRE(headerSerializer.getLenEntityIds() == 1); + REQUIRE(headerSerializer.getLenSeqNum() == 1); + REQUIRE(headerSerializer.getPduType() == cfdp::PduType::FILE_DIRECTIVE); + REQUIRE(headerSerializer.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::NOT_PRESENT); + REQUIRE(headerSerializer.getSegmentationControl() == false); + REQUIRE(headerSerializer.getTransmissionMode() == cfdp::TransmissionModes::ACKNOWLEDGED); + + cfdp::TransactionSeqNum seqNumLocal; + headerSerializer.getTransactionSeqNum(seqNumLocal); + REQUIRE(seqNumLocal.getWidth() == cfdp::WidthInBytes::ONE_BYTE); + REQUIRE(seqNumLocal.getValue() == 2); + cfdp::EntityId sourceDestId; + headerSerializer.getSourceId(sourceDestId); + REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE); + REQUIRE(sourceDestId.getValue() == 0); + headerSerializer.getDestId(sourceDestId); + REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE); + REQUIRE(sourceDestId.getValue() == 1); + + result = headerSerializer.serialize(&serTarget, &serSize, + serBuf.size(), SerializeIF::Endianness::BIG); + REQUIRE(result == retval::CATCH_OK); + REQUIRE(serSize == 7); + // Only version bits are set + REQUIRE(serBuf[0] == 0b00100000); + // PDU data field length is 0 + REQUIRE(serBuf[1] == 0); + REQUIRE(serBuf[2] == 0); + // Entity and Transaction Sequence number are 1 byte large + REQUIRE(serBuf[3] == 0b00010001); + // Source ID + REQUIRE(serBuf[4] == 0); + // Transaction Seq Number + REQUIRE(serBuf[5] == 2); + // Dest ID + REQUIRE(serBuf[6] == 1); + + for(uint8_t idx = 0; idx < 7; idx++) { + ReturnValue_t result = headerSerializer.serialize(&serTarget, &serSize, + idx, SerializeIF::Endianness::BIG); + REQUIRE(result == static_cast(SerializeIF::BUFFER_TOO_SHORT)); + } + + // Set PDU data field len + headerSerializer.setPduDataFieldLen(0x0ff0); + REQUIRE(headerSerializer.getPduDataFieldLen() == 0x0ff0); + REQUIRE(headerSerializer.getSerializedSize() == 7); + REQUIRE(headerSerializer.getWholePduSize() == 7 + 0x0ff0); + serTarget = serBuf.data(); + serSize = 0; + result = headerSerializer.serialize(&serTarget, &serSize, + serBuf.size(), SerializeIF::Endianness::BIG); + REQUIRE(serBuf[1] == 0x0f); + REQUIRE(serBuf[2] == 0xf0); + + pduConf.crcFlag = true; + pduConf.largeFile = true; + pduConf.direction = cfdp::Direction::TOWARDS_SENDER; + pduConf.mode = cfdp::TransmissionModes::UNACKNOWLEDGED; + headerSerializer.setSegmentationControl( + cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION); + headerSerializer.setPduType(cfdp::PduType::FILE_DATA); + headerSerializer.setSegmentMetadataFlag(cfdp::SegmentMetadataFlag::PRESENT); + serTarget = serBuf.data(); + serSize = 0; + result = headerSerializer.serialize(&serTarget, &serSize, + serBuf.size(), SerializeIF::Endianness::BIG); + + // Everything except version bit flipped to one now + REQUIRE(serBuf[0] == 0x3f); + REQUIRE(serBuf[3] == 0x99); + pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff); + pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00); + pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff); + REQUIRE(pduConf.sourceId.getSerializedSize() == 4); + REQUIRE(headerSerializer.getSerializedSize() == 14); + serTarget = serBuf.data(); + serSize = 0; + result = headerSerializer.serialize(&serTarget, &serSize, + serBuf.size(), SerializeIF::Endianness::BIG); + + for(uint8_t idx = 0; idx < 14; idx++) { + ReturnValue_t result = headerSerializer.serialize(&serTarget, &serSize, + idx, SerializeIF::Endianness::BIG); + REQUIRE(result == static_cast(SerializeIF::BUFFER_TOO_SHORT)); + } + REQUIRE(headerSerializer.getCrcFlag() == true); + REQUIRE(headerSerializer.getDirection() == cfdp::Direction::TOWARDS_SENDER); + REQUIRE(headerSerializer.getLargeFileFlag() == true); + REQUIRE(headerSerializer.getLenEntityIds() == 4); + REQUIRE(headerSerializer.getLenSeqNum() == 2); + REQUIRE(headerSerializer.getPduType() == cfdp::PduType::FILE_DATA); + REQUIRE(headerSerializer.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT); + REQUIRE(headerSerializer.getTransmissionMode() == cfdp::TransmissionModes::UNACKNOWLEDGED); + REQUIRE(headerSerializer.getSegmentationControl() == true); + // Last three bits are 2 now (length of seq number) and bit 1 to bit 3 is 4 (len entity IDs) + REQUIRE(serBuf[3] == 0b11001010); + uint32_t entityId = 0; + size_t deSerSize = 0; + SerializeAdapter::deSerialize(&entityId, serBuf.data() + 4, &deSerSize, + SerializeIF::Endianness::NETWORK); + REQUIRE(deSerSize == 4); + REQUIRE(entityId == 0xff00ff00); + uint16_t seqNum = 0; + SerializeAdapter::deSerialize(&seqNum, serBuf.data() + 8, &deSerSize, + SerializeIF::Endianness::NETWORK); + REQUIRE(deSerSize == 2); + REQUIRE(seqNum == 0x0fff); + SerializeAdapter::deSerialize(&entityId, serBuf.data() + 10, &deSerSize, + SerializeIF::Endianness::NETWORK); + REQUIRE(deSerSize == 4); + REQUIRE(entityId == 0x00ff00ff); + + result = pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 0xfff); + REQUIRE(result == retval::CATCH_FAILED); + result = pduConf.sourceId.setValue(cfdp::WidthInBytes::TWO_BYTES, 0xfffff); + REQUIRE(result == retval::CATCH_FAILED); + result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xfffffffff); + REQUIRE(result == retval::CATCH_FAILED); + uint8_t oneByteSourceId = 32; + serTarget = &oneByteSourceId; + size_t deserLen = 1; + pduConf.sourceId.deSerialize(cfdp::WidthInBytes::ONE_BYTE, + const_cast(&serTarget), &deserLen, + SerializeIF::Endianness::MACHINE); + REQUIRE(pduConf.sourceId.getValue() == 32); + + uint16_t twoByteSourceId = 0xf0f0; + serTarget = reinterpret_cast(&twoByteSourceId); + deserLen = 2; + pduConf.sourceId.deSerialize(cfdp::WidthInBytes::TWO_BYTES, + const_cast(&serTarget), &deserLen, + SerializeIF::Endianness::MACHINE); + REQUIRE(pduConf.sourceId.getValue() == 0xf0f0); + + uint32_t fourByteSourceId = 0xf0f0f0f0; + serTarget = reinterpret_cast(&fourByteSourceId); + deserLen = 4; + pduConf.sourceId.deSerialize(cfdp::WidthInBytes::FOUR_BYTES, + const_cast(&serTarget), &deserLen, + SerializeIF::Endianness::MACHINE); + REQUIRE(pduConf.sourceId.getValue() == 0xf0f0f0f0); + + pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 1); + serTarget = serBuf.data(); + serSize = 1; + result = pduConf.sourceId.serialize(&serTarget, &serSize, 1, + SerializeIF::Endianness::MACHINE); + REQUIRE(result == static_cast(SerializeIF::BUFFER_TOO_SHORT)); + } + + SECTION( "Header Deserialization" ) { + // We unittested the serializer before, so we can use it now to generate valid raw CFDP + // data + auto headerSerializer = HeaderSerializer(pduConf, cfdp::PduType::FILE_DIRECTIVE, 0); + ReturnValue_t result = headerSerializer.serialize(&serTarget, &serSize, + serBuf.size(), SerializeIF::Endianness::BIG); + REQUIRE(result == retval::CATCH_OK); + REQUIRE(serBuf[1] == 0); + REQUIRE(serBuf[2] == 0); + // Entity and Transaction Sequence number are 1 byte large + REQUIRE(serBuf[3] == 0b00010001); + REQUIRE(serSize == 7); + // Deser call not strictly necessary + auto headerDeser = HeaderDeserializer(serBuf.data(), serBuf.size()); + + ReturnValue_t serResult = headerDeser.parseData(); + REQUIRE(serResult == retval::CATCH_OK); + REQUIRE(headerDeser.getPduDataFieldLen() == 0); + REQUIRE(headerDeser.getHeaderSize() == 7); + REQUIRE(headerDeser.getWholePduSize() == 7); + REQUIRE(headerDeser.getCrcFlag() == false); + REQUIRE(headerDeser.getDirection() == cfdp::Direction::TOWARDS_RECEIVER); + REQUIRE(headerDeser.getLargeFileFlag() == false); + REQUIRE(headerDeser.getLenEntityIds() == 1); + REQUIRE(headerDeser.getLenSeqNum() == 1); + REQUIRE(headerDeser.getPduType() == cfdp::PduType::FILE_DIRECTIVE); + REQUIRE(headerDeser.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::NOT_PRESENT); + REQUIRE(headerDeser.getSegmentationControl() == false); + REQUIRE(headerDeser.getTransmissionMode() == cfdp::TransmissionModes::ACKNOWLEDGED); + + pduConf.crcFlag = true; + pduConf.largeFile = true; + pduConf.direction = cfdp::Direction::TOWARDS_SENDER; + pduConf.mode = cfdp::TransmissionModes::UNACKNOWLEDGED; + headerSerializer.setSegmentationControl( + cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION); + headerSerializer.setPduType(cfdp::PduType::FILE_DATA); + headerSerializer.setSegmentMetadataFlag(cfdp::SegmentMetadataFlag::PRESENT); + result = pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff); + REQUIRE(result == retval::CATCH_OK); + result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00); + REQUIRE(result == retval::CATCH_OK); + result = pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff); + REQUIRE(result == retval::CATCH_OK); + serTarget = serBuf.data(); + serSize = 0; + result = headerSerializer.serialize(&serTarget, &serSize, + serBuf.size(), SerializeIF::Endianness::BIG); + headerDeser = HeaderDeserializer(serBuf.data(), serBuf.size()); + + result = headerDeser.parseData(); + REQUIRE(result == retval::CATCH_OK); + // Everything except version bit flipped to one now + REQUIRE(serBuf[0] == 0x3f); + REQUIRE(serBuf[3] == 0b11001010); + REQUIRE(headerDeser.getWholePduSize() == 14); + + REQUIRE(headerDeser.getCrcFlag() == true); + REQUIRE(headerDeser.getDirection() == cfdp::Direction::TOWARDS_SENDER); + REQUIRE(headerDeser.getLargeFileFlag() == true); + REQUIRE(headerDeser.getLenEntityIds() == 4); + REQUIRE(headerDeser.getLenSeqNum() == 2); + REQUIRE(headerDeser.getPduType() == cfdp::PduType::FILE_DATA); + REQUIRE(headerDeser.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT); + REQUIRE(headerDeser.getSegmentationControl() == true); + REQUIRE(headerDeser.getTransmissionMode() == cfdp::TransmissionModes::UNACKNOWLEDGED); + + cfdp::TransactionSeqNum seqNumLocal; + headerDeser.getTransactionSeqNum(seqNumLocal); + REQUIRE(seqNumLocal.getWidth() == cfdp::WidthInBytes::TWO_BYTES); + REQUIRE(seqNumLocal.getValue() == 0x0fff); + cfdp::EntityId sourceDestId; + headerDeser.getSourceId(sourceDestId); + REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::FOUR_BYTES); + REQUIRE(sourceDestId.getValue() == 0xff00ff00); + headerDeser.getDestId(sourceDestId); + REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::FOUR_BYTES); + REQUIRE(sourceDestId.getValue() == 0x00ff00ff); + + size_t deSerSize = headerDeser.getWholePduSize(); + serTarget = serBuf.data(); + const uint8_t** serTargetConst = const_cast(&serTarget); + result = headerDeser.parseData(); + REQUIRE(result == retval::CATCH_OK); + + headerDeser.setData(nullptr, -1); + REQUIRE(headerDeser.getHeaderSize() == 0); + headerDeser.setData(serBuf.data(), serBuf.size()); + + serTarget = serBuf.data(); + serSize = 0; + pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 22); + pduConf.destId.setValue(cfdp::WidthInBytes::ONE_BYTE, 48); + result = headerSerializer.serialize(&serTarget, &serSize, + serBuf.size(), SerializeIF::Endianness::BIG); + REQUIRE(result == retval::CATCH_OK); + REQUIRE(headerDeser.getWholePduSize() == 8); + headerDeser.setData(serBuf.data(), serBuf.size()); + + headerDeser.getSourceId(sourceDestId); + REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE); + REQUIRE(sourceDestId.getValue() == 22); + } + + SECTION("File Directive") { + auto fdSer = FileDirectiveSerializer(pduConf, FileDirectives::ACK, 4); + REQUIRE(fdSer.getSerializedSize() == 8); + serTarget = serBuf.data(); + serSize = 0; + result = fdSer.serialize(&serTarget, &serSize, serBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + // Only version bits are set + REQUIRE(serBuf[0] == 0b00100000); + // PDU data field length is 5 (4 + Directive code octet) + REQUIRE(serBuf[1] == 0); + REQUIRE(serBuf[2] == 5); + // Entity and Transaction Sequence number are 1 byte large + REQUIRE(serBuf[3] == 0b00010001); + // Source ID + REQUIRE(serBuf[4] == 0); + // Transaction Seq Number + REQUIRE(serBuf[5] == 2); + // Dest ID + REQUIRE(serBuf[6] == 1); + REQUIRE(serBuf[7] == FileDirectives::ACK); + + serTarget = serBuf.data(); + size_t deserSize = 20; + serSize = 0; + REQUIRE(fdSer.deSerialize(&deserTarget, &deserSize, SerializeIF::Endianness::NETWORK) == + HasReturnvaluesIF::RETURN_FAILED); + REQUIRE(fdSer.serialize(nullptr, nullptr, 85, SerializeIF::Endianness::NETWORK) == + HasReturnvaluesIF::RETURN_FAILED); + for(uint8_t idx = 0; idx < 8; idx++) { + serTarget = serBuf.data(); + serSize = 0; + REQUIRE(fdSer.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::NETWORK) == + SerializeIF::BUFFER_TOO_SHORT); + } + + deserTarget = serBuf.data(); + deserSize = 0; + auto fdDeser = FileDirectiveDeserializer(deserTarget, serBuf.size()); + REQUIRE(fdDeser.getEndianness() == SerializeIF::Endianness::NETWORK); + fdDeser.setEndianness(SerializeIF::Endianness::MACHINE); + REQUIRE(fdDeser.getEndianness() == SerializeIF::Endianness::MACHINE); + fdDeser.setEndianness(SerializeIF::Endianness::NETWORK); + REQUIRE(fdDeser.parseData() == HasReturnvaluesIF::RETURN_OK); + REQUIRE(fdDeser.getFileDirective() == FileDirectives::ACK); + REQUIRE(fdDeser.getPduDataFieldLen() == 5); + REQUIRE(fdDeser.getHeaderSize() == 8); + REQUIRE(fdDeser.getPduType() == cfdp::PduType::FILE_DIRECTIVE); + + serBuf[7] = 0xff; + // Invalid file directive + REQUIRE(fdDeser.parseData() == cfdp::INVALID_DIRECTIVE_FIELDS); + } + + SECTION("FileSize") { + std::array fssBuf = {}; + uint8_t* buffer = fssBuf.data(); + size_t size = 0; + cfdp::FileSize fss; + REQUIRE(fss.getSize() == 0); + fss.setFileSize(0x20, false); + ReturnValue_t result = fss.serialize(&buffer, &size, fssBuf.size(), + SerializeIF::Endianness::MACHINE); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + uint32_t fileSize = 0; + result = SerializeAdapter::deSerialize(&fileSize, fssBuf.data(), nullptr, + SerializeIF::Endianness::MACHINE); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(fileSize == 0x20); + + } +} + diff --git a/tests/src/fsfw_tests/unit/cfdp/testEofPdu.cpp b/tests/src/fsfw_tests/unit/cfdp/testEofPdu.cpp new file mode 100644 index 00000000..9edaf572 --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testEofPdu.cpp @@ -0,0 +1,124 @@ +#include + +#include "fsfw/cfdp/pdu/EofPduDeserializer.h" +#include "fsfw/cfdp/pdu/EofPduSerializer.h" +#include "fsfw/globalfunctions/arrayprinter.h" + +#include + +TEST_CASE( "EOF PDU" , "[EofPdu]") { + using namespace cfdp; + + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::array buf = {}; + uint8_t* bufPtr = buf.data(); + size_t sz = 0; + EntityId destId(WidthInBytes::TWO_BYTES, 2); + EntityIdTlv faultLoc(destId); + FileSize fileSize(12); + // We can already set the fault location, it will be ignored + EofInfo eofInfo(cfdp::ConditionCode::NO_ERROR, 5, fileSize, &faultLoc); + TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15); + EntityId sourceId(WidthInBytes::TWO_BYTES, 1); + + PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); + + auto eofSerializer = EofPduSerializer(pduConf, eofInfo); + SECTION("Serialize") { + result = eofSerializer.serialize(&bufPtr, &sz, buf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(((buf[1] << 8) | buf[2]) == 10); + uint32_t checksum = 0; + result = SerializeAdapter::deSerialize(&checksum, buf.data() + sz - 8, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(checksum == 5); + uint32_t fileSizeVal = 0; + result = SerializeAdapter::deSerialize(&fileSizeVal, buf.data() + sz - 4, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(fileSizeVal == 12); + REQUIRE(buf[sz - 10] == cfdp::FileDirectives::EOF_DIRECTIVE); + REQUIRE(buf[sz - 9] == 0x00); + REQUIRE(sz == 20); + + eofInfo.setConditionCode(cfdp::ConditionCode::FILESTORE_REJECTION); + eofInfo.setFileSize(0x10ffffff10, true); + pduConf.largeFile = true; + // Should serialize with fault location now + auto serializeWithFaultLocation = EofPduSerializer(pduConf, eofInfo); + bufPtr = buf.data(); + sz = 0; + result = serializeWithFaultLocation.serialize(&bufPtr, &sz, buf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(sz == 28); + REQUIRE(buf[10] == cfdp::FileDirectives::EOF_DIRECTIVE); + REQUIRE(buf[11] >> 4 == cfdp::ConditionCode::FILESTORE_REJECTION); + uint64_t fileSizeLarge = 0; + result = SerializeAdapter::deSerialize(&fileSizeLarge, buf.data() + 16, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(fileSizeLarge == 0x10ffffff10); + REQUIRE(buf[sz - 4] == cfdp::TlvTypes::ENTITY_ID); + // width of entity ID is 2 + REQUIRE(buf[sz - 3] == 2); + uint16_t entityIdRaw = 0; + result = SerializeAdapter::deSerialize(&entityIdRaw, buf.data() + sz - 2, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(entityIdRaw == 2); + bufPtr = buf.data(); + sz = 0; + for(size_t idx = 0; idx < 27; idx++) { + result = serializeWithFaultLocation.serialize(&bufPtr, &sz, idx, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT); + bufPtr = buf.data(); + sz = 0; + } + eofInfo.setChecksum(16); + eofInfo.setFaultLoc(nullptr); + } + + SECTION("Deserialize") { + result = eofSerializer.serialize(&bufPtr, &sz, buf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + EntityIdTlv tlv(destId); + EofInfo emptyInfo(&tlv); + auto deserializer = EofPduDeserializer(buf.data(), buf.size(), emptyInfo); + result = deserializer.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(emptyInfo.getConditionCode() == cfdp::ConditionCode::NO_ERROR); + REQUIRE(emptyInfo.getChecksum() == 5); + REQUIRE(emptyInfo.getFileSize().getSize() == 12); + + eofInfo.setConditionCode(cfdp::ConditionCode::FILESTORE_REJECTION); + eofInfo.setFileSize(0x10ffffff10, true); + pduConf.largeFile = true; + // Should serialize with fault location now + auto serializeWithFaultLocation = EofPduSerializer(pduConf, eofInfo); + bufPtr = buf.data(); + sz = 0; + result = serializeWithFaultLocation.serialize(&bufPtr, &sz, buf.size(), + SerializeIF::Endianness::NETWORK); + auto deserializer2 = EofPduDeserializer(buf.data(), buf.size(), emptyInfo); + result = deserializer2.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(emptyInfo.getConditionCode() == cfdp::ConditionCode::FILESTORE_REJECTION); + REQUIRE(emptyInfo.getChecksum() == 5); + REQUIRE(emptyInfo.getFileSize().getSize() == 0x10ffffff10); + REQUIRE(emptyInfo.getFaultLoc()->getType() == cfdp::TlvTypes::ENTITY_ID); + REQUIRE(emptyInfo.getFaultLoc()->getSerializedSize() == 4); + uint16_t destId = emptyInfo.getFaultLoc()->getEntityId().getValue(); + REQUIRE(destId == 2); + for(size_t maxSz = 0; maxSz < deserializer2.getWholePduSize() - 1; maxSz++) { + auto invalidDeser = EofPduDeserializer(buf.data(), maxSz, emptyInfo); + result = invalidDeser.parseData(); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } + +} + + diff --git a/tests/src/fsfw_tests/unit/cfdp/testFileData.cpp b/tests/src/fsfw_tests/unit/cfdp/testFileData.cpp new file mode 100644 index 00000000..8a84a2a3 --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testFileData.cpp @@ -0,0 +1,175 @@ +#include + +#include "fsfw/cfdp/pdu/FileDataDeserializer.h" +#include "fsfw/cfdp/pdu/FileDataSerializer.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/serviceinterface.h" + +#include + +TEST_CASE( "File Data PDU" , "[FileDataPdu]") { + using namespace cfdp; + + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::array fileBuffer = {}; + std::array fileDataBuffer = {}; + uint8_t* buffer = fileDataBuffer.data(); + size_t sz = 0; + EntityId destId(WidthInBytes::TWO_BYTES, 2); + TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15); + EntityId sourceId(WidthInBytes::TWO_BYTES, 1); + PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); + + for(uint8_t idx = 0; idx < 10; idx++) { + fileBuffer[idx] = idx; + } + FileSize offset(50); + FileDataInfo info(offset, fileBuffer.data(), 10); + + SECTION("Serialization") { + FileDataSerializer serializer(pduConf, info); + result = serializer.serialize(&buffer, &sz, fileDataBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(sz == 24); + // 10 file bytes plus 4 byte offset + REQUIRE(((fileDataBuffer[1] << 8) | fileDataBuffer[2]) == 14); + // File Data -> Fourth bit is one + REQUIRE(fileDataBuffer[0] == 0b00110000); + uint32_t offsetRaw = 0; + buffer = fileDataBuffer.data(); + result = SerializeAdapter::deSerialize(&offsetRaw, buffer + 10, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(offsetRaw == 50); + buffer = fileDataBuffer.data() + 14; + for(size_t idx = 0; idx < 10; idx++) { + REQUIRE(buffer[idx] == idx); + } + + REQUIRE(info.hasSegmentMetadata() == false); + info.addSegmentMetadataInfo(cfdp::RecordContinuationState::CONTAINS_START_AND_END, + fileBuffer.data(), 10); + REQUIRE(info.hasSegmentMetadata() == true); + REQUIRE(info.getSegmentationControl() == + cfdp::SegmentationControl::NO_RECORD_BOUNDARIES_PRESERVATION); + info.setSegmentationControl(cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION); + serializer.update(); + REQUIRE(serializer.getSegmentationControl() == + cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION); + buffer = fileDataBuffer.data(); + sz = 0; + serializer.setSegmentationControl(cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION); + + result = serializer.serialize(&buffer, &sz, fileDataBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(((fileDataBuffer[1] << 8) | fileDataBuffer[2]) == 25); + // First bit: Seg Ctrl is set + // Bits 1 to 3 length of enitity IDs is 2 + // Bit 4: Segment metadata flag is set + // Bit 5 to seven: length of transaction seq num is 2 + REQUIRE(fileDataBuffer[3] == 0b10101010); + REQUIRE((fileDataBuffer[10] >> 6) & 0b11 == + cfdp::RecordContinuationState::CONTAINS_START_AND_END); + // Segment metadata length + REQUIRE((fileDataBuffer[10] & 0x3f) == 10); + buffer = fileDataBuffer.data() + 11; + // Check segment metadata + for(size_t idx = 0; idx < 10; idx++) { + REQUIRE(buffer[idx] == idx); + } + // Check filedata + buffer = fileDataBuffer.data() + 25; + for(size_t idx = 0; idx < 10; idx++) { + REQUIRE(buffer[idx] == idx); + } + + for(size_t invalidStartSz = 1; invalidStartSz < sz; invalidStartSz ++) { + buffer = fileDataBuffer.data(); + sz = 0; + result = serializer.serialize(&buffer, &invalidStartSz, sz, + SerializeIF::Endianness::NETWORK); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + + info.setSegmentMetadataFlag(true); + REQUIRE(info.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT); + info.setSegmentMetadataFlag(false); + REQUIRE(info.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::NOT_PRESENT); + info.setRecordContinuationState(cfdp::RecordContinuationState::CONTAINS_END_NO_START); + info.setSegmentMetadataLen(10); + info.setSegmentMetadata(nullptr); + info.setFileData(nullptr, 0); + } + + SECTION("Deserialization") { + FileDataSerializer serializer(pduConf, info); + result = serializer.serialize(&buffer, &sz, fileDataBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + FileSize emptyOffset; + FileDataInfo emptyInfo(emptyOffset); + FileDataDeserializer deserializer(fileDataBuffer.data(), fileDataBuffer.size(), emptyInfo); + result = deserializer.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(deserializer.getWholePduSize() == 24); + REQUIRE(deserializer.getPduDataFieldLen() == 14); + REQUIRE(deserializer.getSegmentationControl() == + cfdp::SegmentationControl::NO_RECORD_BOUNDARIES_PRESERVATION); + REQUIRE(deserializer.getSegmentMetadataFlag() == + cfdp::SegmentMetadataFlag::NOT_PRESENT); + + REQUIRE(emptyInfo.getOffset().getSize() == 50); + REQUIRE(emptyInfo.hasSegmentMetadata() == false); + size_t emptyFileSize = 0; + const uint8_t* fileData = emptyInfo.getFileData(&emptyFileSize); + REQUIRE(emptyFileSize == 10); + for(size_t idx = 0; idx < 10; idx++) { + REQUIRE(fileData[idx] == idx); + } + + deserializer.setEndianness(SerializeIF::Endianness::NETWORK); + + info.addSegmentMetadataInfo(cfdp::RecordContinuationState::CONTAINS_START_AND_END, + fileBuffer.data(), 10); + serializer.update(); + buffer = fileDataBuffer.data(); + sz = 0; + result = serializer.serialize(&buffer, &sz, fileDataBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + result = deserializer.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + REQUIRE(emptyInfo.getOffset().getSize() == 50); + REQUIRE(emptyInfo.hasSegmentMetadata() == true); + REQUIRE(emptyInfo.getRecordContinuationState() == + cfdp::RecordContinuationState::CONTAINS_START_AND_END); + emptyFileSize = 0; + fileData = emptyInfo.getFileData(&emptyFileSize); + REQUIRE(emptyFileSize == 10); + for(size_t idx = 0; idx < 10; idx++) { + REQUIRE(fileData[idx] == idx); + } + size_t segmentMetadataLen = 0; + fileData = emptyInfo.getSegmentMetadata(&segmentMetadataLen); + REQUIRE(segmentMetadataLen == 10); + for(size_t idx = 0; idx < 10; idx++) { + REQUIRE(fileData[idx] == idx); + } + for(size_t invalidPduField = 0; invalidPduField < 24; invalidPduField++) { + fileDataBuffer[1] = (invalidPduField >> 8) & 0xff; + fileDataBuffer[2] = invalidPduField & 0xff; + result = deserializer.parseData(); + // Starting at 15, the file data is parsed. There is not leading file data length + // field to the parser can't check whether the remaining length is valid + if(invalidPduField < 15) { + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } + + } +} diff --git a/tests/src/fsfw_tests/unit/cfdp/testFinishedPdu.cpp b/tests/src/fsfw_tests/unit/cfdp/testFinishedPdu.cpp new file mode 100644 index 00000000..718750de --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testFinishedPdu.cpp @@ -0,0 +1,196 @@ +#include + +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/cfdp/pdu/FinishedPduDeserializer.h" +#include "fsfw/cfdp/pdu/FinishedPduSerializer.h" + +#include + +TEST_CASE( "Finished PDU" , "[FinishedPdu]") { + using namespace cfdp; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::array fnBuffer = {}; + uint8_t* buffer = fnBuffer.data(); + size_t sz = 0; + EntityId destId(WidthInBytes::TWO_BYTES, 2); + TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15); + EntityId sourceId(WidthInBytes::TWO_BYTES, 1); + PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); + + cfdp::Lv emptyFsMsg; + FinishedInfo info(cfdp::ConditionCode::INACTIVITY_DETECTED, + cfdp::FinishedDeliveryCode::DATA_INCOMPLETE, + cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY); + + SECTION("Serialize") { + FinishPduSerializer serializer(pduConf, info); + result = serializer.serialize(&buffer, &sz, fnBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(serializer.getSerializedSize() == 12); + REQUIRE(((fnBuffer[1] << 8) | fnBuffer[2]) == 2); + REQUIRE(fnBuffer[10] == cfdp::FileDirectives::FINISH); + REQUIRE(((fnBuffer[sz - 1] >> 4) & 0x0f) == cfdp::ConditionCode::INACTIVITY_DETECTED); + REQUIRE(((fnBuffer[sz - 1] >> 2) & 0x01) == cfdp::FinishedDeliveryCode::DATA_INCOMPLETE); + REQUIRE((fnBuffer[sz - 1] & 0b11) == cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY); + REQUIRE(sz == 12); + + // Add a filestore response + std::string firstName = "hello.txt"; + cfdp::Lv firstNameLv(reinterpret_cast(firstName.data()), firstName.size()); + FilestoreResponseTlv response(cfdp::FilestoreActionCode::DELETE_FILE, + cfdp::FSR_APPEND_FILE_1_NOT_EXISTS, firstNameLv, nullptr); + FilestoreResponseTlv* responsePtr = &response; + REQUIRE(response.getSerializedSize() == 14); + size_t len = 1; + info.setFilestoreResponsesArray(&responsePtr, &len, &len); + serializer.updateDirectiveFieldLen(); + REQUIRE(serializer.getSerializedSize() == 12 + 14); + sz = 0; + buffer = fnBuffer.data(); + result = serializer.serialize(&buffer, &sz, fnBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(serializer.getSerializedSize() == 12 + 14); + REQUIRE(serializer.getPduDataFieldLen() == 16); + + // Add two filestore responses and a fault location parameter + std::string secondName = "hello2.txt"; + cfdp::Lv secondNameLv(reinterpret_cast(secondName.data()), secondName.size()); + FilestoreResponseTlv response2(cfdp::FilestoreActionCode::DENY_FILE , + cfdp::FSR_SUCCESS, secondNameLv, nullptr); + REQUIRE(response2.getSerializedSize() == 15); + len = 2; + std::array responses {&response, &response2}; + info.setFilestoreResponsesArray(responses.data(), &len, &len); + serializer.updateDirectiveFieldLen(); + + EntityIdTlv faultLoc(destId); + REQUIRE(faultLoc.getSerializedSize() == 4); + info.setFaultLocation(&faultLoc); + serializer.updateDirectiveFieldLen(); + sz = 0; + buffer = fnBuffer.data(); + result = serializer.serialize(&buffer, &sz, fnBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + info.setConditionCode(cfdp::ConditionCode::FILESTORE_REJECTION); + REQUIRE(serializer.getSerializedSize() == 12 + 14 + 15 + 4); + REQUIRE(sz == 12 + 14 + 15 + 4); + info.setFileStatus(cfdp::FinishedFileStatus::DISCARDED_FILESTORE_REJECTION); + REQUIRE(info.getFileStatus() == cfdp::FinishedFileStatus::DISCARDED_FILESTORE_REJECTION); + info.setDeliveryCode(cfdp::FinishedDeliveryCode::DATA_INCOMPLETE); + REQUIRE(info.getDeliveryCode() == cfdp::FinishedDeliveryCode::DATA_INCOMPLETE); + for(size_t maxSz = 0; maxSz < 45; maxSz++) { + sz = 0; + buffer = fnBuffer.data(); + result = serializer.serialize(&buffer, &sz, maxSz, SerializeIF::Endianness::NETWORK); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } + + SECTION("Deserialize") { + FinishedInfo emptyInfo; + FinishPduSerializer serializer(pduConf, info); + result = serializer.serialize(&buffer, &sz, fnBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + FinishPduDeserializer deserializer(fnBuffer.data(), fnBuffer.size(), emptyInfo); + result = deserializer.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(emptyInfo.getFileStatus() == cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY); + REQUIRE(emptyInfo.getConditionCode() == cfdp::ConditionCode::INACTIVITY_DETECTED); + REQUIRE(emptyInfo.getDeliveryCode() == cfdp::FinishedDeliveryCode::DATA_INCOMPLETE); + + // Add a filestore response + sz = 0; + buffer = fnBuffer.data(); + std::string firstName = "hello.txt"; + cfdp::Lv firstNameLv(reinterpret_cast(firstName.data()), firstName.size()); + FilestoreResponseTlv response(cfdp::FilestoreActionCode::DELETE_FILE, + cfdp::FSR_NOT_PERFORMED, firstNameLv, nullptr); + FilestoreResponseTlv* responsePtr = &response; + size_t len = 1; + info.setFilestoreResponsesArray(&responsePtr, &len, &len); + serializer.updateDirectiveFieldLen(); + REQUIRE(serializer.getPduDataFieldLen() == 16); + result = serializer.serialize(&buffer, &sz, fnBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + FilestoreResponseTlv emptyResponse(firstNameLv, nullptr); + responsePtr = &emptyResponse; + emptyInfo.setFilestoreResponsesArray(&responsePtr, nullptr, &len); + FinishPduDeserializer deserializer2(fnBuffer.data(), fnBuffer.size(), emptyInfo); + result = deserializer2.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(emptyInfo.getFsResponsesLen() == 1); + FilestoreResponseTlv** responseArray = nullptr; + emptyInfo.getFilestoreResonses(&responseArray, nullptr, nullptr); + REQUIRE(responseArray[0]->getActionCode() == cfdp::FilestoreActionCode::DELETE_FILE); + REQUIRE(responseArray[0]->getStatusCode() == cfdp::FSR_NOT_PERFORMED); + auto& fileNameRef = responseArray[0]->getFirstFileName(); + size_t stringSize = 0; + const char* string = reinterpret_cast(fileNameRef.getValue(&stringSize)); + std::string firstFileName(string, stringSize); + REQUIRE(firstFileName == "hello.txt"); + + // Add two filestore responses and a fault location parameter + std::string secondName = "hello2.txt"; + cfdp::Lv secondNameLv(reinterpret_cast(secondName.data()), secondName.size()); + FilestoreResponseTlv response2(cfdp::FilestoreActionCode::DENY_FILE , + cfdp::FSR_SUCCESS, secondNameLv, nullptr); + REQUIRE(response2.getSerializedSize() == 15); + len = 2; + std::array responses {&response, &response2}; + info.setFilestoreResponsesArray(responses.data(), &len, &len); + serializer.updateDirectiveFieldLen(); + + EntityIdTlv faultLoc(destId); + info.setFaultLocation(&faultLoc); + serializer.updateDirectiveFieldLen(); + sz = 0; + buffer = fnBuffer.data(); + result = serializer.serialize(&buffer, &sz, fnBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + EntityId emptyId; + EntityIdTlv emptyFaultLoc(emptyId); + emptyInfo.setFaultLocation(&emptyFaultLoc); + response.setFilestoreMessage(&emptyFsMsg); + emptyInfo.setFilestoreResponsesArray(responses.data(), &len, &len); + response2.setFilestoreMessage(&emptyFsMsg); + FinishPduDeserializer deserializer3(fnBuffer.data(), fnBuffer.size(), emptyInfo); + result = deserializer3.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + auto& infoRef = deserializer3.getInfo(); + REQUIRE(deserializer3.getWholePduSize() == 45); + + size_t invalidMaxLen = 1; + emptyInfo.setFilestoreResponsesArray(responses.data(), &len, &invalidMaxLen); + result = deserializer3.parseData(); + REQUIRE(result == cfdp::FINISHED_CANT_PARSE_FS_RESPONSES); + emptyInfo.setFilestoreResponsesArray(nullptr, nullptr, nullptr); + result = deserializer3.parseData(); + REQUIRE(result == cfdp::FINISHED_CANT_PARSE_FS_RESPONSES); + + // Clear condition code + auto tmp = fnBuffer[11]; + fnBuffer[11] = fnBuffer[11] & ~0xf0; + fnBuffer[11] = fnBuffer[11] | (cfdp::ConditionCode::NO_ERROR << 4); + emptyInfo.setFilestoreResponsesArray(responses.data(), &len, &len); + result = deserializer3.parseData(); + REQUIRE(result == cfdp::INVALID_TLV_TYPE); + + fnBuffer[11] = tmp; + // Invalid TLV type, should be entity ID + fnBuffer[sz - 4] = cfdp::TlvTypes::FILESTORE_REQUEST; + result = deserializer3.parseData(); + REQUIRE(result == cfdp::INVALID_TLV_TYPE); + + for(size_t maxSz = 0; maxSz < 45; maxSz++) { + FinishPduDeserializer faultyDeser(fnBuffer.data(), maxSz, emptyInfo); + result = faultyDeser.parseData(); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } +} diff --git a/tests/src/fsfw_tests/unit/cfdp/testKeepAlivePdu.cpp b/tests/src/fsfw_tests/unit/cfdp/testKeepAlivePdu.cpp new file mode 100644 index 00000000..09008650 --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testKeepAlivePdu.cpp @@ -0,0 +1,84 @@ +#include + +#include "fsfw/cfdp/pdu/KeepAlivePduDeserializer.h" +#include "fsfw/cfdp/pdu/KeepAlivePduSerializer.h" +#include "fsfw/globalfunctions/arrayprinter.h" + +#include + +TEST_CASE( "Keep Alive PDU" , "[KeepAlivePdu]") { + using namespace cfdp; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::array kaBuffer = {}; + uint8_t* buffer = kaBuffer.data(); + size_t sz = 0; + EntityId destId(WidthInBytes::TWO_BYTES, 2); + TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15); + EntityId sourceId(WidthInBytes::TWO_BYTES, 1); + PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); + + FileSize progress(0x50); + + SECTION("Serialize") { + KeepAlivePduSerializer serializer(pduConf, progress); + result = serializer.serialize(&buffer, &sz, kaBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(kaBuffer[10] == cfdp::FileDirectives::KEEP_ALIVE); + uint32_t fsRaw = 0; + result = SerializeAdapter::deSerialize(&fsRaw, kaBuffer.data() + 11, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(fsRaw == 0x50); + REQUIRE(sz == 15); + REQUIRE(serializer.getWholePduSize() == 15); + REQUIRE(serializer.getPduDataFieldLen() == 5); + + pduConf.largeFile = true; + serializer.updateDirectiveFieldLen(); + buffer = kaBuffer.data(); + sz = 0; + result = serializer.serialize(&buffer, &sz, kaBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(serializer.getWholePduSize() == 19); + REQUIRE(serializer.getPduDataFieldLen() == 9); + uint64_t fsRawLarge = 0; + result = SerializeAdapter::deSerialize(&fsRawLarge, kaBuffer.data() + 11, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(fsRawLarge == 0x50); + + for(size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) { + buffer = kaBuffer.data(); + sz = 0; + result = serializer.serialize(&buffer, &sz, invalidMaxSz, + SerializeIF::Endianness::NETWORK); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } + + SECTION("Deserialize") { + KeepAlivePduSerializer serializer(pduConf, progress); + result = serializer.serialize(&buffer, &sz, kaBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + // Set another file size + progress.setFileSize(200, false); + KeepAlivePduDeserializer deserializer(kaBuffer.data(), kaBuffer.size(), progress); + result = deserializer.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + auto& progRef = deserializer.getProgress(); + // Should have been overwritten + REQUIRE(progRef.getSize() == 0x50); + sz = deserializer.getWholePduSize(); + + // invalid max size + for(size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) { + deserializer.setData(kaBuffer.data(), invalidMaxSz); + result = deserializer.parseData(); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } +} diff --git a/tests/src/fsfw_tests/unit/cfdp/testMetadataPdu.cpp b/tests/src/fsfw_tests/unit/cfdp/testMetadataPdu.cpp new file mode 100644 index 00000000..50dae9e9 --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testMetadataPdu.cpp @@ -0,0 +1,185 @@ +#include +#include + +#include "fsfw/cfdp/tlv/FilestoreResponseTlv.h" +#include "fsfw/cfdp/pdu/MetadataPduDeserializer.h" +#include "fsfw/cfdp/pdu/MetadataPduSerializer.h" +#include "fsfw/globalfunctions/arrayprinter.h" + +#include + +TEST_CASE( "Metadata PDU" , "[MetadataPdu]") { + using namespace cfdp; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::array mdBuffer = {}; + uint8_t* buffer = mdBuffer.data(); + size_t sz = 0; + EntityId destId(WidthInBytes::TWO_BYTES, 2); + TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15); + EntityId sourceId(WidthInBytes::TWO_BYTES, 1); + PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); + + std::string firstFileName = "hello.txt"; + cfdp::Lv sourceFileName(reinterpret_cast(firstFileName.data()), + firstFileName.size()); + cfdp::Lv destFileName(nullptr, 0); + FileSize fileSize(35); + MetadataInfo info(false, ChecksumType::MODULAR, fileSize, sourceFileName, destFileName); + + FilestoreResponseTlv response(FilestoreActionCode::CREATE_DIRECTORY, FSR_CREATE_NOT_ALLOWED, + sourceFileName, nullptr); + std::array msg = {0x41, 0x42, 0x43}; + cfdp::Tlv responseTlv; + std::array responseBuf = {}; + uint8_t* responseBufPtr = responseBuf.data(); + response.convertToTlv(responseTlv, buffer, responseBuf.size(), + SerializeIF::Endianness::MACHINE); + MessageToUserTlv msgToUser(msg.data(), msg.size()); + std::array options {&responseTlv, &msgToUser}; + REQUIRE(options[0]->getSerializedSize() == 2 + 1 + 10 + 1); + REQUIRE(options[1]->getSerializedSize() == 5); + + SECTION("Serialize") { + MetadataPduSerializer serializer(pduConf, info); + result = serializer.serialize(&buffer, &sz, mdBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(serializer.getWholePduSize() == 27); + REQUIRE(info.getSourceFileName().getSerializedSize() == 10); + REQUIRE(info.getDestFileName().getSerializedSize() == 1); + REQUIRE(info.getSerializedSize() == 16); + REQUIRE((mdBuffer[1] << 8 | mdBuffer[2]) == 17); + REQUIRE(mdBuffer[10] == FileDirectives::METADATA); + // no closure requested and checksum type is modular => 0x00 + REQUIRE(mdBuffer[11] == 0x00); + uint32_t fileSizeRaw = 0; + result = SerializeAdapter::deSerialize(&fileSizeRaw, mdBuffer.data() + 12, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(fileSizeRaw == 35); + REQUIRE(mdBuffer[16] == 9); + REQUIRE(mdBuffer[17] == 'h'); + REQUIRE(mdBuffer[18] == 'e'); + REQUIRE(mdBuffer[19] == 'l'); + REQUIRE(mdBuffer[20] == 'l'); + REQUIRE(mdBuffer[21] == 'o'); + REQUIRE(mdBuffer[22] == '.'); + REQUIRE(mdBuffer[23] == 't'); + REQUIRE(mdBuffer[24] == 'x'); + REQUIRE(mdBuffer[25] == 't'); + REQUIRE(mdBuffer[26] == 0); + + std::string otherFileName = "hello2.txt"; + cfdp::Lv otherFileNameLv(reinterpret_cast(otherFileName.data()), + otherFileName.size()); + info.setSourceFileName(otherFileNameLv); + size_t sizeOfOptions = options.size(); + info.setOptionsArray(options.data(), &sizeOfOptions, &sizeOfOptions); + REQUIRE(info.getMaxOptionsLen() == 2); + info.setMaxOptionsLen(3); + REQUIRE(info.getMaxOptionsLen() == 3); + info.setChecksumType(cfdp::ChecksumType::CRC_32C); + info.setClosureRequested(true); + uint8_t* buffer = mdBuffer.data(); + size_t sz = 0; + serializer.updateDirectiveFieldLen(); + + result = serializer.serialize(&buffer, &sz, mdBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE((mdBuffer[1] << 8 | mdBuffer[2]) == 37); + auto checksumType = static_cast(mdBuffer[11] & 0x0f); + REQUIRE(checksumType == cfdp::ChecksumType::CRC_32C); + bool closureRequested = mdBuffer[11] >> 6 & 0x01; + REQUIRE(closureRequested == true); + // The size of the two options is 19. Summing up: + // - 11 bytes of source file name + // - 1 byte for dest file name + // - 4 for FSS + // - 1 leading byte. + // - 1 byte for PDU type + // PDU header has 10 bytes. + // I am not going to check the options raw content, those are part of the dedicated + // TLV unittests + REQUIRE(sz == 10 + 37); + for(size_t maxSz = 0; maxSz < sz; maxSz++) { + uint8_t* buffer = mdBuffer.data(); + size_t sz = 0; + result = serializer.serialize(&buffer, &sz, maxSz, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT); + } + for(size_t initSz = 1; initSz < 47; initSz++) { + uint8_t* buffer = mdBuffer.data(); + size_t sz = initSz; + result = serializer.serialize(&buffer, &sz, 46, SerializeIF::Endianness::NETWORK); + REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT); + } + info.setDestFileName(destFileName); + } + + SECTION("Deserialize") { + MetadataPduSerializer serializer(pduConf, info); + result = serializer.serialize(&buffer, &sz, mdBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + MetadataPduDeserializer deserializer(mdBuffer.data(), mdBuffer.size(), info); + result = deserializer.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + size_t fullSize = deserializer.getWholePduSize(); + for(size_t maxSz = 0; maxSz < fullSize; maxSz++) { + MetadataPduDeserializer invalidSzDeser(mdBuffer.data(), maxSz, info); + result = invalidSzDeser.parseData(); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + size_t sizeOfOptions = options.size(); + size_t maxSize = 4; + info.setOptionsArray(options.data(), &sizeOfOptions, &maxSize); + REQUIRE(info.getOptionsLen() == 2); + info.setChecksumType(cfdp::ChecksumType::CRC_32C); + info.setClosureRequested(true); + uint8_t* buffer = mdBuffer.data(); + size_t sz = 0; + serializer.updateDirectiveFieldLen(); + + info.setSourceFileName(sourceFileName); + result = serializer.serialize(&buffer, &sz, mdBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + MetadataPduDeserializer deserializer2(mdBuffer.data(), mdBuffer.size(), info); + result = deserializer2.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(options[0]->getType() == cfdp::TlvTypes::FILESTORE_RESPONSE); + REQUIRE(options[0]->getSerializedSize() == 14); + REQUIRE(options[1]->getType() == cfdp::TlvTypes::MSG_TO_USER); + REQUIRE(options[1]->getSerializedSize() == 5); + + for(size_t invalidFieldLen = 0; invalidFieldLen < 36; invalidFieldLen++) { + mdBuffer[1] = (invalidFieldLen >> 8) & 0xff; + mdBuffer[2] = invalidFieldLen & 0xff; + result = deserializer2.parseData(); + if(invalidFieldLen == 17) { + REQUIRE(info.getOptionsLen() == 0); + } + if(invalidFieldLen == 31) { + REQUIRE(info.getOptionsLen() == 1); + } + // This is the precise length where there are no options or one option + if(invalidFieldLen != 17 and invalidFieldLen != 31) { + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } + mdBuffer[1] = (36 >> 8) & 0xff; + mdBuffer[2] = 36 & 0xff; + info.setOptionsArray(nullptr, nullptr, nullptr); + REQUIRE(deserializer2.parseData() == cfdp::METADATA_CANT_PARSE_OPTIONS); + info.setOptionsArray(options.data(), &sizeOfOptions, nullptr); + for(size_t maxSz = 0; maxSz < 46; maxSz++) { + MetadataPduDeserializer invalidSzDeser(mdBuffer.data(), maxSz, info); + result = invalidSzDeser.parseData(); + REQUIRE(result == SerializeIF::STREAM_TOO_SHORT); + } + } +} diff --git a/tests/src/fsfw_tests/unit/cfdp/testNakPdu.cpp b/tests/src/fsfw_tests/unit/cfdp/testNakPdu.cpp new file mode 100644 index 00000000..57ec5140 --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testNakPdu.cpp @@ -0,0 +1,160 @@ +#include + +#include "fsfw/cfdp/pdu/PduConfig.h" +#include "fsfw/cfdp/pdu/NakPduDeserializer.h" +#include "fsfw/cfdp/pdu/NakPduSerializer.h" +#include "fsfw/globalfunctions/arrayprinter.h" + +#include + +TEST_CASE( "NAK PDU" , "[NakPdu]") { + using namespace cfdp; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::array nakBuffer = {}; + uint8_t* buffer = nakBuffer.data(); + size_t sz = 0; + EntityId destId(WidthInBytes::TWO_BYTES, 2); + TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15); + EntityId sourceId(WidthInBytes::TWO_BYTES, 1); + PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); + + FileSize startOfScope(50); + FileSize endOfScope(1050); + NakInfo info(startOfScope, endOfScope); + SECTION("Serializer") { + NakPduSerializer serializer(pduConf, info); + result = serializer.serialize(&buffer, &sz, nakBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(serializer.getSerializedSize() == 19); + REQUIRE(serializer.FileDirectiveSerializer::getSerializedSize() == 11); + REQUIRE(sz == 19); + REQUIRE(serializer.getPduDataFieldLen() == 9); + REQUIRE(((nakBuffer[1] << 8) | nakBuffer[2]) == 0x09); + REQUIRE(nakBuffer[10] == cfdp::FileDirectives::NAK); + uint32_t scope = 0; + result = SerializeAdapter::deSerialize(&scope, nakBuffer.data() + 11, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(scope == 50); + result = SerializeAdapter::deSerialize(&scope, nakBuffer.data() + 15, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(scope == 1050); + + NakInfo::SegmentRequest segReq0(cfdp::FileSize(2020), cfdp::FileSize(2520)); + NakInfo::SegmentRequest segReq1(cfdp::FileSize(2932), cfdp::FileSize(3021)); + // Now add 2 segment requests to NAK info and serialize them as well + std::array segReqs = { segReq0, segReq1 }; + size_t segReqsLen = segReqs.size(); + info.setSegmentRequests(segReqs.data(), &segReqsLen , &segReqsLen); + uint8_t* buffer = nakBuffer.data(); + size_t sz = 0; + serializer.updateDirectiveFieldLen(); + result = serializer.serialize(&buffer, &sz, nakBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(serializer.getSerializedSize() == 35); + REQUIRE(serializer.getPduDataFieldLen() == 25); + REQUIRE(((nakBuffer[1] << 8) | nakBuffer[2]) == 25); + uint32_t segReqScopes = 0; + result = SerializeAdapter::deSerialize(&segReqScopes, nakBuffer.data() + 19, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(segReqScopes == 2020); + result = SerializeAdapter::deSerialize(&segReqScopes, nakBuffer.data() + 23, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(segReqScopes == 2520); + result = SerializeAdapter::deSerialize(&segReqScopes, nakBuffer.data() + 27, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(segReqScopes == 2932); + result = SerializeAdapter::deSerialize(&segReqScopes, nakBuffer.data() + 31, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(segReqScopes == 3021); + + for(size_t maxSz = 0; maxSz < 35; maxSz++) { + uint8_t* buffer = nakBuffer.data(); + size_t sz = 0; + result = serializer.serialize(&buffer, &sz, maxSz, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT); + } + for(size_t sz = 35; sz > 0; sz--) { + uint8_t* buffer = nakBuffer.data(); + size_t locSize = sz; + result = serializer.serialize(&buffer, &locSize, 35, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT); + } + } + + SECTION("Deserializer") { + NakPduSerializer serializer(pduConf, info); + result = serializer.serialize(&buffer, &sz, nakBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + info.getStartOfScope().setFileSize(0, false); + info.getEndOfScope().setFileSize(0, false); + NakPduDeserializer deserializer(nakBuffer.data(), nakBuffer.size(), info); + result = deserializer.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(deserializer.getWholePduSize() == 19); + REQUIRE(info.getStartOfScope().getSize() == 50); + REQUIRE(info.getEndOfScope().getSize() == 1050); + + NakInfo::SegmentRequest segReq0(cfdp::FileSize(2020), cfdp::FileSize(2520)); + NakInfo::SegmentRequest segReq1(cfdp::FileSize(2932), cfdp::FileSize(3021)); + // Now add 2 segment requests to NAK info and serialize them as well + std::array segReqs = { segReq0, segReq1 }; + size_t segReqsLen = segReqs.size(); + info.setSegmentRequests(segReqs.data(), &segReqsLen, &segReqsLen); + uint8_t* buffer = nakBuffer.data(); + size_t sz = 0; + serializer.updateDirectiveFieldLen(); + result = serializer.serialize(&buffer, &sz, nakBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + NakPduDeserializer deserializeWithSegReqs(nakBuffer.data(), nakBuffer.size(), info); + result = deserializeWithSegReqs.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + NakInfo::SegmentRequest* segReqsPtr = nullptr; + size_t readSegReqs = 0; + info.getSegmentRequests(&segReqsPtr, &readSegReqs, nullptr); + REQUIRE(readSegReqs == 2); + REQUIRE(segReqsPtr[0].first.getSize() == 2020); + REQUIRE(segReqsPtr[0].second.getSize() == 2520); + REQUIRE(segReqsPtr[1].first.getSize() == 2932); + REQUIRE(segReqsPtr[1].second.getSize() == 3021); + REQUIRE(deserializeWithSegReqs.getPduDataFieldLen() == 25); + REQUIRE(info.getSegmentRequestsLen() == 2); + for(size_t idx = 0; idx < 34; idx ++) { + NakPduDeserializer faultyDeserializer(nakBuffer.data(), idx, info); + result = faultyDeserializer.parseData(); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + for(size_t pduFieldLen = 0; pduFieldLen < 25; pduFieldLen++) { + nakBuffer[1] = (pduFieldLen >> 8) & 0xff; + nakBuffer[2] = pduFieldLen & 0xff; + NakPduDeserializer faultyDeserializer(nakBuffer.data(), nakBuffer.size(), info); + result = faultyDeserializer.parseData(); + if(pduFieldLen == 9) { + REQUIRE(info.getSegmentRequestsLen() == 0); + } else if(pduFieldLen == 17) { + REQUIRE(info.getSegmentRequestsLen() == 1); + } else if(pduFieldLen == 25) { + REQUIRE(info.getSegmentRequestsLen() == 2); + } + if(pduFieldLen != 9 and pduFieldLen != 17 and pduFieldLen != 25) { + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } + info.setMaxSegmentRequestLen(5); + REQUIRE(info.getSegmentRequestsMaxLen() == 5); + } +} + diff --git a/tests/src/fsfw_tests/unit/cfdp/testPromptPdu.cpp b/tests/src/fsfw_tests/unit/cfdp/testPromptPdu.cpp new file mode 100644 index 00000000..64589e46 --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testPromptPdu.cpp @@ -0,0 +1,71 @@ +#include + +#include "fsfw/cfdp/pdu/PromptPduDeserializer.h" +#include "fsfw/cfdp/pdu/PromptPduSerializer.h" +#include "fsfw/globalfunctions/arrayprinter.h" + +#include + +TEST_CASE( "Prompt PDU" , "[PromptPdu]") { + using namespace cfdp; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::array rawBuf = {}; + uint8_t* buffer = rawBuf.data(); + size_t sz = 0; + EntityId destId(WidthInBytes::TWO_BYTES, 2); + TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15); + EntityId sourceId(WidthInBytes::TWO_BYTES, 1); + PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); + + SECTION("Serialize") { + PromptPduSerializer serializer(pduConf, cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE); + result = serializer.serialize(&buffer, &sz, rawBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(serializer.getWholePduSize() == 12); + REQUIRE(sz == 12); + REQUIRE(serializer.getPduDataFieldLen() == 2); + REQUIRE(rawBuf[10] == FileDirectives::PROMPT); + REQUIRE((rawBuf[sz - 1] >> 7) & 0x01 == cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE); + + for(size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) { + uint8_t* buffer = rawBuf.data(); + size_t sz = 0; + result = serializer.serialize(&buffer, &sz, invalidMaxSz, + SerializeIF::Endianness::NETWORK); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + for(size_t invalidSz = 1; invalidSz < sz; invalidSz++) { + size_t locSz = invalidSz; + uint8_t* buffer = rawBuf.data(); + result = serializer.serialize(&buffer, &locSz, sz, + SerializeIF::Endianness::NETWORK); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } + + SECTION("Deserialize") { + PromptPduSerializer serializer(pduConf, cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE); + result = serializer.serialize(&buffer, &sz, rawBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + PromptPduDeserializer deserializer(rawBuf.data(), rawBuf.size()); + result = deserializer.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(deserializer.getPromptResponseRequired() == + cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE); + sz = deserializer.getWholePduSize(); + rawBuf[2] = 1; + result = deserializer.parseData(); + REQUIRE(result == SerializeIF::STREAM_TOO_SHORT); + rawBuf[2] = 2; + + for(size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) { + deserializer.setData(rawBuf.data(), invalidMaxSz); + result = deserializer.parseData(); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } +} + diff --git a/tests/src/fsfw_tests/unit/cfdp/testTlvsLvs.cpp b/tests/src/fsfw_tests/unit/cfdp/testTlvsLvs.cpp new file mode 100644 index 00000000..15e94ebb --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testTlvsLvs.cpp @@ -0,0 +1,334 @@ +#include "fsfw/cfdp/pdu/PduConfig.h" +#include "fsfw/cfdp/tlv/Tlv.h" +#include "fsfw/cfdp/tlv/Lv.h" + +#include +#include +#include +#include + +#include "fsfw/globalfunctions/arrayprinter.h" +#include +#include +#include + +#include +#include + +TEST_CASE( "CFDP TLV LV" , "[CfdpTlvLv]") { + using namespace cfdp; + int result = HasReturnvaluesIF::RETURN_OK; + std::array rawBuf; + uint8_t* serPtr = rawBuf.data(); + const uint8_t* deserPtr = rawBuf.data(); + size_t deserSize = 0; + cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::TWO_BYTES, 0x0ff0); + + SECTION("TLV Serialization") { + std::array tlvRawBuf; + serPtr = tlvRawBuf.data(); + result = sourceId.serialize(&serPtr, &deserSize, tlvRawBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(deserSize == 2); + auto tlv = Tlv(TlvTypes::ENTITY_ID, tlvRawBuf.data(), deserSize); + REQUIRE(tlv.getSerializedSize() == 4); + REQUIRE(tlv.getLengthField() == 2); + serPtr = rawBuf.data(); + deserSize = 0; + result = tlv.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(deserSize == 4); + REQUIRE(rawBuf[0] == TlvTypes::ENTITY_ID); + REQUIRE(rawBuf[1] == 2); + uint16_t entityId = 0; + SerializeAdapter::deSerialize(&entityId, rawBuf.data() + 2, &deserSize, + SerializeIF::Endianness::NETWORK); + REQUIRE(entityId == 0x0ff0); + + // Set new value + sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 12); + serPtr = tlvRawBuf.data(); + deserSize = 0; + result = sourceId.serialize(&serPtr, &deserSize, tlvRawBuf.size(), + SerializeIF::Endianness::NETWORK); + tlv.setValue(tlvRawBuf.data(), cfdp::WidthInBytes::FOUR_BYTES); + serPtr = rawBuf.data(); + deserSize = 0; + result = tlv.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(rawBuf[0] == TlvTypes::ENTITY_ID); + REQUIRE(rawBuf[1] == 4); + + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + serPtr = rawBuf.data(); + deserSize = 0; + auto tlvInvalid = Tlv(cfdp::TlvTypes::INVALID_TLV, tlvRawBuf.data(), 0); + REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK) != HasReturnvaluesIF::RETURN_OK); + tlvInvalid = Tlv(cfdp::TlvTypes::ENTITY_ID, nullptr, 3); + REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK) != HasReturnvaluesIF::RETURN_OK); + REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, 0, + SerializeIF::Endianness::NETWORK) != HasReturnvaluesIF::RETURN_OK); + REQUIRE(tlvInvalid.getSerializedSize() == 0); + REQUIRE(tlvInvalid.serialize(nullptr, nullptr, 0, + SerializeIF::Endianness::NETWORK) != HasReturnvaluesIF::RETURN_OK); + + Tlv zeroLenField(TlvTypes::FAULT_HANDLER, nullptr, 0); + REQUIRE(zeroLenField.getSerializedSize() == 2); + serPtr = rawBuf.data(); + deserSize = 0; + REQUIRE(zeroLenField.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK) == HasReturnvaluesIF::RETURN_OK); + REQUIRE(rawBuf[0] == TlvTypes::FAULT_HANDLER); + REQUIRE(rawBuf[1] == 0); + } + + SECTION("TLV Deserialization") { + // Serialization was tested before, generate raw data now + std::array tlvRawBuf; + serPtr = tlvRawBuf.data(); + result = sourceId.serialize(&serPtr, &deserSize, tlvRawBuf.size(), + SerializeIF::Endianness::NETWORK); + auto tlvSerialization = Tlv(TlvTypes::ENTITY_ID, tlvRawBuf.data(), deserSize); + serPtr = rawBuf.data(); + deserSize = 0; + result = tlvSerialization.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK); + Tlv tlv; + deserPtr = rawBuf.data(); + result = tlv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(tlv.getSerializedSize() == 4); + REQUIRE(tlv.getType() == TlvTypes::ENTITY_ID); + deserPtr = tlv.getValue(); + uint16_t entityId = 0; + deserSize = 0; + SerializeAdapter::deSerialize(&entityId, deserPtr, &deserSize, + SerializeIF::Endianness::NETWORK); + REQUIRE(entityId == 0x0ff0); + + REQUIRE(tlv.deSerialize(nullptr, nullptr, SerializeIF::Endianness::NETWORK) != + HasReturnvaluesIF::RETURN_OK); + deserPtr = rawBuf.data(); + deserSize = 0; + REQUIRE(tlv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK) == + SerializeIF::STREAM_TOO_SHORT); + // Set invalid TLV + rawBuf[0] = TlvTypes::INVALID_TLV; + deserSize = 4; + REQUIRE(tlv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK) != + HasReturnvaluesIF::RETURN_OK); + + Tlv zeroLenField(TlvTypes::FAULT_HANDLER, nullptr, 0); + serPtr = rawBuf.data(); + deserSize = 0; + REQUIRE(zeroLenField.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK) == HasReturnvaluesIF::RETURN_OK); + deserPtr = rawBuf.data(); + result = zeroLenField.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(zeroLenField.getSerializedSize() == 2); + REQUIRE(deserSize == 0); + } + + SECTION("LV Serialization") { + std::array lvRawBuf; + serPtr = lvRawBuf.data(); + result = sourceId.serialize(&serPtr, &deserSize, lvRawBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(deserSize == 2); + auto lv = cfdp::Lv(lvRawBuf.data(), 2); + auto lvCopy = cfdp::Lv(lv); + REQUIRE(lv.getSerializedSize() == 3); + REQUIRE(lvCopy.getSerializedSize() == 3); + REQUIRE(lv.getValue(nullptr) == lvCopy.getValue(nullptr)); + serPtr = rawBuf.data(); + deserSize = 0; + result = lv.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(deserSize == 3); + REQUIRE(rawBuf[0] == 2); + uint16_t sourceId = 0; + result = SerializeAdapter::deSerialize(&sourceId, rawBuf.data() + 1, &deserSize, + SerializeIF::Endianness::BIG); + REQUIRE(sourceId == 0x0ff0); + + auto lvEmpty = Lv(nullptr, 0); + REQUIRE(lvEmpty.getSerializedSize() == 1); + serPtr = rawBuf.data(); + deserSize = 0; + result = lvEmpty.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(deserSize == 1); + } + + SECTION("LV Deserialization") { + std::array lvRawBuf; + serPtr = lvRawBuf.data(); + result = sourceId.serialize(&serPtr, &deserSize, lvRawBuf.size(), + SerializeIF::Endianness::NETWORK); + auto lv = cfdp::Lv(lvRawBuf.data(), 2); + serPtr = rawBuf.data(); + deserSize = 0; + result = lv.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + Lv uninitLv; + deserPtr = rawBuf.data(); + deserSize = 3; + result = uninitLv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(uninitLv.getSerializedSize() == 3); + const uint8_t* storedValue = uninitLv.getValue(nullptr); + uint16_t sourceId = 0; + result = SerializeAdapter::deSerialize(&sourceId, storedValue, &deserSize, + SerializeIF::Endianness::BIG); + REQUIRE(sourceId == 0x0ff0); + + auto lvEmpty = Lv(nullptr, 0); + REQUIRE(lvEmpty.getSerializedSize() == 1); + serPtr = rawBuf.data(); + deserSize = 0; + result = lvEmpty.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(deserSize == 1); + deserPtr = rawBuf.data(); + result = uninitLv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(uninitLv.getSerializedSize() == 1); + + REQUIRE(uninitLv.deSerialize(nullptr, nullptr, SerializeIF::Endianness::BIG) == + HasReturnvaluesIF::RETURN_FAILED); + serPtr = rawBuf.data(); + deserSize = 0; + REQUIRE(uninitLv.serialize(&serPtr, &deserSize, 0, SerializeIF::Endianness::BIG) == + SerializeIF::BUFFER_TOO_SHORT); + REQUIRE(uninitLv.serialize(nullptr, nullptr, 12, SerializeIF::Endianness::BIG)); + deserSize = 0; + REQUIRE(uninitLv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG) == + SerializeIF::STREAM_TOO_SHORT); + } + + SECTION("Filestore Response TLV") { + std::string name = "hello.txt"; + cfdp::Lv firstName(reinterpret_cast(name.data()), name.size()); + std::string name2 = "hello2.txt"; + cfdp::Lv secondName(reinterpret_cast(name2.data()), name2.size()); + std::string msg = "12345"; + cfdp::Lv fsMsg(reinterpret_cast(msg.data()), msg.size()); + FilestoreResponseTlv response(cfdp::FilestoreActionCode::APPEND_FILE, cfdp::FSR_SUCCESS, + firstName, &fsMsg); + response.setSecondFileName(&secondName); + REQUIRE(response.getLengthField() == 10 + 11 + 6 + 1); + REQUIRE(response.getSerializedSize() == response.getLengthField() + 2); + + cfdp::Tlv rawResponse; + std::array serBuf = {}; + result = response.convertToTlv(rawResponse, serBuf.data(), serBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(rawResponse.getType() == cfdp::TlvTypes::FILESTORE_RESPONSE); + cfdp::Lv emptyMsg; + cfdp::Lv emptySecondName; + FilestoreResponseTlv emptyTlv(firstName, &emptyMsg); + emptyTlv.setSecondFileName(&emptySecondName); + result = emptyTlv.deSerialize(rawResponse, SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(emptyTlv.getActionCode() == cfdp::FilestoreActionCode::APPEND_FILE); + REQUIRE(emptyTlv.getStatusCode() == cfdp::FSR_SUCCESS); + size_t firstNameLen = 0; + const char* firstNamePtr = reinterpret_cast( + emptyTlv.getFirstFileName().getValue(&firstNameLen)); + auto helloString = std::string(firstNamePtr, firstNameLen); + REQUIRE(helloString == "hello.txt"); + } + + SECTION("Filestore Request TLV") { + std::string name = "hello.txt"; + cfdp::Lv firstName(reinterpret_cast(name.data()), name.size()); + std::string name2 = "hello2.txt"; + cfdp::Lv secondName(reinterpret_cast(name2.data()), name2.size()); + FilestoreRequestTlv request(cfdp::FilestoreActionCode::APPEND_FILE, firstName); + + // second name not set yet + REQUIRE(request.getLengthField() == 10 + 1); + REQUIRE(request.getSerializedSize() == request.getLengthField() + 2); + + std::array serBuf = {}; + uint8_t* ptr = serBuf.data(); + size_t sz = 0; + result = request.serialize(&ptr, &sz, serBuf.size(), SerializeIF::Endianness::NETWORK); + REQUIRE(result == cfdp::FILESTORE_REQUIRES_SECOND_FILE); + + ptr = serBuf.data(); + sz = 0; + request.setSecondFileName(&secondName); + size_t expectedSz = request.getLengthField(); + REQUIRE(expectedSz == 10 + 11 + 1); + REQUIRE(request.getSerializedSize() == expectedSz + 2); + result = request.serialize(&ptr, &sz, serBuf.size(), SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(sz == expectedSz + 2); + + FilestoreRequestTlv emptyRequest(firstName); + emptyRequest.setSecondFileName(&secondName); + const uint8_t* constptr = serBuf.data(); + result = emptyRequest.deSerialize(&constptr, &sz, SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + cfdp::Tlv rawRequest; + ptr = serBuf.data(); + sz = 0; + result = request.convertToTlv(rawRequest, serBuf.data(), serBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(rawRequest.getType() == cfdp::TlvTypes::FILESTORE_REQUEST); + + emptyRequest.setActionCode(cfdp::FilestoreActionCode::DELETE_FILE); + result = emptyRequest.deSerialize(rawRequest, SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(emptyRequest.getType() == cfdp::TlvTypes::FILESTORE_REQUEST); + REQUIRE(emptyRequest.getActionCode() == cfdp::FilestoreActionCode::APPEND_FILE); + } + + SECTION("Other") { + MessageToUserTlv emptyTlv; + uint8_t flowLabel = 1; + FlowLabelTlv flowLabelTlv(&flowLabel, 1); + + FaultHandlerOverrideTlv faultOverrideTlv(cfdp::ConditionCode::FILESTORE_REJECTION, + cfdp::FaultHandlerCode::NOTICE_OF_CANCELLATION); + size_t sz = 0; + ReturnValue_t result = faultOverrideTlv.serialize(&serPtr, &sz, rawBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(faultOverrideTlv.getSerializedSize() == 3); + REQUIRE(sz == 3); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + FaultHandlerOverrideTlv emptyOverrideTlv; + result = emptyOverrideTlv.deSerialize(&deserPtr, &sz, SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + EntityId entId(cfdp::WidthInBytes::TWO_BYTES, 0x42); + EntityId emptyId; + EntityIdTlv idTlv(emptyId); + serPtr = rawBuf.data(); + result = idTlv.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK); + cfdp::Tlv rawTlv(cfdp::TlvTypes::ENTITY_ID, rawBuf.data() + 2, 2); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + deserPtr = rawBuf.data(); + result = idTlv.deSerialize(rawTlv, SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + } +}