Add DpWriter (#2593)

* Pull in framework changes from data-products branch

* Pull in changes to DpManager from data-products branch

* Pull in DpWriter from data-products branch

* Fix spelling

* Revise FileNameString

* Fix warnings in CI

* Fix static analysis warnings

* Fix static analysis warnings

* Revise formatting and comments

* Revise banner comments

* Revise FileNameString per PR comment

* Revise path names in config headers

If a header H.hpp exists in the F Prime source base, then

is dangerous. Because [project root] and [fprime root] are both
in the list of include paths, it's not clear whether this means "include
[project root]/config/H.hpp" or "include [fprime root]/config/H.hpp."

On the other hand,

or

has no such ambiguity, because only one of [project root]/config
and [fprime root]/config is in the list of include paths.

* Revise path names in config headers

If a header H.hpp exists in the F Prime source base, then

`#include "config/H.hpp"`

is dangerous. Because [project root] and [fprime root] are both
in the list of include paths, it's not clear whether this means "include
[project root]/config/H.hpp" or "include [fprime root]/config/H.hpp."

On the other hand,

include <config/H.hpp>

or

`#include "config/H.hpp"`

has no such ambiguity, because only one of [project root]/config
and [fprime root]/config is in the list of include paths.
This commit is contained in:
Rob Bocchino 2024-03-28 16:09:38 -07:00 committed by GitHub
parent 40ff91d625
commit b89b5d91c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
67 changed files with 3197 additions and 191 deletions

View File

@ -94,6 +94,7 @@ BUFFERALLOCATIONFAILED
BUFFERGETOUT BUFFERGETOUT
BUFFERMANAGERCOMPONENTIMPLCFG BUFFERMANAGERCOMPONENTIMPLCFG
BUFFERMGR BUFFERMGR
BUFFERTOOSMALLFORPACKET
BUFFQUEUEIN BUFFQUEUEIN
buffsize buffsize
BUGLIST BUGLIST
@ -267,6 +268,7 @@ doxyindexer
doxyrules doxyrules
doxysearch doxysearch
Doxywizard Doxywizard
DPCFG
dpi dpi
DPMANAGER DPMANAGER
DPWRITER DPWRITER
@ -330,6 +332,7 @@ fadvise
FAKELOGGER FAKELOGGER
fallocate fallocate
fbuild fbuild
fdp
fdset fdset
FEEDNAME FEEDNAME
ffff ffff
@ -338,8 +341,11 @@ filedown
FILEDOWNLINK FILEDOWNLINK
FILEDOWNLINKCFG FILEDOWNLINKCFG
FILEID FILEID
FILENAMESTRING
fileopen fileopen
FILEOPENERROR
FILESTUBS FILESTUBS
FILEWRITEERROR
fio fio
Firefox Firefox
FLDP FLDP
@ -480,6 +486,9 @@ integertypename
interoperate interoperate
intlimits intlimits
inttype inttype
INVALIDBUFFER
INVALIDHEADER
INVALIDHEADERHASH
invisi invisi
ioc ioc
ioctl ioctl
@ -774,6 +783,7 @@ PRMDBIMPLTESTER
PRMDBLIMPLCFG PRMDBLIMPLCFG
prmname prmname
probs probs
PROCBUFFERSENDOUT
PRODUCTGETIN PRODUCTGETIN
PRODUCTREQUESTIN PRODUCTREQUESTIN
PRODUCTRESPONSEOUT PRODUCTRESPONSEOUT

View File

@ -58,6 +58,7 @@ namespace Fw {
FW_TYPEID_INTERNAL_INTERFACE_STRING = 51, //!< interface string Buffer type id 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_FIXED_LENGTH_STRING = 52, //!< 256 char string Buffer type id
FW_TYPEID_OBJECT_NAME = 53, //!< ObjectName 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
}; };
} }

View File

