diff --git a/Svc/CmdSequencer/CMakeLists.txt b/Svc/CmdSequencer/CMakeLists.txt index 6b98cf3f05..f6b44958b1 100644 --- a/Svc/CmdSequencer/CMakeLists.txt +++ b/Svc/CmdSequencer/CMakeLists.txt @@ -55,6 +55,7 @@ set(UT_SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/test/ut/SequenceFiles/SizeFieldTooSmallFile.cpp" "${CMAKE_CURRENT_LIST_DIR}/test/ut/SequenceFiles/TooLargeFile.cpp" "${CMAKE_CURRENT_LIST_DIR}/test/ut/SequenceFiles/USecFieldTooShortFile.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/JoinWait.cpp" "${CMAKE_CURRENT_LIST_DIR}/test/ut/Main.cpp" "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" ) diff --git a/Svc/CmdSequencer/CmdSequencerImpl.cpp b/Svc/CmdSequencer/CmdSequencerImpl.cpp index ca1dbf8696..f49c7d3747 100644 --- a/Svc/CmdSequencer/CmdSequencerImpl.cpp +++ b/Svc/CmdSequencer/CmdSequencerImpl.cpp @@ -38,7 +38,8 @@ namespace Svc { m_timeout(0), m_blockState(SEQ_NO_BLOCK), m_opCode(0), - m_cmdSeq(0) + m_cmdSeq(0), + m_join_waiting(false) { } @@ -98,6 +99,10 @@ namespace Svc { SeqBlkState block) { if (not this->requireRunMode(STOPPED)) { + if (m_join_waiting) { + // Inform user previous seq file is not complete + this->log_WARNING_HI_CS_JoinWaitingNotComplete(); + } this->cmdResponse_out(opCode, cmdSeq, Fw::COMMAND_EXECUTION_ERROR); return; } @@ -218,6 +223,23 @@ namespace Svc { this->cmdResponse_out(opCode, cmdSeq, Fw::COMMAND_OK); } + void CmdSequencerComponentImpl::CS_JOIN_WAIT_cmdHandler( + const FwOpcodeType opCode, const U32 cmdSeq) { + + // If there is no running sequence do not wait + if (m_runMode != RUNNING) { + this->log_WARNING_LO_CS_NoSequenceActive(); + this->cmdResponse_out(opCode,cmdSeq,Fw::COMMAND_OK); + return; + } else { + m_join_waiting = true; + Fw::LogStringArg& logFileName = this->m_sequence->getLogFileName(); + this->log_ACTIVITY_HI_CS_JoinWaiting(logFileName, m_cmdSeq, m_opCode); + m_cmdSeq = cmdSeq; + m_opCode = opCode; + } + } + // ---------------------------------------------------------------------- // Private helper methods // ---------------------------------------------------------------------- @@ -251,7 +273,9 @@ namespace Svc { this->seqDone_out(0,0,0,Fw::COMMAND_EXECUTION_ERROR); } - if (SEQ_BLOCK == this->m_blockState) { + if (SEQ_BLOCK == this->m_blockState || m_join_waiting) { + // Do not wait if sequence was canceled or a cmd failed + this->m_join_waiting = false; this->cmdResponse_out(this->m_opCode, this->m_cmdSeq, Fw::COMMAND_EXECUTION_ERROR); } @@ -446,10 +470,11 @@ namespace Svc { this->seqDone_out(0,0,0,Fw::COMMAND_OK); } - if (SEQ_BLOCK == this->m_blockState) { + if (SEQ_BLOCK == this->m_blockState || m_join_waiting) { this->cmdResponse_out(this->m_opCode, this->m_cmdSeq, Fw::COMMAND_OK); } + m_join_waiting = false; this->m_blockState = SEQ_NO_BLOCK; } diff --git a/Svc/CmdSequencer/CmdSequencerImpl.hpp b/Svc/CmdSequencer/CmdSequencerImpl.hpp index 2a034f54dd..93e7cbe05d 100644 --- a/Svc/CmdSequencer/CmdSequencerImpl.hpp +++ b/Svc/CmdSequencer/CmdSequencerImpl.hpp @@ -679,6 +679,15 @@ namespace Svc { const Fw::CmdStringArg& fileName //!< The name of the sequence file ); + //! Implementation for CS_JOIN command handler + //! Wait for sequences that are running to finish. + //! Allow user to run multiple seq files in SEQ_NO_BLOCK mode + //! then wait for them to finish before allowing more seq run request. + void CS_JOIN_WAIT_cmdHandler( + const FwOpcodeType opCode, /*!< The opcode*/ + const U32 cmdSeq /*!< The command sequence number*/ + ); + PRIVATE: // ---------------------------------------------------------------------- @@ -788,7 +797,7 @@ namespace Svc { SeqBlkState m_blockState; FwOpcodeType m_opCode; U32 m_cmdSeq; - + bool m_join_waiting; }; }; diff --git a/Svc/CmdSequencer/Commands.xml b/Svc/CmdSequencer/Commands.xml index 116daea188..225510bd12 100755 --- a/Svc/CmdSequencer/Commands.xml +++ b/Svc/CmdSequencer/Commands.xml @@ -48,4 +48,7 @@ acknowledged. Set the run mode to MANUAL. + + Wait for sequences that are running to finish. Allow user to run multiple seq files in SEQ_NO_BLOCK mode then wait for them to finish before allowing more seq run request. + diff --git a/Svc/CmdSequencer/Events.xml b/Svc/CmdSequencer/Events.xml index d7feafd8b4..38ec11c60c 100755 --- a/Svc/CmdSequencer/Events.xml +++ b/Svc/CmdSequencer/Events.xml @@ -285,4 +285,26 @@ acknowledged. + + Wait for the current running sequence file complete + + + + The name of the sequence file + + + The record number + + + The opcode + + + + + + Cannot run new sequence when current sequence file is still running. + + diff --git a/Svc/CmdSequencer/test/ut/JoinWait.cpp b/Svc/CmdSequencer/test/ut/JoinWait.cpp new file mode 100644 index 0000000000..59ee7e9f51 --- /dev/null +++ b/Svc/CmdSequencer/test/ut/JoinWait.cpp @@ -0,0 +1,97 @@ +// ====================================================================== +// \title JoinWait.hpp +// \author janamian +// \brief cpp file for CmdSequencer test harness implementation class +// +// \copyright +// Copyright 2009-2021, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "Svc/CmdSequencer/test/ut/JoinWait.hpp" +#include "Svc/CmdSequencer/test/ut/Relative.hpp" + +namespace Svc { + + namespace JoinWait { + + // ---------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------- + + Tester :: + Tester(const SequenceFiles::File::Format::t format) : + Svc::Tester(format) + { + + } + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + void Tester :: + test_join_wait_without_active_seq() + { + // Send join wait command when there is no active seq + this->sendCmd_CS_JOIN_WAIT(0, 0); + this->clearAndDispatch(); + // Assert events + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_CS_NoSequenceActive_SIZE(1); + } + + void Tester ::test_join_wait_with_active_seq() { + const U32 numRecords = 1; + SequenceFiles::RelativeFile file(numRecords, this->format); + // Set the time + Fw::Time testTime(TB_WORKSTATION_TIME, 0, 0); + this->setTestTime(testTime); + // Write the file + const char *const fileName = file.getName().toChar(); + file.write(); + // Validate the file + this->validateFile(0, fileName); + // Run the sequence + this->runSequence(0, fileName); + + // Assert that timer is set + ASSERT_EQ( + CmdSequencerComponentImpl::Timer::SET, + this->component.m_cmdTimer.m_state + ); + + // Run one cycle to make sure nothing is dispatched yet + this->invoke_to_schedIn(0, 0); + this->clearAndDispatch(); + ASSERT_from_comCmdOut_SIZE(0); + ASSERT_EVENTS_SIZE(0); + + // Assert that timer hasn't expired + ASSERT_EQ( + CmdSequencerComponentImpl::Timer::SET, + this->component.m_cmdTimer.m_state + ); + + // Request join wait + this->sendCmd_CS_JOIN_WAIT(0, 0); + this->clearAndDispatch(); + // Make sure JOIN_WAIT is active + ASSERT_EVENTS_CS_NoSequenceActive_SIZE(0); + ASSERT_TRUE(this->component.m_join_waiting); + + // Send status back + this->invoke_to_cmdResponseIn(0, 0, 0, Fw::COMMAND_OK); + this->clearAndDispatch(); + + // Make sure we received completion for both command and join_wait + ASSERT_EVENTS_SIZE(2); + // Make sure join wait has been cleared + ASSERT_FALSE(this->component.m_join_waiting); + + } + + } + +} diff --git a/Svc/CmdSequencer/test/ut/JoinWait.hpp b/Svc/CmdSequencer/test/ut/JoinWait.hpp new file mode 100644 index 0000000000..fdc77da958 --- /dev/null +++ b/Svc/CmdSequencer/test/ut/JoinWait.hpp @@ -0,0 +1,55 @@ +// ====================================================================== +// \title JoinWait.hpp +// \author janamian +// \brief hpp file for CmdSequencer test harness implementation class +// +// \copyright +// Copyright 2009-2021, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#ifndef JOIN_WAIT_HPP +#define JOIN_WAIT_HPP + +#include "Svc/CmdSequencer/test/ut/Tester.hpp" + +namespace Svc { + + namespace JoinWait { + + class Tester : + public Svc::Tester + { + + public: + + // ---------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------- + + //! Construct object Tester + Tester( + const SequenceFiles::File::Format::t format = + SequenceFiles::File::Format::F_PRIME //!< The file format to use + ); + + public: + + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + //! Test + void test_join_wait_without_active_seq(); + + void test_join_wait_with_active_seq(); + + }; + + } + +} + +#endif diff --git a/Svc/CmdSequencer/test/ut/Main.cpp b/Svc/CmdSequencer/test/ut/Main.cpp index ae6b91a4ba..739becdbd9 100644 --- a/Svc/CmdSequencer/test/ut/Main.cpp +++ b/Svc/CmdSequencer/test/ut/Main.cpp @@ -19,6 +19,7 @@ #include "Svc/CmdSequencer/test/ut/Tester.hpp" #include "Svc/CmdSequencer/test/ut/Mixed.hpp" #include "Svc/CmdSequencer/test/ut/UnitTest.hpp" +#include "Svc/CmdSequencer/test/ut/JoinWait.hpp" TEST(AMPCS, MissingCRC) { Svc::AMPCS::Tester tester; @@ -379,6 +380,17 @@ TEST(Relative, ValidateAMPCS) { tester.Validate(); } +TEST(JoinWait, JoinWaitNoActiveSeq) { + Svc::JoinWait::Tester tester; + tester.test_join_wait_without_active_seq(); +} + +TEST(JoinWait, JoinWaitWithActiveSeq) { + Svc::JoinWait::Tester tester; + tester.test_join_wait_with_active_seq(); +} + + int main(int argc, char **argv) { // Create ./bin directory for test files Os::FileSystem::createDirectory("./bin");