F´ Flight Software - C/C++ Documentation  NASA-v2.0.1
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
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