-
Notifications
You must be signed in to change notification settings - Fork 1.4k
FpySequencer 0.2 #3552
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FpySequencer 0.2 #3552
Conversation
There was a problem hiding this 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.
this->tlmWrite_Debug(this->getDebugTelemetry()); | ||
} | ||
|
||
FpySequencer_DebugTelemetry FpySequencer::getDebugTelemetry() { |
Check notice
Code scanning / CodeQL
Long function without assertion Note
FpySequencer_IfDirective ifDirective; | ||
FpySequencer_NoOpDirective noOp; | ||
|
||
DirectiveUnion() {} |
Check notice
Code scanning / CodeQL
More than one statement per line Note
FpySequencer_NoOpDirective noOp; | ||
|
||
DirectiveUnion() {} | ||
~DirectiveUnion() {} |
Check notice
Code scanning / CodeQL
More than one statement per line Note
return Fw::Success::FAILURE; | ||
} | ||
} | ||
return Fw::Success::SUCCESS; | ||
} | ||
|
||
// dispatches a deserialized sequencer directive to the right handler. | ||
// return success if successfully handled. | ||
void FpySequencer::dispatchDirective(const DirectiveUnion& directive, const Fpy::DirectiveId& id) { |
Check notice
Code scanning / CodeQL
Long function without assertion Note
return Fw::Success::SUCCESS; | ||
} | ||
|
||
Fw::Success FpySequencer::readHeader() { |
Check notice
Code scanning / CodeQL
Long function without assertion Note
return Fw::Success::FAILURE; | ||
} | ||
|
||
Fw::Success FpySequencer::readBody() { |
Check notice
Code scanning / CodeQL
Long function without assertion Note
} | ||
|
||
deserStatus = this->m_sequenceBuffer.deserialize(this->m_sequenceObj.getfooter()); | ||
Fw::Success FpySequencer::readFooter() { |
Check notice
Code scanning / CodeQL
Long function without assertion Note
// return true if successful | ||
Fw::Success FpySequencer::readBytes(Os::File& file, FwSizeType readLen, bool updateCRC) { | ||
// return success if successful | ||
Fw::Success FpySequencer::readBytes(Os::File& file, FwSizeType expectedReadLen, bool updateCrc) { |
Check notice
Code scanning / CodeQL
Long function without assertion Note
m_runtime(), | ||
m_tlm() | ||
{} | ||
FpySequencer ::FpySequencer(const char* const compName) |
Check notice
Code scanning / CodeQL
Long function without assertion Note
m_statementsDispatched(0), | ||
m_runtime(), | ||
m_debug(), | ||
m_tlm() {} |
Check notice
Code scanning / CodeQL
More than one statement per line Note
//! Pauses the execution of the sequencer once, just before it is about to dispatch the next statement, | ||
//! until unpaused by the DEBUG_CONTINUE command. This command is only valid in the RUNNING state. | ||
//! Debug settings are cleared after a sequence ends execution. | ||
void FpySequencer::DEBUG_BREAK_cmdHandler(FwOpcodeType opCode, //!< The opcode |
Check notice
Code scanning / CodeQL
Long function without assertion Note
//! | ||
//! Continues the execution of the sequence after it has been paused by a debug break. This command | ||
//! is only valid in the RUNNING.DEBUG_BROKEN state. | ||
void FpySequencer::DEBUG_CONTINUE_cmdHandler(FwOpcodeType opCode, //!< The opcode |
Check notice
Code scanning / CodeQL
Long function without assertion Note
@LeStarch this is ready for review |
::testing::InitGoogleTest(&argc, argv); | ||
return RUN_ALL_TESTS(); | ||
} | ||
} |
Check warning
Code scanning / CppCheck
Could not find a newline character at the end of the file. Warning test
ASSERT_CMD_RESPONSE(0, FpySequencer::OPCODE_RUN, 0, Fw::CmdResponse::OK); | ||
} | ||
|
||
} |
Check warning
Code scanning / CppCheck
Could not find a newline character at the end of the file. Warning test
I transitioned all the UTs to using test fixtures. Not sure why we aren't doing this normally. This reduces the number of needed files and boilerplate. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The biggest design issue I see is type-safety of local variables. Right now that buffer could contain anything. Consider adding a type enumeration to each, using PolyType, or some other update to allow for not implicitly changing types.
I'd also like to understand more about how you are using UT fixtures.
Otherwise, the implementation and changes look really solid.
return; | ||
} | ||
this->sequencer_sendSignal_cmd_DEBUG_BREAK( | ||
FpySequencer_DebugBreakpointArgs(true, breakOnce, this->m_runtime.nextStatementIndex)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Follow-Up: can we have a ships passing in the night scenario?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow you got me I don't know what that is but it sounds interesting
when we do lvar allocation:
big question: probably thinking about changing to stack based only? if you have functions, you probably need a function call stack. and if you have a call stack, you might as well use it |
@zimri-leisher I Agree with with your responses. Just need to resolve the last two. Was the last comment for this iteration (as there are no functions yet). |
@LeStarch standby on responses to your last two questions. Yes, the last comment is for the next version of FpySequencer. @LeStarch @timcanham I'm going to put one more feature in this PR as it was rather quick to develop and adds a huge amount of functionality: getting telemetry channel time tags and values. This is a top priority for my team, I hope you won't mind the scope creep. I still think we can get this merged by May 20th.
|
Another question: |
Another question: EDIT--I went ahead and implemented this ^ |
Also while I'm at it I added GET_PRM_VAL. I apologize for the scope creep but these were features I'd already developed on a separate branch and adding them in this PR means we can actually start using this sequencer for non-trivial things! At the moment, all you can do is IF conditions with boolean tlm/prms, but that's enough to really start to hook the sequencer into the wider fprime system. Promise that's it for scope creep. |
Note: |
|
@zimri-leisher added some comments. Almost all were repeating your above todos. You should also merge in the base branch, as configuration changed. |
@LeStarch all feedback is complete I believe. Ready for merge |
return Signal::stmtResponse_success; | ||
} | ||
|
||
Signal FpySequencer::getTlm_directiveHandler(const FpySequencer_GetTlmDirective& directive) { |
Check notice
Code scanning / CodeQL
Long function without assertion Note
return Signal::stmtResponse_success; | ||
} | ||
|
||
Signal FpySequencer::getPrm_directiveHandler(const FpySequencer_GetPrmDirective& directive) { |
Check notice
Code scanning / CodeQL
Long function without assertion Note
@@ -56,31 +58,81 @@ | |||
this->pingOut_out(0, key); | |||
} | |||
|
|||
void TlmChan::TlmGet_handler(FwIndexType portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val) { | |||
Fw::TlmValid TlmChan::TlmGet_handler(FwIndexType portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val) { |
Check notice
Code scanning / CodeQL
Long function without assertion Note
@@ -56,31 +58,81 @@ | |||
this->pingOut_out(0, key); | |||
} | |||
|
|||
void TlmChan::TlmGet_handler(FwIndexType portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val) { | |||
Fw::TlmValid TlmChan::TlmGet_handler(FwIndexType portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val) { |
Check notice
Code scanning / CodeQL
Function too long Note
this->m_lock.unLock(); | ||
} | ||
} | ||
} | ||
|
||
//! Handler for input port TlmGet | ||
Fw::TlmValid TlmPacketizer ::TlmGet_handler(FwIndexType portNum, //!< The port number |
Check notice
Code scanning / CodeQL
Long function without assertion Note
this->m_lock.unLock(); | ||
} | ||
} | ||
} | ||
|
||
//! Handler for input port TlmGet | ||
Fw::TlmValid TlmPacketizer ::TlmGet_handler(FwIndexType portNum, //!< The port number |
Check notice
Code scanning / CodeQL
Function too long Note
FpySequencer_WaitAbsDirective directive; | ||
status = argBuf.deserialize(directive); | ||
new (&deserializedDirective.waitAbs) FpySequencer_WaitAbsDirective(); | ||
status = argBuf.deserialize(deserializedDirective.waitAbs); | ||
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; | ||
} | ||
case Fpy::DirectiveId::SET_LVAR: { | ||
// set local var has some custom deserialization behavior | ||
// we don't write a custom class for it though because that deserialization behavior only | ||
// applies for the initial time we deserialize it out of the statement | ||
|
||
// the behavior in question is that it will grab the entire remaining part of the statement | ||
// arg buf. that is, it uses the remaining length of the statement arg buf to determine the length | ||
// of its value buf. this way we get to save on serializing the value length | ||
|
||
// TODO do some trades on the best way to do this. not confident on this one | ||
|
||
// first deserialize the index | ||
U8 index; | ||
status = argBuf.deserialize(index); | ||
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; | ||
} | ||
|
||
new (&deserializedDirective.setLVar) FpySequencer_SetLocalVarDirective(); | ||
deserializedDirective.setLVar.setindex(index); | ||
|
||
// okay, now deserialize the remaining bytes in the stmt arg buf into the value buf | ||
|
||
// how many bytes are left? | ||
FwSizeType valueSize = argBuf.getBuffLeft(); | ||
|
||
// check to make sure the value will fit in the FpySequencer_SetLocalVarDirective::value buf | ||
if (valueSize > 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.setLVar.getvalue(), valueSize, 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.setLVar.set_valueSize(valueSize); | ||
break; | ||
} | ||
case Fpy::DirectiveId::GOTO: { | ||
new (&deserializedDirective.gotoDirective) FpySequencer_GotoDirective(); | ||
status = argBuf.deserialize(deserializedDirective.gotoDirective); | ||
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; | ||
} | ||
case Fpy::DirectiveId::IF: { | ||
new (&deserializedDirective.ifDirective) FpySequencer_IfDirective(); | ||
status = argBuf.deserialize(deserializedDirective.ifDirective); | ||
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; | ||
} | ||
case Fpy::DirectiveId::NO_OP: { | ||
new (&deserializedDirective.noOp) FpySequencer_NoOpDirective(); | ||
// no op does not need deser | ||
if (argBuf.getBuffLeft() != 0) { | ||
this->log_WARNING_HI_DirectiveDeserializeError(stmt.getopCode(), this->m_runtime.nextStatementIndex - 1, | ||
Fw::SerializeStatus::FW_DESERIALIZE_SIZE_MISMATCH, | ||
argBuf.getBuffLeft(), argBuf.getBuffLength()); | ||
return Fw::Success::FAILURE; | ||
} | ||
break; | ||
} | ||
case Fpy::DirectiveId::GET_TLM: { | ||
new (&deserializedDirective.getTlm) FpySequencer_GetTlmDirective(); | ||
status = argBuf.deserialize(deserializedDirective.getTlm); | ||
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()); |
Check notice
Code scanning / CodeQL
Long switch case Note
SET_LVAR (51 lines)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the expected changes!
@timcanham would you please review the changes to Svc/Tlm*
Also, please agree/disagree with the algorithm of "comparable":
- If time comparable, return newest by time
- If time incomparable, return "updated"
- If neither updated the return "active" buffer for lack of a better choice.
Note: this algorithm only runs when both buffers are valid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor findings that could be done on the next release, but nothing broken that I can see.
@ Size set to 0 if channel not found, or if no value | ||
@ has been received for this channel yet. | ||
ref val: Fw.TlmBuffer | ||
) -> Fw.TlmValid |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a note describing what conditions return INVALID
Change Description
Local variables
New commands
New directives
Misc