From cbbeb55c3270dee5a50c473695e5465e4dd7bef1 Mon Sep 17 00:00:00 2001 From: Gerik Kubiak Date: Wed, 25 Mar 2026 12:17:57 -0700 Subject: [PATCH 1/8] Add unit tests for shrinking processed buffer --- Svc/DpWriter/test/ut/AbstractState.cpp | 20 ++++-- Svc/DpWriter/test/ut/AbstractState.hpp | 11 ++- Svc/DpWriter/test/ut/DpWriterTestMain.cpp | 9 +++ Svc/DpWriter/test/ut/DpWriterTester.cpp | 4 ++ Svc/DpWriter/test/ut/Rules/BufferSendIn.cpp | 70 ++++++++++++++++++++ Svc/DpWriter/test/ut/Rules/BufferSendIn.hpp | 6 ++ Svc/DpWriter/test/ut/Rules/Rules.hpp | 1 + Svc/DpWriter/test/ut/Scenarios/Random.cpp | 2 + Svc/DpWriter/test/ut/TestState/TestState.hpp | 1 + 9 files changed, 116 insertions(+), 8 deletions(-) diff --git a/Svc/DpWriter/test/ut/AbstractState.cpp b/Svc/DpWriter/test/ut/AbstractState.cpp index 2643cf02194..2d45b605305 100644 --- a/Svc/DpWriter/test/ut/AbstractState.cpp +++ b/Svc/DpWriter/test/ut/AbstractState.cpp @@ -24,6 +24,19 @@ namespace Svc { //! Get a data product buffer backed by m_bufferData //! \return The buffer Fw::Buffer AbstractState::getDpBuffer() { + + Fw::DpCfg::ProcType::SerialType procTypes = 0; + for (FwIndexType i = 0; i < Fw::DpCfg::ProcType::NUM_CONSTANTS; i++) { + const bool selector = static_cast(STest::Pick::lowerUpper(0, 1)); + if (selector) { + procTypes = static_cast(procTypes | (1 << i)); + } + } + + return getDpBufferWithProc(procTypes); +} + +Fw::Buffer AbstractState::getDpBufferWithProc(Fw::DpCfg::ProcType::SerialType procTypes) { // Generate the ID const FwDpIdType id = static_cast(STest::Pick::lowerUpper( std::numeric_limits::min(), static_cast(std::numeric_limits::max()))); @@ -45,13 +58,6 @@ Fw::Buffer AbstractState::getDpBuffer() { const U32 microseconds = STest::Pick::startLength(0, 1000000); container.setTimeTag(Fw::Time(seconds, microseconds)); // Update the processing types - Fw::DpCfg::ProcType::SerialType procTypes = 0; - for (FwIndexType i = 0; i < Fw::DpCfg::ProcType::NUM_CONSTANTS; i++) { - const bool selector = static_cast(STest::Pick::lowerUpper(0, 1)); - if (selector) { - procTypes = static_cast(procTypes | (1 << i)); - } - } container.setProcTypes(procTypes); // Update the data size container.setDataSize(dataSize); diff --git a/Svc/DpWriter/test/ut/AbstractState.hpp b/Svc/DpWriter/test/ut/AbstractState.hpp index bda265ab75e..9190cbe360f 100644 --- a/Svc/DpWriter/test/ut/AbstractState.hpp +++ b/Svc/DpWriter/test/ut/AbstractState.hpp @@ -51,7 +51,8 @@ class AbstractState { m_NumFailedWrites(0), m_NumSuccessfulWrites(0), m_NumErrors(0), - m_procTypes(0) {} + m_procTypes(0), + m_procShrinkDataSizeOpt() {} public: // ---------------------------------------------------------------------- @@ -66,10 +67,16 @@ class AbstractState { //! Set the data size void setDataSize(FwSizeType dataSize) { this->m_dataSizeOpt.set(dataSize); } + void clearDataSize() { this->m_dataSizeOpt.clear(); } + //! Get a data product buffer backed by bufferData //! \return The buffer Fw::Buffer getDpBuffer(); + //! Get a data product buffer backed by bufferData + //! \return The buffer + Fw::Buffer getDpBufferWithProc(Fw::DpCfg::ProcType::SerialType procTypes); + private: // ---------------------------------------------------------------------- // Private state variables @@ -127,6 +134,8 @@ class AbstractState { //! Bit mask for processing out port calls Fw::DpCfg::ProcType::SerialType m_procTypes; + + TestUtils::Option m_procShrinkDataSizeOpt; }; } // namespace Svc diff --git a/Svc/DpWriter/test/ut/DpWriterTestMain.cpp b/Svc/DpWriter/test/ut/DpWriterTestMain.cpp index 3f42cb2a7d3..a8f1b71276a 100644 --- a/Svc/DpWriter/test/ut/DpWriterTestMain.cpp +++ b/Svc/DpWriter/test/ut/DpWriterTestMain.cpp @@ -71,6 +71,15 @@ TEST(BufferSendIn, OK) { tester.OK(); } +TEST(BufferSendIn, OKProcShrink) { + COMMENT("Invoke bufferSendIn with nominal input. Shrink the buffer in processing"); + REQUIREMENT("SVC-DPMANAGER-002"); + REQUIREMENT("SVC-DPMANAGER-003"); + REQUIREMENT("SVC-DPMANAGER-004"); + BufferSendIn::Tester tester; + tester.OKProcShrink(); +} + TEST(CLEAR_EVENT_THROTTLE, OK) { COMMENT("Test the CLEAR_EVENT_THROTTLE command."); REQUIREMENT("SVC-DPMANAGER-006"); diff --git a/Svc/DpWriter/test/ut/DpWriterTester.cpp b/Svc/DpWriter/test/ut/DpWriterTester.cpp index ca3dc736846..9057af0fe42 100644 --- a/Svc/DpWriter/test/ut/DpWriterTester.cpp +++ b/Svc/DpWriter/test/ut/DpWriterTester.cpp @@ -35,6 +35,10 @@ void DpWriterTester::from_procBufferSendOut_handler(FwIndexType portNum, Fw::Buf this->pushFromPortEntry_procBufferSendOut(buffer); this->abstractState.m_procTypes = static_cast(this->abstractState.m_procTypes | (1 << portNum)); + + if (this->abstractState.m_procShrinkDataSizeOpt.hasValue()) { + buffer.setSize(Fw::DpContainer::MIN_PACKET_SIZE + this->abstractState.m_procShrinkDataSizeOpt.get()); + } } // ---------------------------------------------------------------------- diff --git a/Svc/DpWriter/test/ut/Rules/BufferSendIn.cpp b/Svc/DpWriter/test/ut/Rules/BufferSendIn.cpp index 56b46cbf3c9..3da6300918f 100644 --- a/Svc/DpWriter/test/ut/Rules/BufferSendIn.cpp +++ b/Svc/DpWriter/test/ut/Rules/BufferSendIn.cpp @@ -79,6 +79,71 @@ void TestState ::action__BufferSendIn__OK() { this->abstractState.m_NumSuccessfulWrites.value++; } +bool TestState ::precondition__BufferSendIn__OKProcShrink() 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__OKProcShrink() { + // 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 + const FwSizeType buffer_data_size = STest::Pick::lowerUpper(AbstractState::MAX_DATA_SIZE/2, AbstractState::MAX_DATA_SIZE); + const FwSizeType shrink_data_size = buffer_data_size / 2; + this->abstractState.setDataSize(buffer_data_size); + Fw::Buffer buffer = this->abstractState.getDpBufferWithProc(1); + // Instruct the proc handler to shrink the buffer + this->abstractState.m_procShrinkDataSizeOpt.set(shrink_data_size); + const FwSizeType exp_buffer_size = Fw::DpContainer::MIN_PACKET_SIZE + shrink_data_size; + // Send the buffer + this->invoke_to_bufferSendIn(0, buffer); + this->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, static_cast(exp_buffer_size), fileName.toChar()); + // Check processing types + this->checkProcTypes(container); + // Check DP notification + ASSERT_from_dpWrittenOut_SIZE(1); + ASSERT_from_dpWrittenOut(0, fileName, container.getPriority(), exp_buffer_size); + // Check deallocation + ASSERT_from_deallocBufferSendOut_SIZE(1); + ASSERT_from_deallocBufferSendOut(0, buffer); + // Check file write + ASSERT_EQ(exp_buffer_size, fileData.pointer); + ASSERT_EQ(0, ::memcmp(buffer.getData(), fileData.writeResult, exp_buffer_size)); + // Check data checksum is valid for the container buffer + Utils::HashBuffer storedHash; + Utils::HashBuffer computedHash; + ASSERT_EQ(Fw::Success::SUCCESS, container.checkDataHash(storedHash, computedHash)); + // Update m_NumBytesWritten + this->abstractState.m_NumBytesWritten.value += exp_buffer_size; + // Update m_NumSuccessfulWrites + this->abstractState.m_NumSuccessfulWrites.value++; + + this->abstractState.clearDataSize(); + this->abstractState.m_procShrinkDataSizeOpt.clear(); +} + bool TestState ::precondition__BufferSendIn__InvalidBuffer() const { bool result = true; return result; @@ -444,6 +509,11 @@ void Tester::OK() { this->testState.printEvents(); } +void Tester::OKProcShrink() { + this->ruleOKProcShrink.apply(this->testState); + this->testState.printEvents(); +} + } // namespace BufferSendIn } // namespace Svc diff --git a/Svc/DpWriter/test/ut/Rules/BufferSendIn.hpp b/Svc/DpWriter/test/ut/Rules/BufferSendIn.hpp index 04c98a3a84c..c9d5f933a51 100644 --- a/Svc/DpWriter/test/ut/Rules/BufferSendIn.hpp +++ b/Svc/DpWriter/test/ut/Rules/BufferSendIn.hpp @@ -28,6 +28,9 @@ class Tester { //! OK void OK(); + //! OKProcShrink + void OKProcShrink(); + //! Invalid buffer void InvalidBuffer(); @@ -57,6 +60,9 @@ class Tester { //! Rule BufferSendIn::OK Rules::BufferSendIn::OK ruleOK; + //! Rule BufferSendIn::OKProcShrink + Rules::BufferSendIn::OKProcShrink ruleOKProcShrink; + //! Rule BufferSendIn::InvalidBuffer Rules::BufferSendIn::InvalidBuffer ruleInvalidBuffer; diff --git a/Svc/DpWriter/test/ut/Rules/Rules.hpp b/Svc/DpWriter/test/ut/Rules/Rules.hpp index 397a76ece2b..14da0a8c25a 100644 --- a/Svc/DpWriter/test/ut/Rules/Rules.hpp +++ b/Svc/DpWriter/test/ut/Rules/Rules.hpp @@ -44,6 +44,7 @@ RULES_DEF_RULE(BufferSendIn, InvalidBuffer) RULES_DEF_RULE(BufferSendIn, InvalidHeader) RULES_DEF_RULE(BufferSendIn, InvalidHeaderHash) RULES_DEF_RULE(BufferSendIn, OK) +RULES_DEF_RULE(BufferSendIn, OKProcShrink) RULES_DEF_RULE(CLEAR_EVENT_THROTTLE, OK) RULES_DEF_RULE(FileOpenStatus, Error) RULES_DEF_RULE(FileOpenStatus, OK) diff --git a/Svc/DpWriter/test/ut/Scenarios/Random.cpp b/Svc/DpWriter/test/ut/Scenarios/Random.cpp index 001bb1bf4b2..6e8770307ae 100644 --- a/Svc/DpWriter/test/ut/Scenarios/Random.cpp +++ b/Svc/DpWriter/test/ut/Scenarios/Random.cpp @@ -32,6 +32,7 @@ Rules::BufferSendIn::InvalidBuffer bufferSendInInvalidBuffer; Rules::BufferSendIn::InvalidHeader bufferSendInInvalidHeader; Rules::BufferSendIn::InvalidHeaderHash bufferSendInInvalidHeaderHash; Rules::BufferSendIn::OK bufferSendInOK; +Rules::BufferSendIn::OKProcShrink bufferSendInOKProcShrink; Rules::CLEAR_EVENT_THROTTLE::OK clearEventThrottleOK; Rules::FileOpenStatus::Error fileOpenStatusError; Rules::FileOpenStatus::OK fileOpenStatusOK; @@ -52,6 +53,7 @@ void Tester ::run(U32 maxNumSteps) { &bufferSendInInvalidHeader, &bufferSendInInvalidHeaderHash, &bufferSendInOK, + &bufferSendInOKProcShrink, &clearEventThrottleOK, &fileOpenStatusError, &fileOpenStatusOK, diff --git a/Svc/DpWriter/test/ut/TestState/TestState.hpp b/Svc/DpWriter/test/ut/TestState/TestState.hpp index ac7a52f13d4..4299e04b965 100644 --- a/Svc/DpWriter/test/ut/TestState/TestState.hpp +++ b/Svc/DpWriter/test/ut/TestState/TestState.hpp @@ -34,6 +34,7 @@ class TestState : public DpWriterTester { TEST_STATE_DEF_RULE(BufferSendIn, InvalidHeader) TEST_STATE_DEF_RULE(BufferSendIn, InvalidHeaderHash) TEST_STATE_DEF_RULE(BufferSendIn, OK) + TEST_STATE_DEF_RULE(BufferSendIn, OKProcShrink) TEST_STATE_DEF_RULE(CLEAR_EVENT_THROTTLE, OK) TEST_STATE_DEF_RULE(FileOpenStatus, Error) TEST_STATE_DEF_RULE(FileOpenStatus, OK) From 543990c8fbc50896f459babd52c95e4c998ffee0 Mon Sep 17 00:00:00 2001 From: Gerik Kubiak Date: Wed, 25 Mar 2026 12:18:45 -0700 Subject: [PATCH 2/8] Update DpWriter to shrink processed buffers after processing --- Svc/DpWriter/DpWriter.cpp | 7 ++++++- Svc/DpWriter/DpWriter.hpp | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Svc/DpWriter/DpWriter.cpp b/Svc/DpWriter/DpWriter.cpp index 1d776599d23..c70a4b08ef0 100644 --- a/Svc/DpWriter/DpWriter.cpp +++ b/Svc/DpWriter/DpWriter.cpp @@ -158,7 +158,7 @@ Fw::Success::T DpWriter::deserializePacketHeader(Fw::Buffer& buffer, Fw::DpConta return status; } -void DpWriter::performProcessing(const Fw::DpContainer& container) { +void DpWriter::performProcessing(Fw::DpContainer& container) { // Get the buffer Fw::Buffer buffer = container.getBuffer(); // Get the bit mask for the processing types @@ -169,6 +169,11 @@ void DpWriter::performProcessing(const Fw::DpContainer& container) { this->procBufferSendOut_out(portNum, buffer); } } + + // Update container buffer size + container.getBuffer().setSize(buffer.getSize()); + container.setDataSize(buffer.getSize() - Fw::DpContainer::MIN_PACKET_SIZE); + container.serializeHeader(); } Fw::Success::T DpWriter::writeFile(const Fw::DpContainer& container, diff --git a/Svc/DpWriter/DpWriter.hpp b/Svc/DpWriter/DpWriter.hpp index 6861c9df9c0..3a51e5957fd 100644 --- a/Svc/DpWriter/DpWriter.hpp +++ b/Svc/DpWriter/DpWriter.hpp @@ -79,7 +79,7 @@ class DpWriter final : public DpWriterComponentBase { ); //! Perform processing on a packet buffer - void performProcessing(const Fw::DpContainer& container //!< The container + void performProcessing(Fw::DpContainer& container //!< The container ); //! Write the file From fc6fa399a1fa4a1a6eb6c4f7c795b236e3ac2454 Mon Sep 17 00:00:00 2001 From: M Starch Date: Mon, 30 Mar 2026 11:49:53 -0700 Subject: [PATCH 3/8] Formatting --- Svc/DpWriter/test/ut/AbstractState.cpp | 1 - Svc/DpWriter/test/ut/Rules/BufferSendIn.cpp | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Svc/DpWriter/test/ut/AbstractState.cpp b/Svc/DpWriter/test/ut/AbstractState.cpp index 2d45b605305..d85b59c9e0c 100644 --- a/Svc/DpWriter/test/ut/AbstractState.cpp +++ b/Svc/DpWriter/test/ut/AbstractState.cpp @@ -24,7 +24,6 @@ namespace Svc { //! Get a data product buffer backed by m_bufferData //! \return The buffer Fw::Buffer AbstractState::getDpBuffer() { - Fw::DpCfg::ProcType::SerialType procTypes = 0; for (FwIndexType i = 0; i < Fw::DpCfg::ProcType::NUM_CONSTANTS; i++) { const bool selector = static_cast(STest::Pick::lowerUpper(0, 1)); diff --git a/Svc/DpWriter/test/ut/Rules/BufferSendIn.cpp b/Svc/DpWriter/test/ut/Rules/BufferSendIn.cpp index 3da6300918f..8b5360d1de3 100644 --- a/Svc/DpWriter/test/ut/Rules/BufferSendIn.cpp +++ b/Svc/DpWriter/test/ut/Rules/BufferSendIn.cpp @@ -99,7 +99,8 @@ void TestState ::action__BufferSendIn__OKProcShrink() { // Update m_NumBuffersReceived this->abstractState.m_NumBuffersReceived.value++; // Construct a random buffer - const FwSizeType buffer_data_size = STest::Pick::lowerUpper(AbstractState::MAX_DATA_SIZE/2, AbstractState::MAX_DATA_SIZE); + const FwSizeType buffer_data_size = + STest::Pick::lowerUpper(AbstractState::MAX_DATA_SIZE / 2, AbstractState::MAX_DATA_SIZE); const FwSizeType shrink_data_size = buffer_data_size / 2; this->abstractState.setDataSize(buffer_data_size); Fw::Buffer buffer = this->abstractState.getDpBufferWithProc(1); From 537206252b0882a4944e688420bd4d5d7c99186e Mon Sep 17 00:00:00 2001 From: Gerik Kubiak Date: Tue, 31 Mar 2026 13:54:32 -0700 Subject: [PATCH 4/8] Updated DpWriter to use the dataSize in the container header to shrink the container size --- Fw/Dp/DpContainer.cpp | 19 +++++++++++++++++++ Fw/Dp/DpContainer.hpp | 4 ++++ Svc/DpWriter/DpWriter.cpp | 20 +++++++++++++++++--- Svc/DpWriter/test/ut/DpWriterTester.cpp | 7 ++++++- 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/Fw/Dp/DpContainer.cpp b/Fw/Dp/DpContainer.cpp index c0dbf55454b..f5c4f79a3e5 100644 --- a/Fw/Dp/DpContainer.cpp +++ b/Fw/Dp/DpContainer.cpp @@ -142,6 +142,25 @@ void DpContainer::setBuffer(const Buffer& buffer) { this->m_dataSize = 0; } +void DpContainer::shrinkBufferSize() { + + // Calculate the assumed size for the Fw::Buffer + const FwSizeType newSize = this->getPacketSize(); + + // Check that the buffer can still store a data product + // AND + // That the update is a shrink operation. Growing an + // Fw::Buffer is not safe + FW_ASSERT(newSize >= MIN_PACKET_SIZE, + static_cast(newSize)); + FW_ASSERT(newSize <= this->m_buffer.getSize(), + static_cast(newSize), + static_cast(this->m_buffer.getSize())); + + // Shrink the Fw::Buffer + this->m_buffer.setSize(newSize); +} + Utils::HashBuffer DpContainer::getHeaderHash() const { const FwSizeType bufferSize = this->m_buffer.getSize(); const FwSizeType minBufferSize = HEADER_HASH_OFFSET + HASH_DIGEST_LENGTH; diff --git a/Fw/Dp/DpContainer.hpp b/Fw/Dp/DpContainer.hpp index 8503f6ae020..d62fb389d2f 100644 --- a/Fw/Dp/DpContainer.hpp +++ b/Fw/Dp/DpContainer.hpp @@ -177,6 +177,10 @@ class DpContainer { void setBuffer(const Buffer& buffer //!< The packet buffer ); + //! Shrink the Fw::Buffer size to match the + //! DataSize in the container header + void shrinkBufferSize(); + //! Invalidate the packet buffer void invalidateBuffer() { this->m_buffer = Fw::Buffer(); diff --git a/Svc/DpWriter/DpWriter.cpp b/Svc/DpWriter/DpWriter.cpp index c70a4b08ef0..7a5f6b8b603 100644 --- a/Svc/DpWriter/DpWriter.cpp +++ b/Svc/DpWriter/DpWriter.cpp @@ -170,10 +170,24 @@ void DpWriter::performProcessing(Fw::DpContainer& container) { } } - // Update container buffer size - container.getBuffer().setSize(buffer.getSize()); - container.setDataSize(buffer.getSize() - Fw::DpContainer::MIN_PACKET_SIZE); + // Updated DpContainer object state with the returned value in the + // container buffer + Fw::SerializeStatus stat = container.deserializeHeader(); + FW_ASSERT(stat == Fw::FW_SERIALIZE_OK, stat); + + // Check that the buffer size is compatible with the data size in + // the container header + FW_ASSERT(container.getDataSize() <= buffer.getSize(), + // Note: May perform a 64 to 32 bit conversion + static_cast(container.getDataSize()), + static_cast(buffer.getSize())); + + // Re-compute and serialize the container header into the buffer + container.updateHeaderHash(); container.serializeHeader(); + + // Shrink internal Fw::Buffer + container.shrinkBufferSize(); } Fw::Success::T DpWriter::writeFile(const Fw::DpContainer& container, diff --git a/Svc/DpWriter/test/ut/DpWriterTester.cpp b/Svc/DpWriter/test/ut/DpWriterTester.cpp index 9057af0fe42..4a88bab0f34 100644 --- a/Svc/DpWriter/test/ut/DpWriterTester.cpp +++ b/Svc/DpWriter/test/ut/DpWriterTester.cpp @@ -37,7 +37,12 @@ void DpWriterTester::from_procBufferSendOut_handler(FwIndexType portNum, Fw::Buf static_cast(this->abstractState.m_procTypes | (1 << portNum)); if (this->abstractState.m_procShrinkDataSizeOpt.hasValue()) { - buffer.setSize(Fw::DpContainer::MIN_PACKET_SIZE + this->abstractState.m_procShrinkDataSizeOpt.get()); + // Update the data size in the container + const FwSizeType newSize = this->abstractState.m_procShrinkDataSizeOpt.get(); + Fw::DpContainer c(0, buffer); + c.deserializeHeader(); + c.setDataSize(newSize); + c.serializeHeader(); } } From 58c93813c076b7a4f19a4a1d3ae1261262cf2383 Mon Sep 17 00:00:00 2001 From: Gerik Kubiak Date: Tue, 31 Mar 2026 14:00:40 -0700 Subject: [PATCH 5/8] Update DpWriter SDD with container shrinking steps --- Svc/DpWriter/docs/sdd.md | 5 +++++ Svc/DpWriter/test/ut/DpWriterTestMain.cpp | 1 + 2 files changed, 6 insertions(+) diff --git a/Svc/DpWriter/docs/sdd.md b/Svc/DpWriter/docs/sdd.md index ebe8c3799ad..0637330eda6 100644 --- a/Svc/DpWriter/docs/sdd.md +++ b/Svc/DpWriter/docs/sdd.md @@ -35,6 +35,7 @@ SVC-DPWRITER-003 | On receiving a data product container _C_, `Svc::DpWriter` sh 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::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 +SVC-DPWRITER-007 | On receiving an `Fw::Buffer` _B_, and after performing any requested processing on _B_, `Svc::DpWriter` shall re-parse the container header and shrink the size of the product. | Allows processing interfaces to compress data products and communicate that compressed state back to `Svc::DpWriter`. | Unit Test ## 3. Design @@ -125,6 +126,10 @@ It does the following: `procBufferSendOut` at port number `N`, passing in `B`. This step updates the memory pointed to by `B` in place. + 1. Re-parse the container header pointed to by `B`. If necessary, + shrink the size of the `B` buffer to be consistent with the data + size in the updated container header. + 1. Write `B` to a file, using the format described in the [**File Format**](#file_format) section. For the time stamp, use the time provided by `timeGetOut`. diff --git a/Svc/DpWriter/test/ut/DpWriterTestMain.cpp b/Svc/DpWriter/test/ut/DpWriterTestMain.cpp index a8f1b71276a..89a8c391f74 100644 --- a/Svc/DpWriter/test/ut/DpWriterTestMain.cpp +++ b/Svc/DpWriter/test/ut/DpWriterTestMain.cpp @@ -76,6 +76,7 @@ TEST(BufferSendIn, OKProcShrink) { REQUIREMENT("SVC-DPMANAGER-002"); REQUIREMENT("SVC-DPMANAGER-003"); REQUIREMENT("SVC-DPMANAGER-004"); + REQUIREMENT("SVC-DPMANAGER-007"); BufferSendIn::Tester tester; tester.OKProcShrink(); } From 88c9bff59af1401bf94d935f0c13830ab1eb0603 Mon Sep 17 00:00:00 2001 From: Gerik Kubiak Date: Tue, 31 Mar 2026 14:02:48 -0700 Subject: [PATCH 6/8] Re-run formatting --- Fw/Dp/DpContainer.cpp | 7 ++----- Svc/DpWriter/DpWriter.cpp | 3 +-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Fw/Dp/DpContainer.cpp b/Fw/Dp/DpContainer.cpp index f5c4f79a3e5..96e1eae6b4c 100644 --- a/Fw/Dp/DpContainer.cpp +++ b/Fw/Dp/DpContainer.cpp @@ -143,7 +143,6 @@ void DpContainer::setBuffer(const Buffer& buffer) { } void DpContainer::shrinkBufferSize() { - // Calculate the assumed size for the Fw::Buffer const FwSizeType newSize = this->getPacketSize(); @@ -151,10 +150,8 @@ void DpContainer::shrinkBufferSize() { // AND // That the update is a shrink operation. Growing an // Fw::Buffer is not safe - FW_ASSERT(newSize >= MIN_PACKET_SIZE, - static_cast(newSize)); - FW_ASSERT(newSize <= this->m_buffer.getSize(), - static_cast(newSize), + FW_ASSERT(newSize >= MIN_PACKET_SIZE, static_cast(newSize)); + FW_ASSERT(newSize <= this->m_buffer.getSize(), static_cast(newSize), static_cast(this->m_buffer.getSize())); // Shrink the Fw::Buffer diff --git a/Svc/DpWriter/DpWriter.cpp b/Svc/DpWriter/DpWriter.cpp index 7a5f6b8b603..944a0ae3a37 100644 --- a/Svc/DpWriter/DpWriter.cpp +++ b/Svc/DpWriter/DpWriter.cpp @@ -179,8 +179,7 @@ void DpWriter::performProcessing(Fw::DpContainer& container) { // the container header FW_ASSERT(container.getDataSize() <= buffer.getSize(), // Note: May perform a 64 to 32 bit conversion - static_cast(container.getDataSize()), - static_cast(buffer.getSize())); + static_cast(container.getDataSize()), static_cast(buffer.getSize())); // Re-compute and serialize the container header into the buffer container.updateHeaderHash(); From bf04a13e3b09b224798e0dad3a00d67d9a179c4a Mon Sep 17 00:00:00 2001 From: Gerik Kubiak Date: Tue, 7 Apr 2026 11:53:40 -0700 Subject: [PATCH 7/8] Reset container structure iff the container was processed. Remove cast comment --- Svc/DpWriter/DpWriter.cpp | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/Svc/DpWriter/DpWriter.cpp b/Svc/DpWriter/DpWriter.cpp index 944a0ae3a37..9d2a3ff745a 100644 --- a/Svc/DpWriter/DpWriter.cpp +++ b/Svc/DpWriter/DpWriter.cpp @@ -164,29 +164,32 @@ void DpWriter::performProcessing(Fw::DpContainer& container) { // Get the bit mask for the processing types const Fw::DpCfg::ProcType::SerialType procTypes = container.getProcTypes(); // Do the processing + bool did_process = false; for (FwIndexType portNum = 0; portNum < NUM_PROCBUFFERSENDOUT_OUTPUT_PORTS; ++portNum) { if ((procTypes & (1 << portNum)) != 0) { this->procBufferSendOut_out(portNum, buffer); + did_process = true; } } - // Updated DpContainer object state with the returned value in the - // container buffer - Fw::SerializeStatus stat = container.deserializeHeader(); - FW_ASSERT(stat == Fw::FW_SERIALIZE_OK, stat); + if (did_process) { + // Updated DpContainer object state with the returned value in the + // container buffer + Fw::SerializeStatus stat = container.deserializeHeader(); + FW_ASSERT(stat == Fw::FW_SERIALIZE_OK, stat); - // Check that the buffer size is compatible with the data size in - // the container header - FW_ASSERT(container.getDataSize() <= buffer.getSize(), - // Note: May perform a 64 to 32 bit conversion - static_cast(container.getDataSize()), static_cast(buffer.getSize())); + // Check that the buffer size is compatible with the data size in + // the container header + FW_ASSERT(container.getDataSize() <= buffer.getSize(), + static_cast(container.getDataSize()), static_cast(buffer.getSize())); - // Re-compute and serialize the container header into the buffer - container.updateHeaderHash(); - container.serializeHeader(); + // Re-compute and serialize the container header into the buffer + container.updateHeaderHash(); + container.serializeHeader(); - // Shrink internal Fw::Buffer - container.shrinkBufferSize(); + // Shrink internal Fw::Buffer + container.shrinkBufferSize(); + } } Fw::Success::T DpWriter::writeFile(const Fw::DpContainer& container, From 678368e7e95b15786d150bd3b0d4577f1b2731e1 Mon Sep 17 00:00:00 2001 From: Gerik Kubiak Date: Wed, 8 Apr 2026 07:56:54 -0700 Subject: [PATCH 8/8] Fixed DpWriter formatting --- Svc/DpWriter/DpWriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Svc/DpWriter/DpWriter.cpp b/Svc/DpWriter/DpWriter.cpp index 9d2a3ff745a..9981c11816f 100644 --- a/Svc/DpWriter/DpWriter.cpp +++ b/Svc/DpWriter/DpWriter.cpp @@ -180,8 +180,8 @@ void DpWriter::performProcessing(Fw::DpContainer& container) { // Check that the buffer size is compatible with the data size in // the container header - FW_ASSERT(container.getDataSize() <= buffer.getSize(), - static_cast(container.getDataSize()), static_cast(buffer.getSize())); + FW_ASSERT(container.getDataSize() <= buffer.getSize(), static_cast(container.getDataSize()), + static_cast(buffer.getSize())); // Re-compute and serialize the container header into the buffer container.updateHeaderHash();