From 896803ad2029fd2089ea2bc3fd1fc556a3430978 Mon Sep 17 00:00:00 2001 From: Zimri Leisher Date: Wed, 8 Oct 2025 15:32:33 -0500 Subject: [PATCH] Add PUSH_TIME directive (#4275) * Add push_time dir * Add docs and UT * format --- Svc/FpySequencer/FpySequencer.hpp | 5 +++ Svc/FpySequencer/FpySequencerDirectives.cpp | 30 ++++++++++++++++- Svc/FpySequencer/FpySequencerDirectives.fppi | 7 ++++ Svc/FpySequencer/FpySequencerRunState.cpp | 14 ++++++++ Svc/FpySequencer/FpySequencerTypes.fpp | 1 + Svc/FpySequencer/docs/sdd.md | 3 +- .../test/ut/FpySequencerTestMain.cpp | 33 +++++++++++++++++++ .../test/ut/FpySequencerTester.cpp | 9 +++++ .../test/ut/FpySequencerTester.hpp | 2 ++ 9 files changed, 102 insertions(+), 2 deletions(-) diff --git a/Svc/FpySequencer/FpySequencer.hpp b/Svc/FpySequencer/FpySequencer.hpp index 3fb0bba67d..a52934b79b 100644 --- a/Svc/FpySequencer/FpySequencer.hpp +++ b/Svc/FpySequencer/FpySequencer.hpp @@ -61,6 +61,7 @@ class FpySequencer : public FpySequencerComponentBase { FpySequencer_DiscardDirective discard; FpySequencer_MemCmpDirective memCmp; FpySequencer_StackCmdDirective stackCmd; + FpySequencer_PushTimeDirective pushTime; DirectiveUnion() {} ~DirectiveUnion() {} @@ -473,6 +474,9 @@ class FpySequencer : public FpySequencerComponentBase { //! Internal interface handler for directive_stackCmd void directive_stackCmd_internalInterfaceHandler(const Svc::FpySequencer_StackCmdDirective& directive) override; + //! Internal interface handler for directive_pushTime + void directive_pushTime_internalInterfaceHandler(const Svc::FpySequencer_PushTimeDirective& directive) override; + void parametersLoaded() override; void parameterUpdated(FwPrmIdType id) override; @@ -747,6 +751,7 @@ class FpySequencer : public FpySequencerComponentBase { Signal discard_directiveHandler(const FpySequencer_DiscardDirective& directive, DirectiveError& error); Signal memCmp_directiveHandler(const FpySequencer_MemCmpDirective& directive, DirectiveError& error); Signal stackCmd_directiveHandler(const FpySequencer_StackCmdDirective& directive, DirectiveError& error); + Signal pushTime_directiveHandler(const FpySequencer_PushTimeDirective& directive, DirectiveError& error); }; } // namespace Svc diff --git a/Svc/FpySequencer/FpySequencerDirectives.cpp b/Svc/FpySequencer/FpySequencerDirectives.cpp index f0d15c1dcd..efc29facfa 100644 --- a/Svc/FpySequencer/FpySequencerDirectives.cpp +++ b/Svc/FpySequencer/FpySequencerDirectives.cpp @@ -322,6 +322,13 @@ void FpySequencer::directive_stackCmd_internalInterfaceHandler(const Svc::FpySeq handleDirectiveErrorCode(Fpy::DirectiveId::STACK_CMD, error); } +//! Internal interface handler for directive_pushTime +void FpySequencer::directive_pushTime_internalInterfaceHandler(const Svc::FpySequencer_PushTimeDirective& directive) { + DirectiveError error = DirectiveError::NO_ERROR; + this->sendSignal(this->pushTime_directiveHandler(directive, error)); + handleDirectiveErrorCode(Fpy::DirectiveId::PUSH_TIME, error); +} + //! Internal interface handler for directive_waitRel Signal FpySequencer::waitRel_directiveHandler(const FpySequencer_WaitRelDirective& directive, DirectiveError& error) { if (this->m_runtime.stackSize < 8) { @@ -443,7 +450,7 @@ Signal FpySequencer::pushTlmValAndTime_directiveHandler(const FpySequencer_PushT return Signal::stmtResponse_failure; } - U8 tlmTimeBuf[Fw::Time::SERIALIZED_SIZE]; + U8 tlmTimeBuf[Fw::Time::SERIALIZED_SIZE] = {}; Fw::ExternalSerializeBuffer timeEsb(tlmTimeBuf, Fw::Time::SERIALIZED_SIZE); Fw::SerializeStatus stat = timeEsb.serializeFrom(tlmTime); @@ -1240,4 +1247,25 @@ Signal FpySequencer::stackCmd_directiveHandler(const FpySequencer_StackCmdDirect return Signal::stmtResponse_success; } + +Signal FpySequencer::pushTime_directiveHandler(const FpySequencer_PushTimeDirective& directive, DirectiveError& error) { + if (Fpy::MAX_STACK_SIZE - Fw::Time::SERIALIZED_SIZE < this->m_runtime.stackSize) { + error = DirectiveError::STACK_OVERFLOW; + return Signal::stmtResponse_failure; + } + + Fw::Time currentTime = this->getTime(); + + U8 currentTimeBuf[Fw::Time::SERIALIZED_SIZE] = {}; + Fw::ExternalSerializeBuffer timeEsb(currentTimeBuf, Fw::Time::SERIALIZED_SIZE); + Fw::SerializeStatus stat = timeEsb.serializeFrom(currentTime); + + // coding error if this failed, we should have enough space + FW_ASSERT(stat == Fw::SerializeStatus::FW_SERIALIZE_OK, static_cast(stat)); + + // push time to end of stack + memcpy(this->m_runtime.stack + this->m_runtime.stackSize, timeEsb.getBuffAddr(), timeEsb.getBuffLength()); + this->m_runtime.stackSize += static_cast(timeEsb.getBuffLength()); + return Signal::stmtResponse_success; +} } // namespace Svc diff --git a/Svc/FpySequencer/FpySequencerDirectives.fppi b/Svc/FpySequencer/FpySequencerDirectives.fppi index 8d70b7181e..bf316168ac 100644 --- a/Svc/FpySequencer/FpySequencerDirectives.fppi +++ b/Svc/FpySequencer/FpySequencerDirectives.fppi @@ -113,6 +113,11 @@ struct StackCmdDirective { argsSize: Fpy.StackSizeType } +@ pushes the current Fw.Time struct to the stack +struct PushTimeDirective { + _empty: U8 +} + internal port directive_waitRel(directive: WaitRelDirective) priority 6 assert internal port directive_waitAbs(directive: WaitAbsDirective) priority 6 assert @@ -149,6 +154,8 @@ internal port directive_memCmp(directive: MemCmpDirective) priority 6 assert internal port directive_stackCmd(directive: StackCmdDirective) priority 6 assert +internal port directive_pushTime(directive: PushTimeDirective) priority 6 assert + enum DirectiveErrorCode { NO_ERROR STMT_OUT_OF_BOUNDS diff --git a/Svc/FpySequencer/FpySequencerRunState.cpp b/Svc/FpySequencer/FpySequencerRunState.cpp index 4555943e4c..58be9e06a3 100644 --- a/Svc/FpySequencer/FpySequencerRunState.cpp +++ b/Svc/FpySequencer/FpySequencerRunState.cpp @@ -348,6 +348,16 @@ Fw::Success FpySequencer::deserializeDirective(const Fpy::Statement& stmt, Direc } break; } + case Fpy::DirectiveId::PUSH_TIME: { + new (&deserializedDirective.pushTime) FpySequencer_PushTimeDirective(); + if (argBuf.getBuffLeft() != 0) { + this->log_WARNING_HI_DirectiveDeserializeError(stmt.get_opCode(), this->currentStatementIdx(), + Fw::SerializeStatus::FW_DESERIALIZE_SIZE_MISMATCH, + argBuf.getBuffLeft(), argBuf.getBuffLength()); + return Fw::Success::FAILURE; + } + break; + } default: { // unsure what this opcode is. check compiler version matches sequencer this->log_WARNING_HI_UnknownSequencerDirective(stmt.get_opCode(), this->currentStatementIdx(), @@ -487,6 +497,10 @@ void FpySequencer::dispatchDirective(const DirectiveUnion& directive, const Fpy: this->directive_stackCmd_internalInterfaceInvoke(directive.stackCmd); return; } + case Fpy::DirectiveId::PUSH_TIME: { + this->directive_pushTime_internalInterfaceInvoke(directive.pushTime); + return; + } } // coding err FW_ASSERT(0, static_cast(id)); diff --git a/Svc/FpySequencer/FpySequencerTypes.fpp b/Svc/FpySequencer/FpySequencerTypes.fpp index 09bdae0f71..68bc6841db 100644 --- a/Svc/FpySequencer/FpySequencerTypes.fpp +++ b/Svc/FpySequencer/FpySequencerTypes.fpp @@ -94,6 +94,7 @@ module Svc { MEMCMP = 65 STACK_CMD = 66 PUSH_TLM_VAL_AND_TIME = 67 + PUSH_TIME = 68 } struct Header { diff --git a/Svc/FpySequencer/docs/sdd.md b/Svc/FpySequencer/docs/sdd.md index 4ed8b87514..0c96a43e0d 100644 --- a/Svc/FpySequencer/docs/sdd.md +++ b/Svc/FpySequencer/docs/sdd.md @@ -95,4 +95,5 @@ The FpySequencer has a set of debugging commands which can be used to pause and | 64 | DISCARD | Discards bytes from the top of the stack | | 65 | MEMCMP | Compares two memory regions on the stack | | 66 | STACK_CMD | Dispatches a command with arguments from the stack | -| 67 | PUSH_TLM_VAL_AND_TIME | Gets a telemetry channel and pushes its value, and then its time, onto the stack | \ No newline at end of file +| 67 | PUSH_TLM_VAL_AND_TIME | Gets a telemetry channel and pushes its value, and then its time, onto the stack | +| 68 | PUSH_TIME | Pushes the current time, from the `timeCaller` port, to the stack | \ No newline at end of file diff --git a/Svc/FpySequencer/test/ut/FpySequencerTestMain.cpp b/Svc/FpySequencer/test/ut/FpySequencerTestMain.cpp index 9a40d00d27..9dcc038c45 100644 --- a/Svc/FpySequencer/test/ut/FpySequencerTestMain.cpp +++ b/Svc/FpySequencer/test/ut/FpySequencerTestMain.cpp @@ -996,6 +996,39 @@ TEST_F(FpySequencerTester, memCmp) { ASSERT_EQ(err, DirectiveError::STACK_ACCESS_OUT_OF_BOUNDS); } +TEST_F(FpySequencerTester, pushTime) { + FpySequencer_PushTimeDirective directive; + DirectiveError err = DirectiveError::NO_ERROR; + Fw::Time testTime(TimeBase::TB_WORKSTATION_TIME, 0, 100, 100); + setTestTime(testTime); + tester_get_m_runtime_ptr()->stackSize = 0; + Signal result = tester_pushTime_directiveHandler(directive, err); + ASSERT_EQ(tester_get_m_runtime_ptr()->stackSize, Fw::Time::SERIALIZED_SIZE); + ASSERT_EQ(result, Signal::stmtResponse_success); + ASSERT_EQ(err, DirectiveError::NO_ERROR); + + // make sure deser'd time is same as input time + Fw::Time deserTime; + Fw::ExternalSerializeBuffer esb(tester_get_m_runtime_ptr()->stack, Fw::Time::SERIALIZED_SIZE); + esb.setBuffLen(Fw::Time::SERIALIZED_SIZE); + ASSERT_EQ(esb.deserializeTo(deserTime), Fw::SerializeStatus::FW_SERIALIZE_OK); + ASSERT_EQ(deserTime, testTime); + clearHistory(); + + // check almost overflow + tester_get_m_runtime_ptr()->stackSize = Fpy::MAX_STACK_SIZE - Fw::Time::SERIALIZED_SIZE; + result = tester_pushTime_directiveHandler(directive, err); + ASSERT_EQ(result, Signal::stmtResponse_success); + ASSERT_EQ(tester_get_m_runtime_ptr()->stackSize, Fpy::MAX_STACK_SIZE); + ASSERT_EQ(err, DirectiveError::NO_ERROR); + + // check overflow + tester_get_m_runtime_ptr()->stackSize = Fpy::MAX_STACK_SIZE - Fw::Time::SERIALIZED_SIZE + 1; + result = tester_pushTime_directiveHandler(directive, err); + ASSERT_EQ(result, Signal::stmtResponse_failure); + ASSERT_EQ(err, DirectiveError::STACK_OVERFLOW); +} + TEST_F(FpySequencerTester, checkShouldWakeMismatchBase) { Fw::Time testTime(TimeBase::TB_WORKSTATION_TIME, 0, 100, 100); setTestTime(testTime); diff --git a/Svc/FpySequencer/test/ut/FpySequencerTester.cpp b/Svc/FpySequencer/test/ut/FpySequencerTester.cpp index ba44fffd08..23394e15e4 100644 --- a/Svc/FpySequencer/test/ut/FpySequencerTester.cpp +++ b/Svc/FpySequencer/test/ut/FpySequencerTester.cpp @@ -276,6 +276,10 @@ void FpySequencerTester::add_MEMCMP(FpySequencer_MemCmpDirective dir) { FW_ASSERT(buf.serializeFrom(dir) == Fw::SerializeStatus::FW_SERIALIZE_OK); addDirective(Fpy::DirectiveId::MEMCMP, buf); } +void FpySequencerTester::add_PUSH_TIME() { + Fw::StatementArgBuffer buf; + addDirective(Fpy::DirectiveId::PUSH_TIME, buf); +} //! Handle a text event void FpySequencerTester::textLogIn(FwEventIdType id, //!< The event ID const Fw::Time& timeTag, //!< The time @@ -406,6 +410,11 @@ Fw::Success FpySequencerTester::tester_deserializeDirective(const Fpy::Statement return this->cmp.deserializeDirective(stmt, deserializedDirective); } +Signal FpySequencerTester::tester_pushTime_directiveHandler(const FpySequencer_PushTimeDirective& directive, + DirectiveError& err) { + return this->cmp.pushTime_directiveHandler(directive, err); +} + Svc::Signal FpySequencerTester::tester_dispatchStatement() { return this->cmp.dispatchStatement(); } diff --git a/Svc/FpySequencer/test/ut/FpySequencerTester.hpp b/Svc/FpySequencer/test/ut/FpySequencerTester.hpp index 28e2543363..f636927519 100644 --- a/Svc/FpySequencer/test/ut/FpySequencerTester.hpp +++ b/Svc/FpySequencer/test/ut/FpySequencerTester.hpp @@ -111,6 +111,7 @@ class FpySequencerTester : public FpySequencerGTestBase, public ::testing::Test void add_STACK_CMD(FpySequencer_StackCmdDirective dir); void add_MEMCMP(Fpy::StackSizeType size); void add_MEMCMP(FpySequencer_MemCmpDirective dir); + void add_PUSH_TIME(); template void add_PUSH_VAL(T val); //! Handle a text event @@ -153,6 +154,7 @@ class FpySequencerTester : public FpySequencerGTestBase, public ::testing::Test Signal tester_discard_directiveHandler(const FpySequencer_DiscardDirective& directive, DirectiveError& err); Signal tester_stackCmd_directiveHandler(const FpySequencer_StackCmdDirective& directive, DirectiveError& err); Signal tester_memCmp_directiveHandler(const FpySequencer_MemCmpDirective& directive, DirectiveError& err); + Signal tester_pushTime_directiveHandler(const FpySequencer_PushTimeDirective& directive, DirectiveError& err); DirectiveError tester_op_or(); DirectiveError tester_op_and(); DirectiveError tester_op_ieq();