F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
CmdSequencerImpl.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title CmdSequencerImpl.cpp
3 // \author Bocchino/Canham
4 // \brief cpp file for CmdDispatcherComponentBase component implementation class
5 //
6 // Copyright (C) 2009-2018 California Institute of Technology.
7 // ALL RIGHTS RESERVED. United States Government Sponsorship
8 // acknowledged.
9 
10 #include <Fw/Com/ComPacket.hpp>
11 #include <Fw/Types/Assert.hpp>
15 extern "C" {
17 }
18 
19 namespace Svc {
20 
21 // ----------------------------------------------------------------------
22 // Construction, initialization, and destruction
23 // ----------------------------------------------------------------------
24 
27  m_FPrimeSequence(*this),
28  m_sequence(&this->m_FPrimeSequence),
29  m_loadCmdCount(0),
30  m_cancelCmdCount(0),
31  m_errorCount(0),
32  m_runMode(STOPPED),
33  m_stepMode(AUTO),
34  m_executedCount(0),
35  m_totalExecutedCount(0),
36  m_sequencesCompletedCount(0),
37  m_timeout(0),
38  m_blockState(Svc::CmdSequencer_BlockState::NO_BLOCK),
39  m_opCode(0),
40  m_cmdSeq(0),
41  m_join_waiting(false) {}
42 
43 void CmdSequencerComponentImpl::setTimeout(const U32 timeout) {
44  this->m_timeout = timeout;
45 }
46 
48  this->m_sequence = &sequence;
49 }
50 
52  Fw::MemAllocator& allocator,
53  const FwSizeType bytes) {
54  this->m_sequence->allocateBuffer(identifier, allocator, bytes);
55 }
56 
58  FW_ASSERT(this->m_runMode == STOPPED, this->m_runMode);
59  if (not this->loadFile(fileName)) {
60  this->m_sequence->clear();
61  }
62 }
63 
65  this->m_sequence->deallocateBuffer(allocator);
66 }
67 
69 
70 // ----------------------------------------------------------------------
71 // Handler implementations
72 // ----------------------------------------------------------------------
73 
74 void CmdSequencerComponentImpl::CS_RUN_cmdHandler(FwOpcodeType opCode,
75  U32 cmdSeq,
76  const Fw::CmdStringArg& fileName,
78  if (not this->requireRunMode(STOPPED)) {
79  if (m_join_waiting) {
80  // Inform user previous seq file is not complete
82  }
84  return;
85  }
86 
87  this->m_blockState = block.e;
88  this->m_cmdSeq = cmdSeq;
89  this->m_opCode = opCode;
90 
91  // load commands
92  if (not this->loadFile(fileName)) {
94  return;
95  }
96 
97  this->m_executedCount = 0;
98 
99  // Check the step mode. If it is auto, start the sequence
100  if (AUTO == this->m_stepMode) {
101  this->m_runMode = RUNNING;
102  if (this->isConnected_seqStartOut_OutputPort(0)) {
103  this->seqStartOut_out(0, this->m_sequence->getStringFileName());
104  }
105  this->performCmd_Step();
106  }
107 
108  if (Svc::CmdSequencer_BlockState::NO_BLOCK == this->m_blockState) {
109  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
110  }
111 }
112 
113 void CmdSequencerComponentImpl::CS_VALIDATE_cmdHandler(FwOpcodeType opCode,
114  U32 cmdSeq,
115  const Fw::CmdStringArg& fileName) {
116  if (!this->requireRunMode(STOPPED)) {
117  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
118  return;
119  }
120 
121  // load commands
122  if (not this->loadFile(fileName)) {
123  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
124  return;
125  }
126 
127  // clear the buffer
128  this->m_sequence->clear();
129 
130  this->log_ACTIVITY_HI_CS_SequenceValid(this->m_sequence->getLogFileName());
131 
132  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
133 }
134 
136 void CmdSequencerComponentImpl::seqRunIn_handler(FwIndexType portNum, const Fw::StringBase& filename) {
137  if (!this->requireRunMode(STOPPED)) {
139  return;
140  }
141 
142  // If file name is non-empty, load a file.
143  // Empty file name means don't load.
144  if (filename != "") {
145  Fw::CmdStringArg cmdStr(filename);
146  const bool status = this->loadFile(cmdStr);
147  if (!status) {
149  return;
150  }
151  } else if (not this->m_sequence->hasMoreRecords()) {
152  // No sequence loaded
154  this->error();
156  return;
157  }
158 
159  this->m_executedCount = 0;
160 
161  // Check the step mode. If it is auto, start the sequence
162  if (AUTO == this->m_stepMode) {
163  this->m_runMode = RUNNING;
164  if (this->isConnected_seqStartOut_OutputPort(0)) {
165  this->seqStartOut_out(0, this->m_sequence->getStringFileName());
166  }
167  this->performCmd_Step();
168  }
169 
170  this->log_ACTIVITY_HI_CS_PortSequenceStarted(this->m_sequence->getLogFileName());
171 }
172 
173 void CmdSequencerComponentImpl ::seqCancelIn_handler(const FwIndexType portNum) {
174  if (RUNNING == this->m_runMode) {
175  this->performCmd_Cancel();
176  this->log_ACTIVITY_HI_CS_SequenceCanceled(this->m_sequence->getLogFileName());
177  ++this->m_cancelCmdCount;
178  this->tlmWrite_CS_CancelCommands(this->m_cancelCmdCount);
179  } else {
181  }
182 }
183 
184 void CmdSequencerComponentImpl::CS_CANCEL_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
185  if (RUNNING == this->m_runMode) {
186  this->performCmd_Cancel();
187  this->log_ACTIVITY_HI_CS_SequenceCanceled(this->m_sequence->getLogFileName());
188  ++this->m_cancelCmdCount;
189  this->tlmWrite_CS_CancelCommands(this->m_cancelCmdCount);
190  } else {
192  }
193  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
194 }
195 
196 void CmdSequencerComponentImpl::CS_JOIN_WAIT_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq) {
197  // If there is no running sequence do not wait
198  if (m_runMode != RUNNING) {
200  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
201  return;
202  } else {
203  m_join_waiting = true;
204  Fw::LogStringArg& logFileName = this->m_sequence->getLogFileName();
205  this->log_ACTIVITY_HI_CS_JoinWaiting(logFileName, m_cmdSeq, m_opCode);
206  m_cmdSeq = cmdSeq;
207  m_opCode = opCode;
208  }
209 }
210 
211 // ----------------------------------------------------------------------
212 // Private helper methods
213 // ----------------------------------------------------------------------
214 
215 bool CmdSequencerComponentImpl ::loadFile(const Fw::StringBase& fileName) {
216  const bool status = this->m_sequence->loadFile(fileName);
217  if (status) {
218  Fw::LogStringArg& logFileName = this->m_sequence->getLogFileName();
219  this->log_ACTIVITY_LO_CS_SequenceLoaded(logFileName);
220  ++this->m_loadCmdCount;
221  this->tlmWrite_CS_LoadCommands(this->m_loadCmdCount);
222  }
223  return status;
224 }
225 
226 void CmdSequencerComponentImpl::error() {
227  ++this->m_errorCount;
228  this->tlmWrite_CS_Errors(m_errorCount);
229 }
230 
231 void CmdSequencerComponentImpl::performCmd_Cancel() {
232  this->m_sequence->reset();
233  this->m_runMode = STOPPED;
234  this->m_cmdTimer.clear();
235  this->m_cmdTimeoutTimer.clear();
236  this->m_executedCount = 0;
237  // write sequence done port with error, if connected
238  if (this->isConnected_seqDone_OutputPort(0)) {
240  }
241 
242  if (Svc::CmdSequencer_BlockState::BLOCK == this->m_blockState || m_join_waiting) {
243  // Do not wait if sequence was canceled or a cmd failed
244  this->m_join_waiting = false;
245  this->cmdResponse_out(this->m_opCode, this->m_cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
246  }
247 
248  this->m_blockState = Svc::CmdSequencer_BlockState::NO_BLOCK;
249 }
250 
251 void CmdSequencerComponentImpl ::cmdResponseIn_handler(FwIndexType portNum,
252  FwOpcodeType opcode,
253  U32 cmdSeq,
254  const Fw::CmdResponse& response) {
255  if (this->m_runMode == STOPPED) {
256  // Sequencer is not running
258  } else {
259  // clear command timeout
260  this->m_cmdTimeoutTimer.clear();
261  if (response != Fw::CmdResponse::OK) {
262  this->commandError(this->m_executedCount, opcode, response.e);
263  this->performCmd_Cancel();
264  } else if (this->m_runMode == RUNNING && this->m_stepMode == AUTO) {
265  // Auto mode
266  this->commandComplete(opcode);
267  if (not this->m_sequence->hasMoreRecords()) {
268  // No data left
269  this->m_runMode = STOPPED;
270  this->sequenceComplete();
271  } else {
272  this->performCmd_Step();
273  }
274  } else {
275  // Manual step mode
276  this->commandComplete(opcode);
277  if (not this->m_sequence->hasMoreRecords()) {
278  this->m_runMode = STOPPED;
279  this->sequenceComplete();
280  }
281  }
282  }
283 }
284 
285 void CmdSequencerComponentImpl ::schedIn_handler(FwIndexType portNum, U32 order) {
286  Fw::Time currTime = this->getTime();
287  // check to see if a command time is pending
288  if (this->m_cmdTimer.isExpiredAt(currTime)) {
289  this->comCmdOut_out(0, m_record.m_command, 0);
290  this->m_cmdTimer.clear();
291  // start command timeout timer
292  this->setCmdTimeout(currTime);
293  } else if (this->m_cmdTimeoutTimer.isExpiredAt(this->getTime())) { // check for command timeout
294  this->log_WARNING_HI_CS_SequenceTimeout(m_sequence->getLogFileName(), this->m_executedCount);
295  // If there is a command timeout, cancel the sequence
296  this->performCmd_Cancel();
297  }
298 }
299 
300 void CmdSequencerComponentImpl ::CS_START_cmdHandler(FwOpcodeType opcode, U32 cmdSeq) {
301  if (not this->m_sequence->hasMoreRecords()) {
302  // No sequence loaded
304  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
305  return;
306  }
307  if (!this->requireRunMode(STOPPED)) {
308  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
309  return;
310  }
311 
312  this->m_blockState = Svc::CmdSequencer_BlockState::NO_BLOCK;
313  this->m_runMode = RUNNING;
314  this->performCmd_Step();
315  this->log_ACTIVITY_HI_CS_CmdStarted(this->m_sequence->getLogFileName());
316  if (this->isConnected_seqStartOut_OutputPort(0)) {
317  this->seqStartOut_out(0, this->m_sequence->getStringFileName());
318  }
319  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::OK);
320 }
321 
322 void CmdSequencerComponentImpl ::CS_STEP_cmdHandler(FwOpcodeType opcode, U32 cmdSeq) {
323  if (this->requireRunMode(RUNNING)) {
324  this->performCmd_Step();
325  // check for special case where end of sequence entry was encountered
326  if (this->m_runMode != STOPPED) {
327  this->log_ACTIVITY_HI_CS_CmdStepped(this->m_sequence->getLogFileName(), this->m_executedCount);
328  }
329  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::OK);
330  } else {
331  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
332  }
333 }
334 
335 void CmdSequencerComponentImpl ::CS_AUTO_cmdHandler(FwOpcodeType opcode, U32 cmdSeq) {
336  if (this->requireRunMode(STOPPED)) {
337  this->m_stepMode = AUTO;
339  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::OK);
340  } else {
341  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
342  }
343 }
344 
345 void CmdSequencerComponentImpl ::CS_MANUAL_cmdHandler(FwOpcodeType opcode, U32 cmdSeq) {
346  if (this->requireRunMode(STOPPED)) {
347  this->m_stepMode = MANUAL;
349  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::OK);
350  } else {
351  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
352  }
353 }
354 
355 // ----------------------------------------------------------------------
356 // Helper methods
357 // ----------------------------------------------------------------------
358 
359 bool CmdSequencerComponentImpl::requireRunMode(RunMode mode) {
360  if (this->m_runMode == mode) {
361  return true;
362  } else {
364  return false;
365  }
366 }
367 
368 void CmdSequencerComponentImpl ::commandError(const U32 number, const FwOpcodeType opCode, const U32 error) {
369  this->log_WARNING_HI_CS_CommandError(this->m_sequence->getLogFileName(), number, opCode, error);
370  this->error();
371 }
372 
373 void CmdSequencerComponentImpl::performCmd_Step() {
374  this->m_sequence->nextRecord(m_record);
375  // set clock time base and context from value set when sequence was loaded
376  const Sequence::Header& header = this->m_sequence->getHeader();
377  this->m_record.m_timeTag.setTimeBase(header.m_timeBase);
378  this->m_record.m_timeTag.setTimeContext(header.m_timeContext);
379 
380  Fw::Time currentTime = this->getTime();
381  switch (this->m_record.m_descriptor) {
383  this->m_runMode = STOPPED;
384  this->sequenceComplete();
385  break;
387  this->performCmd_Step_RELATIVE(currentTime);
388  break;
390  this->performCmd_Step_ABSOLUTE(currentTime);
391  break;
392  default:
393  FW_ASSERT(0, m_record.m_descriptor);
394  }
395 }
396 
397 void CmdSequencerComponentImpl::sequenceComplete() {
398  ++this->m_sequencesCompletedCount;
399  // reset buffer
400  this->m_sequence->clear();
401  this->log_ACTIVITY_HI_CS_SequenceComplete(this->m_sequence->getLogFileName());
402  this->tlmWrite_CS_SequencesCompleted(this->m_sequencesCompletedCount);
403  this->m_executedCount = 0;
404  // write sequence done port, if connected
405  if (this->isConnected_seqDone_OutputPort(0)) {
406  this->seqDone_out(0, 0, 0, Fw::CmdResponse::OK);
407  }
408 
409  if (Svc::CmdSequencer_BlockState::BLOCK == this->m_blockState || m_join_waiting) {
410  this->cmdResponse_out(this->m_opCode, this->m_cmdSeq, Fw::CmdResponse::OK);
411  }
412 
413  m_join_waiting = false;
414  this->m_blockState = Svc::CmdSequencer_BlockState::NO_BLOCK;
415 }
416 
417 void CmdSequencerComponentImpl::commandComplete(const FwOpcodeType opcode) {
418  this->log_ACTIVITY_LO_CS_CommandComplete(this->m_sequence->getLogFileName(), this->m_executedCount, opcode);
419  ++this->m_executedCount;
420  ++this->m_totalExecutedCount;
421  this->tlmWrite_CS_CommandsExecuted(this->m_totalExecutedCount);
422 }
423 
424 void CmdSequencerComponentImpl ::performCmd_Step_RELATIVE(Fw::Time& currentTime) {
425  this->m_record.m_timeTag.add(currentTime.getSeconds(), currentTime.getUSeconds());
426  this->performCmd_Step_ABSOLUTE(currentTime);
427 }
428 
429 void CmdSequencerComponentImpl ::performCmd_Step_ABSOLUTE(Fw::Time& currentTime) {
430  if (currentTime >= this->m_record.m_timeTag) {
431  this->comCmdOut_out(0, m_record.m_command, 0);
432  this->setCmdTimeout(currentTime);
433  } else {
434  this->m_cmdTimer.set(this->m_record.m_timeTag);
435  }
436 }
437 
438 void CmdSequencerComponentImpl ::pingIn_handler(FwIndexType portNum,
439  U32 key
440 ) {
441  // send ping response
442  this->pingOut_out(0, key);
443 }
444 
445 void CmdSequencerComponentImpl ::setCmdTimeout(const Fw::Time& currentTime) {
446  // start timeout timer if enabled and not in step mode
447  if ((this->m_timeout > 0) and (AUTO == this->m_stepMode)) {
448  Fw::Time expTime = currentTime;
449  expTime.add(this->m_timeout, 0);
450  this->m_cmdTimeoutTimer.set(expTime);
451  }
452 }
453 
454 } // namespace Svc
void tlmWrite_CS_LoadCommands(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
void setSequenceFormat(Sequence &sequence)
FwIdType FwOpcodeType
The type of a command opcode.
void log_ACTIVITY_HI_CS_ModeSwitched(Svc::CmdSequencer_SeqMode mode) const
PlatformSizeType FwSizeType
I32 FwEnumStoreType
CmdSequencerComponentImpl(const char *compName)
Construct a CmdSequencer.
void tlmWrite_CS_Errors(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
void log_ACTIVITY_HI_CS_JoinWaiting(const Fw::StringBase &filename, U32 recordNumber, FwOpcodeType opCode) const
void log_WARNING_HI_CS_UnexpectedCompletion(FwOpcodeType opcode) const
void log_ACTIVITY_LO_CS_SequenceLoaded(const Fw::StringBase &fileName) const
Fw::Time m_timeTag
The time tag. NOTE: timeBase and context not filled in.
void pingOut_out(FwIndexType portNum, U32 key)
Invoke output port pingOut.
void log_ACTIVITY_HI_CS_CmdStarted(const Fw::StringBase &filename) const
void comCmdOut_out(FwIndexType portNum, Fw::ComBuffer &data, U32 context)
Invoke output port comCmdOut.
void seqDone_out(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response)
Invoke output port seqDone.
Enum representing a command response.
void log_WARNING_HI_CS_SequenceTimeout(const Fw::StringBase &filename, U32 command) const
void allocateBuffer(FwEnumStoreType identifier, Fw::MemAllocator &allocator, FwSizeType bytes)
Give the sequence representation a memory buffer.
Definition: Sequence.cpp:45
void seqStartOut_out(FwIndexType portNum, const Fw::StringBase &filename)
Invoke output port seqStartOut.
virtual bool hasMoreRecords() const =0
void tlmWrite_CS_CancelCommands(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
void tlmWrite_CS_CommandsExecuted(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
~CmdSequencerComponentImpl()
Destroy a CmdDispatcherComponentBase.
void log_ACTIVITY_HI_CS_PortSequenceStarted(const Fw::StringBase &filename) const
void log_ACTIVITY_HI_CS_SequenceCanceled(const Fw::StringBase &fileName) const
void setTimeContext(FwTimeContextStoreType context)
Definition: Time.cpp:197
void allocateBuffer(const FwEnumStoreType identifier, Fw::MemAllocator &allocator, const FwSizeType bytes)
A sequence with unspecified binary format.
bool isConnected_seqStartOut_OutputPort(FwIndexType portNum)
void deallocateBuffer(Fw::MemAllocator &allocator)
Deallocate the buffer.
Definition: Sequence.cpp:55
U32 getSeconds() const
Definition: Time.cpp:86
T e
The raw enum value.
void setTimeBase(TimeBase timeBase)
Definition: Time.cpp:193
void setTimeout(const U32 seconds)
Command successfully executed.
bool isConnected_seqDone_OutputPort(FwIndexType portNum)
Command had execution error.
static Time add(const Time &a, const Time &b)
Definition: Time.cpp:132
void deallocateBuffer(Fw::MemAllocator &allocator)
Return allocated buffer. Call during shutdown.
virtual bool loadFile(const Fw::StringBase &fileName)=0
U32 getUSeconds() const
Definition: Time.cpp:90
PlatformIndexType FwIndexType
Auto-generated base for CmdSequencer component.
RateGroupDivider component implementation.
virtual void nextRecord(Record &record)=0
void log_ACTIVITY_HI_CS_SequenceComplete(const Fw::StringBase &fileName) const
void log_ACTIVITY_LO_CS_CommandComplete(const Fw::StringBase &fileName, U32 recordNumber, FwOpcodeType opCode) const
void loadSequence(const Fw::StringBase &fileName)
void log_WARNING_HI_CS_CommandError(const Fw::StringBase &fileName, U32 recordNumber, FwOpcodeType opCode, U32 errorStatus) const
#define FW_ASSERT(...)
Definition: Assert.hpp:14
const Header & getHeader() const
Get the sequence header.
Definition: Sequence.cpp:60
void log_ACTIVITY_HI_CS_SequenceValid(const Fw::StringBase &filename) const
void cmdResponse_out(FwOpcodeType opCode, U32 cmdSeq, Fw::CmdResponse response)
Emit command response.
void tlmWrite_CS_SequencesCompleted(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
void log_ACTIVITY_HI_CS_CmdStepped(const Fw::StringBase &filename, U32 command) const