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