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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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