Skip to content

FpySequencer V0.3#3702

Merged
LeStarch merged 27 commits intonasa:develfrom
zimri-leisher:3516-fpy-v03
Jun 26, 2025
Merged

FpySequencer V0.3#3702
LeStarch merged 27 commits intonasa:develfrom
zimri-leisher:3516-fpy-v03

Conversation

@zimri-leisher
Copy link
Collaborator

@zimri-leisher zimri-leisher commented Jun 6, 2025

Related Issue(s) #3615
Has Unit Tests (y/n) y
Documentation Included (y/n) y

Change Description

  • This PR adds registers, and several new directives for interacting with the registers.
    • Each register is an 8 byte array, meant to store an integer or floating point value.
    • Binary comparison directives
      • OR/AND/NOT do bitwise ops on registers
      • A full set of inequality/equality operators allow you to compare numeric values in registers
    • EXIT directive
      • Allows for early completion of sequence, with either failure or success status
    • DESER_SER_REG directives
      • Allows pulling a value from an sreg into a reg. Used to grab specific parts of tlm chan structs
    • SET_REG directive
      • sets a register to a constant value
  • This PR also combines commands and directives. Now, instead of those being separate things, commands are just instances of the "CMD" directive. This saves space in the file and simplifies the code a bit.
  • "local variable" is renamed to "serializable register"
  • TODO rename "register" to something more specific
  • IF directive branches off of a register instead of sreg
  • Add DirectiveError codes, which let you diagnose the specific reason why a sequence failed at a bytecode level. Useful for debugging the sequencer

Copy link

@github-advanced-security github-advanced-security bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

