GCC Code Coverage Report


Directory: ./
File: Svc/CmdSequencer/CmdSequencerImpl.cpp
Date: 2026-09-03 21:13:48
Exec Total Coverage
Lines: 278 313 88.8%
Functions: 32 33 97.0%
Branches: 219 286 76.6%

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 74 CmdSequencerComponentImpl::CmdSequencerComponentImpl(const char* name)
25 : CmdSequencerComponentBase(name),
26
1/1
✓ Branch 4 taken 74 times.
74 m_FPrimeSequence(*this),
27 74 m_sequence(&this->m_FPrimeSequence),
28 74 m_loadCmdCount(0),
29 74 m_cancelCmdCount(0),
30 74 m_errorCount(0),
31 74 m_runMode(STOPPED),
32 74 m_stepMode(AUTO),
33 74 m_executedCount(0),
34 74 m_totalExecutedCount(0),
35 74 m_sequencesCompletedCount(0),
36 74 m_timeout(0),
37 74 m_blockState(Svc::BlockState::NO_BLOCK),
38 74 m_opCode(0),
39 74 m_cmdSeq(0),
40
4/4
✓ Branch 10 taken 74 times.
✓ Branch 16 taken 74 times.
✓ Branch 22 taken 74 times.
✓ Branch 33 taken 74 times.
296 m_join_waiting(false) {}
41
42 74 void CmdSequencerComponentImpl::setTimeout(const U32 timeout) {
43 74 this->m_timeout = timeout;
44 74 }
45
46 24 void CmdSequencerComponentImpl ::setSequenceFormat(Sequence& sequence) {
47 24 this->m_sequence = &sequence;
48 24 }
49
50 74 void CmdSequencerComponentImpl ::allocateBuffer(const FwEnumStoreType identifier,
51 Fw::MemAllocator& allocator,
52 const FwSizeType bytes) {
53 74 this->m_sequence->allocateBuffer(identifier, allocator, bytes);
54 74 }
55
56 3 void CmdSequencerComponentImpl ::loadSequence(const Fw::ConstStringBase& fileName) {
57 3 FW_ASSERT(this->m_runMode == STOPPED, this->m_runMode);
58
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
3 if (not this->loadFile(fileName)) {
59 this->m_sequence->clear();
60 }
61 3 }
62
63 74 void CmdSequencerComponentImpl ::deallocateBuffer(Fw::MemAllocator& allocator) {
64 74 this->m_sequence->deallocateBuffer(allocator);
65 74 }
66
67 148 CmdSequencerComponentImpl::~CmdSequencerComponentImpl() {}
68
69 // ----------------------------------------------------------------------
70 // Handler implementations
71 // ----------------------------------------------------------------------
72
73 49 void CmdSequencerComponentImpl::CS_RUN_cmdHandler(FwOpcodeType opCode,
74 U32 cmdSeq,
75 const Fw::CmdStringArg& fileName,
76 const Svc::BlockState& block) {
77
2/2
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 46 times.
49 if (not this->requireRunMode(STOPPED)) {
78
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
3 if (m_join_waiting) {
79 // Inform user previous seq file is not complete
80 this->log_WARNING_HI_CS_JoinWaitingNotComplete();
81 }
82
2/2
✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
83 3 return;
84 }
85
86
5/8
✗ Branch 3 not taken.
✓ Branch 4 taken 46 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 45 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
46 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
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 46 times.
46 this->m_blockState = block.e;
94 46 this->m_cmdSeq = cmdSeq;
95 46 this->m_opCode = opCode;
96
97 // load commands
98
2/2
✓ Branch 7 taken 16 times.
✓ Branch 8 taken 30 times.
46 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 16 this->m_blockState = Svc::BlockState::NO_BLOCK;
102 16 this->m_opCode = 0;
103 16 this->m_cmdSeq = 0;
104
2/2
✓ Branch 6 taken 16 times.
✓ Branch 9 taken 16 times.
16 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
105 16 return;
106 }
107
108 30 this->m_executedCount = 0;
109
110 // Check the step mode. If it is auto, start the sequence
111
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 27 times.
✓ Branch 6 taken 3 times.
30 if (AUTO == this->m_stepMode) {
112 27 this->m_runMode = RUNNING;
113
3/3
✓ Branch 6 taken 27 times.
✓ Branch 16 taken 27 times.
✓ Branch 21 taken 27 times.
27 this->tlmWrite_CS_CurrentSequence(this->m_sequence->getStringFileName());
114
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 27 times.
27 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 27 this->performCmd_Step();
121 }
122
123
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 29 times.
✓ Branch 6 taken 1 times.
30 if (Svc::BlockState::NO_BLOCK == this->m_blockState) {
124
2/2
✓ Branch 6 taken 29 times.
✓ Branch 9 taken 29 times.
29 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
125 }
126 }
127
128 70 void CmdSequencerComponentImpl::CS_VALIDATE_cmdHandler(FwOpcodeType opCode,
129 U32 cmdSeq,
130 const Fw::CmdStringArg& fileName) {
131 70 FW_ASSERT(this->m_sequence != nullptr);
132
2/2
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 67 times.
70 if (!this->requireRunMode(STOPPED)) {
133
2/2
✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
134 3 return;
135 }
136
137 // load commands
138
2/2
✓ Branch 7 taken 25 times.
✓ Branch 8 taken 42 times.
67 if (not this->loadFile(fileName)) {
139
2/2
✓ Branch 6 taken 25 times.
✓ Branch 9 taken 25 times.
25 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
140 25 return;
141 }
142
143 // clear the buffer
144 42 this->m_sequence->clear();
145
146 42 this->log_ACTIVITY_HI_CS_SequenceValid(this->m_sequence->getLogFileName());
147
148
2/2
✓ Branch 6 taken 42 times.
✓ Branch 9 taken 42 times.
42 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
149 }
150
151 //! Handler for input port seqRunIn
152 13 void CmdSequencerComponentImpl::doSequenceRun(const Fw::StringBase& filename) {
153
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
13 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
2/2
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 10 times.
13 if (!this->requireRunMode(STOPPED)) {
160
2/2
✓ Branch 6 taken 3 times.
✓ Branch 10 taken 3 times.
3 this->seqDone_out(0, 0, 0, Fw::CmdResponse::EXECUTION_ERROR);
161 3 return;
162 }
163
164 // If file name is non-empty, load a file.
165 // Empty file name means don't load.
166
2/2
✓ Branch 7 taken 6 times.
✓ Branch 8 taken 4 times.
10 if (filename != "") {
167
1/1
✓ Branch 5 taken 6 times.
6 Fw::CmdStringArg cmdStr(filename);
168
1/1
✓ Branch 4 taken 6 times.
6 const bool status = this->loadFile(cmdStr);
169
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if (!status) {
170
2/2
✓ Branch 6 taken 1 times.
✓ Branch 10 taken 1 times.
1 this->seqDone_out(0, 0, 0, Fw::CmdResponse::EXECUTION_ERROR);
171 1 return;
172 }
173
4/4
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1 times.
✓ Branch 27 taken 2 times.
✓ Branch 28 taken 2 times.
10 } else if (not this->m_sequence->hasMoreRecords()) {
174 // No sequence loaded
175 2 this->log_WARNING_LO_CS_NoSequenceActive();
176 2 this->error();
177
2/2
✓ Branch 6 taken 2 times.
✓ Branch 10 taken 2 times.
2 this->seqDone_out(0, 0, 0, Fw::CmdResponse::EXECUTION_ERROR);
178 2 return;
179 }
180
181 7 this->m_executedCount = 0;
182
183 // Check the step mode. If it is auto, start the sequence
184
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 7 times.
✗ Branch 6 not taken.
7 if (AUTO == this->m_stepMode) {
185 7 this->m_runMode = RUNNING;
186
3/3
✓ Branch 6 taken 7 times.
✓ Branch 16 taken 7 times.
✓ Branch 21 taken 7 times.
7 this->tlmWrite_CS_CurrentSequence(this->m_sequence->getStringFileName());
187
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
7 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 7 this->performCmd_Step();
194 }
195
196 7 this->log_ACTIVITY_HI_CS_PortSequenceStarted(this->m_sequence->getLogFileName());
197 }
198
199 12 void CmdSequencerComponentImpl::seqRunIn_handler(FwIndexType portNum,
200 const Fw::StringBase& filename,
201 const Svc::SeqArgs& args) {
202 (void)args; // Suppress unused parameter warning
203 12 this->doSequenceRun(filename);
204 12 }
205
206 1 void CmdSequencerComponentImpl::seqDispatchIn_handler(FwIndexType portNum, Fw::StringBase& file_name) {
207 1 this->doSequenceRun(file_name);
208 1 }
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 5 void CmdSequencerComponentImpl::CS_CANCEL_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
222
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 2 times.
5 if (RUNNING == this->m_runMode) {
223 3 this->performCmd_Cancel();
224 3 this->log_ACTIVITY_HI_CS_SequenceCanceled(this->m_sequence->getLogFileName());
225 3 ++this->m_cancelCmdCount;
226
2/2
✓ Branch 6 taken 3 times.
✓ Branch 13 taken 3 times.
3 this->tlmWrite_CS_CancelCommands(this->m_cancelCmdCount);
227 } else {
228 2 this->log_WARNING_LO_CS_NoSequenceActive();
229 }
230
2/2
✓ Branch 6 taken 5 times.
✓ Branch 9 taken 5 times.
5 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
231 5 }
232
233 5 void CmdSequencerComponentImpl::CS_JOIN_WAIT_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq) {
234 // If there is no running sequence do not wait
235
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 4 times.
5 if (m_runMode != RUNNING) {
236 1 this->log_WARNING_LO_CS_NoSequenceActive();
237
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
238 1 return;
239
6/8
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 2 times.
4 } 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 2 this->log_WARNING_HI_CS_JoinWaitingNotComplete();
244
2/2
✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
2 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
245 } else {
246 2 m_join_waiting = true;
247 2 Fw::LogStringArg& logFileName = this->m_sequence->getLogFileName();
248 2 this->log_ACTIVITY_HI_CS_JoinWaiting(logFileName, m_cmdSeq, CmdDispatcherCfg::getEventOpcode(m_opCode));
249 2 m_cmdSeq = cmdSeq;
250 2 m_opCode = opCode;
251 }
252 }
253
254 // ----------------------------------------------------------------------
255 // Private helper methods
256 // ----------------------------------------------------------------------
257
258 122 bool CmdSequencerComponentImpl ::loadFile(const Fw::ConstStringBase& fileName) {
259 122 const bool status = this->m_sequence->loadFile(fileName);
260
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 42 times.
122 if (status) {
261 80 Fw::LogStringArg& logFileName = this->m_sequence->getLogFileName();
262 80 this->log_ACTIVITY_LO_CS_SequenceLoaded(logFileName);
263 80 ++this->m_loadCmdCount;
264
2/2
✓ Branch 6 taken 80 times.
✓ Branch 13 taken 80 times.
80 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 42 this->m_sequence->clear();
275 }
276 122 return status;
277 }
278
279 45 void CmdSequencerComponentImpl::error() {
280 45 ++this->m_errorCount;
281
2/2
✓ Branch 6 taken 45 times.
✓ Branch 13 taken 45 times.
45 this->tlmWrite_CS_Errors(m_errorCount);
282 45 }
283
284 8 void CmdSequencerComponentImpl::performCmd_Cancel() {
285 8 FW_ASSERT(this->m_sequence != nullptr);
286 8 this->m_sequence->reset();
287 8 this->m_runMode = STOPPED;
288 8 this->m_cmdTimer.clear();
289 8 this->m_cmdTimeoutTimer.clear();
290 8 this->m_executedCount = 0;
291 // write sequence done port with error, if connected
292
1/2
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
8 if (this->isConnected_seqDone_OutputPort(0)) {
293
2/2
✓ Branch 6 taken 8 times.
✓ Branch 10 taken 8 times.
8 this->seqDone_out(0, 0, 0, Fw::CmdResponse::EXECUTION_ERROR);
294 }
295
296
4/8
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 8 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 8 times.
8 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 8 this->m_blockState = Svc::BlockState::NO_BLOCK;
303 8 }
304
305 125 void CmdSequencerComponentImpl ::cmdResponseIn_handler(FwIndexType portNum,
306 FwOpcodeType opcode,
307 U32 cmdSeq,
308 const Fw::CmdResponse& response) {
309
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 125 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 122 times.
125 if (this->m_runMode == STOPPED) {
310 // Sequencer is not running
311 3 this->log_WARNING_HI_CS_UnexpectedCompletion(CmdDispatcherCfg::getEventOpcode(opcode));
312 } else {
313 // clear command timeout
314 122 this->m_cmdTimeoutTimer.clear();
315
2/2
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 120 times.
122 if (response != Fw::CmdResponse::OK) {
316
1/2
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
2 this->commandError(this->m_executedCount, opcode, response.e);
317 2 this->performCmd_Cancel();
318
5/8
✗ Branch 3 not taken.
✓ Branch 4 taken 120 times.
✓ Branch 5 taken 120 times.
✗ Branch 6 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 120 times.
✓ Branch 12 taken 106 times.
✓ Branch 13 taken 14 times.
120 } else if (this->m_runMode == RUNNING && this->m_stepMode == AUTO) {
319 // Auto mode
320 106 this->commandComplete(opcode);
321
2/2
✓ Branch 23 taken 19 times.
✓ Branch 24 taken 87 times.
212 if (not this->m_sequence->hasMoreRecords()) {
322 // No data left
323 19 this->m_runMode = STOPPED;
324 19 this->sequenceComplete();
325 } else {
326 87 this->performCmd_Step();
327 }
328 } else {
329 // Manual step mode
330 14 this->commandComplete(opcode);
331
2/2
✓ Branch 23 taken 2 times.
✓ Branch 24 taken 12 times.
14 if (not this->m_sequence->hasMoreRecords()) {
332 2 this->m_runMode = STOPPED;
333 2 this->sequenceComplete();
334 }
335 }
336 }
337 125 }
338
339 26 void CmdSequencerComponentImpl ::schedIn_handler(FwIndexType portNum, U32 order) {
340
1/1
✓ Branch 3 taken 26 times.
26 Fw::Time currTime = this->getTime();
341 // check to see if a command time is pending
342
4/4
✓ Branch 5 taken 26 times.
✓ Branch 8 taken 26 times.
✓ Branch 13 taken 10 times.
✓ Branch 14 taken 16 times.
26 if (this->m_cmdTimer.isExpiredAt(currTime)) {
343
1/1
✓ Branch 8 taken 10 times.
10 this->comCmdOut_out(0, m_record.m_command, 0);
344 10 this->m_cmdTimer.clear();
345 // start command timeout timer
346
1/1
✓ Branch 4 taken 10 times.
10 this->setCmdTimeout(currTime);
347
4/4
✓ Branch 6 taken 16 times.
✓ Branch 9 taken 16 times.
✓ Branch 14 taken 3 times.
✓ Branch 15 taken 13 times.
16 } else if (this->m_cmdTimeoutTimer.isExpiredAt(this->getTime())) { // check for command timeout
348
2/2
✓ Branch 16 taken 3 times.
✓ Branch 21 taken 3 times.
3 this->log_WARNING_HI_CS_SequenceTimeout(m_sequence->getLogFileName(), this->m_executedCount);
349 // If there is a command timeout, cancel the sequence
350
1/1
✓ Branch 4 taken 3 times.
3 this->performCmd_Cancel();
351 }
352 52 }
353
354 9 void CmdSequencerComponentImpl ::CS_START_cmdHandler(FwOpcodeType opcode, U32 cmdSeq) {
355
2/2
✓ Branch 23 taken 3 times.
✓ Branch 24 taken 6 times.
9 if (not this->m_sequence->hasMoreRecords()) {
356 // No sequence loaded
357 3 this->log_WARNING_LO_CS_NoSequenceActive();
358
2/2
✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
359 3 return;
360 }
361
2/2
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3 times.
6 if (!this->requireRunMode(STOPPED)) {
362
2/2
✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
363 3 return;
364 }
365
366 3 this->m_blockState = Svc::BlockState::NO_BLOCK;
367 3 this->m_runMode = RUNNING;
368
3/3
✓ Branch 6 taken 3 times.
✓ Branch 16 taken 3 times.
✓ Branch 21 taken 3 times.
3 this->tlmWrite_CS_CurrentSequence(this->m_sequence->getStringFileName());
369 3 this->log_ACTIVITY_HI_CS_CmdStarted(this->m_sequence->getLogFileName());
370 3 this->performCmd_Step();
371
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
3 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
2/2
✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::OK);
377 }
378
379 15 void CmdSequencerComponentImpl ::CS_STEP_cmdHandler(FwOpcodeType opcode, U32 cmdSeq) {
380 15 FW_ASSERT(this->m_sequence != nullptr);
381
2/2
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 3 times.
15 if (this->requireRunMode(RUNNING)) {
382
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
12 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
1/2
✗ Branch 23 not taken.
✓ Branch 24 taken 12 times.
12 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 12 this->performCmd_Step();
396 // check for special case where end of sequence entry was encountered
397
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 11 times.
✓ Branch 6 taken 1 times.
12 if (this->m_runMode != STOPPED) {
398 11 this->log_ACTIVITY_HI_CS_CmdStepped(this->m_sequence->getLogFileName(), this->m_executedCount);
399 }
400
2/2
✓ Branch 6 taken 12 times.
✓ Branch 9 taken 12 times.
12 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::OK);
401 } else {
402
2/2
✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
403 }
404 }
405
406 6 void CmdSequencerComponentImpl ::CS_AUTO_cmdHandler(FwOpcodeType opcode, U32 cmdSeq) {
407
2/2
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3 times.
6 if (this->requireRunMode(STOPPED)) {
408 3 this->m_stepMode = AUTO;
409
2/2
✓ Branch 6 taken 3 times.
✓ Branch 10 taken 3 times.
3 this->log_ACTIVITY_HI_CS_ModeSwitched(CmdSequencer_SeqMode::AUTO);
410
2/2
✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::OK);
411 } else {
412
2/2
✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
413 }
414 6 }
415
416 6 void CmdSequencerComponentImpl ::CS_MANUAL_cmdHandler(FwOpcodeType opcode, U32 cmdSeq) {
417
2/2
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3 times.
6 if (this->requireRunMode(STOPPED)) {
418 3 this->m_stepMode = MANUAL;
419
2/2
✓ Branch 6 taken 3 times.
✓ Branch 10 taken 3 times.
3 this->log_ACTIVITY_HI_CS_ModeSwitched(CmdSequencer_SeqMode::STEP);
420
2/2
✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::OK);
421 } else {
422
2/2
✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->cmdResponse_out(opcode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
423 }
424 6 }
425
426 // ----------------------------------------------------------------------
427 // Helper methods
428 // ----------------------------------------------------------------------
429
430 165 bool CmdSequencerComponentImpl::requireRunMode(RunMode mode) {
431
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 165 times.
✓ Branch 5 taken 144 times.
✓ Branch 6 taken 21 times.
165 if (this->m_runMode == mode) {
432 144 return true;
433 } else {
434 21 this->log_WARNING_HI_CS_InvalidMode();
435 21 return false;
436 }
437 }
438
439 2 void CmdSequencerComponentImpl ::commandError(const U32 number, const FwOpcodeType opCode, const U32 error) {
440 2 this->log_WARNING_HI_CS_CommandError(this->m_sequence->getLogFileName(), number,
441 CmdDispatcherCfg::getEventOpcode(opCode), error);
442 2 this->error();
443 2 }
444
445 136 void CmdSequencerComponentImpl::performCmd_Step() {
446
1/1
✓ Branch 26 taken 136 times.
136 this->m_sequence->nextRecord(m_record);
447 // set clock time base and context from value set when sequence was loaded
448
1/1
✓ Branch 8 taken 136 times.
136 const Sequence::Header& header = this->m_sequence->getHeader();
449
2/2
✓ Branch 12 taken 136 times.
✓ Branch 15 taken 136 times.
136 this->m_record.m_timeTag.setTimeBase(header.m_timeBase);
450
1/1
✓ Branch 8 taken 136 times.
136 this->m_record.m_timeTag.setTimeContext(header.m_timeContext);
451
452
1/1
✓ Branch 3 taken 136 times.
136 Fw::Time currentTime = this->getTime();
453
4/6
✗ Branch 3 not taken.
✓ Branch 4 taken 136 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 129 times.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
136 switch (this->m_record.m_descriptor) {
454 5 case Sequence::Record::END_OF_SEQUENCE:
455 5 this->m_runMode = STOPPED;
456
1/1
✓ Branch 4 taken 5 times.
5 this->sequenceComplete();
457 5 break;
458 129 case Sequence::Record::RELATIVE:
459
1/1
✓ Branch 4 taken 129 times.
129 this->performCmd_Step_RELATIVE(currentTime);
460 129 break;
461 2 case Sequence::Record::ABSOLUTE:
462
1/1
✓ Branch 4 taken 2 times.
2 this->performCmd_Step_ABSOLUTE(currentTime);
463 2 break;
464 default:
465 FW_ASSERT(false, m_record.m_descriptor);
466 }
467 272 }
468
469 26 void CmdSequencerComponentImpl::sequenceComplete() {
470 26 FW_ASSERT(this->m_sequence != nullptr);
471 26 ++this->m_sequencesCompletedCount;
472 // reset buffer
473 26 this->m_sequence->clear();
474 26 this->log_ACTIVITY_HI_CS_SequenceComplete(this->m_sequence->getLogFileName());
475
2/2
✓ Branch 6 taken 26 times.
✓ Branch 13 taken 26 times.
26 this->tlmWrite_CS_SequencesCompleted(this->m_sequencesCompletedCount);
476 26 this->m_executedCount = 0;
477 // write sequence done port, if connected
478
1/2
✓ Branch 5 taken 26 times.
✗ Branch 6 not taken.
26 if (this->isConnected_seqDone_OutputPort(0)) {
479
2/2
✓ Branch 6 taken 26 times.
✓ Branch 10 taken 26 times.
26 this->seqDone_out(0, 0, 0, Fw::CmdResponse::OK);
480 }
481
482
6/8
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
✓ Branch 5 taken 25 times.
✓ Branch 6 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 25 times.
✓ Branch 12 taken 2 times.
✓ Branch 13 taken 23 times.
26 if (Svc::BlockState::BLOCK == this->m_blockState || m_join_waiting) {
483
2/2
✓ Branch 6 taken 3 times.
✓ Branch 17 taken 3 times.
3 this->cmdResponse_out(this->m_opCode, this->m_cmdSeq, Fw::CmdResponse::OK);
484 }
485
486 26 m_join_waiting = false;
487 26 this->m_blockState = Svc::BlockState::NO_BLOCK;
488
2/2
✓ Branch 6 taken 26 times.
✓ Branch 14 taken 26 times.
26 this->tlmWrite_CS_CurrentSequence(NO_SEQ);
489 26 }
490
491 120 void CmdSequencerComponentImpl::commandComplete(const FwOpcodeType opcode) {
492 120 this->log_ACTIVITY_LO_CS_CommandComplete(this->m_sequence->getLogFileName(), this->m_executedCount,
493 CmdDispatcherCfg::getEventOpcode(opcode));
494 120 ++this->m_executedCount;
495 120 ++this->m_totalExecutedCount;
496
2/2
✓ Branch 6 taken 120 times.
✓ Branch 13 taken 120 times.
120 this->tlmWrite_CS_CommandsExecuted(this->m_totalExecutedCount);
497 120 }
498
499 129 void CmdSequencerComponentImpl ::performCmd_Step_RELATIVE(Fw::Time& currentTime) {
500 129 this->m_record.m_timeTag.add(currentTime.getSeconds(), currentTime.getUSeconds());
501 129 this->performCmd_Step_ABSOLUTE(currentTime);
502 129 }
503
504 131 void CmdSequencerComponentImpl ::performCmd_Step_ABSOLUTE(Fw::Time& currentTime) {
505
2/2
✓ Branch 7 taken 118 times.
✓ Branch 8 taken 13 times.
131 if (currentTime >= this->m_record.m_timeTag) {
506 118 this->comCmdOut_out(0, m_record.m_command, 0);
507 118 this->setCmdTimeout(currentTime);
508 } else {
509
2/2
✓ Branch 8 taken 13 times.
✓ Branch 11 taken 13 times.
13 this->m_cmdTimer.set(this->m_record.m_timeTag);
510 }
511 131 }
512
513 1 void CmdSequencerComponentImpl ::pingIn_handler(FwIndexType portNum, /*!< The port number*/
514 U32 key /*!< Value to return to pinger*/
515 ) {
516 // send ping response
517 1 this->pingOut_out(0, key);
518 1 }
519
520 128 void CmdSequencerComponentImpl ::setCmdTimeout(const Fw::Time& currentTime) {
521 // start timeout timer if enabled and not in step mode
522
4/6
✓ Branch 4 taken 128 times.
✗ Branch 5 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 128 times.
✓ Branch 11 taken 114 times.
✓ Branch 12 taken 14 times.
128 if ((this->m_timeout > 0) and (AUTO == this->m_stepMode)) {
523
1/1
✓ Branch 2 taken 114 times.
114 Fw::Time expTime = currentTime;
524
1/1
✓ Branch 6 taken 114 times.
114 expTime.add(this->m_timeout, 0);
525
2/2
✓ Branch 5 taken 114 times.
✓ Branch 8 taken 114 times.
114 this->m_cmdTimeoutTimer.set(expTime);
526 114 }
527 128 }
528
529 } // namespace Svc
530