F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
FpySequencer.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title FpySequencer.cpp
3 // \author zimri.leisher
4 // \brief cpp file for FpySequencer component implementation class
5 // ======================================================================
6 
8 
9 namespace Svc {
10 
11 // ----------------------------------------------------------------------
12 // Construction, initialization, and destruction
13 // ----------------------------------------------------------------------
14 
15 FpySequencer ::FpySequencer(const char* const compName) :
16  FpySequencerComponentBase(compName),
17  m_sequenceBuffer(),
18  m_allocatorId(0),
19  m_sequenceFilePath("<invalid_seq>"),
20  m_sequenceObj(),
21  m_computedCRC(0),
22  m_sequenceBlockState(),
23  m_savedOpCode(0),
24  m_savedCmdSeq(0),
25  m_goalState(),
26  m_sequencesStarted(0),
27  m_statementsDispatched(0),
28  m_runtime(),
29  m_tlm()
30 {}
31 
33 
37 void FpySequencer::RUN_cmdHandler(FwOpcodeType opCode,
38  U32 cmdSeq,
39  const Fw::CmdStringArg& fileName,
41 ) {
42  // can only run a seq while in idle
44  this->log_WARNING_HI_InvalidCommand(static_cast<I32>(sequencer_getState()));
46  return;
47  }
48 
49  if (block == FpySequencer_BlockState::BLOCK) {
50  // save the opCode and cmdSeq so we can respond later
51  this->m_savedOpCode = opCode;
52  this->m_savedCmdSeq = cmdSeq;
53  }
54 
55  this->sequencer_sendSignal_cmd_RUN(FpySequencer_SequenceExecutionArgs(fileName, block));
56 
57  // only respond if the user doesn't want us to block further execution
58  if (block == FpySequencer_BlockState::NO_BLOCK) {
59  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
60  }
61 }
62 
66 void FpySequencer::VALIDATE_cmdHandler(FwOpcodeType opCode,
67  U32 cmdSeq,
68  const Fw::CmdStringArg& fileName
69 ) {
70  // can only validate a seq while in idle
72  this->log_WARNING_HI_InvalidCommand(static_cast<I32>(sequencer_getState()));
74  return;
75  }
76 
77  // validate always blocks until finished, so save opcode/cmdseq
78  // so we can respond once done
79  this->m_savedOpCode = opCode;
80  this->m_savedCmdSeq = cmdSeq;
81 
83  FpySequencer_SequenceExecutionArgs(fileName, FpySequencer_BlockState::BLOCK));
84 }
85 
89 void FpySequencer::RUN_VALIDATED_cmdHandler(
90  FwOpcodeType opCode,
91  U32 cmdSeq,
92  FpySequencer_BlockState block
93 ) {
94  // can only RUN_VALIDATED if we have validated and are awaiting this exact cmd
96  this->log_WARNING_HI_InvalidCommand(static_cast<I32>(sequencer_getState()));
98  return;
99  }
100 
101  if (block == FpySequencer_BlockState::BLOCK) {
102  // save the opCode and cmdSeq so we can respond later
103  this->m_savedOpCode = opCode;
104  this->m_savedCmdSeq = cmdSeq;
105  }
106 
107  this->sequencer_sendSignal_cmd_RUN_VALIDATED(FpySequencer_SequenceExecutionArgs(this->m_sequenceFilePath, block));
108 
109  // only respond if the user doesn't want us to block further execution
110  if (block == FpySequencer_BlockState::NO_BLOCK) {
111  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
112  }
113 }
114 
118 void FpySequencer::CANCEL_cmdHandler(FwOpcodeType opCode,
119  U32 cmdSeq
120 ) {
121  // only state you can't cancel in is IDLE
122  if (sequencer_getState() == State::IDLE) {
123  this->log_WARNING_HI_InvalidCommand(static_cast<I32>(sequencer_getState()));
124  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
125  return;
126  }
127 
129 
130  // cancel returns immediately and always succeeds
131  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
132 }
133 
136  U32 context
137 ) {
139 }
140 
142  U32 key
143 ) {
144  // send ping response
145  this->pingOut_out(0, key);
146 }
147 
150  FwOpcodeType opCode,
151  U32 cmdSeq,
152  const Fw::CmdResponse& response
153 ) {
154  // TODO ask Rob if there's a better way to check if we're in a superstate. I don't want to have
155  // to update this every time I add a new substate to the RUNNING state.
156 
157  // if we aren't in the RUNNING state:
161  // must be a coding error from an outside component (off nom), or due to CANCEL while running a command (nom).
162  // because we can't be sure that it wasn't a nominal sequence of events leading to this, don't fail the
163  // sequence, just report it
164  this->log_WARNING_LO_CmdResponseWhileNotRunningSequence(static_cast<I32>(this->sequencer_getState()), opCode,
165  response);
166  return;
167  }
168 
169  // okay, we're running a sequence. now let's use the cmdUid to check if the response was for a cmd
170  // from this sequence
171 
172  // the cmdSeq arg is confusingly not the cmdSeq in this case, according to the current implementation
173  // of the CmdDisp. instead, it is the context that we passed in when we originally sent the cmd out.
174  // this context is in turn the cmdUid that we calculated just before sending it. rename the variable for
175  // clarity's sake
176  U32 cmdUid = cmdSeq;
177 
178  // pull the sequence index (modulo 2^16) out of the cmdUid. see the comment in FpySequencer::dispatchCommand
179  // for info on the binary format of this cmdUid. as a reminder, this should be equal to the first 16 bits of
180  // the m_sequencesStarted variable
181  U16 sequenceIndex = static_cast<U16>((cmdUid & 0xFFFF0000) >> 16);
182  U16 currentSequenceIndex = static_cast<U16>(this->m_sequencesStarted & 0xFFFF);
183 
184  // if it was from a different sequence:
185  if (sequenceIndex != currentSequenceIndex) {
186  this->log_WARNING_LO_CmdResponseFromOldSequence(opCode, response, sequenceIndex, currentSequenceIndex);
187  return;
188  }
189 
190  // okay, it was from this sequence. now if anything's wrong from this point on we should fail the sequence
191 
192  // first, make sure we're actually awaiting a command
194  // okay, crap. something from this sequence responded, and we weren't awaiting anything. end it all
195  this->log_WARNING_HI_CmdResponseWhileNotAwaiting(opCode, response);
197  return;
198  }
199 
200  // okay, we were awaiting a command. were we awaiting this opcode?
201  if (opCode != this->m_runtime.currentStatementOpcode || this->m_runtime.currentStatementType != Fpy::StatementType::COMMAND) {
202  // we were not awaiting this opcode. coding error, likely on the part of the responding component or cmd dispatcher
203  this->log_WARNING_HI_WrongCmdResponseOpcode(opCode, response, this->m_runtime.currentStatementOpcode);
205  return;
206  }
207 
208  // okay, we were awaiting this opcode. but was it from this exact statement, or a different one with the same opcode
209  // in the same file?
210 
211  // pull the cmd index (modulo 2^16) out of cmdUid. this should be equal to the first 16 bits of the
212  // m_statementsDispatched variable - 1. the -1 is because
213  U16 cmdIndex = static_cast<U16>(cmdUid & 0xFFFF);
214  // check for coding errors. at this point in the function, we have definitely dispatched a stmt
215  FW_ASSERT(this->m_statementsDispatched > 0);
216  U16 currentCmdIndex = static_cast<U16>((this->m_statementsDispatched - 1) & 0xFFFF);
217 
218  if (cmdIndex != currentCmdIndex) {
219  // we were not awaiting this exact statement, it was a different one with the same opcode. coding error
220  this->log_WARNING_HI_WrongCmdResponseIndex(opCode, response, cmdIndex, currentCmdIndex);
222  return;
223  }
224 
225  // okay, got the right cmd back. we have verified:
226  // 1) we are in the RUNNING state
227  // 2) the response is from this sequence
228  // 3) the response is from the correct opcode
229  // 4) the response is from the correct instance of that opcode in the sequence
230 
231  if (response == Fw::CmdResponse::OK) {
233  } else {
234  this->log_WARNING_HI_StatementFailed(Fpy::StatementType::COMMAND, opCode, this->m_runtime.nextStatementIndex - 1,
235  this->m_sequenceFilePath, response);
237  }
238 }
239 
242  U32 context
243 ) {
244  this->tlmWrite_StatementsDispatched(this->m_statementsDispatched);
245  this->tlmWrite_StatementsFailed(this->m_tlm.statementsFailed);
246  this->tlmWrite_SequencesCancelled(this->m_tlm.sequencesCancelled);
247  this->tlmWrite_SequencesSucceeded(this->m_tlm.sequencesSucceeded);
248  this->tlmWrite_SequencesFailed(this->m_tlm.sequencesFailed);
249  this->tlmWrite_SeqPath(this->m_sequenceFilePath);
250 }
251 
253  Fw::ParamValid valid;
254  this->paramGet_STATEMENT_TIMEOUT_SECS(valid);
255  // check for coding errors--should have a default
257 }
258 
260  Fw::ParamValid valid;
261  switch (id) {
264  break;
265  }
266  default: {
267  FW_ASSERT(0, static_cast<FwAssertArgType>(id)); // coding error, forgot to include in switch statement
268  }
269  }
270 }
271 
272 } // namespace Svc
void log_WARNING_HI_StatementFailed(Svc::Fpy::StatementType stmtType, U32 stmtOpcode, U32 stmtIdx, const Fw::StringBase &filePath, Fw::CmdResponse response) const
Log event StatementFailed.
void log_WARNING_HI_CmdResponseWhileNotAwaiting(U32 opcode, Fw::CmdResponse response) const
Log event CmdResponseWhileNotAwaiting.
void pingIn_handler(FwIndexType portNum, U32 key) override
Handler for input port pingIn.
void sequencer_sendSignal_stmtResponse_success()
Send signal stmtResponse_success to state machine sequencer.
void sequencer_sendSignal_cmd_VALIDATE(const Svc::FpySequencer_SequenceExecutionArgs &value)
Send signal cmd_VALIDATE to state machine sequencer.
Enum representing a command response.
void tlmWrite_SequencesSucceeded(U64 arg, Fw::Time _tlmTime=Fw::Time())
void sequencer_sendSignal_stmtResponse_unexpected()
Send signal stmtResponse_unexpected to state machine sequencer.
Svc_FpySequencer_SequencerStateMachine::State sequencer_getState() const
Get the state of state machine instance sequencer.
void tlmWrite_StatementsFailed(U64 arg, Fw::Time _tlmTime=Fw::Time())
void parametersLoaded() override
Called whenever parameters are loaded.
F32 paramGet_STATEMENT_TIMEOUT_SECS(Fw::ParamValid &valid)
void log_WARNING_HI_WrongCmdResponseOpcode(U32 opcode, Fw::CmdResponse response, U32 expectedOpcode) const
Log event WrongCmdResponseOpcode.
U32 FwOpcodeType
The type of a command opcode.
void cmdResponse_out(FwOpcodeType opCode, U32 cmdSeq, Fw::CmdResponse response)
Emit command response.
void tlmWrite_handler(FwIndexType portNum, U32 context) override
Handler for input port tlmWrite.
void sequencer_sendSignal_cmd_RUN_VALIDATED(const Svc::FpySequencer_SequenceExecutionArgs &value)
Send signal cmd_RUN_VALIDATED to state machine sequencer.
void log_WARNING_HI_WrongCmdResponseIndex(U32 opcode, Fw::CmdResponse response, U16 actualCmdIdx, U16 expectedCmdIdx) const
Log event WrongCmdResponseIndex.
void sequencer_sendSignal_checkTimersIn()
Send signal checkTimersIn to state machine sequencer.
void tlmWrite_StatementsDispatched(U64 arg, Fw::Time _tlmTime=Fw::Time())
sequencer is not taking any action, waiting for a time in the future to continue
void parameterUpdated(FwPrmIdType id) override
Called whenever a parameter is updated.
sequencer is ready to load, validate and run a sequence
void sequencer_sendSignal_stmtResponse_failure()
Send signal stmtResponse_failure to state machine sequencer.
void log_WARNING_LO_CmdResponseWhileNotRunningSequence(I32 state, U32 opcode, Fw::CmdResponse response) const
Log event CmdResponseWhileNotRunningSequence.
U32 FwPrmIdType
The type of a parameter identifier.
Command successfully executed.
void tlmWrite_STATEMENT_TIMEOUT_SECS(F32 arg, Fw::Time _tlmTime=Fw::Time())
Command had execution error.
void sequencer_sendSignal_cmd_CANCEL()
Send signal cmd_CANCEL to state machine sequencer.
void log_WARNING_HI_InvalidCommand(I32 state) const
Log event InvalidCommand.
void cmdResponseIn_handler(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response) override
Handler for input port cmdResponseIn.
void pingOut_out(FwIndexType portNum, U32 key)
Invoke output port pingOut.
void log_WARNING_LO_CmdResponseFromOldSequence(U32 opcode, Fw::CmdResponse response, U16 oldSequenceIdx, U16 currentSequenceIdx) const
Log event CmdResponseFromOldSequence.
void tlmWrite_SequencesFailed(U64 arg, Fw::Time _tlmTime=Fw::Time())
void checkTimers_handler(FwIndexType portNum, U32 context) override
Handler for input port checkTimers.
void tlmWrite_SeqPath(const Fw::StringBase &arg, Fw::Time _tlmTime=Fw::Time())
PlatformIndexType FwIndexType
sequencer is stepping into a single statement and dispatching it
RateGroupDivider component implementation.
Enum representing parameter validity.
Auto-generated base for FpySequencer component.
void sequencer_sendSignal_cmd_RUN(const Svc::FpySequencer_SequenceExecutionArgs &value)
Send signal cmd_RUN to state machine sequencer.
sequencer has validated the sequence and is waiting for a command to run it
void tlmWrite_SequencesCancelled(U64 arg, Fw::Time _tlmTime=Fw::Time())
#define FW_ASSERT(...)
Definition: Assert.hpp:14
FpySequencer(const char *const compName)