F´ Flight Software - C/C++ Documentation  devel
A framework for building embedded system applications to NASA flight quality standards.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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)