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)
16  : SeqDispatcherComponentBase(compName) {}
17 
19 
20 FwIndexType SeqDispatcher::getNextAvailableSequencerIdx() {
21  for (FwIndexType i = 0; i < SeqDispatcherSequencerPorts; i++) {
22  if (this->isConnected_seqRunOut_OutputPort(i) &&
23  this->m_entryTable[i].state == SeqDispatcher_CmdSequencerState::AVAILABLE) {
24  return i;
25  }
26  }
27  return -1;
28 }
29 
30 void SeqDispatcher::runSequence(FwIndexType sequencerIdx,
31  const Fw::StringBase& fileName,
32  Fw::Wait block) {
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 ==
40  static_cast<FwAssertArgType>(this->m_entryTable[sequencerIdx].state));
41 
42  if (block == Fw::Wait::NO_WAIT) {
43  this->m_entryTable[sequencerIdx].state =
45  } else {
46  this->m_entryTable[sequencerIdx].state =
48  }
49 
50  this->m_sequencersAvailable--;
51  this->tlmWrite_sequencersAvailable(this->m_sequencersAvailable);
52  this->m_entryTable[sequencerIdx].sequenceRunning = fileName;
53 
54  this->m_dispatchedCount++;
55  this->tlmWrite_dispatchedCount(this->m_dispatchedCount);
56  this->seqRunOut_out(sequencerIdx,
57  this->m_entryTable[sequencerIdx].sequenceRunning);
58 }
59 
61  FwIndexType portNum,
62  const Fw::StringBase& fileName
63 ) {
64  FW_ASSERT(portNum >= 0 && portNum < SeqDispatcherSequencerPorts,
65  static_cast<FwAssertArgType>(portNum));
66  if (this->m_entryTable[portNum].state ==
68  this->m_entryTable[portNum].state ==
70  // we were aware of this sequencer running a sequence
71  if (this->m_entryTable[portNum].sequenceRunning != fileName) {
72  // uh oh. entry table is wrong
73  // let's just update it to be correct. nothing we can do about
74  // it except raise a warning and update our state
75  this->log_WARNING_HI_ConflictingSequenceStarted(static_cast<U16>(portNum), fileName, this->m_entryTable[portNum].sequenceRunning);
76  this->m_entryTable[portNum].sequenceRunning = fileName;
77  }
78  } else {
79  // we were not aware that this sequencer was running. ground must have
80  // directly commanded that specific sequencer
81 
82  // warn because this may be unintentional
83  this->log_WARNING_LO_UnexpectedSequenceStarted(static_cast<U16>(portNum), fileName);
84 
85  // update the state
86  this->m_entryTable[portNum].state =
88  this->m_entryTable[portNum].sequenceRunning = fileName;
89  this->m_sequencersAvailable--;
90  this->tlmWrite_sequencersAvailable(this->m_sequencersAvailable);
91  }
92 }
93 
95  FwIndexType portNum,
96  FwOpcodeType opCode,
97  U32 cmdSeq,
98  const Fw::CmdResponse& response
99 ) {
100  FW_ASSERT(portNum >= 0 && portNum < SeqDispatcherSequencerPorts,
101  static_cast<FwAssertArgType>(portNum));
102  if (this->m_entryTable[portNum].state !=
104  this->m_entryTable[portNum].state !=
106  // this sequencer was not running a sequence that we were aware of.
107 
108  // we should have caught this in seqStartIn and updated the state
109  // accordingly, but somehow we didn't? very sad and shouldn't happen
110 
111  // anyways, don't have to do anything cuz now that this seq we didn't know
112  // about is done, the sequencer is available again (which is its current
113  // state in our internal entry table already)
114  this->log_WARNING_LO_UnknownSequenceFinished(static_cast<U16>(portNum));
115  } else {
116  // ok, a sequence has finished that we knew about
117  if (this->m_entryTable[portNum].state ==
119  // we need to give a cmd response cuz some other sequence is being blocked
120  // by this
121  this->cmdResponse_out(this->m_entryTable[portNum].opCode,
122  this->m_entryTable[portNum].cmdSeq, response);
123 
124  if (response == Fw::CmdResponse::EXECUTION_ERROR) {
125  // dispatched sequence errored
126  this->m_errorCount++;
127  this->tlmWrite_errorCount(this->m_errorCount);
128  }
129  }
130  }
131 
132  // all command responses mean the sequence is no longer running
133  // so component should be available
134  this->m_entryTable[portNum].state = SeqDispatcher_CmdSequencerState::AVAILABLE;
135  this->m_entryTable[portNum].sequenceRunning = "<no seq>";
136  this->m_sequencersAvailable++;
137  this->tlmWrite_sequencersAvailable(this->m_sequencersAvailable);
138 }
139 
142  const Fw::StringBase& fileName) {
143  FwIndexType idx = this->getNextAvailableSequencerIdx();
144  // no available sequencers
145  if (idx == -1) {
147  return;
148  }
149 
150  this->runSequence(idx, fileName, Fw::Wait::NO_WAIT);
151 }
152 // ----------------------------------------------------------------------
153 // Command handler implementations
154 // ----------------------------------------------------------------------
155 
156 void SeqDispatcher ::RUN_cmdHandler(const FwOpcodeType opCode,
157  const U32 cmdSeq,
158  const Fw::CmdStringArg& fileName,
159  Fw::Wait block) {
160  FwIndexType idx = this->getNextAvailableSequencerIdx();
161  // no available sequencers
162  if (idx == -1) {
164  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
165  return;
166  }
167 
168  this->runSequence(idx, fileName, block);
169 
170  if (block == Fw::Wait::NO_WAIT) {
171  // return instantly
172  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
173  } else {
174  // otherwise don't return a response yet. just save the opCode and cmdSeq
175  // so we can return a response later
176  this->m_entryTable[idx].opCode = opCode;
177  this->m_entryTable[idx].cmdSeq = cmdSeq;
178  }
179 }
180 
181 void SeqDispatcher::LOG_STATUS_cmdHandler(
182  const FwOpcodeType opCode,
183  const U32 cmdSeq) {
184  for(FwIndexType idx = 0; idx < SeqDispatcherSequencerPorts; idx++) {
185  this->log_ACTIVITY_LO_LogSequencerStatus(static_cast<U16>(idx), this->m_entryTable[idx].state, Fw::LogStringArg(this->m_entryTable[idx].sequenceRunning));
186  }
187  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
188 }
189 } // end namespace components
void tlmWrite_sequencersAvailable(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
void tlmWrite_errorCount(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
Wait or don&#39;t wait for something.
Definition: WaitEnumAc.hpp:17
void seqDoneIn_handler(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response)
Handler for input port seqDoneIn.
Enum representing a command response.
void log_WARNING_LO_UnknownSequenceFinished(U16 idx) const
Log event UnknownSequenceFinished.
void log_ACTIVITY_LO_LogSequencerStatus(U16 idx, Svc::SeqDispatcher_CmdSequencerState state, const Fw::StringBase &filename) const
Log event LogSequencerStatus.
U32 FwOpcodeType
The type of a command opcode.
void log_WARNING_LO_UnexpectedSequenceStarted(U16 idx, const Fw::StringBase &newSequence) const
Log event UnexpectedSequenceStarted.
Command successfully executed.
SeqDispatcher(const char *const compName)
void log_WARNING_HI_NoAvailableSequencers() const
Log event NoAvailableSequencers.
Command had execution error.
void seqRunOut_out(FwIndexType portNum, const Fw::StringBase &filename)
Invoke output port seqRunOut.
void seqRunIn_handler(FwIndexType portNum, const Fw::StringBase &fileName)
Handler for input port seqRunIn.
bool isConnected_seqRunOut_OutputPort(FwIndexType portNum)
PlatformIndexType FwIndexType
Auto-generated base for SeqDispatcher component.
RateGroupDivider component implementation.
Don&#39;t wait for something.
Definition: WaitEnumAc.hpp:35
void cmdResponse_out(FwOpcodeType opCode, U32 cmdSeq, Fw::CmdResponse response)
Emit command response.
void seqStartIn_handler(FwIndexType portNum, const Fw::StringBase &fileName)
Handler for input port seqStartIn.
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