Add PUSH_TIME directive (#4275)

* Add push_time dir

* Add docs and UT

* format
This commit is contained in:
Zimri Leisher 2025-10-08 15:32:33 -05:00 committed by GitHub
parent 35840d549d
commit 896803ad20
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 102 additions and 2 deletions

View File

@ -61,6 +61,7 @@ class FpySequencer : public FpySequencerComponentBase {
FpySequencer_DiscardDirective discard; FpySequencer_DiscardDirective discard;
FpySequencer_MemCmpDirective memCmp; FpySequencer_MemCmpDirective memCmp;
FpySequencer_StackCmdDirective stackCmd; FpySequencer_StackCmdDirective stackCmd;
FpySequencer_PushTimeDirective pushTime;
DirectiveUnion() {} DirectiveUnion() {}
~DirectiveUnion() {} ~DirectiveUnion() {}
@ -473,6 +474,9 @@ class FpySequencer : public FpySequencerComponentBase {
//! Internal interface handler for directive_stackCmd //! Internal interface handler for directive_stackCmd
void directive_stackCmd_internalInterfaceHandler(const Svc::FpySequencer_StackCmdDirective& directive) override; 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 parametersLoaded() override;
void parameterUpdated(FwPrmIdType id) override; void parameterUpdated(FwPrmIdType id) override;
@ -747,6 +751,7 @@ class FpySequencer : public FpySequencerComponentBase {
Signal discard_directiveHandler(const FpySequencer_DiscardDirective& directive, DirectiveError& error); Signal discard_directiveHandler(const FpySequencer_DiscardDirective& directive, DirectiveError& error);
Signal memCmp_directiveHandler(const FpySequencer_MemCmpDirective& directive, DirectiveError& error); Signal memCmp_directiveHandler(const FpySequencer_MemCmpDirective& directive, DirectiveError& error);
Signal stackCmd_directiveHandler(const FpySequencer_StackCmdDirective& directive, DirectiveError& error); Signal stackCmd_directiveHandler(const FpySequencer_StackCmdDirective& directive, DirectiveError& error);
Signal pushTime_directiveHandler(const FpySequencer_PushTimeDirective& directive, DirectiveError& error);
}; };
} // namespace Svc } // namespace Svc

View File

@ -322,6 +322,13 @@ void FpySequencer::directive_stackCmd_internalInterfaceHandler(const Svc::FpySeq
handleDirectiveErrorCode(Fpy::DirectiveId::STACK_CMD, error); 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 //! Internal interface handler for directive_waitRel
Signal FpySequencer::waitRel_directiveHandler(const FpySequencer_WaitRelDirective& directive, DirectiveError& error) { Signal FpySequencer::waitRel_directiveHandler(const FpySequencer_WaitRelDirective& directive, DirectiveError& error) {
if (this->m_runtime.stackSize < 8) { if (this->m_runtime.stackSize < 8) {
@ -443,7 +450,7 @@ Signal FpySequencer::pushTlmValAndTime_directiveHandler(const FpySequencer_PushT
return Signal::stmtResponse_failure; 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::ExternalSerializeBuffer timeEsb(tlmTimeBuf, Fw::Time::SERIALIZED_SIZE);
Fw::SerializeStatus stat = timeEsb.serializeFrom(tlmTime); Fw::SerializeStatus stat = timeEsb.serializeFrom(tlmTime);
@ -1240,4 +1247,25 @@ Signal FpySequencer::stackCmd_directiveHandler(const FpySequencer_StackCmdDirect
return Signal::stmtResponse_success; 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<FwAssertArgType>(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<Fpy::StackSizeType>(timeEsb.getBuffLength());
return Signal::stmtResponse_success;
}
} // namespace Svc } // namespace Svc

View File

@ -113,6 +113,11 @@ struct StackCmdDirective {
argsSize: Fpy.StackSizeType 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_waitRel(directive: WaitRelDirective) priority 6 assert
internal port directive_waitAbs(directive: WaitAbsDirective) 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_stackCmd(directive: StackCmdDirective) priority 6 assert
internal port directive_pushTime(directive: PushTimeDirective) priority 6 assert
enum DirectiveErrorCode { enum DirectiveErrorCode {
NO_ERROR NO_ERROR
STMT_OUT_OF_BOUNDS STMT_OUT_OF_BOUNDS

View File

@ -348,6 +348,16 @@ Fw::Success FpySequencer::deserializeDirective(const Fpy::Statement& stmt, Direc
} }
break; 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: { default: {
// unsure what this opcode is. check compiler version matches sequencer // unsure what this opcode is. check compiler version matches sequencer
this->log_WARNING_HI_UnknownSequencerDirective(stmt.get_opCode(), this->currentStatementIdx(), 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); this->directive_stackCmd_internalInterfaceInvoke(directive.stackCmd);
return; return;
} }
case Fpy::DirectiveId::PUSH_TIME: {
this->directive_pushTime_internalInterfaceInvoke(directive.pushTime);
return;
}
} }
// coding err // coding err
FW_ASSERT(0, static_cast<FwAssertArgType>(id)); FW_ASSERT(0, static_cast<FwAssertArgType>(id));

View File

@ -94,6 +94,7 @@ module Svc {
MEMCMP = 65 MEMCMP = 65
STACK_CMD = 66 STACK_CMD = 66
PUSH_TLM_VAL_AND_TIME = 67 PUSH_TLM_VAL_AND_TIME = 67
PUSH_TIME = 68
} }
struct Header { struct Header {

View File

@ -96,3 +96,4 @@ The FpySequencer has a set of debugging commands which can be used to pause and
| 65 | MEMCMP | Compares two memory regions on the stack | | 65 | MEMCMP | Compares two memory regions on the stack |
| 66 | STACK_CMD | Dispatches a command with arguments from 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 | | 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 |

View File

@ -996,6 +996,39 @@ TEST_F(FpySequencerTester, memCmp) {
ASSERT_EQ(err, DirectiveError::STACK_ACCESS_OUT_OF_BOUNDS); 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) { TEST_F(FpySequencerTester, checkShouldWakeMismatchBase) {
Fw::Time testTime(TimeBase::TB_WORKSTATION_TIME, 0, 100, 100); Fw::Time testTime(TimeBase::TB_WORKSTATION_TIME, 0, 100, 100);
setTestTime(testTime); setTestTime(testTime);

View File

@ -276,6 +276,10 @@ void FpySequencerTester::add_MEMCMP(FpySequencer_MemCmpDirective dir) {
FW_ASSERT(buf.serializeFrom(dir) == Fw::SerializeStatus::FW_SERIALIZE_OK); FW_ASSERT(buf.serializeFrom(dir) == Fw::SerializeStatus::FW_SERIALIZE_OK);
addDirective(Fpy::DirectiveId::MEMCMP, buf); addDirective(Fpy::DirectiveId::MEMCMP, buf);
} }
void FpySequencerTester::add_PUSH_TIME() {
Fw::StatementArgBuffer buf;
addDirective(Fpy::DirectiveId::PUSH_TIME, buf);
}
//! Handle a text event //! Handle a text event
void FpySequencerTester::textLogIn(FwEventIdType id, //!< The event ID void FpySequencerTester::textLogIn(FwEventIdType id, //!< The event ID
const Fw::Time& timeTag, //!< The time const Fw::Time& timeTag, //!< The time
@ -406,6 +410,11 @@ Fw::Success FpySequencerTester::tester_deserializeDirective(const Fpy::Statement
return this->cmp.deserializeDirective(stmt, deserializedDirective); 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() { Svc::Signal FpySequencerTester::tester_dispatchStatement() {
return this->cmp.dispatchStatement(); return this->cmp.dispatchStatement();
} }

View File

@ -111,6 +111,7 @@ class FpySequencerTester : public FpySequencerGTestBase, public ::testing::Test
void add_STACK_CMD(FpySequencer_StackCmdDirective dir); void add_STACK_CMD(FpySequencer_StackCmdDirective dir);
void add_MEMCMP(Fpy::StackSizeType size); void add_MEMCMP(Fpy::StackSizeType size);
void add_MEMCMP(FpySequencer_MemCmpDirective dir); void add_MEMCMP(FpySequencer_MemCmpDirective dir);
void add_PUSH_TIME();
template <typename T> template <typename T>
void add_PUSH_VAL(T val); void add_PUSH_VAL(T val);
//! Handle a text event //! 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_discard_directiveHandler(const FpySequencer_DiscardDirective& directive, DirectiveError& err);
Signal tester_stackCmd_directiveHandler(const FpySequencer_StackCmdDirective& 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_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_or();
DirectiveError tester_op_and(); DirectiveError tester_op_and();
DirectiveError tester_op_ieq(); DirectiveError tester_op_ieq();