F´ Flight Software - C/C++ Documentation NASA-v1.6.0
A framework for building embedded system applications to NASA flight quality standards.
Loading...
Searching...
No Matches
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) :
27 CmdSequencerComponentBase(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
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,
99 Svc::CmdSequencer_BlockState block) {
100
101 if (not this->requireRunMode(STOPPED)) {
102 if (m_join_waiting) {
103 // Inform user previous seq file is not complete
104 this->log_WARNING_HI_CS_JoinWaitingNotComplete();
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)) {
166 this->seqDone_out(0,0,0,Fw::CmdResponse::EXECUTION_ERROR);
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) {
176 this->seqDone_out(0,0,0,Fw::CmdResponse::EXECUTION_ERROR);
177 return;
178 }
179 }
180 else if (not this->m_sequence->hasMoreRecords()) {
181 // No sequence loaded
182 this->log_WARNING_LO_CS_NoSequenceActive();
183 this->error();
184 this->seqDone_out(0,0,0,Fw::CmdResponse::EXECUTION_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 {
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 {
221 this->log_WARNING_LO_CS_NoSequenceActive();
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) {
231 this->log_WARNING_LO_CS_NoSequenceActive();
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)) {
273 this->seqDone_out(0,0,0,Fw::CmdResponse::EXECUTION_ERROR);
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 {
415 this->log_WARNING_HI_CS_InvalidMode();
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) {
483 this->log_ACTIVITY_LO_CS_CommandComplete(
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:7
PlatformIntType NATIVE_INT_TYPE
Definition BasicTypes.h:51
PlatformUIntType NATIVE_UINT_TYPE
Definition BasicTypes.h:52
U32 FwOpcodeType
Definition FpConfig.h:56
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
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.
void init(const NATIVE_INT_TYPE queueDepth, const NATIVE_INT_TYPE instance)
Initialize a CmdSequencer.
CmdSequencerComponentImpl(const char *compName)
Construct a CmdSequencer.
void setTimeout(const NATIVE_UINT_TYPE seconds)