Comment on lines +106 to +217
case Fpy::DirectiveId::CMD: {
new (&deserializedDirective.cmd) FpySequencer_CmdDirective();
// same deserialization behavior as SET_LVAR

// first deserialize the opcode
FwOpcodeType opcode;
status = argBuf.deserialize(opcode);
if (status != Fw::SerializeStatus::FW_SERIALIZE_OK) {
this->log_WARNING_HI_DirectiveDeserializeError(stmt.getopCode(), this->m_runtime.nextStatementIndex - 1,
status, argBuf.getBuffLeft(), argBuf.getBuffLength());
return Fw::Success::FAILURE;
}

deserializedDirective.cmd.setopCode(opcode);
// how many bytes are left?
FwSizeType cmdArgBufSize = argBuf.getBuffLeft();

// check to make sure the value will fit in the FpySequencer_CmdDirective::argBuf
if (cmdArgBufSize > Fpy::MAX_LOCAL_VARIABLE_BUFFER_SIZE) {
this->log_WARNING_HI_DirectiveDeserializeError(stmt.getopCode(), this->m_runtime.nextStatementIndex - 1,
Fw::SerializeStatus::FW_DESERIALIZE_FORMAT_ERROR,
argBuf.getBuffLeft(), argBuf.getBuffLength());
return Fw::Success::FAILURE;
}

// okay, it will fit. put it in
status = argBuf.deserialize(deserializedDirective.cmd.getargBuf(), cmdArgBufSize, true);

if (status != Fw::SerializeStatus::FW_SERIALIZE_OK) {
this->log_WARNING_HI_DirectiveDeserializeError(stmt.getopCode(), this->m_runtime.nextStatementIndex - 1,
status, argBuf.getBuffLeft(), argBuf.getBuffLength());
return Fw::Success::FAILURE;
}

// now there should be nothing left, otherwise coding err
FW_ASSERT(argBuf.getBuffLeft() == 0, static_cast<FwAssertArgType>(argBuf.getBuffLeft()));

// and set the buf size now that we know it
deserializedDirective.cmd.set_argBufSize(cmdArgBufSize);
break;
}
// fallthrough on purpose
case Fpy::DirectiveId::DESER_LVAR_8:
case Fpy::DirectiveId::DESER_LVAR_4:
case Fpy::DirectiveId::DESER_LVAR_2:
case Fpy::DirectiveId::DESER_LVAR_1: {
new (&deserializedDirective.deserLocalVar) FpySequencer_DeserLocalVarDirective();

U8 deserSize;

if (stmt.getopCode() == Fpy::DirectiveId::DESER_LVAR_1) {
deserSize = 1;
} else if (stmt.getopCode() == Fpy::DirectiveId::DESER_LVAR_2) {
deserSize = 2;
} else if (stmt.getopCode() == Fpy::DirectiveId::DESER_LVAR_4) {
deserSize = 4;
} else if (stmt.getopCode() == Fpy::DirectiveId::DESER_LVAR_8) {
deserSize = 8;
} else {
FW_ASSERT(0, static_cast<FwAssertArgType>(stmt.getopCode()));
return Fw::Success::FAILURE;
}

deserializedDirective.deserLocalVar.set_deserSize(deserSize);

U8 srcLvarIdx;
status = argBuf.deserialize(srcLvarIdx);
if (status != Fw::SerializeStatus::FW_SERIALIZE_OK) {
this->log_WARNING_HI_DirectiveDeserializeError(stmt.getopCode(), this->m_runtime.nextStatementIndex - 1,
status, argBuf.getBuffLeft(), argBuf.getBuffLength());
return Fw::Success::FAILURE;
}
deserializedDirective.deserLocalVar.setsrcLvarIdx(srcLvarIdx);

FwSizeType srcOffset;
status = argBuf.deserialize(srcOffset);
if (status != Fw::SerializeStatus::FW_SERIALIZE_OK) {
this->log_WARNING_HI_DirectiveDeserializeError(stmt.getopCode(), this->m_runtime.nextStatementIndex - 1,
status, argBuf.getBuffLeft(), argBuf.getBuffLength());
return Fw::Success::FAILURE;
}
deserializedDirective.deserLocalVar.setsrcOffset(srcOffset);

U8 destReg;
status = argBuf.deserialize(destReg);
if (status != Fw::SerializeStatus::FW_SERIALIZE_OK || argBuf.getBuffLeft() != 0) {
this->log_WARNING_HI_DirectiveDeserializeError(stmt.getopCode(), this->m_runtime.nextStatementIndex - 1,
status, argBuf.getBuffLeft(), argBuf.getBuffLength());
return Fw::Success::FAILURE;
}
deserializedDirective.deserLocalVar.setdestReg(destReg);
break;
}
case Fpy::DirectiveId::SET_REG: {
new (&deserializedDirective.setReg) FpySequencer_SetRegDirective();
status = argBuf.deserialize(deserializedDirective.setReg);
if (status != Fw::SerializeStatus::FW_SERIALIZE_OK || argBuf.getBuffLeft() != 0) {
this->log_WARNING_HI_DirectiveDeserializeError(stmt.getopCode(), this->m_runtime.nextStatementIndex - 1,
status, argBuf.getBuffLeft(), argBuf.getBuffLength());
return Fw::Success::FAILURE;
}
break;
}
// fallthrough on purpose
case Fpy::DirectiveId::OR:
case Fpy::DirectiveId::AND:
case Fpy::DirectiveId::EQ:
case Fpy::DirectiveId::NE:
case Fpy::DirectiveId::UGT:
case Fpy::DirectiveId::ULT:
case Fpy::DirectiveId::ULE:
case Fpy::DirectiveId::UGE:

Check notice

Code scanning / CodeQL

Long switch case Note

Switch has at least one case that is too long:
SET_LVAR (51 lines)
.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is legitimate. We should track this as a fix for the future.

|| directive.getres() >= Fpy::NUM_REGISTERS) {
error = DirectiveError::REGISTER_OUT_OF_BOUNDS;
return Signal::stmtResponse_failure;
}

Check notice

Code scanning / CodeQL

Long function without assertion Note

All functions of more than 10 lines should have at least one assertion.
|| directive.getres() >= Fpy::NUM_REGISTERS) {
error = DirectiveError::REGISTER_OUT_OF_BOUNDS;
return Signal::stmtResponse_failure;
}