@ -7,9 +7,9 @@
# Note: using PROJECT_NAME as EXECUTABLE_NAME # 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}/Assert.cpp"
"${CMAKE_CURRENT_LIST_DIR}/String.cpp" "${CMAKE_CURRENT_LIST_DIR}/FileNameString.cpp"
"${CMAKE_CURRENT_LIST_DIR}/InternalInterfaceString.cpp" "${CMAKE_CURRENT_LIST_DIR}/InternalInterfaceString.cpp"
"${CMAKE_CURRENT_LIST_DIR}/MallocAllocator.cpp" "${CMAKE_CURRENT_LIST_DIR}/MallocAllocator.cpp"
"${CMAKE_CURRENT_LIST_DIR}/MemAllocator.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}/PolyType.cpp"
"${CMAKE_CURRENT_LIST_DIR}/SerialBuffer.cpp" "${CMAKE_CURRENT_LIST_DIR}/SerialBuffer.cpp"
"${CMAKE_CURRENT_LIST_DIR}/Serializable.cpp" "${CMAKE_CURRENT_LIST_DIR}/Serializable.cpp"
"${CMAKE_CURRENT_LIST_DIR}/String.cpp"
"${CMAKE_CURRENT_LIST_DIR}/StringType.cpp" "${CMAKE_CURRENT_LIST_DIR}/StringType.cpp"
"${CMAKE_CURRENT_LIST_DIR}/StringUtils.cpp" "${CMAKE_CURRENT_LIST_DIR}/StringUtils.cpp"
"${CMAKE_CURRENT_LIST_DIR}/Types.fpp"
) )
set(MOD_DEPS set(MOD_DEPS
Fw/Cfg Fw/Cfg

View File

@ -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

View File

@ -0,0 +1,37 @@
#ifndef FW_FILENAMESTRING_HPP
#define FW_FILENAMESTRING_HPP
#include <FpConfig.hpp>
#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

View File

@ -9,7 +9,14 @@ namespace Test {
StaticData StaticData::data; StaticData StaticData::data;
void StaticData::setNextStatus(Os::File::Status status) { 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) { 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.openOverwrite = overwrite;
StaticData::data.lastCalled = StaticData::OPEN_FN; StaticData::data.lastCalled = StaticData::OPEN_FN;
StaticData::data.pointer = 0; StaticData::data.pointer = 0;
return StaticData::data.nextStatus; return StaticData::data.openStatus;
} }
void TestFile::close() { void TestFile::close() {
@ -62,32 +69,32 @@ void TestFile::close() {
FileInterface::Status TestFile::size(FwSignedSizeType& size_result) { FileInterface::Status TestFile::size(FwSignedSizeType& size_result) {
StaticData::data.lastCalled = StaticData::SIZE_FN; StaticData::data.lastCalled = StaticData::SIZE_FN;
size_result = StaticData::data.sizeResult; size_result = StaticData::data.sizeResult;
return StaticData::data.nextStatus; return StaticData::data.sizeStatus;
} }
FileInterface::Status TestFile::position(FwSignedSizeType& position_result) { FileInterface::Status TestFile::position(FwSignedSizeType& position_result) {
StaticData::data.lastCalled = StaticData::POSITION_FN; StaticData::data.lastCalled = StaticData::POSITION_FN;
position_result = StaticData::data.positionResult; position_result = StaticData::data.positionResult;
return StaticData::data.nextStatus; return StaticData::data.positionStatus;
} }
FileInterface::Status TestFile::preallocate(FwSignedSizeType offset, FwSignedSizeType length) { FileInterface::Status TestFile::preallocate(FwSignedSizeType offset, FwSignedSizeType length) {
StaticData::data.preallocateOffset = offset; StaticData::data.preallocateOffset = offset;
StaticData::data.preallocateLength = length; StaticData::data.preallocateLength = length;
StaticData::data.lastCalled = StaticData::PREALLOCATE_FN; StaticData::data.lastCalled = StaticData::PREALLOCATE_FN;
return StaticData::data.nextStatus; return StaticData::data.preallocateStatus;
} }
FileInterface::Status TestFile::seek(FwSignedSizeType offset, SeekType seekType) { FileInterface::Status TestFile::seek(FwSignedSizeType offset, SeekType seekType) {
StaticData::data.seekOffset = offset; StaticData::data.seekOffset = offset;
StaticData::data.seekType = seekType; StaticData::data.seekType = seekType;
StaticData::data.lastCalled = StaticData::SEEK_FN; StaticData::data.lastCalled = StaticData::SEEK_FN;
return StaticData::data.nextStatus; return StaticData::data.seekStatus;
} }
FileInterface::Status TestFile::flush() { FileInterface::Status TestFile::flush() {
StaticData::data.lastCalled = StaticData::FLUSH_FN; StaticData::data.lastCalled = StaticData::FLUSH_FN;
return StaticData::data.nextStatus; return StaticData::data.flushStatus;
} }
FileInterface::Status TestFile::read(U8 *buffer, FwSignedSizeType &size, WaitType wait) { FileInterface::Status TestFile::read(U8 *buffer, FwSignedSizeType &size, WaitType wait) {
@ -103,7 +110,7 @@ FileInterface::Status TestFile::read(U8 *buffer, FwSignedSizeType &size, WaitTyp
} else { } else {
size = StaticData::data.readSizeResult; size = StaticData::data.readSizeResult;
} }
return StaticData::data.nextStatus; return StaticData::data.readStatus;
} }
FileInterface::Status TestFile::write(const U8* buffer, FwSignedSizeType &size, WaitType wait) { 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 { } else {
size = StaticData::data.writeSizeResult; size = StaticData::data.writeSizeResult;
} }
return StaticData::data.nextStatus; return StaticData::data.writeStatus;
} }
FileHandle* TestFile::getHandle() { FileHandle* TestFile::getHandle() {

View File

@ -60,8 +60,23 @@ struct StaticData {
//! File pointer //! File pointer
FwSignedSizeType pointer = 0; FwSignedSizeType pointer = 0;
//! Next status to be returned //! Status to return from open
Os::File::Status nextStatus = Os::File::Status::OTHER_ERROR; 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 //! Return of next size call
FwSignedSizeType sizeResult = -1; FwSignedSizeType sizeResult = -1;
//! Return of next position call //! Return of next position call

View File

@ -2,7 +2,7 @@
// \title Os/test/ut/file/SyntheticFileSystem.hpp // \title Os/test/ut/file/SyntheticFileSystem.hpp
// \brief standard template library driven synthetic file system definitions // \brief standard template library driven synthetic file system definitions
// ====================================================================== // ======================================================================
#include "config/FpConfig.h" #include <FpConfig.h>
#include "Os/File.hpp" #include "Os/File.hpp"
#include <map> #include <map>
#include <memory> #include <memory>

View File

@ -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}/CmdSplitter/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Deframer/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Deframer/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/DpManager/") 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}/FatalHandler/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileDownlinkPorts/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileDownlinkPorts/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileDownlink/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileDownlink/")

View File

@ -13,11 +13,12 @@
#ifndef Svc_Deframer_HPP #ifndef Svc_Deframer_HPP
#define Svc_Deframer_HPP #define Svc_Deframer_HPP
#include <DeframerCfg.hpp>
#include "Svc/Deframer/DeframerComponentAc.hpp" #include "Svc/Deframer/DeframerComponentAc.hpp"
#include "Svc/FramingProtocol/DeframingProtocol.hpp" #include "Svc/FramingProtocol/DeframingProtocol.hpp"
#include "Svc/FramingProtocol/DeframingProtocolInterface.hpp" #include "Svc/FramingProtocol/DeframingProtocolInterface.hpp"
#include "Utils/Types/CircularBuffer.hpp" #include "Utils/Types/CircularBuffer.hpp"
#include "config/DeframerCfg.hpp"
namespace Svc { namespace Svc {

View File

@ -52,7 +52,7 @@ void DpManager::productSendIn_handler(const NATIVE_INT_TYPE portNum, FwDpIdType
this->productSendOut_out(portNum, sendBuffer); 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 // Emit telemetry
this->tlmWrite_NumSuccessfulAllocations(this->numSuccessfulAllocations); this->tlmWrite_NumSuccessfulAllocations(this->numSuccessfulAllocations);
this->tlmWrite_NumFailedAllocations(this->numFailedAllocations); this->tlmWrite_NumFailedAllocations(this->numFailedAllocations);

View File

@ -83,7 +83,7 @@ class DpManager : public DpManagerComponentBase {
//! Handler implementation for schedIn //! Handler implementation for schedIn
void schedIn_handler(const NATIVE_INT_TYPE portNum, //!< The port number void schedIn_handler(const NATIVE_INT_TYPE portNum, //!< The port number
NATIVE_UINT_TYPE context //!< The call order U32 context //!< The call order
) final; ) final;
PRIVATE: PRIVATE:

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#ifndef Svc_AbstractState_HPP #ifndef Svc_AbstractState_HPP

View File

@ -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" #include "Fw/Test/UnitTest.hpp"

View File

@ -315,6 +315,9 @@ This rule sends the `CLEAR_EVENT_THROTTLE` command.
1. Apply rule `CLEAR_EVENT_THROTTLE::OK`. 1. Apply rule `CLEAR_EVENT_THROTTLE::OK`.
1. Apply rule `ProductRequestIn::BufferInvalid` 1. Apply rule `ProductRequestIn::BufferInvalid`
**Requirements tested:**
`SVC-DPMANAGER-006`
## 3. Implementation ## 3. Implementation
### 3.1. DpManagerTester and TestState ### 3.1. DpManagerTester and TestState

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#include "Svc/DpManager/test/ut/Rules/BufferGetStatus.hpp" #include "Svc/DpManager/test/ut/Rules/BufferGetStatus.hpp"

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#ifndef Svc_BufferGetStatus_HPP #ifndef Svc_BufferGetStatus_HPP

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#include "STest/Pick/Pick.hpp" #include "STest/Pick/Pick.hpp"

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#ifndef Svc_CLEAR_EVENT_THROTTLE_HPP #ifndef Svc_CLEAR_EVENT_THROTTLE_HPP

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#include <limits> #include <limits>

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#ifndef Svc_ProductGetIn_HPP #ifndef Svc_ProductGetIn_HPP

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#include <limits> #include <limits>

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#ifndef Svc_ProductRequestIn_HPP #ifndef Svc_ProductRequestIn_HPP

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#include "STest/Pick/Pick.hpp" #include "STest/Pick/Pick.hpp"

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#ifndef Svc_ProductSendIn_HPP #ifndef Svc_ProductSendIn_HPP

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#ifndef Svc_Rules_HPP #ifndef Svc_Rules_HPP

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#include "STest/Pick/Pick.hpp" #include "STest/Pick/Pick.hpp"

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#ifndef Svc_SchedIn_HPP #ifndef Svc_SchedIn_HPP

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#include "Svc/DpManager/test/ut/Rules/Testers.hpp" #include "Svc/DpManager/test/ut/Rules/Testers.hpp"

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#ifndef Svc_Testers_HPP #ifndef Svc_Testers_HPP

View File

@ -6,8 +6,7 @@
// \copyright // \copyright
// Copyright (C) 2021 California Institute of Technology. // Copyright (C) 2021 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government Sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#include "STest/Scenario/BoundedScenario.hpp" #include "STest/Scenario/BoundedScenario.hpp"

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#ifndef Svc_Random_HPP #ifndef Svc_Random_HPP

View File

@ -5,9 +5,8 @@
// //
// \copyright // \copyright
// Copyright (C) 2023 California Institute of Technology. // Copyright (C) 2023 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship // ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged. Any commercial use must be negotiated with the Office // acknowledged.
// of Technology Transfer at the California Institute of Technology.
// ====================================================================== // ======================================================================
#ifndef Svc_TestState_HPP #ifndef Svc_TestState_HPP

View File

@ -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()

10
Svc/DpPorts/DpPorts.fpp Normal file
View File

@ -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
)
}

View File

@ -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()

221
Svc/DpWriter/DpWriter.cpp Normal file
View File

@ -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<U32>(buffer.getSize()), static_cast<U32>(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<U32>(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<FwSignedSizeType>(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<U32>(fileStatus), static_cast<U32>(writeSize),
static_cast<U32>(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

157
Svc/DpWriter/DpWriter.fpp Normal file
View File

@ -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
}
}

115
Svc/DpWriter/DpWriter.hpp Normal file
View File

@ -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 <DpCfg.hpp>
#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

View File

@ -21,6 +21,11 @@ before reaching `DpWriter`.
1. Write _B_ to disk. 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 ## 2. Requirements
Requirement | Description | Rationale | Verification Method 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-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-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-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 ## 3. Design
@ -50,6 +56,7 @@ The diagram below shows the `DpWriter` component.
| `async input` | `schedIn` | `Svc.Sched` | Schedule in port | | `async input` | `schedIn` | `Svc.Sched` | Schedule in port |
| `async input` | `bufferSendIn` | `Fw.BufferSend` | Port for receiving data products to write to disk | | `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` | `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 | | `output` | `deallocBufferSendOut` | `Fw.BufferSend` | Port for deallocating data product buffers |
| `time get` | `timeGetOut` | `Fw.Time` | Time get port | | `time get` | `timeGetOut` | `Fw.Time` | Time get port |
| `telemetry` | `tlmOut` | `Fw.Tlm` | Telemetry port | | `telemetry` | `tlmOut` | `Fw.Tlm` | Telemetry port |
@ -66,17 +73,16 @@ The diagram below shows the `DpWriter` component.
### 3.4. Compile-Time Setup ### 3.4. Compile-Time Setup
The configuration constant [`DpWriterNumProcPorts`](../../../config/AcConstants.fpp) 1. The configuration constant [`DpWriterNumProcPorts`](../../../config/AcConstants.fpp)
specifies the number of ports for connecting components that perform specifies the number of ports for connecting components that perform
processing. processing.
1. The configuration [`DP_FILENAME_FORMAT`](../../../config/DpCfg.hpp)
specifies the file name format.
### 3.5. Runtime Setup ### 3.5. Runtime Setup
The `config` function specifies the following constants: No special runtime setup is required.
1. `fileNamePrefix (string)`: The prefix to use for file names.
1. `fileNameSuffix (string)`: The suffix to use for file names.
### 3.6. Port Handlers ### 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`. This handler receives a mutable reference to a buffer `B`.
It does the following: It does the following:
1. Check that `B` is valid and that the first `sizeof(FwPacketDescriptorType)` 1. Check that `B` is valid. If not, emit a warning event.
bytes of the memory referred to by `B` hold the serialized value
[`Fw_PACKET_DP`](../../../Fw/Com/ComPacket.hpp). 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. 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 1. Read the `ProcType` field out of the container header stored in the
memory pointed to by `B`. memory pointed to by `B`. Let the resulting bit mask be `M`.
If the value is a valid port number `N` for `procBufferSendOut`, then invoke
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`. `procBufferSendOut` at port number `N`, passing in `B`.
This step updates the memory pointed to by `B` in place. 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 Format**](#file_format) section. For the time stamp, use the time
provided by `timeGetOut`. 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`.
<a name="file_format"></a> <a name="file_format"></a>
## 4. File Format ## 4. File Format
@ -119,34 +142,42 @@ with the format described in the
### 4.2. File Name ### 4.2. File Name
The name of each file consists of `fileNamePrefix` followed by an The name of each file is formatted with the configurable format string
ID, a time stamp, and `fileNameSuffix`. [`DP_FILENAME_FORMAT`](../../../config/DpCfg.hpp).
The ID consists of an underscore character `_` followed by the container ID. The format string must contain format specifications for the following arguments,
The time stamp consists of an underscore character `_` followed by a seconds in order.
value, an underscore character, and a microseconds value.
For example, suppose that the file name prefix is `container_data` and the Format Specifier | Type |
file name suffix is `.dat`. ---------------- | -----|
Suppose that container ID is 100, the seconds value is 100000, Container ID | `PRI_FwDpIdType`
and the microseconds value is 1000. Time seconds | `PRI_u32`
Then the file name is `container_data_100_100000_1000.dat`. Time microseconds | `PRI_u32`
<a name="ground_interface"></a> <a name="ground_interface"></a>
## 5. Ground Interface ## 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 | | Name | Type | Description |
|------|------|-------------| |------|------|-------------|
| `NumDataProducts` | `U32` | The number of data products handled | | `NumDataProducts` | `U32` | The number of data products handled |
| `NumBytes` | `U64` | The number of bytes handled | | `NumBytes` | `U64` | The number of bytes handled |
### 5.2. Events ### 5.3. Events
| Name | Severity | Description | | Name | Severity | Description |
|------|----------|-------------| |------|----------|-------------|
| `BufferInvalid` | `warning high` | Incoming buffer is invalid |
| `BufferTooSmall` | `warning high` | Incoming buffer is too small to hold a data product container | | `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 ## 6. Example Uses

View File

@ -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 <limits>
#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<FwDpIdType>::min(), std::numeric_limits<FwDpIdType>::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<FwAssertArgType>(bufferSize),
static_cast<FwAssertArgType>(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<FwDpPriorityType>::min(),
std::numeric_limits<FwDpPriorityType>::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<bool>(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<U8>(STest::Pick::any());
}
// Update the data hash
container.updateDataHash();
// Return the buffer
return buffer;
}
} // namespace Svc

View File

@ -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 <cstring>
#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<FwSizeType> m_dataSizeOpt;
public:
// ----------------------------------------------------------------------
// Public state variables
// ----------------------------------------------------------------------
//! The number of buffers received
TestUtils::OnChangeChannel<U32> m_NumBuffersReceived;
//! The number of bytes written
TestUtils::OnChangeChannel<U64> m_NumBytesWritten;
//! The number of failed writes
TestUtils::OnChangeChannel<U32> m_NumFailedWrites;
//! The number of successful writes
TestUtils::OnChangeChannel<U32> m_NumSuccessfulWrites;
//! The number of errors
TestUtils::OnChangeChannel<U32> 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

View File

@ -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();
}

View File

@ -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<Os::File::Status>(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

View File

@ -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

View File

@ -0,0 +1,403 @@
# DpWriter Component Tests
## 1. Abstract State
### 1.1. Variables
| Variable | Type | Description | Initial Value |
|----------|------|-------------|---------------|
| `m_NumBuffersReceived` | `OnChangeChannel<U32>` | The number of buffers received | 0 |
| `m_NumBytesWritten` | `OnChangeChannel<U64>` | The number of bytes written | 0 |
| `m_NumErrors` | `OnChangeChannel<U32>` | The number of errors | 0 |
| `m_NumFailedWrites` | `OnChangeChannel<U32>` | The number of failed writes | 0 |
| `m_NumSuccessfulWrites` | `OnChangeChannel<U32>` | 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.

View File

@ -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 <limits>
#include <string>
#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<FwSizeType>(buffer.getSize()), static_cast<FwSizeType>(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<U32>(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<FwSizeStoreType>::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<U32>(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<U32>(writeStatus), static_cast<U32>(fileData.writeSizeResult),
static_cast<U32>(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

View File

@ -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

View File

@ -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<FwEnumStoreType>(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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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<TestState> { \
RULE_NAME() : Rule<TestState>(#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

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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<TestState>* rules[] = {&bufferSendInBufferTooSmallForData,
&bufferSendInBufferTooSmallForPacket,
&bufferSendInFileOpenError,
&bufferSendInFileWriteError,
&bufferSendInInvalidBuffer,
&bufferSendInInvalidHeader,
&bufferSendInInvalidHeaderHash,
&bufferSendInOK,
&clearEventThrottleOK,
&fileOpenStatusError,
&fileOpenStatusOK,
&fileWriteStatusError,
&fileWriteStatusOK,
&schedInOK};
STest::RandomScenario<TestState> scenario("RandomScenario", rules,
sizeof(rules) / sizeof(STest::RandomScenario<TestState>*));
STest::BoundedScenario<TestState> boundedScenario("BoundedRandomScenario", scenario, maxNumSteps);
const U32 numSteps = boundedScenario.run(this->testState);
printf("Ran %u steps.\n", numSteps);
}
} // namespace Random
} // namespace Scenarios
} // namespace Svc

View File

@ -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

View File

@ -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

View File

@ -13,10 +13,10 @@
#ifndef TestUtils_OnChangeChannel_HPP #ifndef TestUtils_OnChangeChannel_HPP
#define TestUtils_OnChangeChannel_HPP #define TestUtils_OnChangeChannel_HPP
#include <FpConfig.hpp>
#include <cstring> #include <cstring>
#include "TestUtils/Option.hpp" #include "TestUtils/Option.hpp"
#include "config/FpConfig.hpp"
namespace TestUtils { namespace TestUtils {

View File

@ -4,7 +4,7 @@
// \brief hpp file for Hash class // \brief hpp file for Hash class
// //
// \copyright // \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 // ALL RIGHTS RESERVED. United States Government Sponsorship
// acknowledged. // acknowledged.
// //
@ -14,65 +14,68 @@
#define UTILS_HASH_BUFFER_HPP #define UTILS_HASH_BUFFER_HPP
#include <FpConfig.hpp> #include <FpConfig.hpp>
#include <Fw/Types/Serializable.hpp>
#include <Fw/Types/Assert.hpp> #include <Fw/Types/Assert.hpp>
#include <Fw/Types/Serializable.hpp>
#include <Utils/Hash/HashConfig.hpp> #include <Utils/Hash/HashConfig.hpp>
namespace Utils { namespace Utils {
//! \class HashBuffer //! \class HashBuffer
//! \brief A container class for holding a hash buffer //! \brief A container class for holding a hash buffer
//!
class HashBuffer : public Fw::SerializeBufferBase {
public:
// ----------------------------------------------------------------------
// Construction and destruction
// ----------------------------------------------------------------------
//! Construct a HashBuffer object
//! //!
class HashBuffer : public Fw::SerializeBufferBase { HashBuffer(const U8* args, NATIVE_UINT_TYPE size);
public: HashBuffer(const HashBuffer& other);
// ---------------------------------------------------------------------- HashBuffer();
// Construction and destruction
// ----------------------------------------------------------------------
//! Construct a HashBuffer object //! Destroy a HashBuffer object
//! //!
HashBuffer(const U8 *args, NATIVE_UINT_TYPE size); virtual ~HashBuffer();
HashBuffer(const HashBuffer& other);
HashBuffer();
//! Destroy a HashBuffer object // ----------------------------------------------------------------------
//! // Public instance methods
virtual ~HashBuffer(); // ----------------------------------------------------------------------
// ---------------------------------------------------------------------- //! Assign a hash buffer from another hash buffer
// Public instance methods //!
// ---------------------------------------------------------------------- HashBuffer& operator=(const HashBuffer& other);
//! Assign a hash buffer from another hash buffer //! Compare two hash buffers for equality
//! //!
HashBuffer& operator=(const HashBuffer& other); bool operator==(const HashBuffer& other) const;
//! Compare two hash buffers for equality //! Compare two hash buffers for inequality
//! //!
bool operator==(const HashBuffer& other) const; bool operator!=(const HashBuffer& other) const;
//! Compare two hash buffers for inequality //! Get the total buffer length of a hash buffer
//! //!
bool operator!=(const HashBuffer& other) const; NATIVE_UINT_TYPE getBuffCapacity() const; // !< returns capacity, not current size, of buffer
//! Get the total buffer length of a hash buffer //! Get a pointer to the buffer within the hash buffer
//! //!
NATIVE_UINT_TYPE getBuffCapacity() const; // !< returns capacity, not current size, of buffer U8* getBuffAddr();
const U8* getBuffAddr() const;
//! Get a pointer to the buffer within the hash buffer //! Convert bytes 0 through 3 of the hash data to a big-Endian U32 value
//! U32 asBigEndianU32() const;
U8* getBuffAddr();
const U8* getBuffAddr() const;
private: private:
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Private member variables // Private member variables
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
//! The buffer which stores the hash digest //! 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 #endif

View File

@ -1,55 +1,69 @@
#include <Utils/Hash/HashBuffer.hpp> #include <Utils/Hash/HashBuffer.hpp>
#include <cstring> #include <cstring>
#include <algorithm>
#include "Fw/Types/Serializable.hpp"
namespace Utils { namespace Utils {
HashBuffer::HashBuffer() { HashBuffer::HashBuffer() {}
}
HashBuffer::HashBuffer(const U8 *args, NATIVE_UINT_TYPE size) { HashBuffer::HashBuffer(const U8* args, NATIVE_UINT_TYPE size) : Fw::SerializeBufferBase() {
Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(args,size); Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(args, size);
FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,static_cast<NATIVE_INT_TYPE>(stat)); FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, static_cast<NATIVE_INT_TYPE>(stat));
} }
HashBuffer::~HashBuffer() { HashBuffer::~HashBuffer() {}
}
HashBuffer::HashBuffer(const HashBuffer& other) : Fw::SerializeBufferBase() { HashBuffer::HashBuffer(const HashBuffer& other) : Fw::SerializeBufferBase() {
Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(other.m_bufferData,other.getBuffLength()); Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(other.m_bufferData, other.getBuffLength());
FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,static_cast<NATIVE_INT_TYPE>(stat)); FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, static_cast<NATIVE_INT_TYPE>(stat));
} }
HashBuffer& HashBuffer::operator=(const HashBuffer& other) { HashBuffer& HashBuffer::operator=(const HashBuffer& other) {
if(this == &other) { if (this == &other) {
return *this;
}
Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(other.m_bufferData,other.getBuffLength());
FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,static_cast<NATIVE_INT_TYPE>(stat));
return *this; return *this;
} }
bool HashBuffer::operator==(const HashBuffer& other) const { Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(other.m_bufferData, other.getBuffLength());
if( (this->getBuffLength() == other.getBuffLength()) && FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, static_cast<NATIVE_INT_TYPE>(stat));
(memcmp(this->getBuffAddr(), other.getBuffAddr(), this->getBuffLength()) != 0) ){ return *this;
return false;
}
return true;
}
bool HashBuffer::operator!=(const HashBuffer& other) const {
return !(*this == other);
}
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);
}
} }
bool HashBuffer::operator==(const HashBuffer& other) const {
if ((this->getBuffLength() == other.getBuffLength()) &&
(memcmp(this->getBuffAddr(), other.getBuffAddr(), this->getBuffLength()) != 0)) {
return false;
}
return true;
}
bool HashBuffer::operator!=(const HashBuffer& other) const {
return !(*this == other);
}
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);
}
U32 HashBuffer::asBigEndianU32() const {
U32 result = 0;
const FwSizeType bufferSize = sizeof this->m_bufferData;
const FwSizeType numBytes = std::min(bufferSize, static_cast<FwSizeType>(sizeof(U32)));
for (FwSizeType i = 0; i < numBytes; i++) {
result <<= 8;
FW_ASSERT(i < bufferSize, static_cast<FwAssertArgType>(i), static_cast<FwAssertArgType>(bufferSize));
result += this->m_bufferData[i];
}
return result;
}
} // namespace Utils

View File

@ -45,6 +45,9 @@ constant DpManagerNumPorts = 5
@ Size of processing port array for DpWriter @ Size of processing port array for DpWriter
constant DpWriterNumProcPorts = 5 constant DpWriterNumProcPorts = 5
@ The size of a file name string
constant FileNameStringSize = 256
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
# Hub connections. Connections on all deployments should mirror these settings. # Hub connections. Connections on all deployments should mirror these settings.
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------

22
config/DpCfg.hpp Normal file
View File

@ -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 <FpConfig.hpp>
// 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