Skip to content
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

Add sequence dispatcher component #2731

Merged
merged 16 commits into from
Sep 18, 2024

Conversation

zimri-leisher
Copy link
Collaborator

@zimri-leisher zimri-leisher commented May 13, 2024

Related Issue(s) #2608 #2729
Has Unit Tests (y/n) Y
Documentation Included (y/n) Y

Change Description

This PR adds a SeqDispatcher component to Svc which allows command sequences to be automatically distributed among CmdSequencers.

Rationale

CmdSequencers only support running a single command sequence at a time. For complex missions, this necessitates having multiple CmdSequencers. However, without SeqDispatcher, ground operators would have to manually keep track of which CmdSequencers are currently being used. SeqDispatcher automates this process.

Testing/Review Recommendations

This is ported from an internal fork of FPrime which is a few versions out of date. Special care should be taken to make sure that the code seen here is up-to-date with the rest of FPrime. Also, probably should make much more in-depth unit tests.

Future Work

Closes #2729

@zimri-leisher
Copy link
Collaborator Author

zimri-leisher commented May 13, 2024

Hello,
This is a very WIP PR for the SeqDispatcher. Eager to iterate on it with the maintainers and other members of the community!
At the moment all functionality works and some basic testing has been implemented. I had to make some very small changes to CmdSequencer to notify this component when a sequence starts, so that this component can keep track of which sequencers are busy.

Copy link
Contributor

@Joshua-Anderson Joshua-Anderson left a comment

Choose a reason for hiding this comment

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

This is fantastic @zimri-leisher! Looks like the exact architecture I would have recommended. I threw in a few minor comments for consideration

Svc/SeqDispatcher/SeqDispatcher.fpp Outdated Show resolved Hide resolved
Svc/SeqDispatcher/SeqDispatcher.cpp Outdated Show resolved Hide resolved
Copy link
Collaborator

@LeStarch LeStarch left a comment

Choose a reason for hiding this comment

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

In general, I am impressed! I'll ask @timcanham to look over it too.

Svc/CmdSequencer/CmdSequencerImpl.hpp Show resolved Hide resolved
Svc/SeqDispatcher/CMakeLists.txt Outdated Show resolved Hide resolved
Svc/SeqDispatcher/CMakeLists.txt Outdated Show resolved Hide resolved
Svc/SeqDispatcher/SeqDispatcher.cpp Outdated Show resolved Hide resolved
Svc/SeqDispatcher/SeqDispatcherCommands.fppi Outdated Show resolved Hide resolved
@LeStarch
Copy link
Collaborator

@timcanham want to take a look, it is a sequence dispatcher!

@zimri-leisher
Copy link
Collaborator Author

Thanks for all the comments. Sorry that there are a lot of things that are idiomatic to our code that I didn't remove from here, but honestly part of the reason why I wanted to put this in front of you guys was to get exactly this feedback.

I have a question: where would you recommend storing the CmdSequencerState enum and CMD_SEQUENCERS_COUNT const? Should I make a new .fpp file inside of Svc/SeqDispatcher? What should I call it, if so?

@Joshua-Anderson
Copy link
Contributor

Joshua-Anderson commented May 14, 2024

Since CMD_SEQUENCERS_COUNT/SeqDispatcherSequencerCount is a per deployment config option, I'd add a SeqDispatcherCfg.fpp file with this constant to config/, similar to DpCfg.fpp. If you wanted to share CmdSequencerState between CmdSequencer and SeqDispatcher, I might add the enum type to the same file.

@Joshua-Anderson
Copy link
Contributor

Err, since we don't want folks to modify CmdSequencerState, config/ probably isn't the right home for it. Fw/Types/Types.fpp is where we store common types but this is a bit too specific for that. What about using FW::Wait instead of a custom command sequencer enum?

@zimri-leisher
Copy link
Collaborator Author

Alright to the SeqDispatcherCfg.fpp file, will do

With regards to using Fw::Wait, I'd prefer not to, as CmdSequencerState has three values instead of two: AVAILABLE, RUNNING_BLOCK, and RUNNING_NO_BLOCK. I also see a relatively low cost to creating a new enum for this. What I'm realizing right now as I write this is that it should just be an enum internal to the .hpp/.cpp files, because it's not used in the fpp at all.

@Joshua-Anderson
Copy link
Contributor

Joshua-Anderson commented May 14, 2024

@zimri-leisher my bad, I got CmdSequencerState and Svc.CmdSequencer.BlockState confnused.

For component internal enums, you can either add it in the hpp as you suggested, or add it as a standalone type to the SeqDispatcher.fpp file.

The concern we were discussing does arise for the Svc.CmdSequencer.BlockState enum. I'm not sure we want SeqDispatcher to depend on CmdSequencer, since we may want to leave open the option for folks to replace CmdSequencer with their own component.

@zimri-leisher
Copy link
Collaborator Author

Good point, maybe I should change the argument of the RUN command to just take a boolean: blocking or non-blocking. No need for a two-valued enum to exist when we have bools I guess :P

@Joshua-Anderson
Copy link
Contributor

I'd recommend using an enum like FW:Wait (WAIT and NO_WAIT) instead of a bool, because that can make the sequence files more readable SeqDispatch.Run "/myseq.bin", WAIT vs SeqDispatch.Run "/myseq.bin", TRUE

I'd be curious to get folks opinion on what is the clearest.... WAIT/NO_WAIT, BLOCK/NO_BLOCK, TRUE/FALSE

@timcanham
Copy link
Collaborator

IMHO not TRUE/FALSE for the reasons @Joshua-Anderson says, WAIT/NO_WAIT seems a little more understandable in plain English.

@zimri-leisher
Copy link
Collaborator Author

Ok, will make these changes. However just want to mention that I'm out of office for 2 weeks starting this Friday so they might not happen until then.
I have another question which is related to this PR and also our implementation of complex logic in sequences. Not sure where best to ask it so I'll ask it here:

The idea of this PR is that you shouldn't have to know which sequencer you're running a sequence on ahead of time. However, this means that commands inside of the sequence file don't know either. This is a problem if these commands want to modify something about the sequencer--in our case, we want to change which line the sequencer is on based on some runtime criteria inside of a command.

Is there some way that a command handler can tell from which sequencer a command came from? This would solve my problem. I couldn't find a way and so came up with a really gross solution. Hoping one of you has some input on this.

@Joshua-Anderson
Copy link
Contributor

Joshua-Anderson commented May 16, 2024

This is a problem if these commands want to modify something about the sequencer--in our case, we want to change which line the sequencer is on based on some runtime criteria inside of a command.

The way I've seen this approached on past missions is a concept of sequence directives. Effectively these are special commands/opcodes that are only valid within a command sequence, and they dispatch a command to the command sequencer executing the sequence.

Ex: SEQ_WAIT 10 sequence diretive within a command sequence would execute a command on the command sequencer executing the sequence to delay 10 seconds until the next command.

Fprime doesn't have any concept of sequence directives yet, but it's something on our roadmap that we want to add. It probably requires a change to the sequence binary format to add a flag indicating if the "command" opcode is a standard fprime command or if it should be dispatched as a sequence directive instead.

What do you think about a sequence directive approach? Would that solve your use cases?

Have a fantastic vacation and no rush at all on this pull request!

@zimri-leisher
Copy link
Collaborator Author

zimri-leisher commented May 16, 2024

That is kind of what I'm doing, only my solution is hackier. I made a component called GenericSequencer which only has empty commands inside of it. Whenever a real sequencer sees a command from a GenericSequencer (it checks this by deserializing the command, and checking if the opcode is equal to one of the known commands in a generic sequencer), it edits the command packet opcode to instead be the opcode from its own command.
Any pitfalls you can see with this approach? I'm kind of afraid of doing it because messing around with binary packets is not where I want to be, but as far as I can tell it's the most seamless way of doing it.

@Joshua-Anderson
Copy link
Contributor

Joshua-Anderson commented May 16, 2024

@zimri-leisher Yep, very similar approach. Only pitfall is that is it adds commands in your dictionary that you never want to send from the ground. Sequence directives are a slightly cleaner way of accomplishing the same thing.