Check notice

Code scanning / CodeQL

Function too long Note

binaryCmp_directiveHandler has too many lines (81, while 60 are allowed).
Signal FpySequencer::not_directiveHandler(const FpySequencer_NotDirective& directive, DirectiveError& error) {
if (directive.getsrc() >= Fpy::NUM_REGISTERS
|| directive.getres() >= Fpy::NUM_REGISTERS) {
error = DirectiveError::REGISTER_OUT_OF_BOUNDS;

Check notice

Code scanning / CodeQL

Long function without assertion Note

All functions of more than 10 lines should have at least one assertion.
Signal FpySequencer::setLocalVar_directiveHandler(const FpySequencer_SetLocalVarDirective& directive) {
if (directive.getindex() >= Fpy::MAX_SEQUENCE_LOCAL_VARIABLES) {
//! Internal interface handler for directive_setSerReg
Signal FpySequencer::setSerReg_directiveHandler(const FpySequencer_SetSerRegDirective& directive, DirectiveError& error) {

Check notice

Code scanning / CodeQL

Long function without assertion Note

All functions of more than 10 lines should have at least one assertion.
lvar.valueSize = prmValue.getBuffLength();
// copy value into serReg
Runtime::SerializableReg& serReg = this->m_runtime.serRegs[directive.getdestSerRegIndex()];
memcpy(serReg.value, prmValue.getBuffAddr(), static_cast<size_t>(prmValue.getBuffLength()));

Check notice

Code scanning / CodeQL

Long function without assertion Note

All functions of more than 10 lines should have at least one assertion.

Signal FpySequencer::deserSerReg_directiveHandler(const FpySequencer_DeserSerRegDirective& directive, DirectiveError& error) {
if (directive.getsrcSerRegIdx() >= Fpy::NUM_SERIALIZABLE_REGISTERS) {
error = DirectiveError::SER_REG_OUT_OF_BOUNDS;

Check notice

Code scanning / CodeQL

Long function without assertion Note

All functions of more than 10 lines should have at least one assertion.
@zimri-leisher zimri-leisher requested a review from LeStarch June 23, 2025 04:06
@zimri-leisher zimri-leisher marked this pull request as ready for review June 23, 2025 04:06
// values of unspecified type
I64 registers[Fpy::NUM_REGISTERS] = {0};

// local var -> local array, scratch array
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo delete

}

if (conditional) {
if (reg(directive.getconditionalReg())) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if dir uses registers now

return Signal::stmtResponse_failure;
}

// TODO can I use htons/htonl? this code could be way simpler
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd like to do this. are we allowed to use htons/htonl? or is that a linux/posix thing and we don't want to restrict?

::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
} No newline at end of file
// int main(int argc, char** argv) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function wasn't necessary, you can remove it from all fprime components i believe

@zimri-leisher
Copy link
Collaborator Author

Todo remove all references to the word "statement", replace with "directive"

@zimri-leisher
Copy link
Collaborator Author

@LeStarch this is ready for review

@zimri-leisher zimri-leisher self-assigned this Jun 24, 2025
@LeStarch
Copy link
Collaborator

@zimri-leisher is this ready for review?

@zimri-leisher
Copy link
Collaborator Author

@LeStarch this is ready for review

yep!

Zimri Leisher added 2 commits June 26, 2025 11:47
}

} // namespace Svc

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am pretty sure this is necessary....no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no don't believe so, gtest adds it automatically i think

struct CmdDirective {
opCode: FwOpcodeType
@ the arg buf of the cmd
# TODO please don't let me merge this. need to find a better const here
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This statement is specifically telling me to block the merge.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes because I wanted to discuss... how big should the size of the cmd arg buf be in Fpy? I can't reference the FPrime CMD_ARG_BUF_MAX_SIZE because it's a #define constant. For now I'm using the size of the serializable registers

@LeStarch LeStarch merged commit 50d3d4e into nasa:devel Jun 26, 2025
53 of 54 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants