diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index a59f8a9487..09c235a211 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -94,6 +94,7 @@ BUFFERALLOCATIONFAILED BUFFERGETOUT BUFFERMANAGERCOMPONENTIMPLCFG BUFFERMGR +BUFFERTOOSMALLFORPACKET BUFFQUEUEIN buffsize BUGLIST @@ -267,6 +268,7 @@ doxyindexer doxyrules doxysearch Doxywizard +DPCFG dpi DPMANAGER DPWRITER @@ -330,6 +332,7 @@ fadvise FAKELOGGER fallocate fbuild +fdp fdset FEEDNAME ffff @@ -338,8 +341,11 @@ filedown FILEDOWNLINK FILEDOWNLINKCFG FILEID +FILENAMESTRING fileopen +FILEOPENERROR FILESTUBS +FILEWRITEERROR fio Firefox FLDP @@ -480,6 +486,9 @@ integertypename interoperate intlimits inttype +INVALIDBUFFER +INVALIDHEADER +INVALIDHEADERHASH invisi ioc ioctl @@ -774,6 +783,7 @@ PRMDBIMPLTESTER PRMDBLIMPLCFG prmname probs +PROCBUFFERSENDOUT PRODUCTGETIN PRODUCTREQUESTIN PRODUCTRESPONSEOUT diff --git a/Fw/Cfg/SerIds.hpp b/Fw/Cfg/SerIds.hpp index 9082db658e..421922dfa9 100644 --- a/Fw/Cfg/SerIds.hpp +++ b/Fw/Cfg/SerIds.hpp @@ -58,6 +58,7 @@ namespace Fw { FW_TYPEID_INTERNAL_INTERFACE_STRING = 51, //!< interface string Buffer type id FW_TYPEID_FIXED_LENGTH_STRING = 52, //!< 256 char string Buffer type id FW_TYPEID_OBJECT_NAME = 53, //!< ObjectName string Buffer type id + FW_TYPEID_FILE_NAME_STRING = 54, //!< FileName string Buffer type id }; } diff --git a/Fw/Types/CMakeLists.txt b/Fw/Types/CMakeLists.txt index 7dc88339e8..42fb9992ea 100644 --- a/Fw/Types/CMakeLists.txt +++ b/Fw/Types/CMakeLists.txt @@ -7,9 +7,9 @@ # Note: using PROJECT_NAME as EXECUTABLE_NAME #### -set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Types.fpp" +set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Assert.cpp" - "${CMAKE_CURRENT_LIST_DIR}/String.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FileNameString.cpp" "${CMAKE_CURRENT_LIST_DIR}/InternalInterfaceString.cpp" "${CMAKE_CURRENT_LIST_DIR}/MallocAllocator.cpp" "${CMAKE_CURRENT_LIST_DIR}/MemAllocator.cpp" @@ -17,8 +17,10 @@ set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Types.fpp" "${CMAKE_CURRENT_LIST_DIR}/PolyType.cpp" "${CMAKE_CURRENT_LIST_DIR}/SerialBuffer.cpp" "${CMAKE_CURRENT_LIST_DIR}/Serializable.cpp" + "${CMAKE_CURRENT_LIST_DIR}/String.cpp" "${CMAKE_CURRENT_LIST_DIR}/StringType.cpp" "${CMAKE_CURRENT_LIST_DIR}/StringUtils.cpp" + "${CMAKE_CURRENT_LIST_DIR}/Types.fpp" ) set(MOD_DEPS Fw/Cfg diff --git a/Fw/Types/FileNameString.cpp b/Fw/Types/FileNameString.cpp new file mode 100644 index 0000000000..ae189b5a42 --- /dev/null +++ b/Fw/Types/FileNameString.cpp @@ -0,0 +1,54 @@ +#include "Fw/Types/FileNameString.hpp" +#include "Fw/Types/StringUtils.hpp" + +namespace Fw { + +FileNameString::FileNameString(const char* src) : StringBase() { + (void)Fw::StringUtils::string_copy(this->m_buf, src, sizeof(this->m_buf)); +} + +FileNameString::FileNameString(const StringBase& src) : StringBase() { + (void)Fw::StringUtils::string_copy(this->m_buf, src.toChar(), sizeof(this->m_buf)); +} + +FileNameString::FileNameString(const FileNameString& src) : StringBase() { + (void)Fw::StringUtils::string_copy(this->m_buf, src.toChar(), sizeof(this->m_buf)); +} + +FileNameString::FileNameString() : StringBase() { + this->m_buf[0] = 0; +} + +FileNameString& FileNameString::operator=(const FileNameString& other) { + if (this == &other) { + return *this; + } + + (void)Fw::StringUtils::string_copy(this->m_buf, other.toChar(), sizeof(this->m_buf)); + return *this; +} + +FileNameString& FileNameString::operator=(const StringBase& other) { + if (this == &other) { + return *this; + } + + (void)Fw::StringUtils::string_copy(this->m_buf, other.toChar(), sizeof(this->m_buf)); + return *this; +} + +FileNameString& FileNameString::operator=(const char* other) { + Fw::StringUtils::string_copy(this->m_buf, other, sizeof(this->m_buf)); + return *this; +} + +FileNameString::~FileNameString() {} + +const char* FileNameString::toChar() const { + return this->m_buf; +} + +NATIVE_UINT_TYPE FileNameString::getCapacity() const { + return STRING_SIZE; +} +} // namespace Fw diff --git a/Fw/Types/FileNameString.hpp b/Fw/Types/FileNameString.hpp new file mode 100644 index 0000000000..abec0a59c4 --- /dev/null +++ b/Fw/Types/FileNameString.hpp @@ -0,0 +1,37 @@ +#ifndef FW_FILENAMESTRING_HPP +#define FW_FILENAMESTRING_HPP + +#include + +#include "Fw/Cfg/SerIds.hpp" +#include "Fw/Types/StringType.hpp" +#include "config/FppConstantsAc.hpp" + +namespace Fw { + +class FileNameString : public Fw::StringBase { + public: + enum { + SERIALIZED_TYPE_ID = FW_TYPEID_FILE_NAME_STRING, //!< typeid for string type + STRING_SIZE = FileNameStringSize, //!< Storage for string + SERIALIZED_SIZE = STRING_SIZE + sizeof(FwBuffSizeType) //!< Serialized size is size of buffer + size field + }; + + explicit FileNameString(const char* src); //!< char* source constructor + explicit FileNameString(const StringBase& src); //!< other string constructor + explicit FileNameString(const FileNameString& src); //!< String string constructor + FileNameString(); //!< default constructor + FileNameString& operator=(const FileNameString& other); //!< assignment operator + FileNameString& operator=(const StringBase& other); //!< other string assignment operator + FileNameString& operator=(const char* other); //!< char* assignment operator + ~FileNameString(); //!< destructor + + const char* toChar() const; //!< gets char buffer + NATIVE_UINT_TYPE getCapacity() const; //!< return buffer size + + private: + char m_buf[FileNameString::STRING_SIZE]; //!< storage for string data +}; +} // namespace Fw + +#endif diff --git a/Os/Stub/test/File.cpp b/Os/Stub/test/File.cpp index 08c515dec5..092e93de52 100644 --- a/Os/Stub/test/File.cpp +++ b/Os/Stub/test/File.cpp @@ -9,7 +9,14 @@ namespace Test { StaticData StaticData::data; void StaticData::setNextStatus(Os::File::Status status) { - StaticData::data.nextStatus = status; + StaticData::data.openStatus = status; + StaticData::data.sizeStatus = status; + StaticData::data.positionStatus = status; + StaticData::data.preallocateStatus = status; + StaticData::data.seekStatus = status; + StaticData::data.flushStatus = status; + StaticData::data.readStatus = status; + StaticData::data.writeStatus = status; } void StaticData::setSizeResult(FwSignedSizeType size) { @@ -52,7 +59,7 @@ FileInterface::Status TestFile::open(const char *filepath, Mode open_mode, Overw StaticData::data.openOverwrite = overwrite; StaticData::data.lastCalled = StaticData::OPEN_FN; StaticData::data.pointer = 0; - return StaticData::data.nextStatus; + return StaticData::data.openStatus; } void TestFile::close() { @@ -62,32 +69,32 @@ void TestFile::close() { FileInterface::Status TestFile::size(FwSignedSizeType& size_result) { StaticData::data.lastCalled = StaticData::SIZE_FN; size_result = StaticData::data.sizeResult; - return StaticData::data.nextStatus; + return StaticData::data.sizeStatus; } FileInterface::Status TestFile::position(FwSignedSizeType& position_result) { StaticData::data.lastCalled = StaticData::POSITION_FN; position_result = StaticData::data.positionResult; - return StaticData::data.nextStatus; + return StaticData::data.positionStatus; } FileInterface::Status TestFile::preallocate(FwSignedSizeType offset, FwSignedSizeType length) { StaticData::data.preallocateOffset = offset; StaticData::data.preallocateLength = length; StaticData::data.lastCalled = StaticData::PREALLOCATE_FN; - return StaticData::data.nextStatus; + return StaticData::data.preallocateStatus; } FileInterface::Status TestFile::seek(FwSignedSizeType offset, SeekType seekType) { StaticData::data.seekOffset = offset; StaticData::data.seekType = seekType; StaticData::data.lastCalled = StaticData::SEEK_FN; - return StaticData::data.nextStatus; + return StaticData::data.seekStatus; } FileInterface::Status TestFile::flush() { StaticData::data.lastCalled = StaticData::FLUSH_FN; - return StaticData::data.nextStatus; + return StaticData::data.flushStatus; } FileInterface::Status TestFile::read(U8 *buffer, FwSignedSizeType &size, WaitType wait) { @@ -103,7 +110,7 @@ FileInterface::Status TestFile::read(U8 *buffer, FwSignedSizeType &size, WaitTyp } else { size = StaticData::data.readSizeResult; } - return StaticData::data.nextStatus; + return StaticData::data.readStatus; } FileInterface::Status TestFile::write(const U8* buffer, FwSignedSizeType &size, WaitType wait) { @@ -119,7 +126,7 @@ FileInterface::Status TestFile::write(const U8* buffer, FwSignedSizeType &size, } else { size = StaticData::data.writeSizeResult; } - return StaticData::data.nextStatus; + return StaticData::data.writeStatus; } FileHandle* TestFile::getHandle() { diff --git a/Os/Stub/test/File.hpp b/Os/Stub/test/File.hpp index 051bbc1d9d..587a8db867 100644 --- a/Os/Stub/test/File.hpp +++ b/Os/Stub/test/File.hpp @@ -60,8 +60,23 @@ struct StaticData { //! File pointer FwSignedSizeType pointer = 0; - //! Next status to be returned - Os::File::Status nextStatus = Os::File::Status::OTHER_ERROR; + //! Status to return from open + Os::File::Status openStatus = Os::File::Status::OP_OK; + //! Status to return from size + Os::File::Status sizeStatus = Os::File::Status::OP_OK; + //! Status to return from position + Os::File::Status positionStatus = Os::File::Status::OP_OK; + //! Status to return from preallocate + Os::File::Status preallocateStatus = Os::File::Status::OP_OK; + //! Status to return from seek + Os::File::Status seekStatus = Os::File::Status::OP_OK; + //! Status to return from flush + Os::File::Status flushStatus = Os::File::Status::OP_OK; + //! Status to return from read + Os::File::Status readStatus = Os::File::Status::OP_OK; + //! Status to return from write + Os::File::Status writeStatus = Os::File::Status::OP_OK; + //! Return of next size call FwSignedSizeType sizeResult = -1; //! Return of next position call diff --git a/Os/test/ut/file/SyntheticFileSystem.hpp b/Os/test/ut/file/SyntheticFileSystem.hpp index 968101bc35..c20866ec42 100644 --- a/Os/test/ut/file/SyntheticFileSystem.hpp +++ b/Os/test/ut/file/SyntheticFileSystem.hpp @@ -2,7 +2,7 @@ // \title Os/test/ut/file/SyntheticFileSystem.hpp // \brief standard template library driven synthetic file system definitions // ====================================================================== -#include "config/FpConfig.h" +#include #include "Os/File.hpp" #include #include diff --git a/Svc/CMakeLists.txt b/Svc/CMakeLists.txt index b71f3667b4..7e5148c125 100644 --- a/Svc/CMakeLists.txt +++ b/Svc/CMakeLists.txt @@ -26,6 +26,8 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CmdSequencer/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CmdSplitter/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Deframer/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/DpManager/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/DpPorts/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/DpWriter/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FatalHandler/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileDownlinkPorts/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileDownlink/") diff --git a/Svc/Deframer/Deframer.hpp b/Svc/Deframer/Deframer.hpp index 2c8e4db79a..56b75911ea 100644 --- a/Svc/Deframer/Deframer.hpp +++ b/Svc/Deframer/Deframer.hpp @@ -13,11 +13,12 @@ #ifndef Svc_Deframer_HPP #define Svc_Deframer_HPP +#include + #include "Svc/Deframer/DeframerComponentAc.hpp" #include "Svc/FramingProtocol/DeframingProtocol.hpp" #include "Svc/FramingProtocol/DeframingProtocolInterface.hpp" #include "Utils/Types/CircularBuffer.hpp" -#include "config/DeframerCfg.hpp" namespace Svc { diff --git a/Svc/DpManager/DpManager.cpp b/Svc/DpManager/DpManager.cpp index 341d158166..e576a60189 100644 --- a/Svc/DpManager/DpManager.cpp +++ b/Svc/DpManager/DpManager.cpp @@ -52,7 +52,7 @@ void DpManager::productSendIn_handler(const NATIVE_INT_TYPE portNum, FwDpIdType this->productSendOut_out(portNum, sendBuffer); } -void DpManager::schedIn_handler(const NATIVE_INT_TYPE portNum, NATIVE_UINT_TYPE context) { +void DpManager::schedIn_handler(const NATIVE_INT_TYPE portNum, U32 context) { // Emit telemetry this->tlmWrite_NumSuccessfulAllocations(this->numSuccessfulAllocations); this->tlmWrite_NumFailedAllocations(this->numFailedAllocations); diff --git a/Svc/DpManager/DpManager.hpp b/Svc/DpManager/DpManager.hpp index ab3e17fd6f..4dccb09e23 100644 --- a/Svc/DpManager/DpManager.hpp +++ b/Svc/DpManager/DpManager.hpp @@ -83,7 +83,7 @@ class DpManager : public DpManagerComponentBase { //! Handler implementation for schedIn void schedIn_handler(const NATIVE_INT_TYPE portNum, //!< The port number - NATIVE_UINT_TYPE context //!< The call order + U32 context //!< The call order ) final; PRIVATE: diff --git a/Svc/DpManager/test/ut/AbstractState.hpp b/Svc/DpManager/test/ut/AbstractState.hpp index d257ab7108..9f2b0aa004 100644 --- a/Svc/DpManager/test/ut/AbstractState.hpp +++ b/Svc/DpManager/test/ut/AbstractState.hpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #ifndef Svc_AbstractState_HPP diff --git a/Svc/DpManager/test/ut/DpManagerTestMain.cpp b/Svc/DpManager/test/ut/DpManagerTestMain.cpp index e01b0d100c..fe2c7b24fb 100644 --- a/Svc/DpManager/test/ut/DpManagerTestMain.cpp +++ b/Svc/DpManager/test/ut/DpManagerTestMain.cpp @@ -1,5 +1,7 @@ // ====================================================================== -// TestMain.cpp +// \title DpWriterTestMain.cpp +// \author bocchino +// \brief cpp file for DpWriter component test main function // ====================================================================== #include "Fw/Test/UnitTest.hpp" diff --git a/Svc/DpManager/test/ut/README.md b/Svc/DpManager/test/ut/README.md index 1f67640b81..d37ba3a659 100644 --- a/Svc/DpManager/test/ut/README.md +++ b/Svc/DpManager/test/ut/README.md @@ -315,6 +315,9 @@ This rule sends the `CLEAR_EVENT_THROTTLE` command. 1. Apply rule `CLEAR_EVENT_THROTTLE::OK`. 1. Apply rule `ProductRequestIn::BufferInvalid` +**Requirements tested:** +`SVC-DPMANAGER-006` + ## 3. Implementation ### 3.1. DpManagerTester and TestState diff --git a/Svc/DpManager/test/ut/Rules/BufferGetStatus.cpp b/Svc/DpManager/test/ut/Rules/BufferGetStatus.cpp index 3596d436c7..86c37c2404 100644 --- a/Svc/DpManager/test/ut/Rules/BufferGetStatus.cpp +++ b/Svc/DpManager/test/ut/Rules/BufferGetStatus.cpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #include "Svc/DpManager/test/ut/Rules/BufferGetStatus.hpp" diff --git a/Svc/DpManager/test/ut/Rules/BufferGetStatus.hpp b/Svc/DpManager/test/ut/Rules/BufferGetStatus.hpp index a02aa1aa4b..a1ee55596b 100644 --- a/Svc/DpManager/test/ut/Rules/BufferGetStatus.hpp +++ b/Svc/DpManager/test/ut/Rules/BufferGetStatus.hpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #ifndef Svc_BufferGetStatus_HPP diff --git a/Svc/DpManager/test/ut/Rules/CLEAR_EVENT_THROTTLE.cpp b/Svc/DpManager/test/ut/Rules/CLEAR_EVENT_THROTTLE.cpp index f16000c34b..970f101804 100644 --- a/Svc/DpManager/test/ut/Rules/CLEAR_EVENT_THROTTLE.cpp +++ b/Svc/DpManager/test/ut/Rules/CLEAR_EVENT_THROTTLE.cpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #include "STest/Pick/Pick.hpp" diff --git a/Svc/DpManager/test/ut/Rules/CLEAR_EVENT_THROTTLE.hpp b/Svc/DpManager/test/ut/Rules/CLEAR_EVENT_THROTTLE.hpp index 6742465d35..919d9308f2 100644 --- a/Svc/DpManager/test/ut/Rules/CLEAR_EVENT_THROTTLE.hpp +++ b/Svc/DpManager/test/ut/Rules/CLEAR_EVENT_THROTTLE.hpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #ifndef Svc_CLEAR_EVENT_THROTTLE_HPP diff --git a/Svc/DpManager/test/ut/Rules/ProductGetIn.cpp b/Svc/DpManager/test/ut/Rules/ProductGetIn.cpp index d5a8dca0fc..bf4368f10a 100644 --- a/Svc/DpManager/test/ut/Rules/ProductGetIn.cpp +++ b/Svc/DpManager/test/ut/Rules/ProductGetIn.cpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #include diff --git a/Svc/DpManager/test/ut/Rules/ProductGetIn.hpp b/Svc/DpManager/test/ut/Rules/ProductGetIn.hpp index 83aad5b255..a09e55443a 100644 --- a/Svc/DpManager/test/ut/Rules/ProductGetIn.hpp +++ b/Svc/DpManager/test/ut/Rules/ProductGetIn.hpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #ifndef Svc_ProductGetIn_HPP diff --git a/Svc/DpManager/test/ut/Rules/ProductRequestIn.cpp b/Svc/DpManager/test/ut/Rules/ProductRequestIn.cpp index c0028e938e..b3f847c662 100644 --- a/Svc/DpManager/test/ut/Rules/ProductRequestIn.cpp +++ b/Svc/DpManager/test/ut/Rules/ProductRequestIn.cpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #include diff --git a/Svc/DpManager/test/ut/Rules/ProductRequestIn.hpp b/Svc/DpManager/test/ut/Rules/ProductRequestIn.hpp index 20c1f72349..c93521ba6f 100644 --- a/Svc/DpManager/test/ut/Rules/ProductRequestIn.hpp +++ b/Svc/DpManager/test/ut/Rules/ProductRequestIn.hpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #ifndef Svc_ProductRequestIn_HPP diff --git a/Svc/DpManager/test/ut/Rules/ProductSendIn.cpp b/Svc/DpManager/test/ut/Rules/ProductSendIn.cpp index 84c58c88a9..2b1ddb175a 100644 --- a/Svc/DpManager/test/ut/Rules/ProductSendIn.cpp +++ b/Svc/DpManager/test/ut/Rules/ProductSendIn.cpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #include "STest/Pick/Pick.hpp" diff --git a/Svc/DpManager/test/ut/Rules/ProductSendIn.hpp b/Svc/DpManager/test/ut/Rules/ProductSendIn.hpp index c49a282d77..1706fba55c 100644 --- a/Svc/DpManager/test/ut/Rules/ProductSendIn.hpp +++ b/Svc/DpManager/test/ut/Rules/ProductSendIn.hpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #ifndef Svc_ProductSendIn_HPP diff --git a/Svc/DpManager/test/ut/Rules/Rules.hpp b/Svc/DpManager/test/ut/Rules/Rules.hpp index 8b64b02fb9..9dad1993a8 100644 --- a/Svc/DpManager/test/ut/Rules/Rules.hpp +++ b/Svc/DpManager/test/ut/Rules/Rules.hpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #ifndef Svc_Rules_HPP diff --git a/Svc/DpManager/test/ut/Rules/SchedIn.cpp b/Svc/DpManager/test/ut/Rules/SchedIn.cpp index 7625887843..4eea9182c9 100644 --- a/Svc/DpManager/test/ut/Rules/SchedIn.cpp +++ b/Svc/DpManager/test/ut/Rules/SchedIn.cpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #include "STest/Pick/Pick.hpp" diff --git a/Svc/DpManager/test/ut/Rules/SchedIn.hpp b/Svc/DpManager/test/ut/Rules/SchedIn.hpp index c90dc1ab16..f9ece50303 100644 --- a/Svc/DpManager/test/ut/Rules/SchedIn.hpp +++ b/Svc/DpManager/test/ut/Rules/SchedIn.hpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #ifndef Svc_SchedIn_HPP diff --git a/Svc/DpManager/test/ut/Rules/Testers.cpp b/Svc/DpManager/test/ut/Rules/Testers.cpp index cc549bccd8..072cc084f6 100644 --- a/Svc/DpManager/test/ut/Rules/Testers.cpp +++ b/Svc/DpManager/test/ut/Rules/Testers.cpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #include "Svc/DpManager/test/ut/Rules/Testers.hpp" diff --git a/Svc/DpManager/test/ut/Rules/Testers.hpp b/Svc/DpManager/test/ut/Rules/Testers.hpp index 631c744272..03bd31f3fe 100644 --- a/Svc/DpManager/test/ut/Rules/Testers.hpp +++ b/Svc/DpManager/test/ut/Rules/Testers.hpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #ifndef Svc_Testers_HPP diff --git a/Svc/DpManager/test/ut/Scenarios/Random.cpp b/Svc/DpManager/test/ut/Scenarios/Random.cpp index be70314e46..e461d72161 100644 --- a/Svc/DpManager/test/ut/Scenarios/Random.cpp +++ b/Svc/DpManager/test/ut/Scenarios/Random.cpp @@ -6,8 +6,7 @@ // \copyright // Copyright (C) 2021 California Institute of Technology. // ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// acknowledged. // ====================================================================== #include "STest/Scenario/BoundedScenario.hpp" diff --git a/Svc/DpManager/test/ut/Scenarios/Random.hpp b/Svc/DpManager/test/ut/Scenarios/Random.hpp index 387c62f567..fb9a8ba4eb 100644 --- a/Svc/DpManager/test/ut/Scenarios/Random.hpp +++ b/Svc/DpManager/test/ut/Scenarios/Random.hpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #ifndef Svc_Random_HPP diff --git a/Svc/DpManager/test/ut/TestState/TestState.hpp b/Svc/DpManager/test/ut/TestState/TestState.hpp index c70882f57d..9eb9cb139d 100644 --- a/Svc/DpManager/test/ut/TestState/TestState.hpp +++ b/Svc/DpManager/test/ut/TestState/TestState.hpp @@ -5,9 +5,8 @@ // // \copyright // Copyright (C) 2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. Any commercial use must be negotiated with the Office -// of Technology Transfer at the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. // ====================================================================== #ifndef Svc_TestState_HPP diff --git a/Svc/DpPorts/CMakeLists.txt b/Svc/DpPorts/CMakeLists.txt new file mode 100644 index 0000000000..3392df6e07 --- /dev/null +++ b/Svc/DpPorts/CMakeLists.txt @@ -0,0 +1,18 @@ +#### +# F prime CMakeLists.txt: +# +# SOURCE_FILES: combined list of source and autocoding files +# MOD_DEPS: (optional) module dependencies +# +# Note: using PROJECT_NAME as EXECUTABLE_NAME +#### +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/DpPorts.fpp" +) + +set(MOD_DEPS + Fw/Types + Fw/Port +) + +register_fprime_module() diff --git a/Svc/DpPorts/DpPorts.fpp b/Svc/DpPorts/DpPorts.fpp new file mode 100644 index 0000000000..ad5365c94d --- /dev/null +++ b/Svc/DpPorts/DpPorts.fpp @@ -0,0 +1,10 @@ +module Svc { + + @ Send a notification that a data product was written + port DpWritten( + fileName: string size FileNameStringSize @< The file name + $priority: FwDpPriorityType @< The priority + $size: FwSizeType @< The file size + ) + +} diff --git a/Svc/DpWriter/CMakeLists.txt b/Svc/DpWriter/CMakeLists.txt new file mode 100644 index 0000000000..6f58f6270f --- /dev/null +++ b/Svc/DpWriter/CMakeLists.txt @@ -0,0 +1,32 @@ +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/DpWriter.cpp" + "${CMAKE_CURRENT_LIST_DIR}/DpWriter.fpp" +) + +set(MOD_DEPS + Fw/Dp +) + +register_fprime_module() + +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/DpWriter.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/AbstractState.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/DpWriterTestMain.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/DpWriterTester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Rules/BufferSendIn.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Rules/CLEAR_EVENT_THROTTLE.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Rules/FileOpenStatus.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Rules/FileWriteStatus.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Rules/SchedIn.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Rules/Testers.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Scenarios/Random.cpp" +) + +set(UT_MOD_DEPS + STest +) + +set(UT_AUTO_HELPERS ON) +choose_fprime_implementation(Os/File Os_File_Test_Stub) +register_fprime_ut() diff --git a/Svc/DpWriter/DpWriter.cpp b/Svc/DpWriter/DpWriter.cpp new file mode 100644 index 0000000000..6bb929d761 --- /dev/null +++ b/Svc/DpWriter/DpWriter.cpp @@ -0,0 +1,221 @@ +// ====================================================================== +// \title DpWriter.cpp +// \author bocchino +// \brief cpp file for DpWriter component implementation class +// ====================================================================== + +#include "Fw/Com/ComPacket.hpp" +#include "Fw/Types/Serializable.hpp" +#include "Os/File.hpp" +#include "Svc/DpWriter/DpWriter.hpp" +#include "Utils/Hash/Hash.hpp" +#include "config/DpCfg.hpp" +#include "config/FpConfig.hpp" + +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction, initialization, and destruction +// ---------------------------------------------------------------------- + +DpWriter::DpWriter(const char* const compName) : DpWriterComponentBase(compName) {} + +DpWriter::~DpWriter() {} + +// ---------------------------------------------------------------------- +// Handler implementations for user-defined typed input ports +// ---------------------------------------------------------------------- + +void DpWriter::bufferSendIn_handler(const NATIVE_INT_TYPE portNum, Fw::Buffer& buffer) { + Fw::Success::T status = Fw::Success::SUCCESS; + // portNum is unused + (void)portNum; + // Update num buffers received + ++this->m_numBuffersReceived; + // Check that the buffer is valid + if (!buffer.isValid()) { + this->log_WARNING_HI_InvalidBuffer(); + status = Fw::Success::FAILURE; + } + // Check that the buffer is large enough to hold a data product packet + const FwSizeType bufferSize = buffer.getSize(); + if (status == Fw::Success::SUCCESS) { + if (bufferSize < Fw::DpContainer::MIN_PACKET_SIZE) { + this->log_WARNING_HI_BufferTooSmallForPacket(bufferSize, Fw::DpContainer::MIN_PACKET_SIZE); + status = Fw::Success::FAILURE; + } + } + // Set up the container and check that the header hash is valid + Fw::DpContainer container; + if (status == Fw::Success::SUCCESS) { + container.setBuffer(buffer); + Utils::HashBuffer storedHash; + Utils::HashBuffer computedHash; + status = container.checkHeaderHash(storedHash, computedHash); + if (status != Fw::Success::SUCCESS) { + this->log_WARNING_HI_InvalidHeaderHash(bufferSize, storedHash.asBigEndianU32(), + computedHash.asBigEndianU32()); + } + } + // Deserialize the packet header + if (status == Fw::Success::SUCCESS) { + status = this->deserializePacketHeader(buffer, container); + } + // Check that the packet size fits in the buffer + if (status == Fw::Success::SUCCESS) { + const FwSizeType packetSize = container.getPacketSize(); + if (bufferSize < packetSize) { + this->log_WARNING_HI_BufferTooSmallForData(bufferSize, packetSize); + status = Fw::Success::FAILURE; + } + } + // Perform the requested processing + if (status == Fw::Success::SUCCESS) { + this->performProcessing(container); + } + // Construct the file name + Fw::FileNameString fileName; + if (status == Fw::Success::SUCCESS) { + const FwDpIdType containerId = container.getId(); + const Fw::Time timeTag = container.getTimeTag(); + fileName.format(DP_FILENAME_FORMAT, containerId, timeTag.getSeconds(), timeTag.getUSeconds()); + } + FwSizeType fileSize = 0; + // Write the file + if (status == Fw::Success::SUCCESS) { + status = this->writeFile(container, fileName, fileSize); + } + // Send the DpWritten notification + if (status == Fw::Success::SUCCESS) { + this->sendNotification(container, fileName, fileSize); + } + // Deallocate the buffer + if (buffer.isValid()) { + this->deallocBufferSendOut_out(0, buffer); + } + // Update the error count + if (status != Fw::Success::SUCCESS) { + this->m_numErrors++; + } +} + +void DpWriter::schedIn_handler(const NATIVE_INT_TYPE portNum, U32 context) { + // portNum and context are not used + (void)portNum; + (void)context; + // Write telemetry + this->tlmWrite_NumBuffersReceived(this->m_numBuffersReceived); + this->tlmWrite_NumBytesWritten(this->m_numBytesWritten); + this->tlmWrite_NumSuccessfulWrites(this->m_numSuccessfulWrites); + this->tlmWrite_NumFailedWrites(this->m_numFailedWrites); + this->tlmWrite_NumErrors(this->m_numErrors); +} + +// ---------------------------------------------------------------------- +// Handler implementations for commands +// ---------------------------------------------------------------------- + +void DpWriter::CLEAR_EVENT_THROTTLE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { + // opCode and cmdSeq are not used + (void)opCode; + (void)cmdSeq; + // Clear throttling + this->log_WARNING_HI_BufferTooSmallForData_ThrottleClear(); + this->log_WARNING_HI_BufferTooSmallForPacket_ThrottleClear(); + this->log_WARNING_HI_FileOpenError_ThrottleClear(); + this->log_WARNING_HI_FileWriteError_ThrottleClear(); + this->log_WARNING_HI_InvalidBuffer_ThrottleClear(); + this->log_WARNING_HI_InvalidHeaderHash_ThrottleClear(); + this->log_WARNING_HI_InvalidHeader_ThrottleClear(); + // Return command response + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +// ---------------------------------------------------------------------- +// Private helper functions +// ---------------------------------------------------------------------- + +Fw::Success::T DpWriter::deserializePacketHeader(Fw::Buffer& buffer, Fw::DpContainer& container) { + Fw::Success::T status = Fw::Success::SUCCESS; + container.setBuffer(buffer); + const Fw::SerializeStatus serialStatus = container.deserializeHeader(); + if (serialStatus != Fw::FW_SERIALIZE_OK) { + this->log_WARNING_HI_InvalidHeader(static_cast(buffer.getSize()), static_cast(serialStatus)); + status = Fw::Success::FAILURE; + } + return status; +} + +void DpWriter::performProcessing(const Fw::DpContainer& container) { + // Get the buffer + Fw::Buffer buffer = container.getBuffer(); + // Get the bit mask for the processing types + const Fw::DpCfg::ProcType::SerialType procTypes = container.getProcTypes(); + // Do the processing + for (FwIndexType portNum = 0; portNum < NUM_PROCBUFFERSENDOUT_OUTPUT_PORTS; ++portNum) { + if ((procTypes & (1 << portNum)) != 0) { + this->procBufferSendOut_out(portNum, buffer); + } + } +} + +Fw::Success::T DpWriter::writeFile(const Fw::DpContainer& container, + const Fw::FileNameString& fileName, + FwSizeType& fileSize) { + Fw::Success::T status = Fw::Success::SUCCESS; + // Get the buffer + Fw::Buffer buffer = container.getBuffer(); + // Get the file size + fileSize = container.getPacketSize(); + // Open the file + Os::File file; + Os::File::Status fileStatus = file.open(fileName.toChar(), Os::File::OPEN_CREATE); + if (fileStatus != Os::File::OP_OK) { + this->log_WARNING_HI_FileOpenError(static_cast(fileStatus), fileName.toChar()); + status = Fw::Success::FAILURE; + } + // Write the file + if (status == Fw::Success::SUCCESS) { + // Set write size to file size + // On entry to the write call, this is the number of bytes to write + // On return from the write call, this is the number of bytes written + FwSignedSizeType writeSize = fileSize; + fileStatus = file.write(buffer.getData(), writeSize); + // If a successful write occurred, then update the number of bytes written + if (fileStatus == Os::File::OP_OK) { + this->m_numBytesWritten += writeSize; + } + if ((fileStatus == Os::File::OP_OK) and (writeSize == static_cast(fileSize))) { + // If the write status is success, and the number of bytes written + // is the expected number, then record the success + this->log_ACTIVITY_LO_FileWritten(writeSize, fileName.toChar()); + } else { + // Otherwise record the failure + this->log_WARNING_HI_FileWriteError(static_cast(fileStatus), static_cast(writeSize), + static_cast(fileSize), fileName.toChar()); + status = Fw::Success::FAILURE; + } + } + // Update the count of successful or failed writes + if (status == Fw::Success::SUCCESS) { + this->m_numSuccessfulWrites++; + } else { + this->m_numFailedWrites++; + } + // Return the status + return status; +} + +void DpWriter::sendNotification(const Fw::DpContainer& container, + const Fw::FileNameString& fileName, + FwSizeType fileSize) { + if (isConnected_dpWrittenOut_OutputPort(0)) { + // Construct the file name + fileNameString portFileName(fileName.toChar()); + // Get the priority + const FwDpPriorityType priority = container.getPriority(); + this->dpWrittenOut_out(0, portFileName, priority, fileSize); + } +} + +} // end namespace Svc diff --git a/Svc/DpWriter/DpWriter.fpp b/Svc/DpWriter/DpWriter.fpp new file mode 100644 index 0000000000..58d5ee3793 --- /dev/null +++ b/Svc/DpWriter/DpWriter.fpp @@ -0,0 +1,157 @@ +module Svc { + + @ A component for writing data products to disk + active component DpWriter { + + # ---------------------------------------------------------------------- + # Scheduling ports + # ---------------------------------------------------------------------- + + @ Schedule in port + async input port schedIn: Svc.Sched + + # ---------------------------------------------------------------------- + # Ports for handling data products + # ---------------------------------------------------------------------- + + @ Port for receiving data products to write to disk + async input port bufferSendIn: Fw.BufferSend + + @ Port for processing data products + output port procBufferSendOut: [DpWriterNumProcPorts] Fw.BufferSend + + @ Port for sending DpWritten notifications + output port dpWrittenOut: DpWritten + + @ Port for deallocating data product buffers + output port deallocBufferSendOut: Fw.BufferSend + + # ---------------------------------------------------------------------- + # F' special ports + # ---------------------------------------------------------------------- + + @ Command receive port + command recv port cmdIn + + @ Command registration port + command reg port cmdRegIn + + @ Command response port + command resp port cmdResponseOut + + @ Time get port + time get port timeGetOut + + @ Telemetry port + telemetry port tlmOut + + @ Event port + event port eventOut + + @ Text event port + text event port textEventOut + + # ---------------------------------------------------------------------- + # Commands + # ---------------------------------------------------------------------- + + @ Clear event throttling + async command CLEAR_EVENT_THROTTLE + + # ---------------------------------------------------------------------- + # Events + # ---------------------------------------------------------------------- + + @ Received buffer is invalid + event InvalidBuffer \ + severity warning high \ + format "Received buffer is invalid" \ + throttle 10 + + @ Received buffer is too small to hold a data product packet + event BufferTooSmallForPacket( + bufferSize: U32 @< The incoming buffer size + minSize: U32 @< The minimum required size + ) \ + severity warning high \ + format "Received buffer has size {}; minimum required size is {}" \ + throttle 10 + + @ The received buffer has an invalid header hash + event InvalidHeaderHash( + bufferSize: U32 @< The incoming buffer size + storedHash: U32 @< The stored hash value + computedHash: U32 @< The computed hash value + ) \ + severity warning high \ + format "Received a buffer of size {} with an invalid header hash (stored {x}, computed {x})" \ + throttle 10 + + @ Error occurred when deserializing the packet header + event InvalidHeader( + bufferSize: U32 @< The incoming buffer size + errorCode: U32 @< The error code + ) \ + severity warning high \ + format "Received buffer of size {}; deserialization of packet header failed with error code {}" \ + throttle 10 + + @ Received buffer is too small to hold the data specified in the header + event BufferTooSmallForData( + bufferSize: U32 @< The incoming buffer size + minSize: U32 @< The minimum required size + ) \ + severity warning high \ + format "Received buffer has size {}; minimum required size is {}" \ + throttle 10 + + @ An error occurred when opening a file + event FileOpenError( + status: U32 @< The status code returned from the open operation + file: string size FileNameStringSize @< The file + ) \ + severity warning high \ + format "Error {} opening file {}" \ + throttle 10 + + @ An error occurred when writing to a file + event FileWriteError( + status: U32 @< The status code returned from the write operation + bytesWritten: U32 @< The number of bytes successfully written + bytesToWrite: U32 @< The number of bytes attempted + file: string size FileNameStringSize @< The file + ) \ + severity warning high \ + format "Error {} while writing {} of {} bytes to {}" \ + throttle 10 + + @ File written + event FileWritten( + bytes: U32 @< The number of bytes written + file: string size FileNameStringSize @< The file name + ) \ + severity activity low \ + format "Wrote {} bytes to file {}" + + # ---------------------------------------------------------------------- + # Telemetry + # ---------------------------------------------------------------------- + + @ The number of buffers received + telemetry NumBuffersReceived: U32 update on change + + @ The number of bytes written + telemetry NumBytesWritten: U64 update on change + + @ The number of successful writes + telemetry NumSuccessfulWrites: U32 update on change + + @ The number of failed writes + telemetry NumFailedWrites: U32 update on change + + @ The number of errors + telemetry NumErrors: U32 update on change + + } + +} diff --git a/Svc/DpWriter/DpWriter.hpp b/Svc/DpWriter/DpWriter.hpp new file mode 100644 index 0000000000..e016dff2fe --- /dev/null +++ b/Svc/DpWriter/DpWriter.hpp @@ -0,0 +1,115 @@ +// ====================================================================== +// \title DpWriter.hpp +// \author bocchino +// \brief hpp file for DpWriter component implementation class +// ====================================================================== + +#ifndef Svc_DpWriter_HPP +#define Svc_DpWriter_HPP + +#include + +#include "Fw/Dp/DpContainer.hpp" +#include "Fw/Types/FileNameString.hpp" +#include "Fw/Types/String.hpp" +#include "Fw/Types/SuccessEnumAc.hpp" +#include "Svc/DpWriter/DpWriterComponentAc.hpp" + +namespace Svc { + +class DpWriter : public DpWriterComponentBase { + public: + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + //! Construct object DpWriter + //! + DpWriter(const char* const compName //!< The component name + ); + + //! Destroy object DpWriter + //! + ~DpWriter(); + + PRIVATE: + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for bufferSendIn + //! + void bufferSendIn_handler(const NATIVE_INT_TYPE portNum, //!< The port number + Fw::Buffer& fwBuffer //!< The buffer + ) override; + + //! Handler implementation for schedIn + //! + void schedIn_handler(const NATIVE_INT_TYPE portNum, //!< The port number + U32 context //!< The call order + ) override; + + PRIVATE: + // ---------------------------------------------------------------------- + // Handler implementations for commands + // ---------------------------------------------------------------------- + + //! Handler implementation for command CLEAR_EVENT_THROTTLE + //! + //! Clear event throttling + void CLEAR_EVENT_THROTTLE_cmdHandler(FwOpcodeType opCode, //!< The opcode + U32 cmdSeq //!< The command sequence number + ) override; + + PRIVATE: + // ---------------------------------------------------------------------- + // Private helper functions + // ---------------------------------------------------------------------- + + //! Deserialize the packet header + //! \return Success or failure + Fw::Success::T deserializePacketHeader(Fw::Buffer& buffer, //!< The packet buffer + Fw::DpContainer& container //!< The container + ); + + //! Perform processing on a packet buffer + void performProcessing(const Fw::DpContainer& container //!< The container + ); + + //! Write the file + //! \return Success or failure + Fw::Success::T writeFile(const Fw::DpContainer& container, //!< The container (input) + const Fw::FileNameString& fileName, //!< The file name + FwSizeType& fileSize //!< The file size (output) + ); + + //! Send the DpWritten notification + void sendNotification(const Fw::DpContainer& container, //!< The container + const Fw::FileNameString& fileName, //!< The file name + FwSizeType packetSize //!< The packet size + ); + + PRIVATE: + // ---------------------------------------------------------------------- + // Private member variables + // ---------------------------------------------------------------------- + + //! The number of buffers received + U32 m_numBuffersReceived = 0; + + //! The number of bytes written + U64 m_numBytesWritten = 0; + + //! The number of successful writes + U32 m_numSuccessfulWrites = 0; + + //! The number of failed writes + U32 m_numFailedWrites = 0; + + //! The number of errors + U32 m_numErrors = 0; +}; + +} // end namespace Svc + +#endif diff --git a/Svc/DpWriter/docs/sdd.md b/Svc/DpWriter/docs/sdd.md index c5bf08809a..60d8454917 100644 --- a/Svc/DpWriter/docs/sdd.md +++ b/Svc/DpWriter/docs/sdd.md @@ -21,6 +21,11 @@ before reaching `DpWriter`. 1. Write _B_ to disk. + 1. If a notification port is connected, then send out a notification +that the write occurred. +An instance of [`Svc::DpCatalog`](../../DpCatalog/docs/sdd.md) can +receive this notification and use it to update the data product catalog. + ## 2. Requirements Requirement | Description | Rationale | Verification Method @@ -29,7 +34,8 @@ SVC-DPWRITER-001 | `Svc::DpWriter` shall provide a port for receiving `Fw::Buffe SVC-DPWRITER-002 | `Svc::DpWriter` shall provide an array of ports for sending `Fw::Buffer` objects for processing. | This requirement supports downstream processing of the data in the buffer. | Unit Test SVC-DPWRITER-003 | On receiving a data product container _C_, `Svc::DpWriter` shall use the processing type field of the header of _C_ to select zero or more processing ports to invoke, in port order. | The processing type field is a bit mask. A one in bit `2^n` in the bit mask selects port index `n`. | Unit Test SVC-DPWRITER-004 | On receiving an `Fw::Buffer` _B_, and after performing any requested processing on _B_, `Svc::DpWriter` shall write _B_ to disk. | The purpose of `DpWriter` is to write data products to the disk. | Unit Test -SVC-DPWRITER-005 | `Svc::DpManager` shall provide telemetry that reports the number of data products written and the number of bytes written. | This requirement establishes the telemetry interface for the component. | Unit test +SVC-DPWRITER-005 | `Svc::DpWriter` shall provide a port for notifying other components that data products have been written. | This requirement allows `Svc::DpCatalog` or a similar component to update its catalog in real time. | Unit Test +SVC-DPWRITER-006 | `Svc::DpManager` shall provide telemetry that reports the number of buffers received, the number of data products written, the number of bytes written, the number of failed writes, and the number of errors. | This requirement establishes the telemetry interface for the component. | Unit test ## 3. Design @@ -50,6 +56,7 @@ The diagram below shows the `DpWriter` component. | `async input` | `schedIn` | `Svc.Sched` | Schedule in port | | `async input` | `bufferSendIn` | `Fw.BufferSend` | Port for receiving data products to write to disk | | `output` | `procBufferSendOut` | `[DpWriterNumProcPorts] Fw.BufferSend` | Port for processing data products | +| `output` | `dpWrittenOut` | `DpWritten` | Port for sending `DpWritten` notifications | | `output` | `deallocBufferSendOut` | `Fw.BufferSend` | Port for deallocating data product buffers | | `time get` | `timeGetOut` | `Fw.Time` | Time get port | | `telemetry` | `tlmOut` | `Fw.Tlm` | Telemetry port | @@ -66,17 +73,16 @@ The diagram below shows the `DpWriter` component. ### 3.4. Compile-Time Setup -The configuration constant [`DpWriterNumProcPorts`](../../../config/AcConstants.fpp) -specifies the number of ports for connecting components that perform -processing. - -### 3.5. Runtime Setup +1. The configuration constant [`DpWriterNumProcPorts`](../../../config/AcConstants.fpp) + specifies the number of ports for connecting components that perform + processing. -The `config` function specifies the following constants: +1. The configuration [`DP_FILENAME_FORMAT`](../../../config/DpCfg.hpp) + specifies the file name format. -1. `fileNamePrefix (string)`: The prefix to use for file names. +### 3.5. Runtime Setup -1. `fileNameSuffix (string)`: The suffix to use for file names. +No special runtime setup is required. ### 3.6. Port Handlers @@ -89,16 +95,30 @@ This handler sends out the state variables as telemetry. This handler receives a mutable reference to a buffer `B`. It does the following: -1. Check that `B` is valid and that the first `sizeof(FwPacketDescriptorType)` - bytes of the memory referred to by `B` hold the serialized value - [`Fw_PACKET_DP`](../../../Fw/Com/ComPacket.hpp). +1. Check that `B` is valid. If not, emit a warning event. + +1. If the previous step succeeded, then check that the size of `B` is large enough to + hold a data product container packet. If not, emit a warning event. + +1. If the previous steps succeeded, then check that the packet + header of `B` can be successfully deserialized. If not, emit a warning event. -1. If step 1 succeeded, then +1. If the previous steps succeeded, then check that the header + hash of `B` is valid. + If not, emit a warning event. + +1. If the previous steps succeeded, then check that the data + size recorded in the packet header fits within the buffer. + If not, emit a warning event. + +1. If the previous steps succeeded, then 1. Read the `ProcType` field out of the container header stored in the - memory pointed to by `B`. - If the value is a valid port number `N` for `procBufferSendOut`, then invoke + memory pointed to by `B`. Let the resulting bit mask be `M`. + + 1. Visit the port numbers of `procBufferSendOut` in order. + For each port number `N`, if `N` is set in `M`, then invoke `procBufferSendOut` at port number `N`, passing in `B`. This step updates the memory pointed to by `B` in place. @@ -106,7 +126,10 @@ It does the following: Format**](#file_format) section. For the time stamp, use the time provided by `timeGetOut`. -1. Send `B` on `deallocBufferSendOut`. +1. If the file write succeeded and `dpWrittenOut` is connected, then send the + file name, priority, and file size out on `dpWrittenOut`. + +1. If `B` is valid, then send `B` on `deallocBufferSendOut`. ## 4. File Format @@ -119,34 +142,42 @@ with the format described in the ### 4.2. File Name -The name of each file consists of `fileNamePrefix` followed by an -ID, a time stamp, and `fileNameSuffix`. -The ID consists of an underscore character `_` followed by the container ID. -The time stamp consists of an underscore character `_` followed by a seconds -value, an underscore character, and a microseconds value. +The name of each file is formatted with the configurable format string +[`DP_FILENAME_FORMAT`](../../../config/DpCfg.hpp). +The format string must contain format specifications for the following arguments, +in order. -For example, suppose that the file name prefix is `container_data` and the -file name suffix is `.dat`. -Suppose that container ID is 100, the seconds value is 100000, -and the microseconds value is 1000. -Then the file name is `container_data_100_100000_1000.dat`. +Format Specifier | Type | +---------------- | -----| +Container ID | `PRI_FwDpIdType` +Time seconds | `PRI_u32` +Time microseconds | `PRI_u32` ## 5. Ground Interface -### 5.1. Telemetry +### 5.1. Commands + +| Kind | Name | Description | +|------|------|-------------| +| `async` | `CLEAR_EVENT_THROTTLE` | Clear event throttling | + +### 5.2. Telemetry | Name | Type | Description | |------|------|-------------| | `NumDataProducts` | `U32` | The number of data products handled | | `NumBytes` | `U64` | The number of bytes handled | -### 5.2. Events +### 5.3. Events | Name | Severity | Description | |------|----------|-------------| +| `BufferInvalid` | `warning high` | Incoming buffer is invalid | | `BufferTooSmall` | `warning high` | Incoming buffer is too small to hold a data product container | -| `InvalidPacketDescriptor` | `warning high` | Incoming buffer had an invalid packet descriptor | +| `InvalidPacketDescriptor` | `warning high` | Incoming buffer has an invalid packet descriptor | +| `FileOpenError` | `warning high` | An error occurred when opening a file | +| `FileWriteError` | `warning high` | An error occurred when writing to a file | ## 6. Example Uses diff --git a/Svc/DpWriter/test/ut/AbstractState.cpp b/Svc/DpWriter/test/ut/AbstractState.cpp new file mode 100644 index 0000000000..cd07776850 --- /dev/null +++ b/Svc/DpWriter/test/ut/AbstractState.cpp @@ -0,0 +1,73 @@ +// ====================================================================== +// \title AbstractState.cpp +// \author Rob Bocchino +// \brief Implementation file for abstract state +// +// \copyright +// Copyright (C) 2024 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#include + +#include "Fw/Types/Assert.hpp" +#include "STest/Pick/Pick.hpp" +#include "Svc/DpWriter/test/ut/AbstractState.hpp" + +namespace Svc { + +// ---------------------------------------------------------------------- +// Public member functions +// ---------------------------------------------------------------------- + +//! Get a data product buffer backed by m_bufferData +//! \return The buffer +Fw::Buffer AbstractState::getDpBuffer() { + // Generate the ID + const FwDpIdType id = + STest::Pick::lowerUpper(std::numeric_limits::min(), std::numeric_limits::max()); + // Get the data size + const FwSizeType dataSize = this->getDataSize(); + const FwSizeType bufferSize = Fw::DpContainer::getPacketSizeForDataSize(dataSize); + FW_ASSERT(bufferSize <= MAX_BUFFER_SIZE, static_cast(bufferSize), + static_cast(MAX_BUFFER_SIZE)); + // Create the buffer + Fw::Buffer buffer(this->m_bufferData, bufferSize); + // Create the container + Fw::DpContainer container(id, buffer); + // Update the priority + const FwDpPriorityType priority = STest::Pick::lowerUpper(std::numeric_limits::min(), + std::numeric_limits::max()); + container.setPriority(priority); + // Update the time tag + const U32 seconds = STest::Pick::any(); + const U32 microseconds = STest::Pick::startLength(0, 1000000); + container.setTimeTag(Fw::Time(seconds, microseconds)); + // Update the processing types + Fw::DpCfg::ProcType::SerialType procTypes = 0; + for (FwIndexType i = 0; i < Fw::DpCfg::ProcType::NUM_CONSTANTS; i++) { + const bool selector = static_cast(STest::Pick::lowerUpper(0, 1)); + if (selector) { + procTypes |= (1 << i); + } + } + container.setProcTypes(procTypes); + // Update the data size + container.setDataSize(dataSize); + // Serialize the header and update the header hash + container.serializeHeader(); + // Randomize the data + U8* const dataPtr = &this->m_bufferData[Fw::DpContainer::DATA_OFFSET]; + const FwSizeType dataUpperBound = Fw::DpContainer::DATA_OFFSET + dataSize; + FW_ASSERT(dataUpperBound <= bufferSize, dataUpperBound, bufferSize); + for (FwSizeType i = 0; i <= dataSize; i++) { + dataPtr[i] = static_cast(STest::Pick::any()); + } + // Update the data hash + container.updateDataHash(); + // Return the buffer + return buffer; +} + +} // namespace Svc diff --git a/Svc/DpWriter/test/ut/AbstractState.hpp b/Svc/DpWriter/test/ut/AbstractState.hpp new file mode 100644 index 0000000000..bda265ab75 --- /dev/null +++ b/Svc/DpWriter/test/ut/AbstractState.hpp @@ -0,0 +1,134 @@ +// ====================================================================== +// \title AbstractState.hpp +// \author Rob Bocchino +// \brief Header file for abstract state +// +// \copyright +// Copyright (C) 2024 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#ifndef Svc_AbstractState_HPP +#define Svc_AbstractState_HPP + +#include + +#include "Fw/Types/Assert.hpp" +#include "Os/File.hpp" +#include "STest/Pick/Pick.hpp" +#include "Svc/DpWriter/DpWriter.hpp" +#include "TestUtils/OnChangeChannel.hpp" +#include "TestUtils/Option.hpp" + +namespace Svc { + +class AbstractState { + public: + // ---------------------------------------------------------------------- + // Constants + // ---------------------------------------------------------------------- + + //! The minimum data size + static constexpr FwSizeType MIN_DATA_SIZE = 0; + + //! The maximum data size + static constexpr FwSizeType MAX_DATA_SIZE = 1024; + + //! The maximum buffer size + static constexpr FwSizeType MAX_BUFFER_SIZE = Fw::DpContainer::getPacketSizeForDataSize(MAX_DATA_SIZE); + + public: + // ---------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------- + + //! Construct an AbstractState object + AbstractState() + : m_dataSizeOpt(), + m_NumBuffersReceived(0), + m_NumBytesWritten(0), + m_NumFailedWrites(0), + m_NumSuccessfulWrites(0), + m_NumErrors(0), + m_procTypes(0) {} + + public: + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + //! Get the data size + FwSizeType getDataSize() const { + return this->m_dataSizeOpt.getOrElse(STest::Pick::lowerUpper(MIN_DATA_SIZE, MAX_DATA_SIZE)); + } + + //! Set the data size + void setDataSize(FwSizeType dataSize) { this->m_dataSizeOpt.set(dataSize); } + + //! Get a data product buffer backed by bufferData + //! \return The buffer + Fw::Buffer getDpBuffer(); + + private: + // ---------------------------------------------------------------------- + // Private state variables + // ---------------------------------------------------------------------- + + //! The current buffer size + TestUtils::Option m_dataSizeOpt; + + public: + // ---------------------------------------------------------------------- + // Public state variables + // ---------------------------------------------------------------------- + + //! The number of buffers received + TestUtils::OnChangeChannel m_NumBuffersReceived; + + //! The number of bytes written + TestUtils::OnChangeChannel m_NumBytesWritten; + + //! The number of failed writes + TestUtils::OnChangeChannel m_NumFailedWrites; + + //! The number of successful writes + TestUtils::OnChangeChannel m_NumSuccessfulWrites; + + //! The number of errors + TestUtils::OnChangeChannel m_NumErrors; + + //! The number of BufferTooSmallForData events since the last throttle clear + FwSizeType m_bufferTooSmallForDataEventCount = 0; + + //! The number of BufferTooSmallForPacket events since the last throttle clear + FwSizeType m_bufferTooSmallForPacketEventCount = 0; + + //! The number of buffer invalid events since the last throttle clear + FwSizeType m_invalidBufferEventCount = 0; + + //! The number of file open error events since the last throttle clear + FwSizeType m_fileOpenErrorEventCount = 0; + + //! The number of file write error events since the last throttle clear + FwSizeType m_fileWriteErrorEventCount = 0; + + //! The number of invalid header hash events since the last throttle clear + FwSizeType m_invalidHeaderHashEventCount = 0; + + //! The number of invalid header events since the last throttle clear + FwSizeType m_invalidHeaderEventCount = 0; + + //! Data for buffers + U8 m_bufferData[MAX_BUFFER_SIZE] = {}; + + //! Data for write results + U8 m_writeResultData[MAX_BUFFER_SIZE] = {}; + + //! Bit mask for processing out port calls + Fw::DpCfg::ProcType::SerialType m_procTypes; +}; + +} // namespace Svc + +#endif diff --git a/Svc/DpWriter/test/ut/DpWriterTestMain.cpp b/Svc/DpWriter/test/ut/DpWriterTestMain.cpp new file mode 100644 index 0000000000..3f42cb2a7d --- /dev/null +++ b/Svc/DpWriter/test/ut/DpWriterTestMain.cpp @@ -0,0 +1,131 @@ +// ====================================================================== +// \title DpWriterTestMain.cpp +// \author bocchino +// \brief cpp file for DpWriter component test main function +// ====================================================================== + +#include "Fw/Test/UnitTest.hpp" +#include "STest/Random/Random.hpp" +#include "Svc/DpWriter/test/ut/Rules/Testers.hpp" +#include "Svc/DpWriter/test/ut/Scenarios/Random.hpp" + +namespace Svc { + +TEST(BufferSendIn, BufferTooSmallForData) { + COMMENT("Invoke bufferSendIn with a buffer that is too small to hold the data size specified in the header."); + REQUIREMENT("SVC-DPMANAGER-001"); + BufferSendIn::Tester tester; + tester.BufferTooSmallForData(); +} + +TEST(BufferSendIn, BufferTooSmallForPacket) { + COMMENT("Invoke bufferSendIn with a buffer that is too small to hold a data product packet."); + REQUIREMENT("SVC-DPMANAGER-001"); + BufferSendIn::Tester tester; + tester.BufferTooSmallForPacket(); +} + +TEST(BufferSendIn, FileOpenError) { + COMMENT("Invoke bufferSendIn with a file open error."); + REQUIREMENT("SVC-DPMANAGER-001"); + BufferSendIn::Tester tester; + tester.FileOpenError(); +} + +TEST(BufferSendIn, FileWriteError) { + COMMENT("Invoke bufferSendIn with a file write error."); + REQUIREMENT("SVC-DPMANAGER-001"); + BufferSendIn::Tester tester; + tester.FileWriteError(); +} + +TEST(BufferSendIn, InvalidBuffer) { + COMMENT("Invoke bufferSendIn with an invalid buffer."); + REQUIREMENT("SVC-DPMANAGER-001"); + BufferSendIn::Tester tester; + tester.InvalidBuffer(); +} + +TEST(BufferSendIn, InvalidHeader) { + COMMENT("Invoke bufferSendIn with an invalid packet header."); + REQUIREMENT("SVC-DPMANAGER-001"); + BufferSendIn::Tester tester; + tester.InvalidHeader(); +} + +TEST(BufferSendIn, InvalidHeaderHash) { + COMMENT("Invoke bufferSendIn with a buffer that has an invalid header hash."); + REQUIREMENT("SVC-DPMANAGER-001"); + BufferSendIn::Tester tester; + tester.InvalidHeaderHash(); +} + +TEST(BufferSendIn, OK) { + COMMENT("Invoke bufferSendIn with nominal input."); + REQUIREMENT("SVC-DPMANAGER-001"); + REQUIREMENT("SVC-DPMANAGER-002"); + REQUIREMENT("SVC-DPMANAGER-003"); + REQUIREMENT("SVC-DPMANAGER-004"); + REQUIREMENT("SVC-DPMANAGER-005"); + BufferSendIn::Tester tester; + tester.OK(); +} + +TEST(CLEAR_EVENT_THROTTLE, OK) { + COMMENT("Test the CLEAR_EVENT_THROTTLE command."); + REQUIREMENT("SVC-DPMANAGER-006"); + CLEAR_EVENT_THROTTLE::Tester tester; + tester.OK(); +} + +TEST(FileOpenStatus, Error) { + COMMENT("Set the file open status to an error value."); + FileOpenStatus::Tester tester; + tester.Error(); +} + +TEST(FileOpenStatus, OK) { + COMMENT("Set the file open status to OP_OK."); + FileOpenStatus::Tester tester; + tester.OK(); +} + +TEST(FileWriteStatus, Error) { + COMMENT("Set the file write status to an error value."); + FileWriteStatus::Tester tester; + tester.Error(); +} + +TEST(FileWriteStatus, OK) { + COMMENT("Set the file write status to OP_OK."); + FileWriteStatus::Tester tester; + tester.OK(); +} + +TEST(Scenarios, Random) { + COMMENT("Random scenario with all rules."); + REQUIREMENT("SVC-DPMANAGER-001"); + REQUIREMENT("SVC-DPMANAGER-002"); + REQUIREMENT("SVC-DPMANAGER-003"); + REQUIREMENT("SVC-DPMANAGER-004"); + REQUIREMENT("SVC-DPMANAGER-005"); + REQUIREMENT("SVC-DPMANAGER-006"); + const FwSizeType numSteps = 10000; + Scenarios::Random::Tester tester; + tester.run(numSteps); +} + +TEST(SchedIn, OK) { + COMMENT("Invoke schedIn with nominal input."); + REQUIREMENT("SVC-DPMANAGER-006"); + SchedIn::Tester tester; + tester.OK(); +} + +} // namespace Svc + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + STest::Random::seed(); + return RUN_ALL_TESTS(); +} diff --git a/Svc/DpWriter/test/ut/DpWriterTester.cpp b/Svc/DpWriter/test/ut/DpWriterTester.cpp new file mode 100644 index 0000000000..b6ad62aabf --- /dev/null +++ b/Svc/DpWriter/test/ut/DpWriterTester.cpp @@ -0,0 +1,100 @@ +// ====================================================================== +// \title DpWriterTester.cpp +// \author bocchino +// \brief cpp file for DpWriter component test harness implementation class +// ====================================================================== + +#include "DpWriterTester.hpp" +#include "Os/Stub/test/File.hpp" + +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- + +DpWriterTester ::DpWriterTester() + : DpWriterGTestBase("DpWriterTester", DpWriterTester::MAX_HISTORY_SIZE), component("DpWriter") { + this->initComponents(); + this->connectPorts(); + Os::Stub::File::Test::StaticData::data.setNextStatus(Os::File::OP_OK); + Os::Stub::File::Test::StaticData::data.writeResult = this->abstractState.m_writeResultData; + Os::Stub::File::Test::StaticData::data.writeResultSize = sizeof(this->abstractState.m_writeResultData); + Os::Stub::File::Test::StaticData::data.pointer = 0; +} + +DpWriterTester ::~DpWriterTester() {} + +// ---------------------------------------------------------------------- +// Handlers for typed from ports +// ---------------------------------------------------------------------- + +void DpWriterTester ::from_deallocBufferSendOut_handler(NATIVE_INT_TYPE portNum, Fw::Buffer& buffer) { + this->pushFromPortEntry_deallocBufferSendOut(buffer); +} + +void DpWriterTester ::from_dpWrittenOut_handler(NATIVE_INT_TYPE portNum, + const fileNameString& fileName, + FwDpPriorityType priority, + FwSizeType size) { + this->pushFromPortEntry_dpWrittenOut(fileName, priority, size); +} + +void DpWriterTester::from_procBufferSendOut_handler(NATIVE_INT_TYPE portNum, Fw::Buffer& buffer) { + this->pushFromPortEntry_procBufferSendOut(buffer); + this->abstractState.m_procTypes |= (1 << portNum); +} + +// ---------------------------------------------------------------------- +// Public member functions +// ---------------------------------------------------------------------- + +void DpWriterTester::printEvents() { + this->printTextLogHistory(stdout); +} + +// ---------------------------------------------------------------------- +// Protected helper functions +// ---------------------------------------------------------------------- + +Os::File::Status DpWriterTester::pickOsFileError() { + U32 u32Status = STest::Pick::lowerUpper(Os::File::OP_OK + 1, Os::File::MAX_STATUS - 1); + return static_cast(u32Status); +} + +#define TESTER_CHECK_CHANNEL(NAME) \ + { \ + const auto changeStatus = this->abstractState.m_##NAME.updatePrev(); \ + if (changeStatus == TestUtils::OnChangeStatus::CHANGED) { \ + ASSERT_TLM_##NAME##_SIZE(1); \ + ASSERT_TLM_##NAME(0, this->abstractState.m_##NAME.value); \ + } else { \ + ASSERT_TLM_##NAME##_SIZE(0); \ + } \ + } + +void DpWriterTester::constructDpFileName(FwDpIdType id, const Fw::Time& timeTag, Fw::StringBase& fileName) { + fileName.format(DP_FILENAME_FORMAT, id, timeTag.getSeconds(), timeTag.getUSeconds()); +} + +void DpWriterTester::checkProcTypes(const Fw::DpContainer& container) { + FwIndexType expectedNumProcTypes = 0; + const Fw::DpCfg::ProcType::SerialType procTypes = container.getProcTypes(); + for (FwIndexType i = 0; i < Fw::DpCfg::ProcType::NUM_CONSTANTS; i++) { + if (procTypes & (1 << i)) { + ++expectedNumProcTypes; + } + } + ASSERT_from_procBufferSendOut_SIZE(expectedNumProcTypes); + ASSERT_EQ(container.getProcTypes(), this->abstractState.m_procTypes); +} + +void DpWriterTester::checkTelemetry() { + TESTER_CHECK_CHANNEL(NumBuffersReceived); + TESTER_CHECK_CHANNEL(NumBytesWritten); + TESTER_CHECK_CHANNEL(NumSuccessfulWrites); + TESTER_CHECK_CHANNEL(NumFailedWrites); + TESTER_CHECK_CHANNEL(NumErrors); +} + +} // namespace Svc diff --git a/Svc/DpWriter/test/ut/DpWriterTester.hpp b/Svc/DpWriter/test/ut/DpWriterTester.hpp new file mode 100644 index 0000000000..e41dcc0210 --- /dev/null +++ b/Svc/DpWriter/test/ut/DpWriterTester.hpp @@ -0,0 +1,119 @@ +// ====================================================================== +// \title DpWriterTester.hpp +// \author bocchino +// \brief hpp file for DpWriter component test harness implementation class +// ====================================================================== + +#ifndef Svc_DpWriterTester_HPP +#define Svc_DpWriterTester_HPP + +#include "Svc/DpWriter/DpWriter.hpp" +#include "Svc/DpWriter/DpWriterGTestBase.hpp" +#include "Svc/DpWriter/test/ut/AbstractState.hpp" + +namespace Svc { + +class DpWriterTester : public DpWriterGTestBase { + public: + // ---------------------------------------------------------------------- + // Constants + // ---------------------------------------------------------------------- + + // Maximum size of histories storing events, telemetry, and port outputs + static const NATIVE_INT_TYPE MAX_HISTORY_SIZE = 10; + + // Instance ID supplied to the component instance under test + static const NATIVE_INT_TYPE TEST_INSTANCE_ID = 0; + + // Queue depth supplied to the component instance under test + static const NATIVE_INT_TYPE TEST_INSTANCE_QUEUE_DEPTH = 10; + + public: + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + //! Construct object DpWriterTester + DpWriterTester(); + + //! Destroy object DpWriterTester + ~DpWriterTester(); + + private: + // ---------------------------------------------------------------------- + // Handlers for typed from ports + // ---------------------------------------------------------------------- + + //! Handler implementation for deallocBufferSendOut + void from_deallocBufferSendOut_handler(NATIVE_INT_TYPE portNum, //!< The port number + Fw::Buffer& fwBuffer //!< The buffer + ); + + //! Handler implementation for dpWrittenOut + void from_dpWrittenOut_handler(NATIVE_INT_TYPE portNum, //!< The port number + const Svc::DpWrittenPortStrings::StringSize256& fileName, //!< The file name + FwDpPriorityType priority, //!< The priority + FwSizeType size //!< The file size + ); + + //! Handler implementation for procBufferSendOut + void from_procBufferSendOut_handler(NATIVE_INT_TYPE portNum, //!< The port number + Fw::Buffer& fwBuffer //!< The buffer + ); + + public: + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + //! Print events + void printEvents(); + + protected: + // ---------------------------------------------------------------------- + // Protected helper functions + // ---------------------------------------------------------------------- + + //! Pick an Os status other than OP_OK + //! \return The status + static Os::File::Status pickOsFileError(); + + //! Construct a DP file name + static void constructDpFileName(FwDpIdType id, //!< The container ID (input) + const Fw::Time& timeTag, //!< The time tag (input) + Fw::StringBase& fileName //!< The file name (output) + ); + + //! Check processing types + void checkProcTypes(const Fw::DpContainer& container //!< The container + ); + + //! Check telemetry + void checkTelemetry(); + + private: + // ---------------------------------------------------------------------- + // Private helper functions + // ---------------------------------------------------------------------- + + //! Connect ports + void connectPorts(); + + //! Initialize components + void initComponents(); + + protected: + // ---------------------------------------------------------------------- + // Member variables + // ---------------------------------------------------------------------- + + //! The abstract state for testing + AbstractState abstractState; + + //! The component under test + DpWriter component; +}; + +} // namespace Svc + +#endif diff --git a/Svc/DpWriter/test/ut/README.md b/Svc/DpWriter/test/ut/README.md new file mode 100644 index 0000000000..d271b043f2 --- /dev/null +++ b/Svc/DpWriter/test/ut/README.md @@ -0,0 +1,403 @@ +# DpWriter Component Tests + +## 1. Abstract State + +### 1.1. Variables + +| Variable | Type | Description | Initial Value | +|----------|------|-------------|---------------| +| `m_NumBuffersReceived` | `OnChangeChannel` | The number of buffers received | 0 | +| `m_NumBytesWritten` | `OnChangeChannel` | The number of bytes written | 0 | +| `m_NumErrors` | `OnChangeChannel` | The number of errors | 0 | +| `m_NumFailedWrites` | `OnChangeChannel` | The number of failed writes | 0 | +| `m_NumSuccessfulWrites` | `OnChangeChannel` | The number of successful writes | 0 | +| `m_bufferTooSmallForDataEventCount` | `FwSizeType` | The number of `BufferTooSmallForData` events since the last throttle clear |0 | +| `m_bufferTooSmallForPacketEventCount` | `FwSizeType` | The number of `BufferTooSmallForPacket` events since the last throttle clear |0 | +| `m_fileOpenErrorEventCount` | `FwSizeType` | The number of file open error events since the last throttle clear |0 | +| `m_fileWriteErrorEventCount` | `FwSizeType` | The number of file write error events since the last throttle clear |0 | +| `m_invalidBufferEventCount` | `FwSizeType` | The number of buffer invalid events since the last throttle clear |0 | +| `m_invalidHeaderEventCount` | `FwSizeType` | The number of invalid packet descriptor events since the last throttle clear |0 | +| `m_invalidHeaderHashEventCount` | `FwSizeType` | The number of invalid header hash events since the last throttle clear |0 | + +## 2. Rule Groups + +### 2.1. FileOpenStatus + +This rule group manages the file open status in the test harness. + +#### 2.1.1. OK + +This rule sets the file open status to `Os::File::OP_OK`, simulating a system state +in which a file open call succeeds. + +**Precondition:** +`Os::Stub::File::Test::StaticData::data.openStatus != Os::File::OP_OK`. + +**Action:** +`Os::Stub::File::Test::StaticData::data.openStatus = Os::File::OP_OK`. + +**Test:** + +1. Apply rule `FileOpenStatus::Error`. +1. Apply rule `FileOpenStatus::OK`. + +**Requirements tested:** +None (helper rule). + +#### 2.1.2. Error + +This rule sets the file open status to an error value, simulating a system state +in which a file open call fails. + +**Precondition:** +`Os::Stub::File::Test::StaticData::data.openStatus == Os::File::OP_OK`. + +**Action:** +Set `Os::Stub::File::Test::StaticData::data.openStatus` to a random +value other than `Os::File::OP_OK`. + +**Test:** + +1. Apply rule `FileOpenStatus::Error`. + +**Requirements tested:** +None (helper rule). + +### 2.2. FileWriteStatus + +This rule group manages the file write status in the test harness. + +#### 2.2.1. OK + +This rule sets the file open status to `Os::File::OP_OK`, simulating a system state +in which a file write call succeeds. + +**Precondition:** +`Os::Stub::File::Test::StaticData::data.writeStatus != Os::File::OP_OK`. + +**Action:** +`Os::Stub::File::Test::StaticData::data.writeStatus = Os::File::OP_OK`. + +**Test:** + +1. Apply rule `FileWriteStatus::Error`. +1. Apply rule `FileWriteStatus::OK`. + +**Requirements tested:** +None (helper rule). + +#### 2.2.2. Error + +This rule sets the file write status to an error value, simulating a system state +in which a file write call fails. + +**Precondition:** +`Os::Stub::File::Test::StaticData::data.writeStatus == Os::File::OP_OK`. + +**Action:** +Set `Os::Stub::File::Test::StaticData::data.writeStatus` to a random value +other than `Os::File::OP_OK`. + +**Test:** + +1. Apply rule `FileWriteStatus::Error`. + +**Requirements tested:** +None (helper rule). + +### 2.3. SchedIn + +This rule group sends test input to the `schedIn` port. + +#### 2.3.1. OK + +This rule invokes `schedIn` with nominal input. + +**Precondition:** `true` + +**Action:** + +1. Clear history. +1. Invoke `schedIn` with a random context. +1. Check telemetry. + +**Test:** + +1. Apply rule `SchedIn::OK`. + +**Requirements tested:** +`SVC-DPWRITER-006`. + +### 2.4. BufferSendIn + +This rule group sends test input to the `bufferSendIn` port. + +#### 2.4.1. OK + +This rule invokes `bufferSendIn` with nominal input. + +**Precondition:** +`fileOpenStatus == Os::File::OP_OK` and +`fileWriteStatus == Os::File::OP_OK`. + +**Action:** +1. Clear history. +1. Update `m_NumBuffersReceived`. +1. Construct a random buffer _B_ with valid packet data and random processing bits. +1. Send _B_ to `bufferSendIn`. +1. Assert that the event history contains one element. +1. Assert that the event history for `FileWritten` contains one element. +1. Check the event arguments. +1. Check output on processing ports. +1. Check output on notification port. +1. Check output on deallocation port. +1. Verify that `Os::File::write` has been called with the expected arguments. +1. Update `m_NumBytesWritten`. +1. Update `m_NumSuccessfulWrites`. + +**Test:** +1. Apply rule `BufferSendIn::OK`. + +**Requirements tested:** +`SVC-DPWRITER-001`, +`SVC-DPWRITER-002`, +`SVC-DPWRITER-003`, +`SVC-DPWRITER-004`, +`SVC-DPWRITER-005` + +#### 2.4.2. InvalidBuffer + +This rule invokes `bufferSendIn` with an invalid buffer. + +**Precondition:** +`true` + +**Action:** +1. Clear history. +1. Update `m_NumBuffersReceived`. +1. Construct an invalid buffer _B_. +1. If `m_invalidBufferEventCount` < `DpWriterComponentBase::EVENTID_INVALIDBUFFER_THROTTLE`, + then + 1. Assert that the event history contains one element. + 1. Assert that the event history for `InvalidBuffer` contains one element. + 1. Increment `m_invalidBufferEventCount`. +1. Otherwise assert that the event history is empty. +1. Verify no data product file. +1. Verify no port output. +1. Increment `m_NumErrors`. + +**Test:** +1. Apply rule `BufferSendIn::InvalidBuffer`. + +**Requirements tested:** +`SVC-DPWRITER-001` + +#### 2.4.3. BufferTooSmallForPacket + +This rule invokes `bufferSendIn` with a buffer that is too small to +hold a data product packet. + +**Precondition:** +`true` + +**Action:** +1. Clear history. +1. Increment `m_NumBuffersReceived`. +1. Construct a valid buffer _B_ that is too small to hold a data product packet. +1. If `m_bufferTooSmallEventCount` < `DpWriterComponentBase::EVENTID_BUFFERTOOSMALLFORPACKET_THROTTLE`, + then + 1. Assert that the event history contains one element. + 1. Assert that the event history for `BufferTooSmallForPacket` contains one element. + 1. Check the event arguments. + 1. Increment `m_bufferTooSmallEventCount`. +1. Otherwise assert that the event history is empty. +1. Assert no DP written notification. +1. Assert buffer sent for deallocation. +1. Verify no data product file. +1. Increment `m_NumErrors`. + +**Requirements tested:** +`SVC-DPWRITER-001` + +#### 2.4.4. InvalidHeaderHash + +This rule invokes `bufferSendIn` with a buffer that has an invalid +header hash. + +**Precondition:** +`true` + +**Action:** +1. Clear history. +1. Increment `m_NumBuffersReceived`. +1. Construct a valid buffer _B_ that is large enough to hold a data product + packet and that has an invalid header hash. +1. If `m_invalidHeaderHashEventCount` < `DpWriterComponentBase::EVENTID_INVALIDHEADERHASH_THROTTLE`, + then + 1. Assert that the event history contains one element. + 1. Assert that the event history for `InvalidHeaderHash` contains one element. + 1. Check the event arguments. + 1. Increment `m_invalidHeaderHashEventCount`. +1. Otherwise assert that the event history is empty. +1. Assert no DP written notification. +1. Assert buffer sent for deallocation. +1. Verify no data product file. +1. Increment `m_NumErrors`. + +**Test:** +1. Apply rule `BufferSendIn::BufferTooSmallForPacket`. + +**Requirements tested:** +`SVC-DPWRITER-001` + +#### 2.4.5. InvalidHeader + +This rule invokes `bufferSendIn` with an invalid packet header. + +**Precondition:** +`true` + +**Action:** +1. Clear history. +1. Increment `m_NumBuffersReceived`. +1. Construct a valid buffer _B_ with an invalid packet header. +1. If `m_invalidPacketHeaderEventCount` < `DpWriterComponentBase::EVENTID_INVALIDHEADER_THROTTLE`, + then + 1. Assert that the event history contains one element. + 1. Assert that the event history for `InvalidHeader` contains one element. + 1. Check the event arguments. + 1. Increment `m_invalidPacketHeaderEventCount`. +1. Otherwise assert that the event history is empty. +1. Assert no DP written notification. +1. Assert buffer sent for deallocation. +1. Verify no data product file. +1. Increment `m_NumErrors`. + +**Test:** +1. Apply rule `BufferSendIn::InvalidHeader`. + +**Requirements tested:** +`SVC-DPWRITER-001` + +#### 2.4.6. BufferTooSmallForData + +This rule invokes `bufferSendIn` with a buffer that is too small to +hold the data size specified in the header. + +**Precondition:** +`true` + +**Action:** +1. Clear history. +1. Increment `m_NumBuffersReceived`. +1. Construct a valid buffer _B_ with a valid packet header, but + a data size that will not fit in _B_. +1. If `m_bufferTooSmallForDataEventCount` < `DpWriterComponentBase::EVENTID_BUFFERTOOSMALLFORDATA_THROTTLE`, + then + 1. Assert that the event history contains one element. + 1. Assert that the event history for `BufferTooSmallForData` contains one element. + 1. Check the event arguments. + 1. Increment `m_bufferTooSmallForDataEventCount`. +1. Otherwise assert that the event history is empty. +1. Assert no DP written notification. +1. Assert buffer sent for deallocation. +1. Verify no data product file. +1. Increment `m_NumErrors`. + +**Test:** +1. Apply rule `BufferSendIn::BufferTooSmallForData`. + +**Requirements tested:** +`SVC-DPWRITER-001` + +#### 2.4.7. FileOpenError + +This rule invokes `bufferSendIn` with a file open error. + +**Precondition:** +`fileOpenStatus != Os::File::OP_OK` + +**Action:** +1. Clear history. +1. Update `m_NumBuffersReceived`. +1. Construct a random buffer _B_ with valid packet data. +1. Send _B_ to `bufferSendIn`. +1. Assert that the event history contains one element. +1. Assert that the event history for `FileOpenError` contains one element. +1. Check the event arguments. +1. Assert no DP written notification. +1. Assert buffer sent for deallocation. +1. Verify no data product file. +1. Increment `m_NumFailedWrites`. +1. Increment `m_NumErrors`. + +**Test:** +1. Apply rule `FileOpenStatus::Error`. +1. Apply rule `BufferSendIn::FileOpenError`. + +**Requirements tested:** +`SVC-DPWRITER-004` + +#### 2.4.8. FileWriteError + +This rule invokes `bufferSendIn` with a file write error. + +**Precondition:** +`fileOpenStatus == Os::File::OP_OK` and +`fileWriteStatus != Os::File::OP_OK` + +**Action:** +1. Clear history. +1. Update `m_NumBuffersReceived`. +1. Construct a random buffer _B_ with valid packet data. +1. Send _B_ to `bufferSendIn`. +1. Assert that the event history contains one element. +1. Assert that the event history for `FileWriteError` contains one element. +1. Check the event arguments. +1. Assert no DP written notification. +1. Assert buffer sent for deallocation. +1. Verify no data product file. +1. Increment `m_NumFailedWrites`. +1. Increment `m_NumErrors`. + +**Test:** +1. Apply rule `FileWriteStatus::Error`. +1. Apply rule `BufferSendIn::FileWriteError`. + +**Requirements tested:** +`SVC-DPWRITER-004` + +### 2.5. CLEAR_EVENT_THROTTLE + +This rule group tests the `CLEAR_EVENT_THROTTLE` command. + +#### 2.5.1. OK + +This rule sends the `CLEAR_EVENT_THROTTLE` command. + +**Precondition:** `true` + +**Action:** + +1. Clear the history. +1. Send command `CLEAR_EVENT_THROTTLE`. +1. Check the command response. +1. Assert `DpWriterComponentBase::m_InvalidBufferThrottle` == 0. +1. Set `m_bufferTooSmallForDataEventCount` = 0. +1. Set `m_bufferTooSmallForPacketEventCount` = 0. +1. Set `m_fileOpenErrorEventCount` = 0. +1. Set `m_fileWriteErrorEventCount` = 0. +1. Set `m_invalidBufferEventCount` = 0. +1. Set `m_invalidHeaderEventCount` = 0. +1. Set `m_invalidHeaderHashEventCount` = 0. + +**Test:** + +1. Apply rule `BufferSendIn::InvalidBuffer` `DpWriterComponentBase::EVENTID_INVALIDBUFFER_THROTTLE` + 1 times. +1. Apply rule `CLEAR_EVENT_THROTTLE::OK`. +1. Apply rule `BufferSendIn::InvalidBuffer` + +## 3. Implementation + +See [the DpWriter test README](../../../DpWriter/test/ut/README.md) +for a description of the pattern used to implement the tests. diff --git a/Svc/DpWriter/test/ut/Rules/BufferSendIn.cpp b/Svc/DpWriter/test/ut/Rules/BufferSendIn.cpp new file mode 100644 index 0000000000..8a1657b261 --- /dev/null +++ b/Svc/DpWriter/test/ut/Rules/BufferSendIn.cpp @@ -0,0 +1,445 @@ +// ====================================================================== +// \title BufferSendIn.cpp +// \author Rob Bocchino +// \brief BufferSendIn class implementation +// +// \copyright +// Copyright (C) 2024 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#include +#include + +#include "Os/Stub/test/File.hpp" +#include "STest/Pick/Pick.hpp" +#include "Svc/DpWriter/test/ut/Rules/BufferSendIn.hpp" +#include "Svc/DpWriter/test/ut/Rules/Testers.hpp" + +namespace Svc { + +// ---------------------------------------------------------------------- +// Rule definitions +// ---------------------------------------------------------------------- + +bool TestState ::precondition__BufferSendIn__OK() const { + const auto& fileData = Os::Stub::File::Test::StaticData::data; + bool result = true; + result &= (fileData.openStatus == Os::File::Status::OP_OK); + result &= (fileData.writeStatus == Os::File::Status::OP_OK); + return result; +} + +void TestState ::action__BufferSendIn__OK() { + // Clear the history + this->clearHistory(); + // Reset the saved proc types + // These are updated in the from_procBufferSendOut handler + this->abstractState.m_procTypes = 0; + // Reset the file pointer in the stub file implementation + auto& fileData = Os::Stub::File::Test::StaticData::data; + fileData.pointer = 0; + // Update m_NumBuffersReceived + this->abstractState.m_NumBuffersReceived.value++; + // Construct a random buffer + Fw::Buffer buffer = this->abstractState.getDpBuffer(); + // Send the buffer + this->invoke_to_bufferSendIn(0, buffer); + this->component.doDispatch(); + // Deserialize the container header + Fw::DpContainer container; + container.setBuffer(buffer); + const Fw::SerializeStatus status = container.deserializeHeader(); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + // Check events + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_FileWritten_SIZE(1); + Fw::FileNameString fileName; + this->constructDpFileName(container.getId(), container.getTimeTag(), fileName); + ASSERT_EVENTS_FileWritten(0, buffer.getSize(), fileName.toChar()); + // Check processing types + this->checkProcTypes(container); + // Check DP notification + ASSERT_from_dpWrittenOut_SIZE(1); + ASSERT_from_dpWrittenOut(0, fileName, container.getPriority(), buffer.getSize()); + // Check deallocation + ASSERT_from_deallocBufferSendOut_SIZE(1); + ASSERT_from_deallocBufferSendOut(0, buffer); + // Check file write + ASSERT_EQ(buffer.getSize(), fileData.pointer); + ASSERT_EQ(0, ::memcmp(buffer.getData(), fileData.writeResult, buffer.getSize())); + // Update m_NumBytesWritten + this->abstractState.m_NumBytesWritten.value += buffer.getSize(); + // Update m_NumSuccessfulWrites + this->abstractState.m_NumSuccessfulWrites.value++; +} + +bool TestState ::precondition__BufferSendIn__InvalidBuffer() const { + bool result = true; + return result; +} + +void TestState ::action__BufferSendIn__InvalidBuffer() { + // Clear the history + this->clearHistory(); + // Reset the file pointer in the stub file implementation + auto& fileData = Os::Stub::File::Test::StaticData::data; + fileData.pointer = 0; + // Update m_NumBuffersReceived + this->abstractState.m_NumBuffersReceived.value++; + // Construct an invalid buffer + Fw::Buffer buffer; + // Send the buffer + this->invoke_to_bufferSendIn(0, buffer); + this->component.doDispatch(); + // Check events + if (this->abstractState.m_invalidBufferEventCount < DpWriterComponentBase::EVENTID_INVALIDBUFFER_THROTTLE) { + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_InvalidBuffer_SIZE(1); + this->abstractState.m_invalidBufferEventCount++; + } else { + ASSERT_EVENTS_SIZE(0); + } + // Verify no file output + ASSERT_EQ(fileData.pointer, 0); + // Verify no port output + ASSERT_FROM_PORT_HISTORY_SIZE(0); + // Increment m_NumErrors + this->abstractState.m_NumErrors.value++; +} + +bool TestState ::precondition__BufferSendIn__BufferTooSmallForPacket() const { + bool result = true; + return result; +} + +void TestState ::action__BufferSendIn__BufferTooSmallForPacket() { + // Clear the history + this->clearHistory(); + // Reset the file pointer in the stub file implementation + auto& fileData = Os::Stub::File::Test::StaticData::data; + fileData.pointer = 0; + // Update m_NumBuffersReceived + this->abstractState.m_NumBuffersReceived.value++; + // Construct a buffer that is too small to hold a data packet + const FwSizeType minPacketSize = Fw::DpContainer::MIN_PACKET_SIZE; + ASSERT_GT(minPacketSize, 1); + const FwSizeType bufferSize = STest::Pick::lowerUpper(1, minPacketSize - 1); + Fw::Buffer buffer(this->abstractState.m_bufferData, bufferSize); + // Send the buffer + this->invoke_to_bufferSendIn(0, buffer); + this->component.doDispatch(); + // Check events + if (this->abstractState.m_bufferTooSmallForPacketEventCount < + DpWriterComponentBase::EVENTID_BUFFERTOOSMALLFORPACKET_THROTTLE) { + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_BufferTooSmallForPacket(0, bufferSize, minPacketSize); + this->abstractState.m_bufferTooSmallForPacketEventCount++; + } else { + ASSERT_EVENTS_SIZE(0); + } + // Verify no file output + ASSERT_EQ(fileData.pointer, 0); + // Verify port output + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_deallocBufferSendOut(0, buffer); + // Increment m_NumErrors + this->abstractState.m_NumErrors.value++; +} + +bool TestState ::precondition__BufferSendIn__InvalidHeaderHash() const { + bool result = true; + return result; +} + +void TestState ::action__BufferSendIn__InvalidHeaderHash() { + // Clear the history + this->clearHistory(); + // Reset the file pointer in the stub file implementation + auto& fileData = Os::Stub::File::Test::StaticData::data; + fileData.pointer = 0; + // Update m_NumBuffersReceived + this->abstractState.m_NumBuffersReceived.value++; + // Construct a valid buffer + Fw::Buffer buffer = this->abstractState.getDpBuffer(); + // Set up the container + Fw::DpContainer container; + container.setBuffer(buffer); + // Get the header hash + const U32 computedHash = container.getHeaderHash().asBigEndianU32(); + // Perturb the header hash + const U32 storedHash = computedHash + 1; + Utils::HashBuffer storedHashBuffer; + const Fw::SerializeStatus serialStatus = storedHashBuffer.serialize(storedHash); + ASSERT_EQ(serialStatus, Fw::FW_SERIALIZE_OK); + container.setHeaderHash(storedHashBuffer); + // Send the buffer + this->invoke_to_bufferSendIn(0, buffer); + this->component.doDispatch(); + // Check events + if (this->abstractState.m_invalidHeaderHashEventCount < DpWriterComponentBase::EVENTID_INVALIDHEADERHASH_THROTTLE) { + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_InvalidHeaderHash(0, buffer.getSize(), storedHash, computedHash); + this->abstractState.m_invalidHeaderHashEventCount++; + } else { + ASSERT_EVENTS_SIZE(0); + } + // Verify no file output + ASSERT_EQ(fileData.pointer, 0); + // Verify port output + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_deallocBufferSendOut(0, buffer); + // Increment m_NumErrors + this->abstractState.m_NumErrors.value++; +} + +bool TestState ::precondition__BufferSendIn__InvalidHeader() const { + bool result = true; + return result; +} + +void TestState ::action__BufferSendIn__InvalidHeader() { + // Clear the history + this->clearHistory(); + // Reset the file pointer in the stub file implementation + auto& fileData = Os::Stub::File::Test::StaticData::data; + fileData.pointer = 0; + // Update m_NumBuffersReceived + this->abstractState.m_NumBuffersReceived.value++; + // Construct a valid buffer + Fw::Buffer buffer = this->abstractState.getDpBuffer(); + // Invalidate the packet descriptor + U8* const buffAddr = buffer.getData(); + ASSERT_GT(static_cast(buffer.getSize()), static_cast(1)); + buffAddr[0]++; + // Update the header hash + Fw::DpContainer container; + container.setBuffer(buffer); + container.updateHeaderHash(); + // Send the buffer + this->invoke_to_bufferSendIn(0, buffer); + this->component.doDispatch(); + // Check events + if (this->abstractState.m_invalidHeaderEventCount < DpWriterComponentBase::EVENTID_INVALIDHEADER_THROTTLE) { + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_InvalidHeader(0, buffer.getSize(), static_cast(Fw::FW_SERIALIZE_FORMAT_ERROR)); + this->abstractState.m_invalidHeaderEventCount++; + } else { + ASSERT_EVENTS_SIZE(0); + } + // Verify no file output + ASSERT_EQ(fileData.pointer, 0); + // Verify port output + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_deallocBufferSendOut(0, buffer); + // Increment m_NumErrors + this->abstractState.m_NumErrors.value++; +} + +bool TestState ::precondition__BufferSendIn__BufferTooSmallForData() const { + bool result = true; + return result; +} + +void TestState ::action__BufferSendIn__BufferTooSmallForData() { + // Clear the history + this->clearHistory(); + // Reset the file pointer in the stub file implementation + auto& fileData = Os::Stub::File::Test::StaticData::data; + fileData.pointer = 0; + // Update m_NumBuffersReceived + this->abstractState.m_NumBuffersReceived.value++; + // Construct a valid buffer + Fw::Buffer buffer = this->abstractState.getDpBuffer(); + // Set up the container + Fw::DpContainer container; + container.setBuffer(buffer); + // Invalidate the data size + Fw::SerializeStatus serialStatus = container.deserializeHeader(); + ASSERT_EQ(serialStatus, Fw::FW_SERIALIZE_OK); + const FwSizeType dataSize = + STest::Pick::lowerUpper(AbstractState::MAX_DATA_SIZE + 1, std::numeric_limits::max()); + container.setDataSize(dataSize); + container.updateHeaderHash(); + container.serializeHeader(); + // Send the buffer + this->invoke_to_bufferSendIn(0, buffer); + this->component.doDispatch(); + // Check events + if (this->abstractState.m_bufferTooSmallForDataEventCount < DpWriterComponentBase::EVENTID_INVALIDHEADER_THROTTLE) { + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_BufferTooSmallForData(0, buffer.getSize(), container.getPacketSize()); + this->abstractState.m_bufferTooSmallForDataEventCount++; + } else { + ASSERT_EVENTS_SIZE(0); + } + // Verify no file output + ASSERT_EQ(fileData.pointer, 0); + // Verify port output + ASSERT_from_procBufferSendOut_SIZE(0); + ASSERT_from_dpWrittenOut_SIZE(0); + ASSERT_from_deallocBufferSendOut_SIZE(1); + ASSERT_from_deallocBufferSendOut(0, buffer); + // Increment m_NumErrors + this->abstractState.m_NumErrors.value++; +} + +bool TestState ::precondition__BufferSendIn__FileOpenError() const { + const auto& fileData = Os::Stub::File::Test::StaticData::data; + return (fileData.openStatus != Os::File::Status::OP_OK); +} + +void TestState ::action__BufferSendIn__FileOpenError() { + // Clear the history + this->clearHistory(); + // Reset the saved proc types + // These are updated in the from_procBufferSendOut handler + this->abstractState.m_procTypes = 0; + // Reset the file pointer in the stub file implementation + auto& fileData = Os::Stub::File::Test::StaticData::data; + fileData.pointer = 0; + // Update m_NumBuffersReceived + this->abstractState.m_NumBuffersReceived.value++; + // Construct a valid buffer + Fw::Buffer buffer = this->abstractState.getDpBuffer(); + // Set up the container + Fw::DpContainer container; + container.setBuffer(buffer); + container.deserializeHeader(); + // Send the buffer + this->invoke_to_bufferSendIn(0, buffer); + this->component.doDispatch(); + // Check events + if (this->abstractState.m_fileOpenErrorEventCount < DpWriterComponentBase::EVENTID_FILEOPENERROR_THROTTLE) { + ASSERT_EVENTS_SIZE(1); + Fw::FileNameString fileName; + this->constructDpFileName(container.getId(), container.getTimeTag(), fileName); + const Os::File::Status openStatus = fileData.openStatus; + ASSERT_EVENTS_FileOpenError(0, static_cast(openStatus), fileName.toChar()); + this->abstractState.m_fileOpenErrorEventCount++; + } else { + ASSERT_EVENTS_SIZE(0); + } + // Verify no file output + ASSERT_EQ(fileData.pointer, 0); + // Verify port output + this->checkProcTypes(container); + ASSERT_from_dpWrittenOut_SIZE(0); + ASSERT_from_deallocBufferSendOut_SIZE(1); + ASSERT_from_deallocBufferSendOut(0, buffer); + // Increment m_NumFailedWrites + this->abstractState.m_NumFailedWrites.value++; + // Increment m_NumErrors + this->abstractState.m_NumErrors.value++; +} + +bool TestState ::precondition__BufferSendIn__FileWriteError() const { + const auto& fileData = Os::Stub::File::Test::StaticData::data; + bool result = true; + result &= (fileData.openStatus == Os::File::Status::OP_OK); + result &= (fileData.writeStatus != Os::File::Status::OP_OK); + return result; +} + +void TestState ::action__BufferSendIn__FileWriteError() { + // Clear the history + this->clearHistory(); + // Reset the saved proc types + // These are updated in the from_procBufferSendOut handler + this->abstractState.m_procTypes = 0; + // Update m_NumBuffersReceived + this->abstractState.m_NumBuffersReceived.value++; + // Construct a valid buffer + Fw::Buffer buffer = this->abstractState.getDpBuffer(); + // Set up the container + Fw::DpContainer container; + container.setBuffer(buffer); + container.deserializeHeader(); + // Get the file size + const FwSizeType fileSize = container.getPacketSize(); + // Turn off file writing + auto& fileData = Os::Stub::File::Test::StaticData::data; + U8* const savedWriteResult = fileData.writeResult; + fileData.writeResult = nullptr; + // Adjust size result of write + fileData.writeSizeResult = STest::Pick::lowerUpper(0, fileSize); + // Send the buffer + this->invoke_to_bufferSendIn(0, buffer); + this->component.doDispatch(); + // Check events + if (this->abstractState.m_fileWriteErrorEventCount < DpWriterComponentBase::EVENTID_FILEWRITEERROR_THROTTLE) { + ASSERT_EVENTS_SIZE(1); + Fw::FileNameString fileName; + this->constructDpFileName(container.getId(), container.getTimeTag(), fileName); + const Os::File::Status writeStatus = Os::Stub::File::Test::StaticData::data.writeStatus; + ASSERT_EVENTS_FileWriteError(0, static_cast(writeStatus), static_cast(fileData.writeSizeResult), + static_cast(fileSize), fileName.toChar()); + this->abstractState.m_fileWriteErrorEventCount++; + } else { + ASSERT_EVENTS_SIZE(0); + } + // Verify port output + this->checkProcTypes(container); + ASSERT_from_dpWrittenOut_SIZE(0); + ASSERT_from_deallocBufferSendOut_SIZE(1); + ASSERT_from_deallocBufferSendOut(0, buffer); + // Increment m_NumFailedWrites + this->abstractState.m_NumFailedWrites.value++; + // Increment m_NumErrors + this->abstractState.m_NumErrors.value++; + // Turn on file writing + fileData.writeResult = savedWriteResult; +} + +namespace BufferSendIn { + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +void Tester::BufferTooSmallForData() { + this->ruleBufferTooSmallForData.apply(this->testState); + this->testState.printEvents(); +} + +void Tester::BufferTooSmallForPacket() { + this->ruleBufferTooSmallForPacket.apply(this->testState); + this->testState.printEvents(); +} + +void Tester::FileOpenError() { + Testers::fileOpenStatus.ruleError.apply(this->testState); + this->ruleFileOpenError.apply(this->testState); + this->testState.printEvents(); +} + +void Tester::FileWriteError() { + Testers::fileWriteStatus.ruleError.apply(this->testState); + this->ruleFileWriteError.apply(this->testState); + this->testState.printEvents(); +} + +void Tester::InvalidBuffer() { + this->ruleInvalidBuffer.apply(this->testState); + this->testState.printEvents(); +} + +void Tester::InvalidHeader() { + this->ruleInvalidHeader.apply(this->testState); + this->testState.printEvents(); +} + +void Tester::InvalidHeaderHash() { + this->ruleInvalidHeaderHash.apply(this->testState); + this->testState.printEvents(); +} + +void Tester::OK() { + this->ruleOK.apply(this->testState); + this->testState.printEvents(); +} + +} // namespace BufferSendIn + +} // namespace Svc diff --git a/Svc/DpWriter/test/ut/Rules/BufferSendIn.hpp b/Svc/DpWriter/test/ut/Rules/BufferSendIn.hpp new file mode 100644 index 0000000000..04c98a3a84 --- /dev/null +++ b/Svc/DpWriter/test/ut/Rules/BufferSendIn.hpp @@ -0,0 +1,94 @@ +// ====================================================================== +// \title BufferSendIn.hpp +// \author Rob Bocchino +// \brief BufferSendIn class interface +// +// \copyright +// Copyright (C) 2024 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#ifndef Svc_BufferSendIn_HPP +#define Svc_BufferSendIn_HPP + +#include "Svc/DpWriter/test/ut/Rules/Rules.hpp" +#include "Svc/DpWriter/test/ut/TestState/TestState.hpp" + +namespace Svc { + +namespace BufferSendIn { + +class Tester { + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + //! OK + void OK(); + + //! Invalid buffer + void InvalidBuffer(); + + //! Buffer too small for packet + void BufferTooSmallForPacket(); + + //! Invalid header hash + void InvalidHeaderHash(); + + //! Invalid header + void InvalidHeader(); + + //! Buffer too small for data + void BufferTooSmallForData(); + + //! File open error + void FileOpenError(); + + //! File write error + void FileWriteError(); + + public: + // ---------------------------------------------------------------------- + // Rules + // ---------------------------------------------------------------------- + + //! Rule BufferSendIn::OK + Rules::BufferSendIn::OK ruleOK; + + //! Rule BufferSendIn::InvalidBuffer + Rules::BufferSendIn::InvalidBuffer ruleInvalidBuffer; + + //! Rule BufferSendIn::BufferTooSmallForPacket + Rules::BufferSendIn::BufferTooSmallForPacket ruleBufferTooSmallForPacket; + + //! Rule BufferSendIn::InvalidHeaderHash + Rules::BufferSendIn::InvalidHeaderHash ruleInvalidHeaderHash; + + //! Rule BufferSendIn::InvalidHeader + Rules::BufferSendIn::InvalidHeader ruleInvalidHeader; + + //! Rule BufferSendIn::BufferTooSmallForData + Rules::BufferSendIn::BufferTooSmallForData ruleBufferTooSmallForData; + + //! Rule BufferSendIn::FileOpenError + Rules::BufferSendIn::FileOpenError ruleFileOpenError; + + //! Rule BufferSendIn::FileWriteError + Rules::BufferSendIn::FileWriteError ruleFileWriteError; + + public: + // ---------------------------------------------------------------------- + // Public member variables + // ---------------------------------------------------------------------- + + //! Test state + TestState testState; +}; + +} // namespace BufferSendIn + +} // namespace Svc + +#endif diff --git a/Svc/DpWriter/test/ut/Rules/CLEAR_EVENT_THROTTLE.cpp b/Svc/DpWriter/test/ut/Rules/CLEAR_EVENT_THROTTLE.cpp new file mode 100644 index 0000000000..7296d3797f --- /dev/null +++ b/Svc/DpWriter/test/ut/Rules/CLEAR_EVENT_THROTTLE.cpp @@ -0,0 +1,71 @@ +// ====================================================================== +// \title CLEAR_EVENT_THROTTLE.cpp +// \author Rob Bocchino +// \brief CLEAR_EVENT_THROTTLE class implementation +// +// \copyright +// Copyright (C) 2024 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#include "STest/Pick/Pick.hpp" +#include "Svc/DpWriter/test/ut/Rules/CLEAR_EVENT_THROTTLE.hpp" +#include "Svc/DpWriter/test/ut/Rules/Testers.hpp" + +namespace Svc { + +// ---------------------------------------------------------------------- +// Rule definitions +// ---------------------------------------------------------------------- + +bool TestState ::precondition__CLEAR_EVENT_THROTTLE__OK() const { + return true; +} + +void TestState ::action__CLEAR_EVENT_THROTTLE__OK() { + // Clear history + this->clearHistory(); + // Send the command + const FwEnumStoreType instance = static_cast(STest::Pick::any()); + const U32 cmdSeq = STest::Pick::any(); + this->sendCmd_CLEAR_EVENT_THROTTLE(instance, cmdSeq); + this->component.doDispatch(); + // Check the command response + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE(0, DpWriterComponentBase::OPCODE_CLEAR_EVENT_THROTTLE, cmdSeq, Fw::CmdResponse::OK); + // Check the concrete state + ASSERT_EQ(this->component.DpWriterComponentBase::m_BufferTooSmallForDataThrottle, 0); + ASSERT_EQ(this->component.DpWriterComponentBase::m_BufferTooSmallForPacketThrottle, 0); + ASSERT_EQ(this->component.DpWriterComponentBase::m_FileOpenErrorThrottle, 0); + ASSERT_EQ(this->component.DpWriterComponentBase::m_FileWriteErrorThrottle, 0); + ASSERT_EQ(this->component.DpWriterComponentBase::m_InvalidBufferThrottle, 0); + ASSERT_EQ(this->component.DpWriterComponentBase::m_InvalidHeaderHashThrottle, 0); + ASSERT_EQ(this->component.DpWriterComponentBase::m_InvalidHeaderThrottle, 0); + // Update the abstract state + this->abstractState.m_bufferTooSmallForDataEventCount = 0; + this->abstractState.m_bufferTooSmallForPacketEventCount = 0; + this->abstractState.m_fileOpenErrorEventCount = 0; + this->abstractState.m_fileWriteErrorEventCount = 0; + this->abstractState.m_invalidBufferEventCount = 0; + this->abstractState.m_invalidHeaderEventCount = 0; + this->abstractState.m_invalidHeaderHashEventCount = 0; +} + +namespace CLEAR_EVENT_THROTTLE { + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +void Tester ::OK() { + for (FwSizeType i = 0; i <= DpWriterComponentBase::EVENTID_INVALIDBUFFER_THROTTLE; i++) { + Testers::bufferSendIn.ruleInvalidBuffer.apply(this->testState); + } + this->ruleOK.apply(this->testState); + Testers::bufferSendIn.ruleInvalidBuffer.apply(this->testState); +} + +} // namespace CLEAR_EVENT_THROTTLE + +} // namespace Svc diff --git a/Svc/DpWriter/test/ut/Rules/CLEAR_EVENT_THROTTLE.hpp b/Svc/DpWriter/test/ut/Rules/CLEAR_EVENT_THROTTLE.hpp new file mode 100644 index 0000000000..ee64817f1c --- /dev/null +++ b/Svc/DpWriter/test/ut/Rules/CLEAR_EVENT_THROTTLE.hpp @@ -0,0 +1,57 @@ +// ====================================================================== +// \title CLEAR_EVENT_THROTTLE.hpp +// \author Rob Bocchino +// \brief CLEAR_EVENT_THROTTLE class interface +// +// \copyright +// Copyright (C) 2024 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#ifndef Svc_CLEAR_EVENT_THROTTLE_HPP +#define Svc_CLEAR_EVENT_THROTTLE_HPP + +#include "Svc/DpWriter/test/ut/Rules/Rules.hpp" +#include "Svc/DpWriter/test/ut/TestState/TestState.hpp" + +namespace Svc { + + namespace CLEAR_EVENT_THROTTLE { + + class Tester { + + public: + + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + //! OK + void OK(); + + public: + + // ---------------------------------------------------------------------- + // Rules + // ---------------------------------------------------------------------- + + //! Rule CLEAR_EVENT_THROTTLE::OK + Rules::CLEAR_EVENT_THROTTLE::OK ruleOK; + + public: + + // ---------------------------------------------------------------------- + // Public member variables + // ---------------------------------------------------------------------- + + //! Test state + TestState testState; + + }; + + } + +} + +#endif diff --git a/Svc/DpWriter/test/ut/Rules/FileOpenStatus.cpp b/Svc/DpWriter/test/ut/Rules/FileOpenStatus.cpp new file mode 100644 index 0000000000..ed0f346e16 --- /dev/null +++ b/Svc/DpWriter/test/ut/Rules/FileOpenStatus.cpp @@ -0,0 +1,59 @@ +// ====================================================================== +// \title FileOpenStatus.cpp +// \author Rob Bocchino +// \brief FileOpenStatus class implementation +// +// \copyright +// Copyright (C) 2024 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#include "Os/Stub/test/File.hpp" +#include "Svc/DpWriter/test/ut/Rules/FileOpenStatus.hpp" +#include "Svc/DpWriter/test/ut/Rules/Testers.hpp" + +namespace Svc { + +// ---------------------------------------------------------------------- +// Rule definitions +// ---------------------------------------------------------------------- + +bool TestState ::precondition__FileOpenStatus__OK() const { + const auto& fileData = Os::Stub::File::Test::StaticData::data; + return (fileData.openStatus != Os::File::Status::OP_OK); +} + +void TestState ::action__FileOpenStatus__OK() { + auto& fileData = Os::Stub::File::Test::StaticData::data; + fileData.openStatus = Os::File::Status::OP_OK; +} + +bool TestState ::precondition__FileOpenStatus__Error() const { + const auto& fileData = Os::Stub::File::Test::StaticData::data; + return (fileData.openStatus == Os::File::Status::OP_OK); +} + +void TestState ::action__FileOpenStatus__Error() { + auto& fileData = Os::Stub::File::Test::StaticData::data; + fileData.openStatus = DpWriterTester::pickOsFileError(); +} + +namespace FileOpenStatus { + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +void Tester::OK() { + this->ruleError.apply(this->testState); + this->ruleOK.apply(this->testState); +} + +void Tester::Error() { + this->ruleError.apply(this->testState); +} + +} // namespace FileOpenStatus + +} // namespace Svc diff --git a/Svc/DpWriter/test/ut/Rules/FileOpenStatus.hpp b/Svc/DpWriter/test/ut/Rules/FileOpenStatus.hpp new file mode 100644 index 0000000000..ea3e452bfa --- /dev/null +++ b/Svc/DpWriter/test/ut/Rules/FileOpenStatus.hpp @@ -0,0 +1,63 @@ +// ====================================================================== +// \title FileOpenStatus.hpp +// \author Rob Bocchino +// \brief FileOpenStatus class interface +// +// \copyright +// Copyright (C) 2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#ifndef Svc_FileOpenStatus_HPP +#define Svc_FileOpenStatus_HPP + +#include "Svc/DpWriter/test/ut/Rules/Rules.hpp" +#include "Svc/DpWriter/test/ut/TestState/TestState.hpp" + +namespace Svc { + + namespace FileOpenStatus { + + class Tester { + + public: + + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + //! OK + void OK(); + + //! Error + void Error(); + + public: + + // ---------------------------------------------------------------------- + // Rules + // ---------------------------------------------------------------------- + + //! Rule FileOpenStatus::OK + Rules::FileOpenStatus::OK ruleOK; + + //! Rule FileOpenStatus::Error + Rules::FileOpenStatus::Error ruleError; + + private: + + // ---------------------------------------------------------------------- + // Public member variables + // ---------------------------------------------------------------------- + + //! Test state + TestState testState; + + }; + + } + +} + +#endif diff --git a/Svc/DpWriter/test/ut/Rules/FileWriteStatus.cpp b/Svc/DpWriter/test/ut/Rules/FileWriteStatus.cpp new file mode 100644 index 0000000000..d4bc6efa21 --- /dev/null +++ b/Svc/DpWriter/test/ut/Rules/FileWriteStatus.cpp @@ -0,0 +1,59 @@ +// ====================================================================== +// \title FileWriteStatus.cpp +// \author Rob Bocchino +// \brief FileWriteStatus class implementation +// +// \copyright +// Copyright (C) 2024 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#include "Os/Stub/test/File.hpp" +#include "Svc/DpWriter/test/ut/Rules/FileWriteStatus.hpp" +#include "Svc/DpWriter/test/ut/Rules/Testers.hpp" + +namespace Svc { + +// ---------------------------------------------------------------------- +// Rule definitions +// ---------------------------------------------------------------------- + +bool TestState ::precondition__FileWriteStatus__OK() const { + const auto& fileData = Os::Stub::File::Test::StaticData::data; + return (fileData.writeStatus != Os::File::Status::OP_OK); +} + +void TestState ::action__FileWriteStatus__OK() { + auto& fileData = Os::Stub::File::Test::StaticData::data; + fileData.writeStatus = Os::File::Status::OP_OK; +} + +bool TestState ::precondition__FileWriteStatus__Error() const { + const auto& fileData = Os::Stub::File::Test::StaticData::data; + return (fileData.writeStatus == Os::File::Status::OP_OK); +} + +void TestState ::action__FileWriteStatus__Error() { + auto& fileData = Os::Stub::File::Test::StaticData::data; + fileData.writeStatus = DpWriterTester::pickOsFileError(); +} + +namespace FileWriteStatus { + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +void Tester::OK() { + this->ruleError.apply(this->testState); + this->ruleOK.apply(this->testState); +} + +void Tester::Error() { + this->ruleError.apply(this->testState); +} + +} // namespace FileWriteStatus + +} // namespace Svc diff --git a/Svc/DpWriter/test/ut/Rules/FileWriteStatus.hpp b/Svc/DpWriter/test/ut/Rules/FileWriteStatus.hpp new file mode 100644 index 0000000000..2cebc6cabe --- /dev/null +++ b/Svc/DpWriter/test/ut/Rules/FileWriteStatus.hpp @@ -0,0 +1,63 @@ +// ====================================================================== +// \title FileWriteStatus.hpp +// \author Rob Bocchino +// \brief FileWriteStatus class interface +// +// \copyright +// Copyright (C) 2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#ifndef Svc_FileWriteStatus_HPP +#define Svc_FileWriteStatus_HPP + +#include "Svc/DpWriter/test/ut/Rules/Rules.hpp" +#include "Svc/DpWriter/test/ut/TestState/TestState.hpp" + +namespace Svc { + + namespace FileWriteStatus { + + class Tester { + + public: + + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + //! OK + void OK(); + + //! Error + void Error(); + + public: + + // ---------------------------------------------------------------------- + // Rules + // ---------------------------------------------------------------------- + + //! Rule FileWriteStatus::OK + Rules::FileWriteStatus::OK ruleOK; + + //! Rule FileWriteStatus::Error + Rules::FileWriteStatus::Error ruleError; + + private: + + // ---------------------------------------------------------------------- + // Public member variables + // ---------------------------------------------------------------------- + + //! Test state + TestState testState; + + }; + + } + +} + +#endif diff --git a/Svc/DpWriter/test/ut/Rules/Rules.hpp b/Svc/DpWriter/test/ut/Rules/Rules.hpp new file mode 100644 index 0000000000..f285e2c042 --- /dev/null +++ b/Svc/DpWriter/test/ut/Rules/Rules.hpp @@ -0,0 +1,54 @@ +// ====================================================================== +// \title Rules.hpp +// \author Rob Bocchino +// \brief Rules for testing DpWriter +// +// \copyright +// Copyright (C) 2024 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#ifndef Svc_Rules_HPP +#define Svc_Rules_HPP + +#include "STest/Rule/Rule.hpp" + +#include "Svc/DpWriter/test/ut/TestState/TestState.hpp" + +#define RULES_DEF_RULE(GROUP_NAME, RULE_NAME) \ + namespace GROUP_NAME { \ + \ + struct RULE_NAME : public STest::Rule { \ + RULE_NAME() : Rule(#GROUP_NAME "." #RULE_NAME) {} \ + \ + bool precondition(const TestState& state) { return state.precondition__##GROUP_NAME##__##RULE_NAME(); } \ + \ + void action(TestState& state) { state.action__##GROUP_NAME##__##RULE_NAME(); } \ + }; \ + } + +namespace Svc { + +namespace Rules { + +RULES_DEF_RULE(BufferSendIn, BufferTooSmallForData) +RULES_DEF_RULE(BufferSendIn, BufferTooSmallForPacket) +RULES_DEF_RULE(BufferSendIn, FileOpenError) +RULES_DEF_RULE(BufferSendIn, FileWriteError) +RULES_DEF_RULE(BufferSendIn, InvalidBuffer) +RULES_DEF_RULE(BufferSendIn, InvalidHeader) +RULES_DEF_RULE(BufferSendIn, InvalidHeaderHash) +RULES_DEF_RULE(BufferSendIn, OK) +RULES_DEF_RULE(CLEAR_EVENT_THROTTLE, OK) +RULES_DEF_RULE(FileOpenStatus, Error) +RULES_DEF_RULE(FileOpenStatus, OK) +RULES_DEF_RULE(FileWriteStatus, Error) +RULES_DEF_RULE(FileWriteStatus, OK) +RULES_DEF_RULE(SchedIn, OK) + +} // namespace Rules + +} // namespace Svc + +#endif diff --git a/Svc/DpWriter/test/ut/Rules/SchedIn.cpp b/Svc/DpWriter/test/ut/Rules/SchedIn.cpp new file mode 100644 index 0000000000..269957e298 --- /dev/null +++ b/Svc/DpWriter/test/ut/Rules/SchedIn.cpp @@ -0,0 +1,49 @@ +// ====================================================================== +// \title SchedIn.cpp +// \author Rob Bocchino +// \brief SchedIn class implementation +// +// \copyright +// Copyright (C) 2024 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#include "STest/Pick/Pick.hpp" +#include "Svc/DpWriter/test/ut/Rules/SchedIn.hpp" +#include "Svc/DpWriter/test/ut/Rules/Testers.hpp" + +namespace Svc { + +// ---------------------------------------------------------------------- +// Rule definitions +// ---------------------------------------------------------------------- + +bool TestState ::precondition__SchedIn__OK() const { + return true; +} + +void TestState ::action__SchedIn__OK() { + // Clear history + this->clearHistory(); + // Invoke schedIn port + const U32 context = STest::Pick::any(); + this->invoke_to_schedIn(0, context); + this->component.doDispatch(); + // Check telemetry + this->checkTelemetry(); +} + +namespace SchedIn { + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +void Tester ::OK() { + this->ruleOK.apply(this->testState); +} + +} // namespace SchedIn + +} // namespace Svc diff --git a/Svc/DpWriter/test/ut/Rules/SchedIn.hpp b/Svc/DpWriter/test/ut/Rules/SchedIn.hpp new file mode 100644 index 0000000000..8427049e20 --- /dev/null +++ b/Svc/DpWriter/test/ut/Rules/SchedIn.hpp @@ -0,0 +1,57 @@ +// ====================================================================== +// \title SchedIn.hpp +// \author Rob Bocchino +// \brief SchedIn class interface +// +// \copyright +// Copyright (C) 2024 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#ifndef Svc_SchedIn_HPP +#define Svc_SchedIn_HPP + +#include "Svc/DpWriter/test/ut/Rules/Rules.hpp" +#include "Svc/DpWriter/test/ut/TestState/TestState.hpp" + +namespace Svc { + + namespace SchedIn { + + class Tester { + + public: + + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + //! OK + void OK(); + + public: + + // ---------------------------------------------------------------------- + // Rules + // ---------------------------------------------------------------------- + + //! Rule SchedIn::OK + Rules::SchedIn::OK ruleOK; + + public: + + // ---------------------------------------------------------------------- + // Public member variables + // ---------------------------------------------------------------------- + + //! Test state + TestState testState; + + }; + + } + +} + +#endif diff --git a/Svc/DpWriter/test/ut/Rules/Testers.cpp b/Svc/DpWriter/test/ut/Rules/Testers.cpp new file mode 100644 index 0000000000..b67015ea16 --- /dev/null +++ b/Svc/DpWriter/test/ut/Rules/Testers.cpp @@ -0,0 +1,28 @@ +// ====================================================================== +// \title Testers.cpp +// \author Rob Bocchino +// \brief Testers class implementation +// +// \copyright +// Copyright (C) 2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#include "Svc/DpWriter/test/ut/Rules/Testers.hpp" + +namespace Svc { + + namespace Testers { + + BufferSendIn::Tester bufferSendIn; + + FileOpenStatus::Tester fileOpenStatus; + + FileWriteStatus::Tester fileWriteStatus; + + SchedIn::Tester schedIn; + + } + +} diff --git a/Svc/DpWriter/test/ut/Rules/Testers.hpp b/Svc/DpWriter/test/ut/Rules/Testers.hpp new file mode 100644 index 0000000000..ab711540fb --- /dev/null +++ b/Svc/DpWriter/test/ut/Rules/Testers.hpp @@ -0,0 +1,39 @@ +// ====================================================================== +// \title Testers.hpp +// \author Rob Bocchino +// \brief Testers class interface +// +// \copyright +// Copyright (C) 2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// ====================================================================== + +#ifndef Svc_Testers_HPP +#define Svc_Testers_HPP + +#include "Svc/DpWriter/test/ut/Rules/BufferSendIn.hpp" +#include "Svc/DpWriter/test/ut/Rules/CLEAR_EVENT_THROTTLE.hpp" +#include "Svc/DpWriter/test/ut/Rules/FileOpenStatus.hpp" +#include "Svc/DpWriter/test/ut/Rules/FileWriteStatus.hpp" +#include "Svc/DpWriter/test/ut/Rules/SchedIn.hpp" + +namespace Svc { + + namespace Testers { + + extern BufferSendIn::Tester bufferSendIn; + + extern CLEAR_EVENT_THROTTLE::Tester clearEventThrottle; + + extern FileOpenStatus::Tester fileOpenStatus; + + extern FileWriteStatus::Tester fileWriteStatus; + + extern SchedIn::Tester schedIn; + + } + +} + +#endif diff --git a/Svc/DpWriter/test/ut/Scenarios/Random.cpp b/Svc/DpWriter/test/ut/Scenarios/Random.cpp new file mode 100644 index 0000000000..c9c309b535 --- /dev/null +++ b/Svc/DpWriter/test/ut/Scenarios/Random.cpp @@ -0,0 +1,72 @@ +// ====================================================================== +// \title Random.hpp +// \author Rob Bocchino +// \brief Random scenario +// +// \copyright +// Copyright (C) 2024 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#include "STest/Scenario/BoundedScenario.hpp" +#include "STest/Scenario/RandomScenario.hpp" +#include "Svc/DpWriter/test/ut/Rules/Rules.hpp" +#include "Svc/DpWriter/test/ut/Scenarios/Random.hpp" + +namespace Svc { + +namespace Scenarios { + +namespace Random { + +// ---------------------------------------------------------------------- +// Rule definitions +// ---------------------------------------------------------------------- + +Rules::BufferSendIn::BufferTooSmallForData bufferSendInBufferTooSmallForData; +Rules::BufferSendIn::BufferTooSmallForPacket bufferSendInBufferTooSmallForPacket; +Rules::BufferSendIn::FileOpenError bufferSendInFileOpenError; +Rules::BufferSendIn::FileWriteError bufferSendInFileWriteError; +Rules::BufferSendIn::InvalidBuffer bufferSendInInvalidBuffer; +Rules::BufferSendIn::InvalidHeader bufferSendInInvalidHeader; +Rules::BufferSendIn::InvalidHeaderHash bufferSendInInvalidHeaderHash; +Rules::BufferSendIn::OK bufferSendInOK; +Rules::CLEAR_EVENT_THROTTLE::OK clearEventThrottleOK; +Rules::FileOpenStatus::Error fileOpenStatusError; +Rules::FileOpenStatus::OK fileOpenStatusOK; +Rules::FileWriteStatus::Error fileWriteStatusError; +Rules::FileWriteStatus::OK fileWriteStatusOK; +Rules::SchedIn::OK schedInOK; + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +void Tester ::run(FwSizeType maxNumSteps) { + STest::Rule* rules[] = {&bufferSendInBufferTooSmallForData, + &bufferSendInBufferTooSmallForPacket, + &bufferSendInFileOpenError, + &bufferSendInFileWriteError, + &bufferSendInInvalidBuffer, + &bufferSendInInvalidHeader, + &bufferSendInInvalidHeaderHash, + &bufferSendInOK, + &clearEventThrottleOK, + &fileOpenStatusError, + &fileOpenStatusOK, + &fileWriteStatusError, + &fileWriteStatusOK, + &schedInOK}; + STest::RandomScenario scenario("RandomScenario", rules, + sizeof(rules) / sizeof(STest::RandomScenario*)); + STest::BoundedScenario boundedScenario("BoundedRandomScenario", scenario, maxNumSteps); + const U32 numSteps = boundedScenario.run(this->testState); + printf("Ran %u steps.\n", numSteps); +} + +} // namespace Random + +} // namespace Scenarios + +} // namespace Svc diff --git a/Svc/DpWriter/test/ut/Scenarios/Random.hpp b/Svc/DpWriter/test/ut/Scenarios/Random.hpp new file mode 100644 index 0000000000..f96b76d262 --- /dev/null +++ b/Svc/DpWriter/test/ut/Scenarios/Random.hpp @@ -0,0 +1,48 @@ +// ====================================================================== +// \title Random.hpp +// \author Rob Bocchino +// \brief Random scenario +// +// \copyright +// Copyright (C) 2024 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#ifndef Svc_Random_HPP +#define Svc_Random_HPP + +#include "Svc/DpWriter/test/ut/TestState/TestState.hpp" + +namespace Svc { + +namespace Scenarios { + +namespace Random { + +class Tester { + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + //! Run the random scenario + void run(FwSizeType maxNumSteps //!< The maximum number of steps + ); + + private: + // ---------------------------------------------------------------------- + // Private member variables + // ---------------------------------------------------------------------- + + //! Test state + TestState testState; +}; + +} // namespace Random + +} // namespace Scenarios + +} // namespace Svc + +#endif diff --git a/Svc/DpWriter/test/ut/TestState/TestState.hpp b/Svc/DpWriter/test/ut/TestState/TestState.hpp new file mode 100644 index 0000000000..ac7a52f13d --- /dev/null +++ b/Svc/DpWriter/test/ut/TestState/TestState.hpp @@ -0,0 +1,47 @@ +// ====================================================================== +// \title TestState.hpp +// \author Rob Bocchino +// \brief Test state for testing DpWriter +// +// \copyright +// Copyright (C) 2024 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government sponsorship +// acknowledged. +// ====================================================================== + +#ifndef Svc_TestState_HPP +#define Svc_TestState_HPP + +#include "Svc/DpWriter/test/ut/DpWriterTester.hpp" + +#define TEST_STATE_DEF_RULE(GROUP_NAME, RULE_NAME) \ + bool precondition__##GROUP_NAME##__##RULE_NAME() const; \ + void action__##GROUP_NAME##__##RULE_NAME(); + +namespace Svc { + +class TestState : public DpWriterTester { + public: + // ---------------------------------------------------------------------- + // Rule definitions + // ---------------------------------------------------------------------- + + TEST_STATE_DEF_RULE(BufferSendIn, BufferTooSmallForData) + TEST_STATE_DEF_RULE(BufferSendIn, BufferTooSmallForPacket) + TEST_STATE_DEF_RULE(BufferSendIn, FileOpenError) + TEST_STATE_DEF_RULE(BufferSendIn, FileWriteError) + TEST_STATE_DEF_RULE(BufferSendIn, InvalidBuffer) + TEST_STATE_DEF_RULE(BufferSendIn, InvalidHeader) + TEST_STATE_DEF_RULE(BufferSendIn, InvalidHeaderHash) + TEST_STATE_DEF_RULE(BufferSendIn, OK) + TEST_STATE_DEF_RULE(CLEAR_EVENT_THROTTLE, OK) + TEST_STATE_DEF_RULE(FileOpenStatus, Error) + TEST_STATE_DEF_RULE(FileOpenStatus, OK) + TEST_STATE_DEF_RULE(FileWriteStatus, Error) + TEST_STATE_DEF_RULE(FileWriteStatus, OK) + TEST_STATE_DEF_RULE(SchedIn, OK) +}; + +} // namespace Svc + +#endif diff --git a/TestUtils/OnChangeChannel.hpp b/TestUtils/OnChangeChannel.hpp index 40d73e36b0..775f6c1713 100644 --- a/TestUtils/OnChangeChannel.hpp +++ b/TestUtils/OnChangeChannel.hpp @@ -13,10 +13,10 @@ #ifndef TestUtils_OnChangeChannel_HPP #define TestUtils_OnChangeChannel_HPP +#include #include #include "TestUtils/Option.hpp" -#include "config/FpConfig.hpp" namespace TestUtils { diff --git a/Utils/Hash/HashBuffer.hpp b/Utils/Hash/HashBuffer.hpp index eeee42da2a..bf35e25f36 100644 --- a/Utils/Hash/HashBuffer.hpp +++ b/Utils/Hash/HashBuffer.hpp @@ -4,7 +4,7 @@ // \brief hpp file for Hash class // // \copyright -// Copyright 2009-2015, by the California Institute of Technology. +// Copyright 2009-2024, by the California Institute of Technology. // ALL RIGHTS RESERVED. United States Government Sponsorship // acknowledged. // @@ -14,65 +14,68 @@ #define UTILS_HASH_BUFFER_HPP #include -#include #include +#include #include namespace Utils { - //! \class HashBuffer - //! \brief A container class for holding a hash buffer +//! \class HashBuffer +//! \brief A container class for holding a hash buffer +//! +class HashBuffer : public Fw::SerializeBufferBase { + public: + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + //! Construct a HashBuffer object + //! + HashBuffer(const U8* args, NATIVE_UINT_TYPE size); + HashBuffer(const HashBuffer& other); + HashBuffer(); + + //! Destroy a HashBuffer object + //! + virtual ~HashBuffer(); + + // ---------------------------------------------------------------------- + // Public instance methods + // ---------------------------------------------------------------------- + + //! Assign a hash buffer from another hash buffer + //! + HashBuffer& operator=(const HashBuffer& other); + + //! Compare two hash buffers for equality + //! + bool operator==(const HashBuffer& other) const; + + //! Compare two hash buffers for inequality + //! + bool operator!=(const HashBuffer& other) const; + + //! Get the total buffer length of a hash buffer + //! + NATIVE_UINT_TYPE getBuffCapacity() const; // !< returns capacity, not current size, of buffer + + //! Get a pointer to the buffer within the hash buffer + //! + U8* getBuffAddr(); + const U8* getBuffAddr() const; + + //! Convert bytes 0 through 3 of the hash data to a big-Endian U32 value + U32 asBigEndianU32() const; + + private: + // ---------------------------------------------------------------------- + // Private member variables + // ---------------------------------------------------------------------- + + //! The buffer which stores the hash digest //! - class HashBuffer : public Fw::SerializeBufferBase { - public: - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - //! Construct a HashBuffer object - //! - HashBuffer(const U8 *args, NATIVE_UINT_TYPE size); - HashBuffer(const HashBuffer& other); - HashBuffer(); - - //! Destroy a HashBuffer object - //! - virtual ~HashBuffer(); - - // ---------------------------------------------------------------------- - // Public instance methods - // ---------------------------------------------------------------------- - - //! Assign a hash buffer from another hash buffer - //! - HashBuffer& operator=(const HashBuffer& other); - - //! Compare two hash buffers for equality - //! - bool operator==(const HashBuffer& other) const; - - //! Compare two hash buffers for inequality - //! - bool operator!=(const HashBuffer& other) const; - - //! Get the total buffer length of a hash buffer - //! - NATIVE_UINT_TYPE getBuffCapacity() const; // !< returns capacity, not current size, of buffer - - //! Get a pointer to the buffer within the hash buffer - //! - U8* getBuffAddr(); - const U8* getBuffAddr() const; - - private: - // ---------------------------------------------------------------------- - // Private member variables - // ---------------------------------------------------------------------- - - //! The buffer which stores the hash digest - //! - U8 m_bufferData[HASH_DIGEST_LENGTH]; // packet data buffer - }; -} + U8 m_bufferData[HASH_DIGEST_LENGTH] = {}; // packet data buffer +}; +} // namespace Utils #endif diff --git a/Utils/Hash/HashBufferCommon.cpp b/Utils/Hash/HashBufferCommon.cpp index 237f3b535f..31ac7957b1 100644 --- a/Utils/Hash/HashBufferCommon.cpp +++ b/Utils/Hash/HashBufferCommon.cpp @@ -1,55 +1,69 @@ #include #include -namespace Utils { +#include - HashBuffer::HashBuffer() { - } +#include "Fw/Types/Serializable.hpp" - HashBuffer::HashBuffer(const U8 *args, NATIVE_UINT_TYPE size) { - Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(args,size); - FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,static_cast(stat)); - } +namespace Utils { - HashBuffer::~HashBuffer() { - } +HashBuffer::HashBuffer() {} - HashBuffer::HashBuffer(const HashBuffer& other) : Fw::SerializeBufferBase() { - Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(other.m_bufferData,other.getBuffLength()); - FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,static_cast(stat)); - } +HashBuffer::HashBuffer(const U8* args, NATIVE_UINT_TYPE size) : Fw::SerializeBufferBase() { + Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(args, size); + FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, static_cast(stat)); +} - HashBuffer& HashBuffer::operator=(const HashBuffer& other) { - if(this == &other) { - return *this; - } +HashBuffer::~HashBuffer() {} - Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(other.m_bufferData,other.getBuffLength()); - FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,static_cast(stat)); +HashBuffer::HashBuffer(const HashBuffer& other) : Fw::SerializeBufferBase() { + Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(other.m_bufferData, other.getBuffLength()); + FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, static_cast(stat)); +} + +HashBuffer& HashBuffer::operator=(const HashBuffer& other) { + if (this == &other) { return *this; } - bool HashBuffer::operator==(const HashBuffer& other) const { - if( (this->getBuffLength() == other.getBuffLength()) && - (memcmp(this->getBuffAddr(), other.getBuffAddr(), this->getBuffLength()) != 0) ){ - return false; - } - return true; - } + Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(other.m_bufferData, other.getBuffLength()); + FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, static_cast(stat)); + return *this; +} - bool HashBuffer::operator!=(const HashBuffer& other) const { - return !(*this == other); +bool HashBuffer::operator==(const HashBuffer& other) const { + if ((this->getBuffLength() == other.getBuffLength()) && + (memcmp(this->getBuffAddr(), other.getBuffAddr(), this->getBuffLength()) != 0)) { + return false; } + return true; +} - const U8* HashBuffer::getBuffAddr() const { - return this->m_bufferData; - } +bool HashBuffer::operator!=(const HashBuffer& other) const { + return !(*this == other); +} - U8* HashBuffer::getBuffAddr() { - return this->m_bufferData; - } +const U8* HashBuffer::getBuffAddr() const { + return this->m_bufferData; +} + +U8* HashBuffer::getBuffAddr() { + return this->m_bufferData; +} + +NATIVE_UINT_TYPE HashBuffer::getBuffCapacity() const { + return sizeof(this->m_bufferData); +} - NATIVE_UINT_TYPE HashBuffer::getBuffCapacity() const { - return sizeof(this->m_bufferData); +U32 HashBuffer::asBigEndianU32() const { + U32 result = 0; + const FwSizeType bufferSize = sizeof this->m_bufferData; + const FwSizeType numBytes = std::min(bufferSize, static_cast(sizeof(U32))); + for (FwSizeType i = 0; i < numBytes; i++) { + result <<= 8; + FW_ASSERT(i < bufferSize, static_cast(i), static_cast(bufferSize)); + result += this->m_bufferData[i]; } + return result; } +} // namespace Utils diff --git a/config/AcConstants.fpp b/config/AcConstants.fpp index fb4b5e6087..8dc7bbcd73 100644 --- a/config/AcConstants.fpp +++ b/config/AcConstants.fpp @@ -45,6 +45,9 @@ constant DpManagerNumPorts = 5 @ Size of processing port array for DpWriter constant DpWriterNumProcPorts = 5 +@ The size of a file name string +constant FileNameStringSize = 256 + # ---------------------------------------------------------------------- # Hub connections. Connections on all deployments should mirror these settings. # ---------------------------------------------------------------------- diff --git a/config/DpCfg.hpp b/config/DpCfg.hpp new file mode 100644 index 0000000000..bbbb3d13fb --- /dev/null +++ b/config/DpCfg.hpp @@ -0,0 +1,22 @@ +// ====================================================================== +// \title DpCfg.hpp +// \author bocchino +// \brief hpp file for data product configuration +// +// \copyright +// Copyright 2024, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#ifndef DPCFG_HPP +#define DPCFG_HPP + +#include + +// The format string for a file name +// The format arguments are container ID, time seconds, and time microseconds +constexpr const char *DP_FILENAME_FORMAT = "Dp_%08" PRI_FwDpIdType "_%08" PRIu32 "_%08" PRIu32 ".fdp"; + +#endif