I think your approach will work well and as a future improvement we can work on the design and implementation of sequence directives for fprime. I'll make sure you get tagged in the github discussions on the topic once we get started.

@zimri-leisher
Copy link
Collaborator Author

zimri-leisher commented Jul 25, 2024

Well, I took my time, but I'm back and gonna get this merged. Just pushed some changes to allow the code to build, and incorporated all of your feedback so far.

What's the best way to add my name to the allowed words list? It's failing on spell check lol

@zimri-leisher zimri-leisher changed the title [DRAFT] Add sequence dispatcher component Add sequence dispatcher component Jul 25, 2024
@thomas-bc
Copy link
Collaborator

@zimri-leisher you can add words that aren't recognized to the https://github.com/nasa/fprime/blob/devel/.github/actions/spelling/expect.txt

@zimri-leisher
Copy link
Collaborator Author

Any help on this error?
image
/workspaces/fprime/fprime/build-fprime-automatic-native-ut/F-Prime/Svc/SeqDispatcher/SeqDispatcherTesterBase.cpp:1170:5: error: no matching function for call to ‘Fw::String::String(Fw::String&)’

Looks like I can fix it by removing explicit from this line in String.hpp:
image

@thomas-bc
Copy link
Collaborator

@zimri-leisher could using the FileNameString type help?

@zimri-leisher
Copy link
Collaborator Author

It seems the problem was that the (previously unused) CmdSeqIn port took in a string like ref filename: Fw.String instead of filename: string size X
Once I fixed it, the unit test compilation errors went away.

Svc/SeqDispatcher/SeqDispatcher.cpp Fixed Show fixed Hide fixed
Svc/SeqDispatcher/SeqDispatcher.cpp Fixed Show fixed Hide fixed
Svc/SeqDispatcher/SeqDispatcher.cpp Dismissed Show dismissed Hide dismissed
Svc/SeqDispatcher/SeqDispatcher.cpp Fixed Show fixed Hide fixed
Svc/SeqDispatcher/SeqDispatcher.cpp Fixed Show fixed Hide fixed
Svc/SeqDispatcher/SeqDispatcher.cpp Fixed Show fixed Hide fixed
}

