F´ Flight Software - C/C++ Documentation  NASA-v2.0.1
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
7 // Copyright (C) 2009-2018 California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10 //
11 // ======================================================================
12 
13 #include <Fw/Types/Assert.hpp>
16 #include <Fw/Com/ComPacket.hpp>
18 extern "C" {
20 }
21 
22 namespace Svc {
23 
24  // ----------------------------------------------------------------------
25  // Construction, initialization, and destruction
26  // ----------------------------------------------------------------------
27 
29  CmdSequencerComponentImpl(const char* name) :
30  CmdSequencerComponentBase(name),
31  m_FPrimeSequence(*this),
32  m_sequence(&this->m_FPrimeSequence),
33  m_loadCmdCount(0),
34  m_cancelCmdCount(0),
35  m_errorCount(0),
36  m_runMode(STOPPED),
37  m_stepMode(AUTO),
38  m_executedCount(0),
39  m_totalExecutedCount(0),
40  m_sequencesCompletedCount(0),
41  m_timeout(0)
42  {
43 
44  }
45 
47  const NATIVE_INT_TYPE instance) {
48  CmdSequencerComponentBase::init(queueDepth, instance);
49  }
50 
52  this->m_timeout = timeout;
53  }
54 
57  {
58  this->m_sequence = &sequence;
59  }
60 
63  const NATIVE_INT_TYPE identifier,
64  Fw::MemAllocator& allocator,
65  const NATIVE_UINT_TYPE bytes
66  )
67  {
68  this->m_sequence->allocateBuffer(identifier, allocator, bytes);
69  }
70 
73  {
74  FW_ASSERT(this->m_runMode == STOPPED, this->m_runMode);
75  if (not this->loadFile(fileName)) {
76  this->m_sequence->clear();
77  }
78  }
79 
82  {
83  this->m_sequence->deallocateBuffer(allocator);
84  }
85 
87 
88  }
89 
90  // ----------------------------------------------------------------------
91  // Handler implementations
92  // ----------------------------------------------------------------------
93 
94  void CmdSequencerComponentImpl::CS_RUN_cmdHandler(
95  FwOpcodeType opCode,
96  U32 cmdSeq,
97  const Fw::CmdStringArg& fileName) {
98 
99  if (not this->requireRunMode(STOPPED)) {
100  this->cmdResponse_out(opCode, cmdSeq, Fw::COMMAND_EXECUTION_ERROR);
101  return;
102  }
103 
104  // load commands
105  if (not this->loadFile(fileName)) {
106  this->cmdResponse_out(opCode, cmdSeq, Fw::COMMAND_EXECUTION_ERROR);
107  return;
108  }
109 
110  this->m_executedCount = 0;
111 
112  // Check the step mode. If it is auto, start the sequence
113  if (AUTO == this->m_stepMode) {
114  this->m_runMode = RUNNING;
115  this->performCmd_Step();
116  }
117 
118  this->cmdResponse_out(opCode, cmdSeq, Fw::COMMAND_OK);
119  }
120 
121  void CmdSequencerComponentImpl::CS_VALIDATE_cmdHandler(
122  FwOpcodeType opCode,
123  U32 cmdSeq,
124  const Fw::CmdStringArg& fileName
125  ) {
126 
127  if (!this->requireRunMode(STOPPED)) {
128  this->cmdResponse_out(opCode, cmdSeq, Fw::COMMAND_EXECUTION_ERROR);
129  return;
130  }
131 
132  // load commands
133  if (not this->loadFile(fileName)) {
134  this->cmdResponse_out(opCode, cmdSeq, Fw::COMMAND_EXECUTION_ERROR);
135  return;
136  }
137 
138  // clear the buffer
139  this->m_sequence->clear();
140 
141  this->log_ACTIVITY_HI_CS_SequenceValid(this->m_sequence->getLogFileName());
142 
143  this->cmdResponse_out(opCode, cmdSeq, Fw::COMMAND_OK);
144 
145  }
146 
148  void CmdSequencerComponentImpl::seqRunIn_handler(
149  NATIVE_INT_TYPE portNum,
150  Fw::EightyCharString &filename
151  ) {
152 
153  if (!this->requireRunMode(STOPPED)) {
154  this->seqDone_out(0,0,0,Fw::COMMAND_EXECUTION_ERROR);
155  return;
156  }
157 
158  // If file name is non-empty, load a file.
159  // Empty file name means don't load.
160  if (filename != "") {
161  Fw::CmdStringArg cmdStr(filename);
162  const bool status = this->loadFile(cmdStr);
163  if (!status) {
164  this->seqDone_out(0,0,0,Fw::COMMAND_EXECUTION_ERROR);
165  return;
166  }
167  }
168  else if (not this->m_sequence->hasMoreRecords()) {
169  // No sequence loaded
170  this->log_WARNING_LO_CS_NoSequenceActive();
171  this->error();
172  this->seqDone_out(0,0,0,Fw::COMMAND_EXECUTION_ERROR);
173  return;
174  }
175 
176  this->m_executedCount = 0;
177 
178  // Check the step mode. If it is auto, start the sequence
179  if (AUTO == this->m_stepMode) {
180  this->m_runMode = RUNNING;
181  this->performCmd_Step();
182  }
183 
184  this->log_ACTIVITY_HI_CS_PortSequenceStarted(this->m_sequence->getLogFileName());
185  }
186 
187  void CmdSequencerComponentImpl::CS_CANCEL_cmdHandler(
188  FwOpcodeType opCode, U32 cmdSeq) {
189  if (RUNNING == this->m_runMode) {
190  this->performCmd_Cancel();
191  this->log_ACTIVITY_HI_CS_SequenceCanceled(this->m_sequence->getLogFileName());
192  ++this->m_cancelCmdCount;
193  this->tlmWrite_CS_CancelCommands(this->m_cancelCmdCount);
194  } else {
195  this->log_WARNING_LO_CS_NoSequenceActive();
196  }
197  this->cmdResponse_out(opCode, cmdSeq, Fw::COMMAND_OK);
198  }
199 
200  // ----------------------------------------------------------------------
201  // Private helper methods
202  // ----------------------------------------------------------------------
203 
204  bool CmdSequencerComponentImpl ::
205  loadFile(const Fw::CmdStringArg& fileName)
206  {
207  const bool status = this->m_sequence->loadFile(fileName);
208  if (status) {
209  Fw::LogStringArg& logFileName = this->m_sequence->getLogFileName();
210  this->log_ACTIVITY_LO_CS_SequenceLoaded(logFileName);
211  ++this->m_loadCmdCount;
212  this->tlmWrite_CS_LoadCommands(this->m_loadCmdCount);
213  }
214  return status;
215  }
216 
217  void CmdSequencerComponentImpl::error(void) {
218  ++this->m_errorCount;
219  this->tlmWrite_CS_Errors(m_errorCount);
220  }
221 
222  void CmdSequencerComponentImpl::performCmd_Cancel(void) {
223  this->m_sequence->reset();
224  this->m_runMode = STOPPED;
225  this->m_cmdTimer.clear();
226  this->m_cmdTimeoutTimer.clear();
227  this->m_executedCount = 0;
228  // write sequence done port with error, if connected
229  if (this->isConnected_seqDone_OutputPort(0)) {
230  this->seqDone_out(0,0,0,Fw::COMMAND_EXECUTION_ERROR);
231  }
232 
233  }
234 
235  void CmdSequencerComponentImpl ::
236  cmdResponseIn_handler(
237  NATIVE_INT_TYPE portNum,
238  FwOpcodeType opcode,
239  U32 cmdSeq,
240  Fw::CommandResponse response
241  )
242  {
243  if (this->m_runMode == STOPPED) {
244  // Sequencer is not running
245  this->log_WARNING_HI_CS_UnexpectedCompletion(opcode);
246  } else {
247  // clear command timeout
248  this->m_cmdTimeoutTimer.clear();
249  if (response != Fw::COMMAND_OK) {
250  this->commandError(this->m_executedCount, opcode, response);
251  this->performCmd_Cancel();
252  } else if (this->m_runMode == RUNNING && this->m_stepMode == AUTO) {
253  // Auto mode
254  this->commandComplete(opcode);
255  if (not this->m_sequence->hasMoreRecords()) {
256  // No data left
257  this->m_runMode = STOPPED;
258  this->sequenceComplete();
259  } else {
260  this->performCmd_Step();
261  }
262  } else {
263  // Manual step mode
264  this->commandComplete(opcode);
265  if (not this->m_sequence->hasMoreRecords()) {
266  this->m_runMode = STOPPED;
267  this->sequenceComplete();
268  }
269  }
270  }
271  }
272 
273  void CmdSequencerComponentImpl ::
274  schedIn_handler(NATIVE_INT_TYPE portNum, NATIVE_UINT_TYPE order)
275  {
276 
277  Fw::Time currTime = this->getTime();
278  // check to see if a command time is pending
279  if (this->m_cmdTimer.isExpiredAt(currTime)) {
280  this->comCmdOut_out(0, m_record.m_command, 0);
281  this->m_cmdTimer.clear();
282  // start command timeout timer
283  this->setCmdTimeout(currTime);
284  } else if (this->m_cmdTimeoutTimer.isExpiredAt(this->getTime())) { // check for command timeout
285  this->log_WARNING_HI_CS_SequenceTimeout(
286  m_sequence->getLogFileName(),
287  this->m_executedCount
288  );
289  // If there is a command timeout, cancel the sequence
290  this->performCmd_Cancel();
291  }
292  }
293 
294  void CmdSequencerComponentImpl ::
295  CS_START_cmdHandler(FwOpcodeType opcode, U32 cmdSeq)
296  {
297  if (not this->m_sequence->hasMoreRecords()) {
298  // No sequence loaded
299  this->log_WARNING_LO_CS_NoSequenceActive();
300  this->cmdResponse_out(opcode, cmdSeq, Fw::COMMAND_EXECUTION_ERROR);
301  return;
302  }
303  if (!this->requireRunMode(STOPPED)) {
304  this->cmdResponse_out(opcode, cmdSeq, Fw::COMMAND_EXECUTION_ERROR);
305  return;
306  }
307  this->m_runMode = RUNNING;
308  this->performCmd_Step();
309  this->log_ACTIVITY_HI_CS_CmdStarted(this->m_sequence->getLogFileName());
310  this->cmdResponse_out(opcode, cmdSeq, Fw::COMMAND_OK);
311  }
312 
313  void CmdSequencerComponentImpl ::
314  CS_STEP_cmdHandler(FwOpcodeType opcode, U32 cmdSeq)
315  {
316  if (this->requireRunMode(RUNNING)) {
317  this->performCmd_Step();
318  // check for special case where end of sequence entry was encountered
319  if (this->m_runMode != STOPPED) {
320  this->log_ACTIVITY_HI_CS_CmdStepped(
321  this->m_sequence->getLogFileName(),
322  this->m_executedCount
323  );
324  }
325  this->cmdResponse_out(opcode, cmdSeq, Fw::COMMAND_OK);
326  } else {
327  this->cmdResponse_out(opcode, cmdSeq, Fw::COMMAND_EXECUTION_ERROR);
328  }
329  }
330 
331  void CmdSequencerComponentImpl ::
332  CS_AUTO_cmdHandler(FwOpcodeType opcode, U32 cmdSeq)
333  {
334  if (this->requireRunMode(STOPPED)) {
335  this->m_stepMode = AUTO;
336  this->log_ACTIVITY_HI_CS_ModeSwitched(SEQ_AUTO_MODE);
337  this->cmdResponse_out(opcode, cmdSeq, Fw::COMMAND_OK);
338  } else {
339  this->cmdResponse_out(opcode, cmdSeq, Fw::COMMAND_EXECUTION_ERROR);
340  }
341  }
342 
343  void CmdSequencerComponentImpl ::
344  CS_MANUAL_cmdHandler(FwOpcodeType opcode, U32 cmdSeq)
345  {
346  if (this->requireRunMode(STOPPED)) {
347  this->m_stepMode = MANUAL;
348  this->log_ACTIVITY_HI_CS_ModeSwitched(SEQ_STEP_MODE);
349  this->cmdResponse_out(opcode, cmdSeq, Fw::COMMAND_OK);
350  } else {
351  this->cmdResponse_out(opcode, cmdSeq, Fw::COMMAND_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 {
363  this->log_WARNING_HI_CS_InvalidMode();
364  return false;
365  }
366  }
367 
368  void CmdSequencerComponentImpl ::
369  commandError(
370  const U32 number,
371  const U32 opCode,
372  const U32 error
373  )
374  {
375  this->log_WARNING_HI_CS_CommandError(
376  this->m_sequence->getLogFileName(),
377  number,
378  opCode,
379  error
380  );
381  this->error();
382  }
383 
384  void CmdSequencerComponentImpl::performCmd_Step(void) {
385 
386  this->m_sequence->nextRecord(m_record);
387  // set clock time base and context from value set when sequence was loaded
388  const Sequence::Header& header = this->m_sequence->getHeader();
389  this->m_record.m_timeTag.setTimeBase(header.m_timeBase);
390  this->m_record.m_timeTag.setTimeContext(header.m_timeContext);
391 
392  Fw::Time currentTime = this->getTime();
393  switch (this->m_record.m_descriptor) {
395  this->m_runMode = STOPPED;
396  this->sequenceComplete();
397  break;
399  this->performCmd_Step_RELATIVE(currentTime);
400  break;
402  this->performCmd_Step_ABSOLUTE(currentTime);
403  break;
404  default:
405  FW_ASSERT(0, m_record.m_descriptor);
406  }
407  }
408 
409  void CmdSequencerComponentImpl::sequenceComplete(void) {
410  ++this->m_sequencesCompletedCount;
411  // reset buffer
412  this->m_sequence->clear();
413  this->log_ACTIVITY_HI_CS_SequenceComplete(this->m_sequence->getLogFileName());
414  this->tlmWrite_CS_SequencesCompleted(this->m_sequencesCompletedCount);
415  this->m_executedCount = 0;
416  // write sequence done port, if connected
417  if (this->isConnected_seqDone_OutputPort(0)) {
418  this->seqDone_out(0,0,0,Fw::COMMAND_OK);
419  }
420  }
421 
422  void CmdSequencerComponentImpl::commandComplete(const U32 opcode) {
423  this->log_ACTIVITY_LO_CS_CommandComplete(
424  this->m_sequence->getLogFileName(),
425  this->m_executedCount,
426  opcode
427  );
428  ++this->m_executedCount;
429  ++this->m_totalExecutedCount;
430  this->tlmWrite_CS_CommandsExecuted(this->m_totalExecutedCount);
431  }
432 
433  void CmdSequencerComponentImpl ::
434  performCmd_Step_RELATIVE(Fw::Time& currentTime)
435  {
436  this->m_record.m_timeTag.add(currentTime.getSeconds(),currentTime.getUSeconds());
437  this->performCmd_Step_ABSOLUTE(currentTime);
438  }
439 
440  void CmdSequencerComponentImpl ::
441  performCmd_Step_ABSOLUTE(Fw::Time& currentTime)
442  {
443  if (currentTime >= this->m_record.m_timeTag) {
444  this->comCmdOut_out(0, m_record.m_command, 0);
445  this->setCmdTimeout(currentTime);
446  } else {
447  this->m_cmdTimer.set(this->m_record.m_timeTag);
448  }
449  }
450 
451  void CmdSequencerComponentImpl ::
452  pingIn_handler(
453  NATIVE_INT_TYPE portNum,
454  U32 key
455  )
456  {
457  // send ping response
458  this->pingOut_out(0,key);
459  }
460 
461  void CmdSequencerComponentImpl ::
462  setCmdTimeout(const Fw::Time &currentTime)
463  {
464  // start timeout timer if enabled and not in step mode
465  if ((this->m_timeout > 0) and (AUTO == this->m_stepMode)) {
466  Fw::Time expTime = currentTime;
467  expTime.add(this->m_timeout,0);
468  this->m_cmdTimeoutTimer.set(expTime);
469  }
470  }
471 
472 }
473 
Svc::CmdSequencerComponentImpl::CmdSequencerComponentImpl
CmdSequencerComponentImpl(const char *compName)
Construct a CmdSequencer.
Definition: CmdSequencerImpl.cpp:29
Svc::CmdSequencerComponentImpl::Sequence::deallocateBuffer
void deallocateBuffer(Fw::MemAllocator &allocator)
Deallocate the buffer.
Definition: Sequence.cpp:100
Svc::CmdSequencerComponentImpl::Sequence::Record::m_descriptor
Descriptor m_descriptor
The descriptor.
Definition: CmdSequencerImpl.hpp:230
Fw::Time
Definition: Time.hpp:10
Svc::CmdSequencerComponentImpl::setTimeout
void setTimeout(NATIVE_UINT_TYPE seconds)
Definition: CmdSequencerImpl.cpp:51
Serializable.hpp
Fw::LogStringArg
Definition: LogString.hpp:11
Svc::CmdSequencerComponentImpl::Sequence::clear
virtual void clear(void)=0
Svc::CmdSequencerComponentImpl::Sequence::Record::END_OF_SEQUENCE
@ END_OF_SEQUENCE
end of sequence
Definition: CmdSequencerImpl.hpp:215
Fw::EightyCharString
Definition: EightyCharString.hpp:10
Fw::Time::getUSeconds
U32 getUSeconds(void) const
Definition: Time.cpp:138
Svc::CmdSequencerComponentImpl::Sequence::loadFile
virtual bool loadFile(const Fw::CmdStringArg &fileName)=0
Fw::CmdStringArg
Definition: CmdString.hpp:11
Assert.hpp
Svc::CmdSequencerComponentImpl::Sequence::Record::ABSOLUTE
@ ABSOLUTE
Absolute time.
Definition: CmdSequencerImpl.hpp:213
Svc::CmdSequencerComponentImpl::allocateBuffer
void allocateBuffer(const NATIVE_INT_TYPE identifier, Fw::MemAllocator &allocator, const NATIVE_UINT_TYPE bytes)
Definition: CmdSequencerImpl.cpp:62
Svc::CmdSequencerComponentImpl::Sequence::reset
virtual void reset(void)=0
SerialBuffer.hpp
Svc::CmdSequencerComponentImpl::Sequence::Record::RELATIVE
@ RELATIVE
Relative time.
Definition: CmdSequencerImpl.hpp:214
Svc::CmdSequencerComponentImpl::Sequence::Record::m_command
Fw::ComBuffer m_command
The command.
Definition: CmdSequencerImpl.hpp:236
Svc::CmdSequencerComponentImpl::Sequence::allocateBuffer
void allocateBuffer(const NATIVE_INT_TYPE identifier, Fw::MemAllocator &allocator, const NATIVE_UINT_TYPE bytes)
Give the sequence representation a memory buffer.
Definition: Sequence.cpp:79
FwOpcodeType
#define FwOpcodeType
Type representation for a command opcode.
Definition: FpConfig.hpp:62
NATIVE_UINT_TYPE
unsigned int NATIVE_UINT_TYPE
native unsigned integer type declaration
Definition: BasicTypes.hpp:30
Fw::Time::setTimeBase
void setTimeBase(TimeBase timeBase)
Definition: Time.cpp:246
Svc::CmdSequencerComponentImpl::deallocateBuffer
void deallocateBuffer(Fw::MemAllocator &allocator)
Return allocated buffer. Call during shutdown.
Definition: CmdSequencerImpl.cpp:81
FW_ASSERT
#define FW_ASSERT(...)
Definition: Assert.hpp:9
Svc::CmdSequencerComponentImpl::Sequence::getHeader
const Header & getHeader(void) const
Get the sequence header.
Definition: Sequence.cpp:111
Fw::MemAllocator
Definition: MemAllocator.hpp:44
Svc::CmdSequencerComponentImpl::init
void init(const NATIVE_INT_TYPE queueDepth, const NATIVE_INT_TYPE instance)
Initialize a CmdSequencer.
Definition: CmdSequencerImpl.cpp:46
Fw::Time::getSeconds
U32 getSeconds(void) const
Definition: Time.cpp:134
Svc::CmdSequencerComponentImpl::~CmdSequencerComponentImpl
~CmdSequencerComponentImpl(void)
Destroy a CmdDispatcherComponentBase.
Definition: CmdSequencerImpl.cpp:86
lib_crc.h
Svc
Definition: ActiveRateGroupImplCfg.hpp:18
Svc::CmdSequencerComponentImpl::Sequence::getLogFileName
Fw::LogStringArg & getLogFileName(void)
Definition: Sequence.cpp:130
Svc::CmdSequencerComponentImpl::Sequence::nextRecord
virtual void nextRecord(Record &record)=0
CmdSequencerImpl.hpp
Fw::Time::setTimeContext
void setTimeContext(FwTimeContextStoreType context)
Definition: Time.cpp:250
Fw::Time::add
static Time add(Time &a, Time &b)
Definition: Time.cpp:188
Svc::CmdSequencerComponentImpl::Sequence
A sequence with unspecified binary format.
Definition: CmdSequencerImpl.hpp:52
Svc::CmdSequencerComponentImpl::Sequence::Record::m_timeTag
Fw::Time m_timeTag
The time tag. NOTE: timeBase and context not filled in.
Definition: CmdSequencerImpl.hpp:233
NATIVE_INT_TYPE
int NATIVE_INT_TYPE
native integer type declaration
Definition: BasicTypes.hpp:29
Svc::CmdSequencerComponentImpl::Sequence::hasMoreRecords
virtual bool hasMoreRecords(void) const =0
Svc::CmdSequencerComponentImpl::setSequenceFormat
void setSequenceFormat(Sequence &sequence)
Definition: CmdSequencerImpl.cpp:56
ComPacket.hpp
Svc::CmdSequencerComponentImpl::loadSequence
void loadSequence(const Fw::EightyCharString &fileName)
Definition: CmdSequencerImpl.cpp:72