GCC Code Coverage Report


Directory: Svc/FpySequencer/
File: FpySequencer.cpp
Date: 2026-09-03 21:17:55
Exec Total Coverage
Lines: 201 250 80.4%
Functions: 23 24 95.8%
Branches: 220 251 87.6%

Line Branch Exec Source
1 // ======================================================================
2 // \title FpySequencer.cpp
3 // \author zimri.leisher
4 // \brief cpp file for FpySequencer component implementation class
5 // ======================================================================
6
7 #include <Fw/Prm/ParamValid.hpp>
8 #include <Svc/FpySequencer/FpySequencer.hpp>
9 #include <config/CommandDispatcherImplCfg.hpp>
10 #include <new>
11
12 namespace Svc {
13
14 // ----------------------------------------------------------------------
15 // Construction, initialization, and destruction
16 // ----------------------------------------------------------------------
17
18 297 FpySequencer ::FpySequencer(const char* const compName)
19 : FpySequencerComponentBase(compName),
20
1/1
✓ Branch 4 taken 297 times.
297 m_sequenceBuffer(),
21 297 m_allocatorId(0),
22
1/1
✓ Branch 4 taken 297 times.
297 m_sequenceFilePath("<invalid_seq>"),
23
1/1
✓ Branch 5 taken 297 times.
297 m_sequenceObj(),
24
1/1
✓ Branch 5 taken 297 times.
297 m_computedCRC(),
25 297 m_totalExpectedArgSize(0),
26
1/1
✓ Branch 5 taken 297 times.
297 m_sequenceBlockState(),
27 297 m_savedOpCode(0),
28 297 m_savedCmdSeq(0),
29
1/1
✓ Branch 4 taken 297 times.
297 m_sequenceArgs(0, 0),
30
1/1
✓ Branch 5 taken 297 times.
297 m_goalState(),
31 297 m_sequencesStarted(0),
32 297 m_statementsDispatched(0),
33
1/1
✓ Branch 7 taken 297 times.
297 m_runtime(),
34 297 m_breakpoint(),
35 297 m_debug(),
36
2/2
✓ Branch 11 taken 297 times.
✓ Branch 20 taken 297 times.
891 m_tlm() {}
37
38 594 FpySequencer ::~FpySequencer() {}
39
40 //! Handler for command RUN
41 //!
42 //! Loads, validates and runs a sequence
43 40 void FpySequencer::RUN_cmdHandler(FwOpcodeType opCode, //!< The opcode
44 U32 cmdSeq, //!< The command sequence number
45 const Fw::CmdStringArg& fileName, //!< The name of the sequence file
46 const BlockState& block //!< Return command status when complete or not
47 ) {
48 // Empty args and delegate to RUN_ARGS handler
49
2/2
✓ Branch 8 taken 40 times.
✓ Branch 12 taken 40 times.
40 this->RUN_ARGS_cmdHandler(opCode, cmdSeq, fileName, block, Svc::SeqArgs{0, 0});
50 40 }
51
52 43 void FpySequencer ::RUN_ARGS_cmdHandler(FwOpcodeType opCode, //!< The opcode
53 U32 cmdSeq, //!< The command sequence number
54 const Fw::CmdStringArg& fileName, //!< The name of the sequence file
55 const Svc::BlockState& block, //!< Return command status when complete or not
56 const Svc::SeqArgs& args //!< Arguments to pass to the sequencer
57 ) {
58 // can only run a seq while in idle
59
3/3
✓ Branch 3 taken 43 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 42 times.
43 if (sequencer_getState() != State::IDLE) {
60
2/2
✓ Branch 7 taken 1 times.
✓ Branch 14 taken 1 times.
1 this->log_WARNING_HI_InvalidCommand(static_cast<I32>(sequencer_getState()));
61
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
62 1 return;
63 }
64
65
2/2
✓ Branch 4 taken 41 times.
✓ Branch 5 taken 1 times.
42 if (block == BlockState::BLOCK) {
66 // save the opCode and cmdSeq so we can respond later
67 41 this->m_savedOpCode = opCode;
68 41 this->m_savedCmdSeq = cmdSeq;
69 }
70
71 // Store args for pushArgsToStack action
72
2/2
✓ Branch 13 taken 42 times.
✓ Branch 17 taken 42 times.
42 this->sequencer_sendSignal_cmd_RUN(FpySequencer_SequenceExecutionArgs(fileName, block, args));
73
74 // only respond if the user doesn't want us to block further execution
75
2/2
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 41 times.
42 if (block == BlockState::NO_BLOCK) {
76
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
77 }
78 }
79
80 //! Handler for command VALIDATE
81 //!
82 //! Loads and validates a sequence
83 10 void FpySequencer::VALIDATE_cmdHandler(FwOpcodeType opCode, //!< The opcode
84 U32 cmdSeq, //!< The command sequence number
85 const Fw::CmdStringArg& fileName //!< The name of the sequence file
86 ) {
87
2/2
✓ Branch 8 taken 10 times.
✓ Branch 12 taken 10 times.
10 this->VALIDATE_ARGS_cmdHandler(opCode, cmdSeq, fileName, Svc::SeqArgs{0, 0});
88 10 }
89
90 //! Handler implementation for command VALIDATE_ARGS
91 //!
92 //! Loads and validates a sequence with arguments
93 18 void FpySequencer ::VALIDATE_ARGS_cmdHandler(FwOpcodeType opCode,
94 U32 cmdSeq,
95 const Fw::CmdStringArg& fileName,
96 const Svc::SeqArgs& buffer) {
97 // can only validate a seq while in idle
98
3/3
✓ Branch 3 taken 18 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 17 times.
18 if (sequencer_getState() != State::IDLE) {
99
2/2
✓ Branch 7 taken 1 times.
✓ Branch 14 taken 1 times.
1 this->log_WARNING_HI_InvalidCommand(static_cast<I32>(sequencer_getState()));
100
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
101 1 return;
102 }
103
104 // validate always blocks until finished, so save opcode/cmdseq
105 // so we can respond once done
106 17 this->m_savedOpCode = opCode;
107 17 this->m_savedCmdSeq = cmdSeq;
108
109 // VALIDATE_ARGS receives args via command interface
110 // Store args for pushArgsToStack action when RUN_VALIDATED is called
111
2/2
✓ Branch 9 taken 17 times.
✓ Branch 13 taken 17 times.
17 this->sequencer_sendSignal_cmd_VALIDATE(FpySequencer_SequenceExecutionArgs(fileName, BlockState::BLOCK, buffer));
112 }
113
114 5 void FpySequencer::RUN_VALIDATED_cmdHandler(FwOpcodeType opCode, //!< The opcode
115 U32 cmdSeq, //!< The command sequence number
116 const BlockState& block //!< Return command status when complete or not
117 ) {
118 // can only RUN_VALIDATED if we have validated and are awaiting this exact cmd
119
3/3
✓ Branch 3 taken 5 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 4 times.
5 if (sequencer_getState() != State::AWAITING_CMD_RUN_VALIDATED) {
120
2/2
✓ Branch 7 taken 1 times.
✓ Branch 14 taken 1 times.
1 this->log_WARNING_HI_InvalidCommand(static_cast<I32>(sequencer_getState()));
121
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
122 1 return;
123 }
124
125
2/2
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
4 if (block == BlockState::BLOCK) {
126 // save the opCode and cmdSeq so we can respond later
127 2 this->m_savedOpCode = opCode;
128 2 this->m_savedCmdSeq = cmdSeq;
129 }
130
131
1/1
✓ Branch 5 taken 4 times.
8 this->sequencer_sendSignal_cmd_RUN_VALIDATED(
132
1/1
✓ Branch 12 taken 4 times.
8 FpySequencer_SequenceExecutionArgs(this->m_sequenceFilePath, block, this->m_sequenceArgs));
133
134 // only respond if the user doesn't want us to block further execution
135
2/2
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
4 if (block == BlockState::NO_BLOCK) {
136
2/2
✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
2 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
137 }
138 }
139
140 //! Handler for command CANCEL
141 //!
142 //! Cancels a running or validated sequence
143 2 void FpySequencer::CANCEL_cmdHandler(FwOpcodeType opCode, //!< The opcode
144 U32 cmdSeq //!< The command sequence number
145 ) {
146 // only state you can't cancel in is IDLE
147
3/3
✓ Branch 3 taken 2 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
2 if (sequencer_getState() == State::IDLE) {
148
2/2
✓ Branch 7 taken 1 times.
✓ Branch 14 taken 1 times.
1 this->log_WARNING_HI_InvalidCommand(static_cast<I32>(sequencer_getState()));
149
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
150 1 return;
151 }
152
153 1 this->sequencer_sendSignal_cmd_CANCEL();
154
155 // cancel returns immediately and always succeeds
156
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
157 }
158
159 //! Handler for command SET_BREAKPOINT
160 //!
161 //! Sets the breakpoint which will pause the execution of the sequencer when
162 //! reached, until unpaused by the CONTINUE command. Will pause just before
163 //! dispatching the specified statement. This command is valid in all states. Breakpoint
164 //! settings are cleared after a sequence ends execution.
165 1 void FpySequencer::SET_BREAKPOINT_cmdHandler(FwOpcodeType opCode, //!< The opcode
166 U32 cmdSeq, //!< The command sequence number
167 U32 stmtIdx, //!< The statement index to pause execution before.
168 bool breakOnce //!< Whether or not to break only once at this breakpoint
169 ) {
170
2/2
✓ Branch 6 taken 1 times.
✓ Branch 10 taken 1 times.
1 this->sequencer_sendSignal_cmd_SET_BREAKPOINT(FpySequencer_BreakpointArgs(true, breakOnce, stmtIdx));
171
172
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
173 1 }
174
175 //! Handler for command BREAK
176 //!
177 //! Pauses the execution of the sequencer, just before it is about to dispatch the next statement,
178 //! until unpaused by the CONTINUE command, or stepped by the STEP command. This command is only valid
179 //! in substates of the RUNNING state that are not RUNNING.PAUSED.
180 3 void FpySequencer::BREAK_cmdHandler(FwOpcodeType opCode, //!< The opcode
181 U32 cmdSeq //!< The command sequence number
182 ) {
183
14/24
✓ Branch 6 taken 3 times.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 1 times.
✓ Branch 14 taken 2 times.
✓ Branch 20 taken 1 times.
✓ Branch 21 taken 1 times.
✓ Branch 22 taken 2 times.
✓ Branch 23 taken 1 times.
✓ Branch 26 taken 2 times.
✓ Branch 27 taken 1 times.
✓ Branch 29 taken 3 times.
✗ Branch 30 not taken.
✓ Branch 33 taken 3 times.
✗ Branch 34 not taken.
✓ Branch 36 taken 2 times.
✓ Branch 37 taken 1 times.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
3 if (!this->isRunningState(this->sequencer_getState()) || this->sequencer_getState() == State::RUNNING_PAUSED) {
184 // can only break while running, and not paused
185
2/2
✓ Branch 7 taken 2 times.
✓ Branch 14 taken 2 times.
2 this->log_WARNING_HI_InvalidCommand(static_cast<I32>(sequencer_getState()));
186
2/2
✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
2 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
187 2 return;
188 }
189 1 this->sequencer_sendSignal_cmd_BREAK();
190
191
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
192 }
193
194 //! Handler for command CONTINUE
195 //!
196 //! Continues the automatic execution of the sequence after it has been paused. If a breakpoint is still
197 //! set, it may pause again on that breakpoint. This command is only valid in the RUNNING.PAUSED state.
198 2 void FpySequencer::CONTINUE_cmdHandler(FwOpcodeType opCode, //!< The opcode
199 U32 cmdSeq //!< The command sequence number
200 ) {
201
3/3
✓ Branch 3 taken 2 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
2 if (this->sequencer_getState() != State::RUNNING_PAUSED) {
202
2/2
✓ Branch 7 taken 1 times.
✓ Branch 14 taken 1 times.
1 this->log_WARNING_HI_InvalidCommand(static_cast<I32>(sequencer_getState()));
203
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
204 1 return;
205 }
206
207 1 this->sequencer_sendSignal_cmd_CONTINUE();
208
209
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
210 }
211
212 //! Handler for command CLEAR_BREAKPOINT
213 //!
214 //! Clears the breakpoint, but does not continue executing the sequence. This command
215 //! is valid in all states. This happens automatically when a sequence ends execution.
216 1 void FpySequencer::CLEAR_BREAKPOINT_cmdHandler(FwOpcodeType opCode, //!< The opcode
217 U32 cmdSeq //!< The command sequence number
218 ) {
219 1 this->sequencer_sendSignal_cmd_CLEAR_BREAKPOINT();
220 1 this->log_ACTIVITY_HI_BreakpointCleared();
221
222
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
223 1 }
224
225 //! Handler for command STEP
226 //!
227 //! Dispatches and awaits the result of the next directive, or ends the sequence if no more directives remain.
228 //! Returns to the RUNNING.PAUSED state if the directive executes successfully. This command is only valid in the
229 //! RUNNING.PAUSED state.
230 4 void FpySequencer::STEP_cmdHandler(FwOpcodeType opCode, //!< The opcode
231 U32 cmdSeq //!< The command sequence number
232 ) {
233
3/3
✓ Branch 3 taken 4 times.
✓ Branch 12 taken 2 times.
✓ Branch 13 taken 2 times.
4 if (this->sequencer_getState() != State::RUNNING_PAUSED) {
234
2/2
✓ Branch 7 taken 2 times.
✓ Branch 14 taken 2 times.
2 this->log_WARNING_HI_InvalidCommand(static_cast<I32>(sequencer_getState()));
235
2/2
✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
2 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
236 2 return;
237 }
238
239 2 this->sequencer_sendSignal_cmd_STEP();
240
2/2
✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
2 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
241 }
242
243 //! Handler for command DUMP_STACK_TO_FILE
244 //!
245 //! Writes the contents of the stack to a file. This command is only valid in the RUNNING.PAUSED state.
246 3 void FpySequencer::DUMP_STACK_TO_FILE_cmdHandler(FwOpcodeType opCode, //!< The opcode
247 U32 cmdSeq, //!< The command sequence number
248 const Fw::CmdStringArg& fileName //!< The name of the output file
249 ) {
250
3/3
✓ Branch 3 taken 3 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 2 times.
3 if (this->sequencer_getState() != State::RUNNING_PAUSED) {
251
2/2
✓ Branch 7 taken 1 times.
✓ Branch 14 taken 1 times.
1 this->log_WARNING_HI_InvalidCommand(static_cast<I32>(sequencer_getState()));
252
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
253 1 return;
254 }
255
1/1
✓ Branch 2 taken 2 times.
2 Os::File sequenceFile;
256
1/1
✓ Branch 6 taken 2 times.
2 Os::File::Status status = sequenceFile.open(fileName.toChar(), Os::File::OPEN_WRITE);
257
258
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (status != Os::File::Status::OP_OK) {
259
1/1
✓ Branch 8 taken 1 times.
1 this->log_WARNING_HI_FileOpenError(fileName, static_cast<I32>(status));
260
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
261 1 return;
262 }
263
264 1 FwSizeType writeSize = static_cast<FwSizeType>(this->m_runtime.stack.size);
265
1/1
✓ Branch 4 taken 1 times.
1 status = sequenceFile.write(this->m_runtime.stack.bytes, writeSize);
266
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
1 if (status != Os::File::Status::OP_OK || writeSize != this->m_runtime.stack.size) {
267 this->log_WARNING_HI_FileWriteError(writeSize, fileName, static_cast<I32>(status));
268 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
269 return;
270 }
271
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
272 1 return;
273 2 }
274 //! Handler for input port checkTimers
275 4 void FpySequencer::checkTimers_handler(FwIndexType portNum, //!< The port number
276 U32 context //!< The call order
277 ) {
278 4 this->sequencer_sendSignal_checkTimersIn();
279 4 }
280
281 1 void FpySequencer::pingIn_handler(FwIndexType portNum, /*!< The port number*/
282 U32 key /*!< Value to return to pinger*/
283 ) {
284 // send ping response
285 1 this->pingOut_out(0, key);
286 1 }
287
288 //! Handler for input port cmdResponseIn
289 8 void FpySequencer::cmdResponseIn_handler(FwIndexType portNum, //!< The port number
290 FwOpcodeType opCode, //!< Command Op Code
291 U32 cmdSeq, //!< Command Sequence
292 const Fw::CmdResponse& response //!< The command response argument
293 ) {
294 // if we aren't in the RUNNING state:
295
3/3
✓ Branch 6 taken 8 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 7 times.
8 if (!this->isRunningState(sequencer_getState())) {
296 // must be a coding error from an outside component (off nom), or due to CANCEL while running a command (nom).
297 // because we can't be sure that it wasn't a nominal sequence of events leading to this, don't fail the
298 // sequence, just report it
299
2/2
✓ Branch 8 taken 1 times.
✓ Branch 15 taken 1 times.
1 this->log_WARNING_LO_CmdResponseWhileNotRunningSequence(static_cast<I32>(this->sequencer_getState()),
300 CmdDispatcherCfg::getEventOpcode(opCode), response);
301 1 return;
302 }
303
304 // okay, we're running a sequence. now let's use the cmdUid to check if the response was for a cmd
305 // from this sequence
306
307 // the cmdSeq arg is confusingly not the cmdSeq in this case, according to the current implementation
308 // of the CmdDisp. instead, it is the context that we passed in when we originally sent the cmd out.
309 // this context is in turn the cmdUid that we calculated just before sending it. rename the variable for
310 // clarity's sake
311 7 U32 cmdUid = cmdSeq;
312
313 // pull the sequence index (modulo 2^16) out of the cmdUid. see the comment in FpySequencer::dispatchCommand
314 // for info on the binary format of this cmdUid. as a reminder, this should be equal to the first 16 bits of
315 // the m_sequencesStarted variable
316 7 U16 sequenceIndex = static_cast<U16>((cmdUid & 0xFFFF0000) >> 16);
317 7 U16 currentSequenceIndex = static_cast<U16>(this->m_sequencesStarted & 0xFFFF);
318
319 // if it was from a different sequence:
320
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
7 if (sequenceIndex != currentSequenceIndex) {
321 1 this->log_WARNING_LO_CmdResponseFromOldSequence(CmdDispatcherCfg::getEventOpcode(opCode), response,
322 sequenceIndex, currentSequenceIndex);
323 1 return;
324 }
325
326 // okay, it was from this sequence. now if anything's wrong from this point on we should fail the sequence
327
328 // first, make sure we're actually awaiting a statement response
329
3/3
✓ Branch 3 taken 6 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 5 times.
6 if (this->sequencer_getState() != State::RUNNING_AWAITING_STATEMENT_RESPONSE) {
330 // okay, crap. something from this sequence responded, and we weren't awaiting anything. end it all
331 1 this->log_WARNING_HI_CmdResponseWhileNotAwaiting(CmdDispatcherCfg::getEventOpcode(opCode), response);
332 1 this->sequencer_sendSignal_stmtResponse_unexpected();
333 1 return;
334 }
335
336
2/2
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 4 times.
5 if (this->m_runtime.currentStatementOpcode != Fpy::DirectiveId::CONST_CMD &&
337
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
1 this->m_runtime.currentStatementOpcode != Fpy::DirectiveId::STACK_CMD) {
338 // we were not awaiting a cmd response, we were waiting for a directive
339 this->log_WARNING_HI_CmdResponseWhileAwaitingDirective(CmdDispatcherCfg::getEventOpcode(opCode), response,
340 this->m_runtime.currentStatementOpcode);
341 this->sequencer_sendSignal_stmtResponse_unexpected();
342 return;
343 }
344
345 // okay, we were awaiting a cmd response. were we awaiting this opcode?
346
2/2
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 4 times.
5 if (opCode != this->m_runtime.currentCmdOpcode) {
347 // we were not awaiting this opcode. coding error, likely on the part of the responding component or cmd
348 // dispatcher
349 2 this->log_WARNING_HI_WrongCmdResponseOpcode(CmdDispatcherCfg::getEventOpcode(opCode), response,
350 1 CmdDispatcherCfg::getEventOpcode(this->m_runtime.currentCmdOpcode));
351 1 this->sequencer_sendSignal_stmtResponse_unexpected();
352 1 return;
353 }
354
355 // okay, we were awaiting this opcode. but was it from this exact statement, or a different one with the same opcode
356 // in the same file?
357
358 // pull the cmd index (modulo 2^16) out of cmdUid. this should be equal to the first 16 bits of the
359 // m_statementsDispatched variable
360 4 U16 cmdIndex = static_cast<U16>(cmdUid & 0xFFFF);
361 // check for coding errors. at this point in the function, we have definitely dispatched a stmt
362 4 FW_ASSERT(this->m_statementsDispatched > 0);
363 4 U16 currentCmdIndex = static_cast<U16>((this->m_statementsDispatched) & 0xFFFF);
364
365
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (cmdIndex != currentCmdIndex) {
366 // we were not awaiting this exact statement, it was a different one with the same opcode. coding error
367 2 this->log_WARNING_HI_WrongCmdResponseIndex(CmdDispatcherCfg::getEventOpcode(opCode), response, cmdIndex,
368 currentCmdIndex);
369 2 this->sequencer_sendSignal_stmtResponse_unexpected();
370 2 return;
371 }
372
373 // okay, got the right cmd back. we have verified:
374 // 1) we are in the RUNNING state
375 // 2) the response is from this sequence
376 // 3) the response is from the correct opcode
377 // 4) the response is from the correct instance of that opcode in the sequence
378
379 // always succeed; the cmd response value is pushed to the stack so the sequence
380 // can branch on it if desired
381 2 this->sequencer_sendSignal_stmtResponse_success();
382
383 // push the cmd response to the stack so we can branch off of it
384 // the constCmd/stackCmd directive handlers guarantee there is room for this push
385
1/2
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
2 this->m_runtime.stack.push(static_cast<Fw::CmdResponse::SerialType>(response.e));
386 }
387
388 2 void FpySequencer ::seqCancelIn_handler(FwIndexType portNum) {
389 // only state you can't cancel in is IDLE
390
3/3
✓ Branch 3 taken 2 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
2 if (sequencer_getState() == State::IDLE) {
391
2/2
✓ Branch 7 taken 1 times.
✓ Branch 14 taken 1 times.
1 this->log_WARNING_HI_InvalidSeqCancelCall(static_cast<I32>(sequencer_getState()));
392 1 return;
393 }
394 1 this->sequencer_sendSignal_cmd_CANCEL();
395 }
396
397 //! Handler for input port seqRunIn
398 3 void FpySequencer::seqRunIn_handler(FwIndexType portNum, const Fw::StringBase& filename, const Svc::SeqArgs& args) {
399 // can only run a seq while in idle
400
3/3
✓ Branch 3 taken 3 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 2 times.
3 if (sequencer_getState() != State::IDLE) {
401
2/2
✓ Branch 7 taken 1 times.
✓ Branch 14 taken 1 times.
1 this->log_WARNING_HI_InvalidSeqRunCall(static_cast<I32>(sequencer_getState()));
402 1 return;
403 }
404
405 // seqRunIn is never blocking - store args for pushArgsToStack action
406 // Args must be serialized in F' big-endian format by the caller before being sent
407
2/2
✓ Branch 6 taken 2 times.
✓ Branch 10 taken 2 times.
2 this->sequencer_sendSignal_cmd_RUN(FpySequencer_SequenceExecutionArgs(filename, BlockState::NO_BLOCK, args));
408 }
409
410 //! Handler for input port tlmWrite
411 1 void FpySequencer::tlmWrite_handler(FwIndexType portNum, //!< The port number
412 U32 context //!< The call order
413 ) {
414
3/3
✓ Branch 6 taken 1 times.
✓ Branch 11 taken 1 times.
✓ Branch 18 taken 1 times.
1 this->tlmWrite_State(static_cast<FwEnumStoreType>(this->sequencer_getState()));
415
2/2
✓ Branch 6 taken 1 times.
✓ Branch 13 taken 1 times.
1 this->tlmWrite_StatementsDispatched(this->m_statementsDispatched);
416
2/2
✓ Branch 6 taken 1 times.
✓ Branch 13 taken 1 times.
1 this->tlmWrite_StatementsFailed(this->m_tlm.statementsFailed);
417
2/2
✓ Branch 6 taken 1 times.
✓ Branch 13 taken 1 times.
1 this->tlmWrite_SequencesCancelled(this->m_tlm.sequencesCancelled);
418
2/2
✓ Branch 6 taken 1 times.
✓ Branch 13 taken 1 times.
1 this->tlmWrite_SequencesSucceeded(this->m_tlm.sequencesSucceeded);
419
2/2
✓ Branch 6 taken 1 times.
✓ Branch 13 taken 1 times.
1 this->tlmWrite_SequencesFailed(this->m_tlm.sequencesFailed);
420
2/2
✓ Branch 6 taken 1 times.
✓ Branch 12 taken 1 times.
1 this->tlmWrite_LastDirectiveError(this->m_tlm.lastDirectiveError);
421
2/2
✓ Branch 6 taken 1 times.
✓ Branch 13 taken 1 times.
1 this->tlmWrite_DirectiveErrorIndex(this->m_tlm.directiveErrorIndex);
422
2/2
✓ Branch 6 taken 1 times.
✓ Branch 12 taken 1 times.
1 this->tlmWrite_DirectiveErrorId(this->m_tlm.directiveErrorId);
423
2/2
✓ Branch 6 taken 1 times.
✓ Branch 12 taken 1 times.
1 this->tlmWrite_SeqPath(this->m_sequenceFilePath);
424
425
2/2
✓ Branch 6 taken 1 times.
✓ Branch 13 taken 1 times.
1 this->tlmWrite_BreakpointIndex(this->m_breakpoint.breakpointIndex);
426
3/4
✓ Branch 6 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✓ Branch 14 taken 1 times.
1 this->tlmWrite_BreakOnlyOnceOnBreakpoint(this->m_breakpoint.breakOnlyOnceOnBreakpoint);
427
3/4
✓ Branch 6 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✓ Branch 14 taken 1 times.
1 this->tlmWrite_BreakBeforeNextLine(this->m_breakpoint.breakBeforeNextLine);
428
3/4
✓ Branch 6 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✓ Branch 14 taken 1 times.
1 this->tlmWrite_BreakpointInUse(this->m_breakpoint.breakpointInUse);
429
430 1 this->updateDebugTelemetryStruct();
431
2/2
✓ Branch 6 taken 1 times.
✓ Branch 13 taken 1 times.
1 this->tlmWrite_Debug_NextCmdOpcode(this->m_debug.nextCmdOpcode);
432
2/2
✓ Branch 6 taken 1 times.
✓ Branch 13 taken 1 times.
1 this->tlmWrite_Debug_NextStatementOpcode(this->m_debug.nextStatementOpcode);
433
3/4
✓ Branch 6 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✓ Branch 14 taken 1 times.
1 this->tlmWrite_Debug_NextStatementReadSuccess(this->m_debug.nextStatementReadSuccess);
434
2/2
✓ Branch 6 taken 1 times.
✓ Branch 13 taken 1 times.
1 this->tlmWrite_Debug_NextStatementIndex(this->m_debug.nextStatementIndex);
435
3/4
✓ Branch 6 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✓ Branch 14 taken 1 times.
1 this->tlmWrite_Debug_ReachedEndOfFile(this->m_debug.reachedEndOfFile);
436
2/2
✓ Branch 6 taken 1 times.
✓ Branch 13 taken 1 times.
1 this->tlmWrite_Debug_StackSize(this->m_debug.stackSize);
437 1 }
438
439 1 void FpySequencer::updateDebugTelemetryStruct() {
440 // only send debug tlm when we are paused
441
2/3
✓ Branch 3 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 if (this->sequencer_getState() == State::RUNNING_PAUSED) {
442 if (this->m_runtime.nextStatementIndex >= this->m_sequenceObj.get_header().get_statementCount()) {
443 // reached end of file, turn on EOF flag and otherwise send some default tlm
444 this->m_debug.reachedEndOfFile = true;
445 this->m_debug.nextStatementReadSuccess = false;
446 this->m_debug.nextStatementOpcode = 0;
447 this->m_debug.nextCmdOpcode = 0;
448 this->m_debug.nextStatementIndex = this->m_runtime.nextStatementIndex;
449 this->m_debug.stackSize = this->m_runtime.stack.size;
450 return;
451 }
452
453 FW_ASSERT(this->m_runtime.nextStatementIndex < Fpy::MAX_SEQUENCE_STATEMENT_COUNT,
454 static_cast<FwAssertArgType>(this->m_runtime.nextStatementIndex));
455 const Fpy::Statement& nextStmt = this->m_sequenceObj.get_statements()[this->m_runtime.nextStatementIndex];
456 DirectiveUnion directiveUnion;
457 Fw::Success status = this->deserializeDirective(nextStmt, directiveUnion);
458
459 if (status != Fw::Success::SUCCESS) {
460 this->m_debug.reachedEndOfFile = false;
461 this->m_debug.nextStatementReadSuccess = false;
462 this->m_debug.nextStatementOpcode = nextStmt.get_opCode();
463 this->m_debug.nextCmdOpcode = 0;
464 this->m_debug.nextStatementIndex = this->m_runtime.nextStatementIndex;
465 this->m_debug.stackSize = this->m_runtime.stack.size;
466 return;
467 }
468
469 if (nextStmt.get_opCode() == Fpy::DirectiveId::CONST_CMD) {
470 // send opcode of the cmd to the ground
471 this->m_debug.reachedEndOfFile = false;
472 this->m_debug.nextStatementReadSuccess = true;
473 this->m_debug.nextStatementOpcode = nextStmt.get_opCode();
474 this->m_debug.nextCmdOpcode = directiveUnion.constCmd.get_opCode();
475 this->m_debug.nextStatementIndex = this->m_runtime.nextStatementIndex;
476 this->m_debug.stackSize = this->m_runtime.stack.size;
477 return;
478 }
479
480 this->m_debug.reachedEndOfFile = false;
481 this->m_debug.nextStatementReadSuccess = true;
482 this->m_debug.nextStatementOpcode = nextStmt.get_opCode();
483 this->m_debug.nextCmdOpcode = 0;
484 this->m_debug.nextStatementIndex = this->m_runtime.nextStatementIndex;
485 this->m_debug.stackSize = this->m_runtime.stack.size;
486 return;
487 }
488 // send some default tlm when we aren't in debug break
489 1 this->m_debug.reachedEndOfFile = false;
490 1 this->m_debug.nextStatementReadSuccess = false;
491 1 this->m_debug.nextStatementOpcode = 0;
492 1 this->m_debug.nextCmdOpcode = 0;
493 1 this->m_debug.nextStatementIndex = 0;
494 1 this->m_debug.stackSize = 0;
495 }
496
497 void FpySequencer::parametersLoaded() {
498 parameterUpdated(PARAMID_STATEMENT_TIMEOUT_SECS);
499 parameterUpdated(PARAMID_SEQ_BASE_DIR);
500 }
501
502 14 void FpySequencer::parameterUpdated(FwPrmIdType id) {
503
1/1
✓ Branch 2 taken 14 times.
14 Fw::ParamValid valid;
504
2/3
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
14 switch (id) {
505 7 case PARAMID_STATEMENT_TIMEOUT_SECS: {
506
3/3
✓ Branch 6 taken 7 times.
✓ Branch 13 taken 7 times.
✓ Branch 16 taken 7 times.
7 this->tlmWrite_PRM_STATEMENT_TIMEOUT_SECS(this->paramGet_STATEMENT_TIMEOUT_SECS(valid));
507 7 break;
508 }
509 7 case PARAMID_SEQ_BASE_DIR: {
510
3/3
✓ Branch 6 taken 7 times.
✓ Branch 11 taken 7 times.
✓ Branch 15 taken 7 times.
7 this->tlmWrite_PRM_SEQ_BASE_DIR(this->paramGet_SEQ_BASE_DIR(valid));
511 7 break;
512 }
513 default: {
514 FW_ASSERT(false, static_cast<FwAssertArgType>(id)); // coding error, forgot to include in switch statement
515 }
516 }
517
518 14 FW_ASSERT(FW_PARAM_OK(valid), static_cast<FwAssertArgType>(valid.e));
519 28 }
520
521 20 bool FpySequencer::isRunningState(State state) {
522 // TODO ask Rob if there's a better way to check if we're in a superstate. I don't want to have
523 // to update this every time I add a new substate to the RUNNING state.
524
525
4/4
✓ Branch 6 taken 11 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 9 times.
✓ Branch 9 taken 2 times.
43 return state == State::RUNNING_AWAITING_STATEMENT_RESPONSE || state == State::RUNNING_DISPATCH_STATEMENT ||
526
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 8 times.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 6 times.
43 state == State::RUNNING_PAUSED || state == State::RUNNING_SLEEPING;
527 }
528
529 } // namespace Svc
530