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