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, const Fw::StringBase& fileName, Fw::Wait block) {
30  // this function is only designed for internal usage
31  // we can guarantee it cannot be called with input that would fail
32  FW_ASSERT(sequencerIdx >= 0 && sequencerIdx < SeqDispatcherSequencerPorts,
33  static_cast<FwAssertArgType>(sequencerIdx));
34  FW_ASSERT(this->isConnected_seqRunOut_OutputPort(sequencerIdx));
35  FW_ASSERT(this->m_entryTable[sequencerIdx].state == SeqDispatcher_CmdSequencerState::AVAILABLE,
36  static_cast<FwAssertArgType>(this->m_entryTable[sequencerIdx].state));
37 
38  if (block == Fw::Wait::NO_WAIT) {
39  this->m_entryTable[sequencerIdx].state = SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_NO_BLOCK;
40  } else {
41  this->m_entryTable[sequencerIdx].state = SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_BLOCK;
42  }
43 
44  this->m_sequencersAvailable--;
45  this->tlmWrite_sequencersAvailable(this->m_sequencersAvailable);
46  this->m_entryTable[sequencerIdx].sequenceRunning = fileName;
47 
48  this->m_dispatchedCount++;
49  this->tlmWrite_dispatchedCount(this->m_dispatchedCount);
50  this->seqRunOut_out(sequencerIdx, this->m_entryTable[sequencerIdx].sequenceRunning);
51 }
52 
54  const Fw::StringBase& fileName
55 ) {
56  FW_ASSERT(portNum >= 0 && portNum < SeqDispatcherSequencerPorts, static_cast<FwAssertArgType>(portNum));
57  if (this->m_entryTable[portNum].state == SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_BLOCK ||
58  this->m_entryTable[portNum].state == SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_NO_BLOCK) {
59  // we were aware of this sequencer running a sequence
60  if (this->m_entryTable[portNum].sequenceRunning != fileName) {
61  // uh oh. entry table is wrong
62  // let's just update it to be correct. nothing we can do about
63  // it except raise a warning and update our state
64  this->log_WARNING_HI_ConflictingSequenceStarted(static_cast<U16>(portNum), fileName,
65  this->m_entryTable[portNum].sequenceRunning);
66  this->m_entryTable[portNum].sequenceRunning = fileName;
67  }
68  } else {
69  // we were not aware that this sequencer was running. ground must have
70  // directly commanded that specific sequencer
71 
72  // warn because this may be unintentional
73  this->log_WARNING_LO_UnexpectedSequenceStarted(static_cast<U16>(portNum), fileName);
74 
75  // update the state
76  this->m_entryTable[portNum].state = SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_NO_BLOCK;
77  this->m_entryTable[portNum].sequenceRunning = fileName;
78  this->m_sequencersAvailable--;
79  this->tlmWrite_sequencersAvailable(this->m_sequencersAvailable);
80  }
81 }
82 
84  FwOpcodeType opCode,
85  U32 cmdSeq,
86  const Fw::CmdResponse& response
87 ) {
88  FW_ASSERT(portNum >= 0 && portNum < SeqDispatcherSequencerPorts, static_cast<FwAssertArgType>(portNum));
89  if (this->m_entryTable[portNum].state != SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_BLOCK &&
90  this->m_entryTable[portNum].state != SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_NO_BLOCK) {
91  // this sequencer was not running a sequence that we were aware of.
92 
93  // we should have caught this in seqStartIn and updated the state
94  // accordingly, but somehow we didn't? very sad and shouldn't happen
95 
96  // anyways, don't have to do anything cuz now that this seq we didn't know
97  // about is done, the sequencer is available again (which is its current
98  // state in our internal entry table already)
99  this->log_WARNING_LO_UnknownSequenceFinished(static_cast<U16>(portNum));
100  } else {
101  // ok, a sequence has finished that we knew about
102  if (this->m_entryTable[portNum].state == SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_BLOCK) {
103  // we need to give a cmd response cuz some other sequence is being blocked
104  // by this
105  this->cmdResponse_out(this->m_entryTable[portNum].opCode, this->m_entryTable[portNum].cmdSeq, response);
106 
107  if (response == Fw::CmdResponse::EXECUTION_ERROR) {
108  // dispatched sequence errored
109  this->m_errorCount++;
110  this->tlmWrite_errorCount(this->m_errorCount);
111  }
112  }
113  }
114 
115  // all command responses mean the sequence is no longer running
116  // so component should be available
117  this->m_entryTable[portNum].state = SeqDispatcher_CmdSequencerState::AVAILABLE;
118  this->m_entryTable[portNum].sequenceRunning = "<no seq>";
119  this->m_sequencersAvailable++;
120  this->tlmWrite_sequencersAvailable(this->m_sequencersAvailable);
121 }
122 
125  FwIndexType idx = this->getNextAvailableSequencerIdx();
126  // no available sequencers
127  if (idx == -1) {
129  return;
130  }
131 
132  this->runSequence(idx, fileName, Fw::Wait::NO_WAIT);
133 }
134 // ----------------------------------------------------------------------
135 // Command handler implementations
136 // ----------------------------------------------------------------------
137 
138 void SeqDispatcher ::RUN_cmdHandler(const FwOpcodeType opCode,
139  const U32 cmdSeq,
140  const Fw::CmdStringArg& fileName,
141  Fw::Wait block) {
142  FwIndexType idx = this->getNextAvailableSequencerIdx();
143  // no available sequencers
144  if (idx == -1) {
146  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
147  return;
148  }
149 
150  this->runSequence(idx, fileName, block);
151 
152  if (block == Fw::Wait::NO_WAIT) {
153  // return instantly
154  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
155  } else {
156  // otherwise don't return a response yet. just save the opCode and cmdSeq
157  // so we can return a response later
158  this->m_entryTable[idx].opCode = opCode;
159  this->m_entryTable[idx].cmdSeq = cmdSeq;
160  }
161 }
162 
163 void SeqDispatcher::LOG_STATUS_cmdHandler(const FwOpcodeType opCode,
164  const U32 cmdSeq) {
165  for (FwIndexType idx = 0; idx < SeqDispatcherSequencerPorts; idx++) {
166  this->log_ACTIVITY_LO_LogSequencerStatus(static_cast<U16>(idx), this->m_entryTable[idx].state,
167  Fw::LogStringArg(this->m_entryTable[idx].sequenceRunning));
168  }
169  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
170 }
171 } // 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
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 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