F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
SeqDispatcher.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title SeqDispatcher.cpp
3 // \author zimri.leisher
4 // \brief cpp file for SeqDispatcher component implementation class
5 // ======================================================================
6 
8 
9 namespace Svc {
10 
11 // ----------------------------------------------------------------------
12 // Construction, initialization, and destruction
13 // ----------------------------------------------------------------------
14 
15 SeqDispatcher ::SeqDispatcher(const char* const compName) : SeqDispatcherComponentBase(compName) {}
16 
18 
19 FwIndexType SeqDispatcher::getNextAvailableSequencerIdx() {
20  for (FwIndexType i = 0; i < SeqDispatcherSequencerPorts; i++) {
21  if (this->isConnected_seqRunOut_OutputPort(i) &&
22  this->m_entryTable[i].state == SeqDispatcher_CmdSequencerState::AVAILABLE) {
23  return i;
24  }
25  }
26  return -1;
27 }
28 
29 void SeqDispatcher::runSequence(FwIndexType sequencerIdx,
30  const Fw::ConstStringBase& fileName,
31  BlockState block,
32  const Svc::SeqArgs& args) {
33  // this function is only designed for internal usage
34  // we can guarantee it cannot be called with input that would fail
35  FW_ASSERT(sequencerIdx >= 0 && sequencerIdx < SeqDispatcherSequencerPorts,
36  static_cast<FwAssertArgType>(sequencerIdx));
37  FW_ASSERT(this->isConnected_seqRunOut_OutputPort(sequencerIdx));
38  FW_ASSERT(this->m_entryTable[sequencerIdx].state == SeqDispatcher_CmdSequencerState::AVAILABLE,
39  static_cast<FwAssertArgType>(this->m_entryTable[sequencerIdx].state));
40 
41  if (block == BlockState::NO_BLOCK) {
42  this->m_entryTable[sequencerIdx].state = SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_NO_BLOCK;
43  } else {
44  this->m_entryTable[sequencerIdx].state = SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_BLOCK;
45  }
46 
47  this->m_sequencersAvailable--;
48  this->tlmWrite_sequencersAvailable(this->m_sequencersAvailable);
49  this->m_entryTable[sequencerIdx].sequenceRunning = fileName;
50 
51  this->m_dispatchedCount++;
52  this->tlmWrite_dispatchedCount(this->m_dispatchedCount);
53  this->seqRunOut_out(sequencerIdx, this->m_entryTable[sequencerIdx].sequenceRunning, args);
54 }
55 
57  const Fw::StringBase& fileName,
58  const Svc::SeqArgs& args
59 ) {
60  (void)args; // Suppress unused parameter warning
61  FW_ASSERT(portNum >= 0 && portNum < SeqDispatcherSequencerPorts, static_cast<FwAssertArgType>(portNum));
62  if (this->m_entryTable[portNum].state == SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_BLOCK ||
63  this->m_entryTable[portNum].state == SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_NO_BLOCK) {
64  // we were aware of this sequencer running a sequence
65  if (this->m_entryTable[portNum].sequenceRunning != fileName) {
66  // uh oh. entry table is wrong
67  // let's just update it to be correct. nothing we can do about
68  // it except raise a warning and update our state
69  this->log_WARNING_HI_ConflictingSequenceStarted(static_cast<U16>(portNum), fileName,
70  this->m_entryTable[portNum].sequenceRunning);
71  this->m_entryTable[portNum].sequenceRunning = fileName;
72  }
73  } else {
74  // we were not aware that this sequencer was running. ground must have
75  // directly commanded that specific sequencer
76 
77  // warn because this may be unintentional
78  this->log_WARNING_LO_UnexpectedSequenceStarted(static_cast<U16>(portNum), fileName);
79 
80  // update the state
81  this->m_entryTable[portNum].state = SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_NO_BLOCK;
82  this->m_entryTable[portNum].sequenceRunning = fileName;
83  this->m_sequencersAvailable--;
84  this->tlmWrite_sequencersAvailable(this->m_sequencersAvailable);
85  }
86 }
87 
89  FwOpcodeType opCode,
90  U32 cmdSeq,
91  const Fw::CmdResponse& response
92 ) {
93  FW_ASSERT(portNum >= 0 && portNum < SeqDispatcherSequencerPorts, static_cast<FwAssertArgType>(portNum));
94  if (this->m_entryTable[portNum].state != SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_BLOCK &&
95  this->m_entryTable[portNum].state != SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_NO_BLOCK) {
96  // this sequencer was not running a sequence that we were aware of.
97 
98  // we should have caught this in seqStartIn and updated the state
99  // accordingly, but somehow we didn't? very sad and shouldn't happen
100 
101  // anyways, don't have to do anything cuz now that this seq we didn't know
102  // about is done, the sequencer is available again (which is its current
103  // state in our internal entry table already)
104  this->log_WARNING_LO_UnknownSequenceFinished(static_cast<U16>(portNum));
105  // sequencer was already counted available; don't increment again
106  this->m_entryTable[portNum].state = SeqDispatcher_CmdSequencerState::AVAILABLE;
107  this->m_entryTable[portNum].sequenceRunning = "<no seq>";
108  return;
109  } else {
110  // ok, a sequence has finished that we knew about
111  if (this->m_entryTable[portNum].state == SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_BLOCK) {
112  // we need to give a cmd response cuz some other sequence is being blocked
113  // by this
114  this->cmdResponse_out(this->m_entryTable[portNum].opCode, this->m_entryTable[portNum].cmdSeq, response);
115 
116  if (response == Fw::CmdResponse::EXECUTION_ERROR) {
117  // dispatched sequence errored
118  this->m_errorCount++;
119  this->tlmWrite_errorCount(this->m_errorCount);
120  }
121  }
122  }
123 
124  // all command responses mean the sequence is no longer running
125  // so component should be available
126  this->m_entryTable[portNum].state = SeqDispatcher_CmdSequencerState::AVAILABLE;
127  this->m_entryTable[portNum].sequenceRunning = "<no seq>";
128  this->m_sequencersAvailable++;
129  this->tlmWrite_sequencersAvailable(this->m_sequencersAvailable);
130 }
131 
133 void SeqDispatcher::seqRunIn_handler(FwIndexType portNum, const Fw::StringBase& fileName, const Svc::SeqArgs& args) {
134  FwIndexType idx = this->getNextAvailableSequencerIdx();
135  // no available sequencers
136  if (idx == -1) {
138  return;
139  }
140 
141  this->runSequence(idx, fileName, BlockState::NO_BLOCK, args);
142 }
143 // ----------------------------------------------------------------------
144 // Command handler implementations
145 // ----------------------------------------------------------------------
146 
147 // RUN command delegates to RUN_ARGS with empty arguments for backward compatibility
148 void SeqDispatcher ::RUN_cmdHandler(const FwOpcodeType opCode,
149  const U32 cmdSeq,
150  const Fw::CmdStringArg& fileName,
151  const BlockState& block) {
152  // Create empty args and delegate to RUN_ARGS handler
153  Svc::SeqArgs emptyArgs{0, 0};
154  this->RUN_ARGS_cmdHandler(opCode, cmdSeq, fileName, block, emptyArgs);
155 }
156 
157 // RUN_ARGS command dispatches a sequence with optional arguments to the first available sequencer
158 void SeqDispatcher ::RUN_ARGS_cmdHandler(const FwOpcodeType opCode,
159  const U32 cmdSeq,
160  const Fw::CmdStringArg& fileName,
161  const BlockState& block,
162  const Svc::SeqArgs& buffer) {
163  FwIndexType idx = this->getNextAvailableSequencerIdx();
164  // no available sequencers
165  if (idx == -1) {
167  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
168  return;
169  }
170 
171  this->runSequence(idx, fileName, block, buffer);
172 
173  if (block == BlockState::NO_BLOCK) {
174  // return instantly
175  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
176  } else {
177  // otherwise don't return a response yet. just save the opCode and cmdSeq
178  // so we can return a response later
179  this->m_entryTable[idx].opCode = opCode;
180  this->m_entryTable[idx].cmdSeq = cmdSeq;
181  }
182 }
183 
184 void SeqDispatcher::LOG_STATUS_cmdHandler(const FwOpcodeType opCode,
185  const U32 cmdSeq) {
186  for (FwIndexType idx = 0; idx < SeqDispatcherSequencerPorts; idx++) {
187  this->log_ACTIVITY_LO_LogSequencerStatus(static_cast<U16>(idx), this->m_entryTable[idx].state,
188  Fw::LogStringArg(this->m_entryTable[idx].sequenceRunning));
189  }
190  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
191 }
192 
193 void SeqDispatcher::CANCEL_NAME_cmdHandler(
194  const FwOpcodeType opCode,
195  const U32 cmdSeq,
196  const Fw::CmdStringArg& fileName) {
197  bool canceled = false;
198  for (FwIndexType idx = 0; idx < SeqDispatcherSequencerPorts; idx++) {
199  // only slots actively running the named sequence are candidates
200  const bool running = this->m_entryTable[idx].state != SeqDispatcher_CmdSequencerState::AVAILABLE;
201  if (running && this->m_entryTable[idx].sequenceRunning == fileName) {
202  if (this->isConnected_seqCancelOut_OutputPort(idx)) {
203  this->seqCancelOut_out(idx);
204  // Entry table is cleared via seqDoneIn_handler
205  this->log_ACTIVITY_HI_SequenceCanceled(static_cast<U16>(idx),
206  Fw::LogStringArg(this->m_entryTable[idx].sequenceRunning));
207  this->tlmWrite_canceledCount(++this->m_canceledCount);
208  canceled = true;
209  }
210  }
211  }
212 
213  if (canceled) {
214  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
215  } else {
217  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
218  }
219 }
220 
224 void SeqDispatcher::CANCEL_ALL_cmdHandler(const FwOpcodeType opCode,
225  const U32 cmdSeq) {
226  for (FwIndexType idx = 0; idx < SeqDispatcherSequencerPorts; idx++) {
227  const bool running = this->m_entryTable[idx].state != SeqDispatcher_CmdSequencerState::AVAILABLE;
228  if (running && this->isConnected_seqCancelOut_OutputPort(idx)) {
229  this->seqCancelOut_out(idx);
230  // Entry table is cleared via seqDoneIn_handler
231  this->log_ACTIVITY_HI_SequenceCanceled(static_cast<U16>(idx),
232  Fw::LogStringArg(this->m_entryTable[idx].sequenceRunning));
233  this->tlmWrite_canceledCount(++this->m_canceledCount);
234  }
235  }
236  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
237 }
238 } // namespace Svc
void tlmWrite_sequencersAvailable(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
void tlmWrite_errorCount(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
FwIdType FwOpcodeType
The type of a command opcode.
bool isConnected_seqRunOut_OutputPort(FwIndexType portNum) const
void seqDoneIn_handler(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response)
Handler for input port seqDoneIn.
Enum representing a command response.
void tlmWrite_canceledCount(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
bool isConnected_seqCancelOut_OutputPort(FwIndexType portNum) const
void log_WARNING_LO_CancelSequenceNotFound(const Fw::StringBase &filename) const
Log event CancelSequenceNotFound.
void log_WARNING_LO_UnknownSequenceFinished(U16 idx) const
Log event UnknownSequenceFinished.
Sequencer blocking state.
void seqRunOut_out(FwIndexType portNum, const Fw::StringBase &filename, const Svc::SeqArgs &args) const
Invoke output port seqRunOut.
void seqRunIn_handler(FwIndexType portNum, const Fw::StringBase &fileName, const Svc::SeqArgs &args)
Handler for input port seqRunIn.
void log_WARNING_LO_UnexpectedSequenceStarted(U16 idx, const Fw::StringBase &newSequence) const
Log event UnexpectedSequenceStarted.
Command successfully executed.
void seqStartIn_handler(FwIndexType portNum, const Fw::StringBase &fileName, const Svc::SeqArgs &args)
Handler for input port seqStartIn.
SeqDispatcher(const char *const compName)
void log_WARNING_HI_NoAvailableSequencers() const
Log event NoAvailableSequencers.
Command had execution error.
void log_ACTIVITY_LO_LogSequencerStatus(U16 idx, const Svc::SeqDispatcher_CmdSequencerState &state, const Fw::StringBase &filename) const
Log event LogSequencerStatus.
A read-only abstract superclass for StringBase.
PlatformIndexType FwIndexType
Auto-generated base for SeqDispatcher component.
RateGroupDivider component implementation.
void seqCancelOut_out(FwIndexType portNum) const
Invoke output port seqCancelOut.
void cmdResponse_out(FwOpcodeType opCode, U32 cmdSeq, Fw::CmdResponse response)
Emit command response.
void log_ACTIVITY_HI_SequenceCanceled(U16 idx, const Fw::StringBase &filename) const
Log event SequenceCanceled.
void log_WARNING_HI_ConflictingSequenceStarted(U16 idx, const Fw::StringBase &newSequence, const Fw::StringBase &sequenceInInternalState) const
Log event ConflictingSequenceStarted.
#define FW_ASSERT(...)
Definition: Assert.hpp:14
void tlmWrite_dispatchedCount(U32 arg, Fw::Time _tlmTime=Fw::Time()) const