F´ Flight Software - C/C++ Documentation  devel
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/Types/Assert.hpp>
13 #include <Fw/Com/ComPacket.hpp>
15 extern "C" {
17 }
18 
19 namespace Svc {
20 
21  // ----------------------------------------------------------------------
22  // Construction, initialization, and destruction
23  // ----------------------------------------------------------------------
24 
26  CmdSequencerComponentImpl(const char* name) :
28  m_FPrimeSequence(*this),
29  m_sequence(&this->m_FPrimeSequence),
30  m_loadCmdCount(0),
31  m_cancelCmdCount(0),
32  m_errorCount(0),
33  m_runMode(STOPPED),
34  m_stepMode(AUTO),
35  m_executedCount(0),
36  m_totalExecutedCount(0),
37  m_sequencesCompletedCount(0),
38  m_timeout(0),
39  m_blockState(Svc::CmdSequencer_BlockState::NO_BLOCK),
40  m_opCode(0),
41  m_cmdSeq(0),
42  m_join_waiting(false)
43  {
44 
45  }
46 
48  this->m_timeout = timeout;
49  }
50 
53  {
54  this->m_sequence = &sequence;
55  }
56 
59  const NATIVE_INT_TYPE identifier,
60  Fw::MemAllocator& allocator,
61  const NATIVE_UINT_TYPE bytes
62  )
63  {
64  this->m_sequence->allocateBuffer(identifier, allocator, bytes);
65  }
66 
68  loadSequence(const Fw::StringBase& fileName)
69  {
70  FW_ASSERT(this->m_runMode == STOPPED, this->m_runMode);
71  if (not this->loadFile(fileName)) {
72  this->m_sequence->clear();
73  }
74  }
75 
78  {
79  this->m_sequence->deallocateBuffer(allocator);
80  }
81 
83 
84  }
85 
86  // ----------------------------------------------------------------------
87  // Handler implementations
88  // ----------------------------------------------------------------------
89 
90  void CmdSequencerComponentImpl::CS_RUN_cmdHandler(
91  FwOpcodeType opCode,
92  U32 cmdSeq,
93  const Fw::CmdStringArg& fileName,
95 
96  if (not this->requireRunMode(STOPPED)) {
97  if (m_join_waiting) {
98  // Inform user previous seq file is not complete
100  }
101  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
102  return;
103  }
104 
105  this->m_blockState = block.e;
106  this->m_cmdSeq = cmdSeq;
107  this->m_opCode = opCode;
108 
109  // load commands
110  if (not this->loadFile(fileName)) {
111  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
112  return;
113  }
114 
115  this->m_executedCount = 0;
116 
117  // Check the step mode. If it is auto, start the sequence
118  if (AUTO == this->m_stepMode) {
119  this->m_runMode = RUNNING;
121  this->seqStartOut_out(0, this->m_sequence->getStringFileName());
122  }
123  this->performCmd_Step();
124  }
125 
126  if (Svc::CmdSequencer_BlockState::NO_BLOCK == this->m_blockState) {
127  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
128  }
129  }
130 
131  void CmdSequencerComponentImpl::CS_VALIDATE_cmdHandler(
132  FwOpcodeType opCode,
133  U32 cmdSeq,
134  const Fw::CmdStringArg& fileName
135  ) {
136 
137  if (!this->requireRunMode(STOPPED)) {
138  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
139  return;
140  }
141 
142  // load commands
143  if (not this->loadFile(fileName)) {
144  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
145  return;
146  }
147 
148  // clear the buffer
149  this->m_sequence->clear();
150 
151  this->log_ACTIVITY_HI_CS_SequenceValid(this->m_sequence->getLogFileName());
152 
153  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
154 
155  }
156 
158  void CmdSequencerComponentImpl::seqRunIn_handler(
159  NATIVE_INT_TYPE portNum,
160  const Fw::StringBase& filename
161  ) {
162 
163  if (!this->requireRunMode(STOPPED)) {
165  return;
166  }
167 
168  // If file name is non-empty, load a file.
169  // Empty file name means don't load.
170  if (filename != "") {
171  Fw::CmdStringArg cmdStr(filename);
172  const bool status = this->loadFile(cmdStr);
173  if (!status) {
175  return;
176  }
177  }
178  else if (not this->m_sequence->hasMoreRecords()) {
179  // No sequence loaded
181  this->error();
183  return;
184  }
185 
186  this->m_executedCount = 0;
187 
188  // Check the step mode. If it is auto, start the sequence
189  if (AUTO == this->m_stepMode) {
190  this->m_runMode = RUNNING;
192  this->seqStartOut_out(0, this->m_sequence->getStringFileName());
193  }
194  this->performCmd_Step();
195  }
196 
197  this->log_ACTIVITY_HI_CS_PortSequenceStarted(this->m_sequence->getLogFileName());
198  }
199 
200  void CmdSequencerComponentImpl ::
201  seqCancelIn_handler(
202  const NATIVE_INT_TYPE portNum
203  ) {
204  if (RUNNING == this->m_runMode) {
205  this->performCmd_Cancel();
206  this->log_ACTIVITY_HI_CS_SequenceCanceled(this->m_sequence->getLogFileName());
207  ++this->m_cancelCmdCount;
208  this->tlmWrite_CS_CancelCommands(this->m_cancelCmdCount);
209  } else {
211  }
212  }
213 
214  void CmdSequencerComponentImpl::CS_CANCEL_cmdHandler(
215  FwOpcodeType opCode, U32 cmdSeq) {
216  if (RUNNING == this->m_runMode) {
217  this->performCmd_Cancel();
218  this->log_ACTIVITY_HI_CS_SequenceCanceled(this->m_sequence->getLogFileName());
219  ++this->m_cancelCmdCount;
220  this->tlmWrite_CS_CancelCommands(this->m_cancelCmdCount);
221  } else {
223  }
224  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
225  }
226 
227  void CmdSequencerComponentImpl::CS_JOIN_WAIT_cmdHandler(
228  const FwOpcodeType opCode, const U32 cmdSeq) {
229 
230  // If there is no running sequence do not wait
231  if (m_runMode != RUNNING) {
233  this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK);
234  return;
235  } else {
236  m_join_waiting = true;
237  Fw::LogStringArg& logFileName = this->m_sequence->getLogFileName();
238  this->log_ACTIVITY_HI_CS_JoinWaiting(logFileName, m_cmdSeq, m_opCode);
239  m_cmdSeq = cmdSeq;
240  m_opCode = opCode;
241  }
242  }
243 
244  // ----------------------------------------------------------------------
245  // Private helper methods
246  // ----------------------------------------------------------------------
247 
248  bool CmdSequencerComponentImpl ::
249  loadFile(const Fw::StringBase& fileName)
250  {
251  const bool status = this->m_sequence->loadFile(fileName);
252  if (status) {
253  Fw::LogStringArg& logFileName = this->m_sequence->getLogFileName();
254  this->log_ACTIVITY_LO_CS_SequenceLoaded(logFileName);
255  ++this->m_loadCmdCount;
256  this->tlmWrite_CS_LoadCommands(this->m_loadCmdCount);
257  }
258  return status;
259  }
260 
261  void CmdSequencerComponentImpl::error() {
262  ++this->m_errorCount;
263  this->tlmWrite_CS_Errors(m_errorCount);
264  }
265 
266  void CmdSequencerComponentImpl::performCmd_Cancel() {
267  this->m_sequence->reset();
268  this->m_runMode = STOPPED;
269  this->m_cmdTimer.clear();
270  this->m_cmdTimeoutTimer.clear();
271  this->m_executedCount = 0;
272  // write sequence done port with error, if connected
273  if (this->isConnected_seqDone_OutputPort(0)) {
275  }
276 
277  if (Svc::CmdSequencer_BlockState::BLOCK == this->m_blockState || m_join_waiting) {
278  // Do not wait if sequence was canceled or a cmd failed
279  this->m_join_waiting = false;
280  this->cmdResponse_out(this->m_opCode, this->m_cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
281  }
282 
283  this->m_blockState = Svc::CmdSequencer_BlockState::NO_BLOCK;
284  }
285 
286  void CmdSequencerComponentImpl ::
287  cmdResponseIn_handler(
288  NATIVE_INT_TYPE portNum,
289  FwOpcodeType opcode,
290  U32 cmdSeq,
291  const Fw::CmdResponse& response
292  )
293  {
294  if (this->m_runMode == STOPPED) {
295  // Sequencer is not running
297  } else {
298  // clear command timeout
299  this->m_cmdTimeoutTimer.clear();
300  if (response != Fw::CmdResponse::OK) {
301  this->commandError(this->m_executedCount, opcode, response.e);
302  this->performCmd_Cancel();
303  } else if (this->m_runMode == RUNNING && this->m_stepMode == AUTO) {
304  // Auto mode
305  this->commandComplete(opcode);
306  if (not this->m_sequence->hasMoreRecords()) {
307  // No data left
308  this->m_runMode = STOPPED;
309  this->sequenceComplete();
310  } else {
311  this->performCmd_Step();
312  }
313  } else {
314  // Manual step mode
315  this->commandComplete(opcode);
316  if (not this->m_sequence->hasMoreRecords()) {
317  this->m_runMode = STOPPED;
318  this->sequenceComplete();
319  }
320  }
321  }
322  }
323 
324  void CmdSequencerComponentImpl ::
325  schedIn_handler(NATIVE_INT_TYPE portNum, NATIVE_UINT_TYPE order)
326  {
327 
328  Fw::Time currTime = this->getTime();
329  // check to see if a command time is pending
330  if (this->m_cmdTimer.isExpiredAt(currTime)) {
331  this->comCmdOut_out(0, m_record.m_command, 0);
332  this->m_cmdTimer.clear();
333  // start command timeout timer
334  this->setCmdTimeout(currTime);
335  } else if (this->m_cmdTimeoutTimer.isExpiredAt(this->getTime())) { // check for command timeout
337  m_sequence->getLogFileName(),
338  this->m_executedCount
339  );
340  // If there is a command timeout, cancel the sequence
341  this->performCmd_Cancel();
342  }
343  }
344 
345  void CmdSequencerComponentImpl ::
346  CS_START_cmdHandler(FwOpcodeType opcode, U32 cmdSeq)
347  {
348  if (not this->m_sequence->hasMoreRecords()) {
349  // No sequence loaded
351  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
352  return;
353  }
354  if (!this->requireRunMode(STOPPED)) {
355  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
356  return;
357  }
358 
359  this->m_blockState = Svc::CmdSequencer_BlockState::NO_BLOCK;
360  this->m_runMode = RUNNING;
361  this->performCmd_Step();
362  this->log_ACTIVITY_HI_CS_CmdStarted(this->m_sequence->getLogFileName());
364  this->seqStartOut_out(0, this->m_sequence->getStringFileName());
365  }
366  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::OK);
367  }
368 
369  void CmdSequencerComponentImpl ::
370  CS_STEP_cmdHandler(FwOpcodeType opcode, U32 cmdSeq)
371  {
372  if (this->requireRunMode(RUNNING)) {
373  this->performCmd_Step();
374  // check for special case where end of sequence entry was encountered
375  if (this->m_runMode != STOPPED) {
377  this->m_sequence->getLogFileName(),
378  this->m_executedCount
379  );
380  }
381  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::OK);
382  } else {
383  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
384  }
385  }
386 
387  void CmdSequencerComponentImpl ::
388  CS_AUTO_cmdHandler(FwOpcodeType opcode, U32 cmdSeq)
389  {
390  if (this->requireRunMode(STOPPED)) {
391  this->m_stepMode = AUTO;
393  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::OK);
394  } else {
395  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
396  }
397  }
398 
399  void CmdSequencerComponentImpl ::
400  CS_MANUAL_cmdHandler(FwOpcodeType opcode, U32 cmdSeq)
401  {
402  if (this->requireRunMode(STOPPED)) {
403  this->m_stepMode = MANUAL;
405  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::OK);
406  } else {
407  this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
408  }
409  }
410 
411  // ----------------------------------------------------------------------
412  // Helper methods
413  // ----------------------------------------------------------------------
414 
415  bool CmdSequencerComponentImpl::requireRunMode(RunMode mode) {
416  if (this->m_runMode == mode) {
417  return true;
418  } else {
420  return false;
421  }
422  }
423 
424  void CmdSequencerComponentImpl ::
425  commandError(
426  const U32 number,
427  const U32 opCode,
428  const U32 error
429  )
430  {
432  this->m_sequence->getLogFileName(),
433  number,
434  opCode,
435  error
436  );
437  this->error();
438  }
439 
440  void CmdSequencerComponentImpl::performCmd_Step() {
441 
442  this->m_sequence->nextRecord(m_record);
443  // set clock time base and context from value set when sequence was loaded
444  const Sequence::Header& header = this->m_sequence->getHeader();
445  this->m_record.m_timeTag.setTimeBase(header.m_timeBase);
446  this->m_record.m_timeTag.setTimeContext(header.m_timeContext);
447 
448  Fw::Time currentTime = this->getTime();
449  switch (this->m_record.m_descriptor) {
451  this->m_runMode = STOPPED;
452  this->sequenceComplete();
453  break;
455  this->performCmd_Step_RELATIVE(currentTime);
456  break;
458  this->performCmd_Step_ABSOLUTE(currentTime);
459  break;
460  default:
461  FW_ASSERT(0, m_record.m_descriptor);
462  }
463  }
464 
465  void CmdSequencerComponentImpl::sequenceComplete() {
466  ++this->m_sequencesCompletedCount;
467  // reset buffer
468  this->m_sequence->clear();
469  this->log_ACTIVITY_HI_CS_SequenceComplete(this->m_sequence->getLogFileName());
470  this->tlmWrite_CS_SequencesCompleted(this->m_sequencesCompletedCount);
471  this->m_executedCount = 0;
472  // write sequence done port, if connected
473  if (this->isConnected_seqDone_OutputPort(0)) {
474  this->seqDone_out(0,0,0,Fw::CmdResponse::OK);
475  }
476 
477  if (Svc::CmdSequencer_BlockState::BLOCK == this->m_blockState || m_join_waiting) {
478  this->cmdResponse_out(this->m_opCode, this->m_cmdSeq, Fw::CmdResponse::OK);
479  }
480 
481  m_join_waiting = false;
482  this->m_blockState = Svc::CmdSequencer_BlockState::NO_BLOCK;
483 
484  }
485 
486  void CmdSequencerComponentImpl::commandComplete(const U32 opcode) {
488  this->m_sequence->getLogFileName(),
489  this->m_executedCount,
490  opcode
491  );
492  ++this->m_executedCount;
493  ++this->m_totalExecutedCount;
494  this->tlmWrite_CS_CommandsExecuted(this->m_totalExecutedCount);
495  }
496 
497  void CmdSequencerComponentImpl ::
498  performCmd_Step_RELATIVE(Fw::Time& currentTime)
499  {
500  this->m_record.m_timeTag.add(currentTime.getSeconds(),currentTime.getUSeconds());
501  this->performCmd_Step_ABSOLUTE(currentTime);
502  }
503 
504  void CmdSequencerComponentImpl ::
505  performCmd_Step_ABSOLUTE(Fw::Time& currentTime)
506  {
507  if (currentTime >= this->m_record.m_timeTag) {
508  this->comCmdOut_out(0, m_record.m_command, 0);
509  this->setCmdTimeout(currentTime);
510  } else {
511  this->m_cmdTimer.set(this->m_record.m_timeTag);
512  }
513  }
514 
515  void CmdSequencerComponentImpl ::
516  pingIn_handler(
517  NATIVE_INT_TYPE portNum,
518  U32 key
519  )
520  {
521  // send ping response
522  this->pingOut_out(0,key);
523  }
524 
525  void CmdSequencerComponentImpl ::
526  setCmdTimeout(const Fw::Time &currentTime)
527  {
528  // start timeout timer if enabled and not in step mode
529  if ((this->m_timeout > 0) and (AUTO == this->m_stepMode)) {
530  Fw::Time expTime = currentTime;
531  expTime.add(this->m_timeout,0);
532  this->m_cmdTimeoutTimer.set(expTime);
533  }
534  }
535 
536 }
537 
#define FW_ASSERT(...)
Definition: Assert.hpp:14
PlatformIntType NATIVE_INT_TYPE
Definition: BasicTypes.h:55
PlatformUIntType NATIVE_UINT_TYPE
Definition: BasicTypes.h:56
U32 FwOpcodeType
Definition: FpConfig.h:91
Enum representing a command response.
@ EXECUTION_ERROR
Command had execution error.
@ OK
Command successfully executed.
T e
The raw enum value.
Definition: Time.hpp:9
static Time add(const Time &a, const Time &b)
Definition: Time.cpp:193
U32 getUSeconds() const
Definition: Time.cpp:139
void setTimeContext(FwTimeContextStoreType context)
Definition: Time.cpp:255
void setTimeBase(TimeBase timeBase)
Definition: Time.cpp:251
U32 getSeconds() const
Definition: Time.cpp:135
Auto-generated base for CmdSequencer component.
bool isConnected_seqStartOut_OutputPort(FwIndexType portNum)
void log_ACTIVITY_HI_CS_CmdStepped(const Fw::StringBase &filename, U32 command)
void tlmWrite_CS_CancelCommands(U32 arg, Fw::Time _tlmTime=Fw::Time())
void seqDone_out(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response)
Invoke output port seqDone.
void tlmWrite_CS_CommandsExecuted(U32 arg, Fw::Time _tlmTime=Fw::Time())
void seqStartOut_out(FwIndexType portNum, const Fw::StringBase &filename)
Invoke output port seqStartOut.
void log_ACTIVITY_LO_CS_CommandComplete(const Fw::StringBase &fileName, U32 recordNumber, U32 opCode)
bool isConnected_seqDone_OutputPort(FwIndexType portNum)
void log_ACTIVITY_HI_CS_SequenceComplete(const Fw::StringBase &fileName)
void log_WARNING_HI_CS_SequenceTimeout(const Fw::StringBase &filename, U32 command)
void tlmWrite_CS_Errors(U32 arg, Fw::Time _tlmTime=Fw::Time())
void pingOut_out(FwIndexType portNum, U32 key)
Invoke output port pingOut.
void log_ACTIVITY_HI_CS_ModeSwitched(Svc::CmdSequencer_SeqMode mode)
void log_ACTIVITY_HI_CS_SequenceCanceled(const Fw::StringBase &fileName)
void cmdResponse_out(FwOpcodeType opCode, U32 cmdSeq, Fw::CmdResponse response)
Emit command response.
void log_ACTIVITY_HI_CS_PortSequenceStarted(const Fw::StringBase &filename)
void log_ACTIVITY_HI_CS_SequenceValid(const Fw::StringBase &filename)
void comCmdOut_out(FwIndexType portNum, Fw::ComBuffer &data, U32 context)
Invoke output port comCmdOut.
void log_ACTIVITY_LO_CS_SequenceLoaded(const Fw::StringBase &fileName)
void log_ACTIVITY_HI_CS_JoinWaiting(const Fw::StringBase &filename, U32 recordNumber, U32 opCode)
void log_WARNING_HI_CS_CommandError(const Fw::StringBase &fileName, U32 recordNumber, U32 opCode, U32 errorStatus)
void log_ACTIVITY_HI_CS_CmdStarted(const Fw::StringBase &filename)
void tlmWrite_CS_LoadCommands(U32 arg, Fw::Time _tlmTime=Fw::Time())
void tlmWrite_CS_SequencesCompleted(U32 arg, Fw::Time _tlmTime=Fw::Time())
Fw::Time m_timeTag
The time tag. NOTE: timeBase and context not filled in.
A sequence with unspecified binary format.
void allocateBuffer(NATIVE_INT_TYPE identifier, Fw::MemAllocator &allocator, NATIVE_UINT_TYPE bytes)
Give the sequence representation a memory buffer.
Definition: Sequence.cpp:77
virtual bool loadFile(const Fw::StringBase &fileName)=0
virtual void nextRecord(Record &record)=0
void deallocateBuffer(Fw::MemAllocator &allocator)
Deallocate the buffer.
Definition: Sequence.cpp:94
virtual bool hasMoreRecords() const =0
const Header & getHeader() const
Get the sequence header.
Definition: Sequence.cpp:105
~CmdSequencerComponentImpl()
Destroy a CmdDispatcherComponentBase.
void deallocateBuffer(Fw::MemAllocator &allocator)
Return allocated buffer. Call during shutdown.
CmdSequencerComponentImpl(const char *compName)
Construct a CmdSequencer.
void setTimeout(const NATIVE_UINT_TYPE seconds)
void loadSequence(const Fw::StringBase &fileName)
void setSequenceFormat(Sequence &sequence)
void allocateBuffer(const NATIVE_INT_TYPE identifier, Fw::MemAllocator &allocator, const NATIVE_UINT_TYPE bytes)