//! Handler for input port seqRunIn
void SeqDispatcher::seqRunIn_handler(NATIVE_INT_TYPE portNum,

Check notice

Code scanning / CodeQL

Use of basic integral type Note

portNum uses the basic integral type int rather than a typedef with size and signedness.
Svc/SeqDispatcher/SeqDispatcher.cpp Dismissed Show dismissed Hide dismissed
const U32 cmdSeq,
const Fw::CmdStringArg& fileName,
Fw::Wait block) {
FwIndexType idx = this->getNextAvailableSequencerIdx();

Check notice

Code scanning / CodeQL

Use of basic integral type Note

idx uses the basic integral type int rather than a typedef with size and signedness.
Svc/SeqDispatcher/SeqDispatcher.cpp Fixed Show fixed Hide fixed
@LeStarch
Copy link
Collaborator

Framework failure caused by: #2835. Will rerun.

@zimri-leisher
Copy link
Collaborator Author

Okay, ready for review again.

Copy link
Collaborator

@LeStarch LeStarch left a comment

Choose a reason for hiding this comment

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

Looks very good! An EVR could be made high instead of low because it is a problem with a direct user command.

Tests could be more complete, and SDD is blank.

Other (very minor style points):

  1. Typically in compound if clauses we put () around each sub-phrase. e.g. if ((A) || (B)). for clarity. Your code is perfectly clear, so no real issue here.
  2. Typically we don't return bool but rather opt for an enumeration that describes the issue. This is truly a "did work" or "did not work", so it is ok.

None of this is a blocker. Good work! I'd like another set of eyes....let me see if @timcanham will review. In the mean-time, consider that EVR to be made high.

Svc/Seq/Seq.fpp Show resolved Hide resolved
Svc/SeqDispatcher/SeqDispatcherEvents.fppi Outdated Show resolved Hide resolved
Svc/SeqDispatcher/docs/sdd.md Show resolved Hide resolved
@zimri-leisher
Copy link
Collaborator Author

zimri-leisher commented Aug 28, 2024

I made the changes to the SDD file and event.
I agree, the unit tests are a bit lacking, I would like to add a couple more.
One question: would we like to retroactively come up with requirements for this component?

Svc/SeqDispatcher/SeqDispatcher.cpp Dismissed Show dismissed Hide dismissed
Svc/SeqDispatcher/SeqDispatcher.cpp Dismissed Show dismissed Hide dismissed
Svc/SeqDispatcher/SeqDispatcher.cpp Dismissed Show dismissed Hide dismissed
void SeqDispatcher::LOG_STATUS_cmdHandler(
const FwOpcodeType opCode, /*!< The opcode*/
const U32 cmdSeq) { /*!< The command sequence number*/
for(FwIndexType idx = 0; idx < SeqDispatcherSequencerPorts; idx++) {

Check notice

Code scanning / CodeQL

Use of basic integral type Note

idx uses the basic integral type int rather than a typedef with size and signedness.
@LeStarch
Copy link
Collaborator

Known file CI failure. I captured the failing random seed, and re-ran. We have an issue to look into these failures.

@timcanham
Copy link
Collaborator

@zimri-leisher Do you plan to release ./docs/sdd.md in a future release?

Copy link
Collaborator

@timcanham timcanham left a comment

Choose a reason for hiding this comment

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

@zimri-leisher This looks really great! Minor comments only. If you don't wish to make any changes, I'll approve.

Svc/SeqDispatcher/SeqDispatcherEvents.fppi Outdated Show resolved Hide resolved
Svc/SeqDispatcher/SeqDispatcher.hpp Outdated Show resolved Hide resolved
Svc/SeqDispatcher/SeqDispatcherEvents.fppi Outdated Show resolved Hide resolved
Svc/SeqDispatcher/SeqDispatcher.cpp Outdated Show resolved Hide resolved
Svc/SeqDispatcher/SeqDispatcher.cpp Outdated Show resolved Hide resolved
Svc/SeqDispatcher/SeqDispatcher.cpp Show resolved Hide resolved
Copy link
Contributor

@garthwatney garthwatney left a comment

Choose a reason for hiding this comment

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

Overall looks very good. I have included my review comments.

Svc/SeqDispatcher/SeqDispatcher.cpp Show resolved Hide resolved
Svc/SeqDispatcher/SeqDispatcher.cpp Outdated Show resolved Hide resolved
Svc/SeqDispatcher/SeqDispatcher.hpp Show resolved Hide resolved
@LeStarch
Copy link
Collaborator

LeStarch commented Sep 3, 2024

@zimri-leisher I noted some things that could be future work, some things that would be nice to do now. Would you please note those items you intend to close-out for this PR, and which you'd prefer to see as a future work item?

That way I know what to confirm is done before merging and what I should track as future work.

Thanks for all the hard work!

@zimri-leisher
Copy link
Collaborator Author

Okay, I fixed most of the new comments. Any pointers for the unit tests?

// directly commanded that specific sequencer

// warn because this may be unintentional
this->log_WARNING_LO_UnexpectedSequenceStarted(static_cast<U16>(portNum), fileName);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter fileName has not been checked.
return;
}

this->runSequence(idx, fileName, Fw::Wait::NO_WAIT);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter fileName has not been checked.
// no available sequencers
if (idx == -1) {
this->log_WARNING_HI_NoAvailableSequencers();
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter opCode has not been checked.
// no available sequencers
if (idx == -1) {
this->log_WARNING_HI_NoAvailableSequencers();
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter cmdSeq has not been checked.
return;
}

this->runSequence(idx, fileName, block);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter fileName has not been checked.
return;
}

this->runSequence(idx, fileName, block);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter block has not been checked.
Svc/SeqDispatcher/SeqDispatcher.cpp Dismissed Show dismissed Hide dismissed
Svc/SeqDispatcher/SeqDispatcher.cpp Dismissed Show dismissed Hide dismissed
@LeStarch
Copy link
Collaborator

I am going to merge and take action for adding rules testing!

@LeStarch LeStarch merged commit b0716ad into nasa:devel Sep 18, 2024
35 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.

Distributing command sequences throughout CmdSequencers
6 participants