GCC Code Coverage Report


Directory: ./
File: Svc/CmdSequencer/CmdSequencerImpl.cpp
Date: 2026-09-03 22:12:29
Exec Total Coverage
Lines: 114 313 36.4%
Functions: 16 33 48.5%
Branches: 58 234 24.8%

Line Branch Exec Source
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/Com/ComPacket.hpp>
11 #include <Fw/Types/Assert.hpp>
12 #include <Fw/Types/SerialBuffer.hpp>
13 #include <Fw/Types/Serializable.hpp>
14 #include <Svc/CmdSequencer/CmdSequencerImpl.hpp>
15 #include <Utils/Hash/Hash.hpp>
16 #include <config/CommandDispatcherImplCfg.hpp>
17
18 namespace Svc {
19
20 // ----------------------------------------------------------------------
21 // Construction, initialization, and destruction
22 // ----------------------------------------------------------------------
23
24 1 CmdSequencerComponentImpl::CmdSequencerComponentImpl(const char* name)
25 : CmdSequencerComponentBase(name),
26 1 m_FPrimeSequence(*this),
27 1 m_sequence(&this->m_FPrimeSequence),
28 1 m_loadCmdCount(0),
29 1 m_cancelCmdCount(0),
30 1 m_errorCount(0),
31 1 m_runMode(STOPPED),
32 1 m_stepMode(AUTO),
33 1 m_executedCount(0),
34 1 m_totalExecutedCount(0),
35 1 m_sequencesCompletedCount(0),
36 1 m_timeout(0),
37 1 m_blockState(Svc::BlockState::NO_BLOCK),
38 1 m_opCode(0),
39 1 m_cmdSeq(0),
40
5/5
✓ Branch 2 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 8 taken 1 times.
✓ Branch 11 taken 1 times.
✓ Branch 14 taken 1 times.
1 m_join_waiting(false) {}
41
42 void CmdSequencerComponentImpl::setTimeout(const U32 timeout) {
43 this->m_timeout = timeout;
44 }
45
46 void CmdSequencerComponentImpl ::setSequenceFormat(Sequence& sequence) {
47 this->m_sequence = &sequence;
48 }
49
50 1 void CmdSequencerComponentImpl ::allocateBuffer(const FwEnumStoreType identifier,
51 Fw::MemAllocator& allocator,
52 const FwSizeType bytes) {
53 1 this->m_sequence->allocateBuffer(identifier, allocator, bytes);
54 1 }
55
56 void CmdSequencerComponentImpl ::loadSequence(const Fw::ConstStringBase& fileName) {
57 FW_ASSERT(this->m_runMode == STOPPED, this->m_runMode);
58 if (not this->loadFile(fileName)) {
59 this->m_sequence->clear();
60 }
61 }
62
63 1 void CmdSequencerComponentImpl ::deallocateBuffer(Fw::MemAllocator& allocator) {
64 1 this->m_sequence->deallocateBuffer(allocator);
65 1 }
66
67 2 CmdSequencerComponentImpl::~CmdSequencerComponentImpl() {}
68
69 // ----------------------------------------------------------------------
70 // Handler implementations
71 // ----------------------------------------------------------------------
72
73 2 void CmdSequencerComponentImpl::CS_RUN_cmdHandler(FwOpcodeType opCode,
74 U32 cmdSeq,
75 const Fw::CmdStringArg& fileName,
76 const Svc::BlockState& block) {
77
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (not this->requireRunMode(STOPPED)) {
78 if (m_join_waiting) {
79 // Inform user previous seq file is not complete
80 this->log_WARNING_HI_CS_JoinWaitingNotComplete();
81 }
82 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
83 return;
84 }
85
86
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if ((Svc::BlockState::BLOCK == block.e) && (MANUAL == this->m_stepMode)) {
87 // In MANUAL mode nothing executes until CS_STEP, so a BLOCK response could never be sent
88 this->log_WARNING_HI_CS_InvalidMode();
89 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
90 return;
91 }
92
93 2 this->m_blockState = block.e;
94 2 this->m_cmdSeq = cmdSeq;
95 2 this->m_opCode = opCode;
96
97 // load commands
98
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (not this->loadFile(fileName)) {
99 // Clear the recorded command state so a later port-driven run cannot
100 // emit a duplicate response for this already-answered command
101 this->m_blockState = Svc::BlockState::NO_BLOCK;
102 this->m_opCode = 0;
103 this->m_cmdSeq = 0;
104 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
105 return;
106 }
107
108 2 this->m_executedCount = 0;
109
110 // Check the step mode. If it is auto, start the sequence
111
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (AUTO == this->m_stepMode) {
112 2 this->m_runMode = RUNNING;
113
3/3
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
2 this->tlmWrite_CS_CurrentSequence(this->m_sequence->getStringFileName());
114
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (this->isConnected_seqStartOut_OutputPort(0)) {
115 // Create empty SeqArgs as placeholder
116 // Use parameterized constructor to ensure m_size is initialized to 0
117 Svc::SeqArgs emptyArgs{0, 0};
118 this->seqStartOut_out(0, this->m_sequence->getStringFileName(), emptyArgs);
119 }
120 2 this->performCmd_Step();
121 }
122
123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (Svc::BlockState::NO_BLOCK == this->m_blockState) {
124 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
125 }
126 }
127
128 void CmdSequencerComponentImpl::CS_VALIDATE_cmdHandler(FwOpcodeType opCode,
129 U32 cmdSeq,
130 const Fw::CmdStringArg& fileName) {
131 FW_ASSERT(this->m_sequence != nullptr);
132 if (!this->requireRunMode(STOPPED)) {
133 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
134 return;
135 }
136
137 // load commands
138 if (not this->loadFile(fileName)) {
139 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
140 return;
141 }
142
143 // clear the buffer
144 this->m_sequence->clear();
145
146 this->log_ACTIVITY_HI_CS_SequenceValid(this->m_sequence->getLogFileName());
147
148 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
149 }
150
151 //! Handler for input port seqRunIn
152 void CmdSequencerComponentImpl::doSequenceRun(const Fw::StringBase& filename) {
153 if (MANUAL == this->m_stepMode) {
154 // In MANUAL mode nothing executes until CS_STEP, so a port-driven run would wedge
155 this->log_WARNING_HI_CS_InvalidMode();
156 this->seqDone_out(0, 0, 0, Fw::CmdResponse::EXECUTION_ERROR);
157 return;
158 }
159 if (!this->requireRunMode(STOPPED)) {
160 this->seqDone_out(0, 0, 0, Fw::CmdResponse::EXECUTION_ERROR);
161 return;
162 }
163
164 // If file name is non-empty, load a file.
165 // Empty file name means don't load.
166 if (filename != "") {
167 Fw::CmdStringArg cmdStr(filename);
168 const bool status = this->loadFile(cmdStr);
169 if (!status) {
170 this->seqDone_out(0, 0, 0, Fw::CmdResponse::EXECUTION_ERROR);
171 return;
172 }
173 } else if (not this->m_sequence->hasMoreRecords()) {
174 // No sequence loaded
175 this->log_WARNING_LO_CS_NoSequenceActive();
176 this->error();
177 this->seqDone_out(0, 0, 0, Fw::CmdResponse::EXECUTION_ERROR);
178 return;
179 }
180
181 this->m_executedCount = 0;
182
183 // Check the step mode. If it is auto, start the sequence
184 if (AUTO == this->m_stepMode) {
185 this->m_runMode = RUNNING;
186 this->tlmWrite_CS_CurrentSequence(this->m_sequence->getStringFileName());
187 if (this->isConnected_seqStartOut_OutputPort(0)) {
188 // Create empty SeqArgs as placeholder
189 // Use parameterized constructor to ensure m_size is initialized to 0
190 Svc::SeqArgs emptyArgs{0, 0};
191 this->seqStartOut_out(0, this->m_sequence->getStringFileName(), emptyArgs);
192 }
193 this->performCmd_Step();
194 }
195
196 this->log_ACTIVITY_HI_CS_PortSequenceStarted(this->m_sequence->getLogFileName());
197 }
198
199 void CmdSequencerComponentImpl::seqRunIn_handler(FwIndexType portNum,
200 const Fw::StringBase& filename,
201 const Svc::SeqArgs& args) {
202 (void)args; // Suppress unused parameter warning
203 this->doSequenceRun(filename);
204 }
205
206 void CmdSequencerComponentImpl::seqDispatchIn_handler(FwIndexType portNum, Fw::StringBase& file_name) {
207 this->doSequenceRun(file_name);
208 }
209
210 void CmdSequencerComponentImpl ::seqCancelIn_handler(const FwIndexType portNum) {
211 if (RUNNING == this->m_runMode) {
212 this->performCmd_Cancel();
213 this->log_ACTIVITY_HI_CS_SequenceCanceled(this->m_sequence->getLogFileName());
214 ++this->m_cancelCmdCount;
215 this->tlmWrite_CS_CancelCommands(this->m_cancelCmdCount);
216 } else {
217 this->log_WARNING_LO_CS_NoSequenceActive();
218 }
219 }
220
221 void CmdSequencerComponentImpl::CS_CANCEL_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
222 if (RUNNING == this->m_runMode) {
223 this->performCmd_Cancel();
224 this->log_ACTIVITY_HI_CS_SequenceCanceled(this->m_sequence->getLogFileName());
225 ++this->m_cancelCmdCount;
226 this->tlmWrite_CS_CancelCommands(this->m_cancelCmdCount);
227 } else {
228 this->log_WARNING_LO_CS_NoSequenceActive();
229 }
230 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
231 }
232
233 void CmdSequencerComponentImpl::CS_JOIN_WAIT_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq) {
234 // If there is no running sequence do not wait
235 if (m_runMode != RUNNING) {
236 this->log_WARNING_LO_CS_NoSequenceActive();
237 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
238 return;
239 } else if ((Svc::BlockState::BLOCK == this->m_blockState) || this->m_join_waiting) {
240 // A command response is already owed to a BLOCK-mode CS_RUN caller or a
241 // previous CS_JOIN_WAIT caller. Reject rather than overwrite that state,
242 // which would leave the original caller without a completion response.
243 this->log_WARNING_HI_CS_JoinWaitingNotComplete();
244 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
245 } else {
246 m_join_waiting = true;
247 Fw::LogStringArg& logFileName = this->m_sequence->getLogFileName();
248 this->log_ACTIVITY_HI_CS_JoinWaiting(logFileName, m_cmdSeq, CmdDispatcherCfg::getEventOpcode(m_opCode));
249 m_cmdSeq = cmdSeq;
250 m_opCode = opCode;
251 }
252 }
253
254 // ----------------------------------------------------------------------
255 // Private helper methods
256 // ----------------------------------------------------------------------
257
258 2 bool CmdSequencerComponentImpl ::loadFile(const Fw::ConstStringBase& fileName) {
259 2 const bool status = this->m_sequence->loadFile(fileName);
260
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (status) {
261 2 Fw::LogStringArg& logFileName = this->m_sequence->getLogFileName();
262 2 this->log_ACTIVITY_LO_CS_SequenceLoaded(logFileName);
263 2 ++this->m_loadCmdCount;
264
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2 this->tlmWrite_CS_LoadCommands(this->m_loadCmdCount);
265 } else {
266 // A partial load may have populated m_buffer before an intermediate
267 // validation step (e.g. CRC, time, record structure) failed. Without
268 // an explicit reset, FPrimeSequence::hasMoreRecords() still returns
269 // true because getDeserializeSizeLeft() > 0, so a subsequent CS_START
270 // bypasses the "no sequence active" guard and reaches
271 // FPrimeSequence::nextRecord, which asserts on the failed deserialize
272 // and aborts the FSW. Clearing the sequence on every load failure
273 // closes that window.
274 this->m_sequence->clear();
275 }
276 2 return status;
277 }
278
279 void CmdSequencerComponentImpl::error() {
280 ++this->m_errorCount;
281 this->tlmWrite_CS_Errors(m_errorCount);
282 }
283
284 void CmdSequencerComponentImpl::performCmd_Cancel() {
285 FW_ASSERT(this->m_sequence != nullptr);
286 this->m_sequence->reset();
287 this->m_runMode = STOPPED;
288 this->m_cmdTimer.clear();
289 this->m_cmdTimeoutTimer.clear();
290 this->m_executedCount = 0;
291 // write sequence done port with error, if connected
292 if (this->isConnected_seqDone_OutputPort(0)) {
293 this->seqDone_out(0, 0, 0, Fw::CmdResponse::EXECUTION_ERROR);
294 }
295
296 if (Svc::BlockState::BLOCK == this->m_blockState || m_join_waiting) {
297 // Do not wait if sequence was canceled or a cmd failed
298 this->m_join_waiting = false;
299 this->cmdResponse_out(this->m_opCode, this->m_cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
300 }
301
302 this->m_blockState = Svc::BlockState::NO_BLOCK;
303 }
304
305 5 void CmdSequencerComponentImpl ::cmdResponseIn_handler(FwIndexType portNum,
306 FwOpcodeType opcode,
307 U32 cmdSeq,
308 const Fw::CmdResponse& response) {
309
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (this->m_runMode == STOPPED) {
310 // Sequencer is not running
311 this->log_WARNING_HI_CS_UnexpectedCompletion(CmdDispatcherCfg::getEventOpcode(opcode));
312 } else {
313 // clear command timeout
314 5 this->m_cmdTimeoutTimer.clear();
315
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (response != Fw::CmdResponse::OK) {
316 this->commandError(this->m_executedCount, opcode, response.e);
317 this->performCmd_Cancel();
318
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 } else if (this->m_runMode == RUNNING && this->m_stepMode == AUTO) {
319 // Auto mode
320 5 this->commandComplete(opcode);
321
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
10 if (not this->m_sequence->hasMoreRecords()) {
322 // No data left
323 2 this->m_runMode = STOPPED;
324 2 this->sequenceComplete();
325 } else {
326 3 this->performCmd_Step();
327 }
328 } else {
329 // Manual step mode
330 this->commandComplete(opcode);
331 if (not this->m_sequence->hasMoreRecords()) {
332 this->m_runMode = STOPPED;
333 this->sequenceComplete();
334 }
335 }
336 }
337 5 }
338
339 118 void CmdSequencerComponentImpl ::schedIn_handler(FwIndexType portNum, U32 order) {
340
1/1
✓ Branch 1 taken 118 times.
118 Fw::Time currTime = this->getTime();
341 // check to see if a command time is pending
342
4/4
✓ Branch 1 taken 118 times.
✓ Branch 4 taken 118 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 117 times.
118 if (this->m_cmdTimer.isExpiredAt(currTime)) {
343
1/1
✓ Branch 1 taken 1 times.
1 this->comCmdOut_out(0, m_record.m_command, 0);
344 1 this->m_cmdTimer.clear();
345 // start command timeout timer
346
1/1
✓ Branch 1 taken 1 times.
1 this->setCmdTimeout(currTime);
347
3/4
✓ Branch 1 taken 117 times.
✓ Branch 4 taken 117 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 117 times.
117 } else if (this->m_cmdTimeoutTimer.isExpiredAt(this->getTime())) { // check for command timeout
348 this->log_WARNING_HI_CS_SequenceTimeout(m_sequence->getLogFileName(), this->m_executedCount);
349 // If there is a command timeout, cancel the sequence
350 this->performCmd_Cancel();
351 }
352 118 }
353
354 void CmdSequencerComponentImpl ::CS_START_cmdHandler(FwOpcodeType opcode, U32 cmdSeq) {
355 if (not this->m_sequence->hasMoreRecords()) {
356 // No sequence loaded
357 this->log_WARNING_LO_CS_NoSequenceActive();
358 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
359 return;
360 }
361 if (!this->requireRunMode(STOPPED)) {
362 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
363 return;
364 }
365
366 this->m_blockState = Svc::BlockState::NO_BLOCK;
367 this->m_runMode = RUNNING;
368 this->tlmWrite_CS_CurrentSequence(this->m_sequence->getStringFileName());
369 this->log_ACTIVITY_HI_CS_CmdStarted(this->m_sequence->getLogFileName());
370 this->performCmd_Step();
371 if (this->isConnected_seqStartOut_OutputPort(0)) {
372 // Create empty SeqArgs as placeholder
373 Svc::SeqArgs emptyArgs{0, 0};
374 this->seqStartOut_out(0, this->m_sequence->getStringFileName(), emptyArgs);
375 }
376 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::OK);
377 }
378
379 void CmdSequencerComponentImpl ::CS_STEP_cmdHandler(FwOpcodeType opcode, U32 cmdSeq) {
380 FW_ASSERT(this->m_sequence != nullptr);
381 if (this->requireRunMode(RUNNING)) {
382 if (MANUAL != this->m_stepMode) {
383 // CS_STEP is valid only in MANUAL step mode
384 this->log_WARNING_HI_CS_InvalidMode();
385 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
386 return;
387 }
388 if (not this->m_sequence->hasMoreRecords()) {
389 // A sequence with no end-of-sequence record leaves nothing to step; stepping anyway
390 // asserts in the sequence reader
391 this->log_WARNING_LO_CS_NoSequenceActive();
392 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
393 return;
394 }
395 this->performCmd_Step();
396 // check for special case where end of sequence entry was encountered
397 if (this->m_runMode != STOPPED) {
398 this->log_ACTIVITY_HI_CS_CmdStepped(this->m_sequence->getLogFileName(), this->m_executedCount);
399 }
400 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::OK);
401 } else {
402 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
403 }
404 }
405
406 void CmdSequencerComponentImpl ::CS_AUTO_cmdHandler(FwOpcodeType opcode, U32 cmdSeq) {
407 if (this->requireRunMode(STOPPED)) {
408 this->m_stepMode = AUTO;
409 this->log_ACTIVITY_HI_CS_ModeSwitched(CmdSequencer_SeqMode::AUTO);
410 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::OK);
411 } else {
412 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
413 }
414 }
415
416 void CmdSequencerComponentImpl ::CS_MANUAL_cmdHandler(FwOpcodeType opcode, U32 cmdSeq) {
417 if (this->requireRunMode(STOPPED)) {
418 this->m_stepMode = MANUAL;
419 this->log_ACTIVITY_HI_CS_ModeSwitched(CmdSequencer_SeqMode::STEP);
420 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::OK);
421 } else {
422 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
423 }
424 }
425
426 // ----------------------------------------------------------------------
427 // Helper methods
428 // ----------------------------------------------------------------------
429
430 2 bool CmdSequencerComponentImpl::requireRunMode(RunMode mode) {
431
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (this->m_runMode == mode) {
432 2 return true;
433 } else {
434 this->log_WARNING_HI_CS_InvalidMode();
435 return false;
436 }
437 }
438
439 void CmdSequencerComponentImpl ::commandError(const U32 number, const FwOpcodeType opCode, const U32 error) {
440 this->log_WARNING_HI_CS_CommandError(this->m_sequence->getLogFileName(), number,
441 CmdDispatcherCfg::getEventOpcode(opCode), error);
442 this->error();
443 }
444
445 5 void CmdSequencerComponentImpl::performCmd_Step() {
446
1/1
✓ Branch 1 taken 5 times.
5 this->m_sequence->nextRecord(m_record);
447 // set clock time base and context from value set when sequence was loaded
448
1/1
✓ Branch 1 taken 5 times.
5 const Sequence::Header& header = this->m_sequence->getHeader();
449
2/2
✓ Branch 1 taken 5 times.
✓ Branch 4 taken 5 times.
5 this->m_record.m_timeTag.setTimeBase(header.m_timeBase);
450
1/1
✓ Branch 1 taken 5 times.
5 this->m_record.m_timeTag.setTimeContext(header.m_timeContext);
451
452
1/1
✓ Branch 1 taken 5 times.
5 Fw::Time currentTime = this->getTime();
453
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
5 switch (this->m_record.m_descriptor) {
454 case Sequence::Record::END_OF_SEQUENCE:
455 this->m_runMode = STOPPED;
456 this->sequenceComplete();
457 break;
458 5 case Sequence::Record::RELATIVE:
459
1/1
✓ Branch 1 taken 5 times.
5 this->performCmd_Step_RELATIVE(currentTime);
460 5 break;
461 case Sequence::Record::ABSOLUTE:
462 this->performCmd_Step_ABSOLUTE(currentTime);
463 break;
464 default:
465 FW_ASSERT(false, m_record.m_descriptor);
466 }
467 5 }
468
469 2 void CmdSequencerComponentImpl::sequenceComplete() {
470 2 FW_ASSERT(this->m_sequence != nullptr);
471 2 ++this->m_sequencesCompletedCount;
472 // reset buffer
473 2 this->m_sequence->clear();
474 2 this->log_ACTIVITY_HI_CS_SequenceComplete(this->m_sequence->getLogFileName());
475
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2 this->tlmWrite_CS_SequencesCompleted(this->m_sequencesCompletedCount);
476 2 this->m_executedCount = 0;
477 // write sequence done port, if connected
478
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (this->isConnected_seqDone_OutputPort(0)) {
479 this->seqDone_out(0, 0, 0, Fw::CmdResponse::OK);
480 }
481
482
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (Svc::BlockState::BLOCK == this->m_blockState || m_join_waiting) {
483
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2 this->cmdResponse_out(this->m_opCode, this->m_cmdSeq, Fw::CmdResponse::OK);
484 }
485
486 2 m_join_waiting = false;
487 2 this->m_blockState = Svc::BlockState::NO_BLOCK;
488
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2 this->tlmWrite_CS_CurrentSequence(NO_SEQ);
489 2 }
490
491 5 void CmdSequencerComponentImpl::commandComplete(const FwOpcodeType opcode) {
492 5 this->log_ACTIVITY_LO_CS_CommandComplete(this->m_sequence->getLogFileName(), this->m_executedCount,
493 CmdDispatcherCfg::getEventOpcode(opcode));
494 5 ++this->m_executedCount;
495 5 ++this->m_totalExecutedCount;
496
2/2
✓ Branch 1 taken 5 times.
✓ Branch 4 taken 5 times.
5 this->tlmWrite_CS_CommandsExecuted(this->m_totalExecutedCount);
497 5 }
498
499 5 void CmdSequencerComponentImpl ::performCmd_Step_RELATIVE(Fw::Time& currentTime) {
500 5 this->m_record.m_timeTag.add(currentTime.getSeconds(), currentTime.getUSeconds());
501 5 this->performCmd_Step_ABSOLUTE(currentTime);
502 5 }
503
504 5 void CmdSequencerComponentImpl ::performCmd_Step_ABSOLUTE(Fw::Time& currentTime) {
505
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 times.
5 if (currentTime >= this->m_record.m_timeTag) {
506 4 this->comCmdOut_out(0, m_record.m_command, 0);
507 4 this->setCmdTimeout(currentTime);
508 } else {
509
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->m_cmdTimer.set(this->m_record.m_timeTag);
510 }
511 5 }
512
513 59 void CmdSequencerComponentImpl ::pingIn_handler(FwIndexType portNum, /*!< The port number*/
514 U32 key /*!< Value to return to pinger*/
515 ) {
516 // send ping response
517 59 this->pingOut_out(0, key);
518 59 }
519
520 5 void CmdSequencerComponentImpl ::setCmdTimeout(const Fw::Time& currentTime) {
521 // start timeout timer if enabled and not in step mode
522
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
5 if ((this->m_timeout > 0) and (AUTO == this->m_stepMode)) {
523 Fw::Time expTime = currentTime;
524 expTime.add(this->m_timeout, 0);
525 this->m_cmdTimeoutTimer.set(expTime);
526 }
527 5 }
528
529 } // namespace Svc
530