GCC Code Coverage Report


Directory: ./
File: Svc/CmdSequencer/CmdSequencerImpl.cpp
Date: 2026-09-23 22:11:34
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 121 void CmdSequencerComponentImpl ::schedIn_handler(FwIndexType portNum, U32 order) {
340
1/1
✓ Branch 1 taken 121 times.
121 Fw::Time currTime = this->getTime();
341 // check to see if a command time is pending
342
4/4
✓ Branch 1 taken 121 times.
✓ Branch 4 taken 121 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 120 times.
121 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 120 times.
✓ Branch 4 taken 120 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 120 times.
120 } 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 121 }
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 61 void CmdSequencerComponentImpl ::pingIn_handler(FwIndexType portNum, /*!< The port number*/
514 U32 key /*!< Value to return to pinger*/
515 ) {
516 // send ping response
517 61 this->pingOut_out(0, key);
518 61 }
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