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  Fw::Wait 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 == Fw::Wait::NO_WAIT) {
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  } else {
106  // ok, a sequence has finished that we knew about
107  if (this->m_entryTable[portNum].state == SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_BLOCK) {
108  // we need to give a cmd response cuz some other sequence is being blocked
109  // by this
110  this->cmdResponse_out(this->m_entryTable[portNum].opCode, this->m_entryTable[portNum].cmdSeq, response);
111 
112  if (response == Fw::CmdResponse::EXECUTION_ERROR) {
113  // dispatched sequence errored
114  this->m_errorCount++;
115  this->tlmWrite_errorCount(this->m_errorCount);
116  }
117  }
118  }
119 
120  // all command responses mean the sequence is no longer running
121  // so component should be available
122  this->m_entryTable[portNum].state = SeqDispatcher_CmdSequencerState::AVAILABLE;
123  this->m_entryTable[portNum].sequenceRunning = "<no seq>";
124  this->m_sequencersAvailable++;
125  this->tlmWrite_sequencersAvailable(this->m_sequencersAvailable);
126 }
127 
129 void SeqDispatcher::seqRunIn_handler(FwIndexType portNum, const Fw::StringBase& fileName, const Svc::SeqArgs& args) {
130  FwIndexType idx = this->getNextAvailableSequencerIdx();
131  // no available sequencers
132  if (idx == -1) {
134  return;
135  }
136 
137  this->runSequence(idx, fileName, Fw::Wait::NO_WAIT, args);
138 }
139 // ----------------------------------------------------------------------
140 // Command handler implementations
141 // ----------------------------------------------------------------------
142 
143 // RUN command delegates to RUN_ARGS with empty arguments for backward compatibility
144 void SeqDispatcher ::RUN_cmdHandler(const FwOpcodeType opCode,
145  const U32 cmdSeq,
146  const Fw::CmdStringArg& fileName,
147  Fw::Wait block) {
148  // Create empty args and delegate to RUN_ARGS handler
149  Svc::SeqArgs emptyArgs{0, 0};
150  this->RUN_ARGS_cmdHandler(opCode, cmdSeq, fileName, block, emptyArgs);
151 }
152 
153 // RUN_ARGS command dispatches a sequence with optional arguments to the first available sequencer
154 void SeqDispatcher ::RUN_ARGS_cmdHandler(const FwOpcodeType opCode,
155  const U32 cmdSeq,
156  const Fw::CmdStringArg& fileName,
157  Fw::Wait block,
158  Svc::SeqArgs buffer) {
159  FwIndexType idx = this->getNextAvailableSequencerIdx();
160  // no available sequencers
161  if (idx == -1) {
163  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
164  return;
165  }
166 
167  this->runSequence(idx, fileName, block, buffer);
168 
169  if (block == Fw::Wait::NO_WAIT) {
170  // return instantly
171  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
172  } else {
173  // otherwise don't return a response yet. just save the opCode and cmdSeq
174  // so we can return a response later
175  this->m_entryTable[idx].opCode = opCode;
176  this->m_entryTable[idx].cmdSeq = cmdSeq;
177  }
178 }
179 
180 void SeqDispatcher::LOG_STATUS_cmdHandler(const FwOpcodeType opCode,
181  const U32 cmdSeq) {
182  for (FwIndexType idx = 0; idx < SeqDispatcherSequencerPorts; idx++) {
183  this->log_ACTIVITY_LO_LogSequencerStatus(static_cast<U16>(idx), this->m_entryTable[idx].state,
184  Fw::LogStringArg(this->m_entryTable[idx].sequenceRunning));
185  }
186  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
187 }
188 } // 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.
Wait or don&#39;t wait for something.
Definition: WaitEnumAc.hpp:17
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 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.
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.
A read-only abstract superclass for StringBase.
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 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