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>
15extern "C" {
17}
18
19namespace 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
56 void CmdSequencerComponentImpl ::
57 setSequenceFormat(Sequence& sequence)
58 {
59 this->m_sequence = &sequence;
60 }
61
62 void CmdSequencerComponentImpl ::
63 allocateBuffer(
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
72 void CmdSequencerComponentImpl ::
73 loadSequence(const Fw::String& 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
81 void CmdSequencerComponentImpl ::
82 deallocateBuffer(Fw::MemAllocator& allocator)
83 {
84 this->m_sequence->deallocateBuffer(allocator);
85 }
86
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 }
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)) {
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)) {
141 return;
142 }
143
144 // load commands
145 if (not this->loadFile(fileName)) {
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
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 {
209 this->log_WARNING_LO_CS_NoSequenceActive();
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::CmdStringArg& 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
295 this->log_WARNING_HI_CS_UnexpectedCompletion(opcode);
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
335 this->log_WARNING_HI_CS_SequenceTimeout(
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
349 this->log_WARNING_LO_CS_NoSequenceActive();
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) {
372 this->log_ACTIVITY_HI_CS_CmdStepped(
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;
388 this->log_ACTIVITY_HI_CS_ModeSwitched(CmdSequencer_SeqMode::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;
400 this->log_ACTIVITY_HI_CS_ModeSwitched(CmdSequencer_SeqMode::STEP);
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 {
427 this->log_WARNING_HI_CS_CommandError(
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:56
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
static Time add(const Time &a, const Time &b)
Definition Time.cpp:193
U32 getUSeconds() const
Definition Time.cpp:139
void set(U32 seconds, U32 useconds)
Definition Time.cpp:25
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 tlmWrite_CS_CancelCommands(U32 arg, Fw::Time _tlmTime=Fw::Time())
void log_ACTIVITY_HI_CS_SequenceComplete(const Fw::LogStringArg &fileName)
bool isConnected_seqDone_OutputPort(NATIVE_INT_TYPE portNum)
void tlmWrite_CS_CommandsExecuted(U32 arg, Fw::Time _tlmTime=Fw::Time())
void seqDone_out(NATIVE_INT_TYPE portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response)
Invoke output port seqDone.
void tlmWrite_CS_Errors(U32 arg, Fw::Time _tlmTime=Fw::Time())
void cmdResponse_out(FwOpcodeType opCode, U32 cmdSeq, Fw::CmdResponse response)
Emit command response.
void log_ACTIVITY_LO_CS_CommandComplete(const Fw::LogStringArg &fileName, U32 recordNumber, U32 opCode)
void log_ACTIVITY_HI_CS_SequenceCanceled(const Fw::LogStringArg &fileName)
void log_ACTIVITY_HI_CS_PortSequenceStarted(const Fw::LogStringArg &filename)
void log_ACTIVITY_HI_CS_JoinWaiting(const Fw::LogStringArg &filename, U32 recordNumber, U32 opCode)
void log_ACTIVITY_HI_CS_SequenceValid(const Fw::LogStringArg &filename)
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 void nextRecord(Record &record)=0
virtual bool hasMoreRecords() const =0
const Header & getHeader() const
Get the sequence header.
Definition Sequence.cpp:105
~CmdSequencerComponentImpl()
Destroy a CmdDispatcherComponentBase.
CmdSequencerComponentImpl(const char *compName)
Construct a CmdSequencer.
void setTimeout(const NATIVE_UINT_TYPE seconds)