GCC Code Coverage Report


Directory: ./
File: Svc/FpySequencer/FpySequencer.hpp
Date: 2026-11-03 21:15:54
Exec Total Coverage
Lines: 2 2 100.0%
Functions: 2 2 100.0%
Branches: 0 0 -%

Line Branch Exec Source
1 // ======================================================================
2 // \title FpySequencer.hpp
3 // \author zimri.leisher
4 // \brief hpp file for FpySequencer component implementation class
5 // ======================================================================
6
7 #ifndef FpySequencer_HPP
8 #define FpySequencer_HPP
9
10 #include <atomic>
11 #include <random>
12 #include "Fw/Types/FileNameString.hpp"
13 #include "Fw/Types/MemAllocator.hpp"
14 #include "Fw/Types/StringBase.hpp"
15 #include "Fw/Types/SuccessEnumAc.hpp"
16 #include "Fw/Types/WaitEnumAc.hpp"
17 #include "Os/File.hpp"
18 #include "Os/FilePathUtils.hpp"
19 #include "Svc/FpySequencer/DirectiveIdEnumAc.hpp"
20 #include "Svc/FpySequencer/FooterSerializableAc.hpp"
21 #include "Svc/FpySequencer/FppConstantsAc.hpp"
22 #include "Svc/FpySequencer/FpySequencerComponentAc.hpp"
23 #include "Svc/FpySequencer/FpySequencer_GoalStateEnumAc.hpp"
24 #include "Svc/FpySequencer/HeaderSerializableAc.hpp"
25 #include "Svc/FpySequencer/SequenceSerializableAc.hpp"
26 #include "Svc/FpySequencer/StatementSerializableAc.hpp"
27 #include "Svc/Seq/BlockStateEnumAc.hpp"
28 #include "Utils/Hash/Hash.hpp"
29 #include "config/FppConstantsAc.hpp"
30
31 static_assert(Svc::Fpy::MAX_SEQUENCE_ARG_COUNT <= std::numeric_limits<U8>::max(),
32 "Sequence arg count must be below U8 max");
33 static_assert(Svc::Fpy::MAX_SEQUENCE_STATEMENT_COUNT <= std::numeric_limits<U16>::max(),
34 "Sequence statement count must be below U16 max");
35 static_assert(Svc::Fpy::MAX_STACK_SIZE <= std::numeric_limits<Svc::Fpy::StackSizeType>::max(),
36 "Max stack size must be below Svc::Fpy::StackSizeType max");
37 static_assert(Svc::Fpy::MAX_STACK_SIZE >= static_cast<FwSizeType>(FW_TLM_BUFFER_MAX_SIZE),
38 "Max stack size must be greater than max tlm buffer size");
39 static_assert(Svc::Fpy::MAX_STACK_SIZE >= static_cast<FwSizeType>(FW_PARAM_BUFFER_MAX_SIZE),
40 "Max stack size must be greater than max prm buffer size");
41
42 namespace Svc {
43
44 using Signal = FpySequencer_SequencerStateMachineStateMachineBase::Signal;
45 using State = FpySequencer_SequencerStateMachineStateMachineBase::State;
46 using DirectiveError = Fpy::DirectiveErrorCode;
47
48 class FpySequencer : public FpySequencerComponentBase {
49 friend class FpySequencerTester;
50
51 public:
52 union DirectiveUnion {
53 FpySequencer_WaitRelDirective waitRel;
54 FpySequencer_WaitAbsDirective waitAbs;
55 FpySequencer_GotoDirective gotoDirective;
56 FpySequencer_IfDirective ifDirective;
57 FpySequencer_NoOpDirective noOp;
58 FpySequencer_PushTlmValDirective pushTlmVal;
59 FpySequencer_PushTlmValAndTimeDirective pushTlmValAndTime;
60 FpySequencer_PushPrmDirective pushPrm;
61 FpySequencer_ConstCmdDirective constCmd;
62 FpySequencer_StackOpDirective stackOp;
63 FpySequencer_ExitDirective exit;
64 FpySequencer_AllocateDirective allocate;
65 FpySequencer_StoreRelConstOffsetDirective storeRelConstOffset;
66 FpySequencer_LoadRelDirective loadRel;
67 FpySequencer_PushValDirective pushVal;
68 FpySequencer_DiscardDirective discard;
69 FpySequencer_MemCmpDirective memCmp;
70 FpySequencer_StackCmdDirective stackCmd;
71 FpySequencer_PushTimeDirective pushTime;
72 FpySequencer_SetSeedDirective setSeed;
73 FpySequencer_PushRandDirective pushRand;
74 FpySequencer_GetFieldDirective getField;
75 FpySequencer_PeekDirective peek;
76 FpySequencer_StoreRelDirective storeRel;
77 FpySequencer_CallDirective call;
78 FpySequencer_ReturnDirective returnDirective;
79 FpySequencer_LoadAbsDirective loadAbs;
80 FpySequencer_StoreAbsDirective storeAbs;
81 FpySequencer_StoreAbsConstOffsetDirective storeAbsConstOffset;
82 FpySequencer_PopEventDirective popEvent;
83 FpySequencer_PopSerializableDirective popSerializable;
84
85 2217 DirectiveUnion() {}
86 2217 ~DirectiveUnion() {}
87 };
88
89 class Stack {
90 public:
91 // the byte array of the program stack, storing lvars, operands and function calls
92 U8 bytes[Fpy::MAX_STACK_SIZE] = {0};
93 // how many bytes high the stack is
94 Fpy::StackSizeType size = 0;
95 // the byte offset from the start of the stack where the current function's local variables begin.
96 // analogous to a 'frame pointer'.
97 Fpy::StackSizeType currentFrameStart = 0;
98
99 // pops a value off of the top of the stack
100 // converts it from big endian
101 template <typename T>
102 T pop();
103
104 // pushes a value onto the top of the stack
105 // converts it to big endian
106 template <typename T>
107 void push(T val);
108
109 // pops a byte array from the top of the stack into the destination array
110 // does not convert endianness
111 void pop(U8* dest, Fpy::StackSizeType size);
112
113 // pushes a byte array to the top of the stack from the source array
114 // leaves the source array unmodified
115 // does not convert endianness
116 void push(const U8* src, Fpy::StackSizeType size);
117
118 // pushes zero bytes to the stack
119 void pushZeroes(Fpy::StackSizeType byteCount);
120
121 // returns a pointer to the next unused byte at the top of the stack
122 U8* top();
123
124 // Copies data from one region of the stack to another
125 // Asserts that both regions are within bounds and do not overlap
126 // Does not modify stack size
127 void copy(Fpy::StackSizeType destOffset, Fpy::StackSizeType srcOffset, Fpy::StackSizeType copySize);
128
129 // Moves data within the stack (handles overlapping regions)
130 // Asserts that both source and destination are within bounds
131 // Does not modify stack size
132 void move(Fpy::StackSizeType destOffset, Fpy::StackSizeType srcOffset, Fpy::StackSizeType moveSize);
133 };
134
135 // ----------------------------------------------------------------------
136 // Construction, initialization, and destruction
137 // ----------------------------------------------------------------------
138
139 //! Construct object FpySequencer
140 //!
141 FpySequencer(const char* const compName /*!< The component name*/
142 );
143
144 //! Destroy object FpySequencer
145 //!
146 ~FpySequencer();
147
148 private:
149 //! Handler for command RUN
150 //!
151 //! Loads, validates and runs a sequence
152 void RUN_cmdHandler(FwOpcodeType opCode, //!< The opcode
153 U32 cmdSeq, //!< The command sequence number
154 const Fw::CmdStringArg& fileName, //!< The name of the sequence file
155 const Svc::BlockState& block //!< Return command status when complete or not
156 ) override;
157
158 //! Handler implementation for command RUN_ARGS
159 void RUN_ARGS_cmdHandler(FwOpcodeType opCode, //!< The opcode
160 U32 cmdSeq, //!< The command sequence number
161 const Fw::CmdStringArg& fileName, //!< The name of the sequence file
162 const Svc::BlockState& block, //!< Return command status when complete or not
163 const Svc::SeqArgs& args //!< Arguments to pass to the sequencer
164 ) override;
165
166 //! Handler for command VALIDATE
167 //!
168 //! Loads and validates a sequence
169 void VALIDATE_cmdHandler(FwOpcodeType opCode, //!< The opcode
170 U32 cmdSeq, //!< The command sequence number
171 const Fw::CmdStringArg& fileName //!< The name of the sequence file
172 ) override;
173
174 //! Handler implementation for command VALIDATE_ARGS
175 //!
176 //! Loads and validates a sequence with arguments
177 void VALIDATE_ARGS_cmdHandler(FwOpcodeType opCode, //!< The opcode
178 U32 cmdSeq, //!< The command sequence number
179 const Fw::CmdStringArg& fileName, //!< The name of the sequence file
180 const Svc::SeqArgs& buffer //!< Arguments to pass to the sequencer
181 ) override;
182
183 //! Handler implementation for command RUN_VALIDATED
184 //!
185 //! Must be called after VALIDATE. Runs the sequence that was validated.
186 void RUN_VALIDATED_cmdHandler(FwOpcodeType opCode, //!< The opcode
187 U32 cmdSeq, //!< The command sequence number
188 const Svc::BlockState& block //!< Return command status when complete or not
189 ) override;
190
191 //! Handler for command CANCEL
192 //!
193 //! Cancels a running or validated sequence
194 void CANCEL_cmdHandler(FwOpcodeType opCode, //!< The opcode
195 U32 cmdSeq //!< The command sequence number
196 ) override;
197
198 //! Handler for command SET_BREAKPOINT
199 //!
200 //! Sets the breakpoint which will pause the execution of the sequencer when
201 //! reached, until unpaused by the CONTINUE command. Will pause just before
202 //! dispatching the specified statement. This command is valid in all states. Breakpoint
203 //! settings are cleared after a sequence ends execution.
204 void SET_BREAKPOINT_cmdHandler(FwOpcodeType opCode, //!< The opcode
205 U32 cmdSeq, //!< The command sequence number
206 U32 stmtIdx, //!< The statement index to pause execution before.
207 bool breakOnce //!< Whether or not to break only once at this breakpoint
208 ) override;
209
210 //! Handler for command BREAK
211 //!
212 //! Pauses the execution of the sequencer, just before it is about to dispatch the next statement,
213 //! until unpaused by the CONTINUE command, or stepped by the STEP command. This command is only valid in the
214 //! RUNNING state.
215 void BREAK_cmdHandler(FwOpcodeType opCode, //!< The opcode
216 U32 cmdSeq //!< The command sequence number
217 ) override;
218
219 //! Handler for command CONTINUE
220 //!
221 //! Continues the automatic execution of the sequence after it has been paused. If a breakpoint is still
222 //! set, it may pause again on that breakpoint. This command is only valid in the RUNNING.PAUSED state.
223 void CONTINUE_cmdHandler(FwOpcodeType opCode, //!< The opcode
224 U32 cmdSeq //!< The command sequence number
225 ) override;
226
227 //! Handler for command CLEAR_BREAKPOINT
228 //!
229 //! Clears the breakpoint, but does not continue executing the sequence. This command
230 //! is valid in all states. This happens automatically when a sequence ends execution.
231 void CLEAR_BREAKPOINT_cmdHandler(FwOpcodeType opCode, //!< The opcode
232 U32 cmdSeq //!< The command sequence number
233 ) override;
234
235 //! Handler for command STEP
236 //!
237 //! Dispatches and awaits the result of the next directive, or ends the sequence if no more directives remain.
238 //! Returns to the RUNNING.PAUSED state if the directive executes successfully. This command is only valid in the
239 //! RUNNING.PAUSED state.
240 void STEP_cmdHandler(FwOpcodeType opCode, //!< The opcode
241 U32 cmdSeq //!< The command sequence number
242 ) override;
243
244 //! Handler for command DUMP_STACK_TO_FILE
245 //!
246 //! Writes the contents of the stack to a file. This command is only valid in the RUNNING.PAUSED state.
247 void DUMP_STACK_TO_FILE_cmdHandler(FwOpcodeType opCode, //!< The opcode
248 U32 cmdSeq, //!< The command sequence number
249 const Fw::CmdStringArg& fileName //!< The name of the output file
250 ) override;
251
252 // ----------------------------------------------------------------------
253 // Functions to implement for internal state machine actions
254 // ----------------------------------------------------------------------
255
256 //! Implementation for action signalEntered of state machine Svc_FpySequencer_SequencerStateMachine
257 //!
258 //! simply raises the "entered" signal
259 void Svc_FpySequencer_SequencerStateMachine_action_signalEntered(
260 SmId smId, //!< The state machine id
261 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
262 ) override;
263
264 //! Implementation for action setSequenceFilePath of state machine Svc_FpySequencer_SequencerStateMachine
265 //!
266 //! sets the current sequence file path member var
267 void Svc_FpySequencer_SequencerStateMachine_action_setSequenceFilePath(
268 SmId smId, //!< The state machine id
269 Svc_FpySequencer_SequencerStateMachine::Signal signal, //!< The signal
270 const Svc::FpySequencer_SequenceExecutionArgs& value //!< The value
271 ) override;
272
273 //! Implementation for action setSequenceBlockState of state machine Svc_FpySequencer_SequencerStateMachine
274 //!
275 //! sets the block state of the sequence to be run
276 void Svc_FpySequencer_SequencerStateMachine_action_setSequenceBlockState(
277 SmId smId, //!< The state machine id
278 Svc_FpySequencer_SequencerStateMachine::Signal signal, //!< The signal
279 const Svc::FpySequencer_SequenceExecutionArgs& value //!< The value
280 ) override;
281
282 //! Implementation for action setSequenceArguments of state machine Svc_FpySequencer_SequencerStateMachine
283 //!
284 //! sets the arguments to pass to the sequence
285 void Svc_FpySequencer_SequencerStateMachine_action_setSequenceArguments(
286 SmId smId, //!< The state machine id
287 Svc_FpySequencer_SequencerStateMachine::Signal signal, //!< The signal
288 const Svc::FpySequencer_SequenceExecutionArgs& value //!< The value
289 ) override;
290
291 //! Implementation for action validate of state machine Svc_FpySequencer_SequencerStateMachine
292 //!
293 //! performs all steps necessary for sequence validation, and raises a signal result_success or result_failure
294 void Svc_FpySequencer_SequencerStateMachine_action_validate(
295 SmId smId, //!< The state machine id
296 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
297 ) override;
298
299 //! Implementation for action report_seqSucceeded of state machine Svc_FpySequencer_SequencerStateMachine
300 //!
301 //! reports that a sequence succeeded
302 void Svc_FpySequencer_SequencerStateMachine_action_report_seqSucceeded(
303 SmId smId, //!< The state machine id
304 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
305 ) override;
306
307 //! Implementation for action report_seqCancelled of state machine Svc_FpySequencer_SequencerStateMachine
308 //!
309 //! reports that a sequence was cancelled
310 void Svc_FpySequencer_SequencerStateMachine_action_report_seqCancelled(
311 SmId smId, //!< The state machine id
312 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
313 ) override;
314
315 //! Implementation for action setGoalState_RUNNING of state machine Svc_FpySequencer_SequencerStateMachine
316 //!
317 //! sets the goal state to RUNNING
318 void Svc_FpySequencer_SequencerStateMachine_action_setGoalState_RUNNING(
319 SmId smId, //!< The state machine id
320 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
321 ) override;
322
323 //! Implementation for action setGoalState_VALID of state machine Svc_FpySequencer_SequencerStateMachine
324 //!
325 //! sets the goal state to VALID
326 void Svc_FpySequencer_SequencerStateMachine_action_setGoalState_VALID(
327 SmId smId, //!< The state machine id
328 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
329 ) override;
330
331 //! Implementation for action setGoalState_IDLE of state machine Svc_FpySequencer_SequencerStateMachine
332 //!
333 //! sets the goal state to IDLE
334 void Svc_FpySequencer_SequencerStateMachine_action_setGoalState_IDLE(
335 SmId smId, //!< The state machine id
336 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
337 ) override;
338
339 //! Implementation for action sendCmdResponse_OK of state machine Svc_FpySequencer_SequencerStateMachine
340 //!
341 //! responds to the calling command with OK
342 void Svc_FpySequencer_SequencerStateMachine_action_sendCmdResponse_OK(
343 SmId smId, //!< The state machine id
344 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
345 ) override;
346
347 //! Implementation for action sendCmdResponse_EXECUTION_ERROR of state machine
348 //! Svc_FpySequencer_SequencerStateMachine
349 //!
350 //! responds to the calling command with EXECUTION_ERROR
351 void Svc_FpySequencer_SequencerStateMachine_action_sendCmdResponse_EXECUTION_ERROR(
352 SmId smId, //!< The state machine id
353 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
354 ) override;
355
356 //! Implementation for action dispatchStatement of state machine Svc_FpySequencer_SequencerStateMachine
357 //!
358 //! iterates to the next statement and dispatches it
359 void Svc_FpySequencer_SequencerStateMachine_action_dispatchStatement(
360 SmId smId, //!< The state machine id
361 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
362 ) override;
363
364 //! Implementation for action clearSequenceFile of state machine Svc_FpySequencer_SequencerStateMachine
365 //!
366 //! clears all variables related to the loading/validating of the sequence file
367 void Svc_FpySequencer_SequencerStateMachine_action_clearSequenceFile(
368 SmId smId, //!< The state machine id
369 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
370 ) override;
371
372 //! Implementation for action clearSequenceArguments of state machine Svc_FpySequencer_SequencerStateMachine
373 //!
374 //! clears arguments
375 void Svc_FpySequencer_SequencerStateMachine_action_clearSequenceArguments(
376 SmId smId, //!< The state machine id
377 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
378 ) override;
379
380 //! Implementation for action checkShouldWake of state machine Svc_FpySequencer_SequencerStateMachine
381 //!
382 //! checks if sequencer should wake from sleep
383 void Svc_FpySequencer_SequencerStateMachine_action_checkShouldWake(
384 SmId smId, //!< The state machine id
385 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
386 ) override;
387
388 //! Implementation for action resetRuntime of state machine Svc_FpySequencer_SequencerStateMachine
389 //!
390 //! resets the sequence runtime
391 void Svc_FpySequencer_SequencerStateMachine_action_resetRuntime(
392 SmId smId, //!< The state machine id
393 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
394 ) override;
395
396 //! Implementation for action checkStatementTimeout of state machine Svc_FpySequencer_SequencerStateMachine
397 //!
398 //! checks if the current statement has timed out
399 void Svc_FpySequencer_SequencerStateMachine_action_checkStatementTimeout(
400 SmId smId, //!< The state machine id
401 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
402 ) override;
403
404 //! Implementation for action incrementSequenceCounter of state machine Svc_FpySequencer_SequencerStateMachine
405 //!
406 //! increments the m_sequencesStarted counter
407 void Svc_FpySequencer_SequencerStateMachine_action_incrementSequenceCounter(
408 SmId smId, //!< The state machine id
409 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
410 ) override;
411
412 //! Implementation for action pushArgsToStack of state machine Svc_FpySequencer_SequencerStateMachine
413 //!
414 //! pushes sequence arguments to the stack
415 void Svc_FpySequencer_SequencerStateMachine_action_pushArgsToStack(
416 SmId smId, //!< The state machine id
417 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
418 ) override;
419
420 //! Implementation for action clearBreakpoint of state machine Svc_FpySequencer_SequencerStateMachine
421 //!
422 //! clears the breakpoint, allowing execution of the sequence to continue
423 void Svc_FpySequencer_SequencerStateMachine_action_clearBreakpoint(
424 SmId smId, //!< The state machine id
425 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
426 ) override;
427
428 //! Implementation for action report_seqBroken of state machine Svc_FpySequencer_SequencerStateMachine
429 //!
430 //! reports that a breakpoint was hit
431 void Svc_FpySequencer_SequencerStateMachine_action_report_seqBroken(
432 SmId smId, //!< The state machine id
433 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
434 ) override;
435
436 //! Implementation for action setBreakpoint of state machine Svc_FpySequencer_SequencerStateMachine
437 //!
438 //! sets the breakpoint to the provided args
439 void Svc_FpySequencer_SequencerStateMachine_action_setBreakpoint(
440 SmId smId, //!< The state machine id
441 Svc_FpySequencer_SequencerStateMachine::Signal signal, //!< The signal
442 const Svc::FpySequencer_BreakpointArgs& value //!< The value
443 ) override;
444
445 //! Implementation for action setBreakBeforeNextLine of state machine Svc_FpySequencer_SequencerStateMachine
446 //!
447 //! sets the "break on next line" flag to true
448 void Svc_FpySequencer_SequencerStateMachine_action_setBreakBeforeNextLine(
449 SmId smId, //!< The state machine id
450 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
451 ) override;
452
453 //! Implementation for action clearBreakBeforeNextLine of state machine Svc_FpySequencer_SequencerStateMachine
454 //!
455 //! sets the "break on next line" flag to false
456 void Svc_FpySequencer_SequencerStateMachine_action_clearBreakBeforeNextLine(
457 SmId smId, //!< The state machine id
458 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
459 ) override;
460
461 //! Implementation for action report_seqFailed of state machine Svc_FpySequencer_SequencerStateMachine
462 //!
463 //! called when a sequence failed to execute successfully
464 void Svc_FpySequencer_SequencerStateMachine_action_report_seqFailed(
465 SmId smId, //!< The state machine id
466 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
467 ) override;
468
469 //! Implementation for action report_seqStarted of state machine Svc_FpySequencer_SequencerStateMachine
470 //!
471 //! reports that a sequence was started
472 void Svc_FpySequencer_SequencerStateMachine_action_report_seqStarted(
473 SmId smId, //!< The state machine id
474 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
475 ) override;
476
477 protected:
478 // ----------------------------------------------------------------------
479 // Functions to implement for internal state machine guards
480 // ----------------------------------------------------------------------
481
482 //! Implementation for guard goalStateIs_RUNNING of state machine Svc_FpySequencer_SequencerStateMachine
483 //!
484 //! return true if the goal state is RUNNING
485 bool Svc_FpySequencer_SequencerStateMachine_guard_goalStateIs_RUNNING(
486 SmId smId, //!< The state machine id
487 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
488 ) const override;
489
490 //! Implementation for guard shouldBreak of state machine Svc_FpySequencer_SequencerStateMachine
491 //!
492 //! return true if should break at this point in execution, before dispatching
493 //! next stmt
494 bool Svc_FpySequencer_SequencerStateMachine_guard_shouldBreak(
495 SmId smId, //!< The state machine id
496 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
497 ) const override;
498
499 //! Implementation for guard breakOnce of state machine Svc_FpySequencer_SequencerStateMachine
500 //!
501 //! return true if this breakpoint should only happen once
502 bool Svc_FpySequencer_SequencerStateMachine_guard_breakOnce(
503 SmId smId, //!< The state machine id
504 Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
505 ) const override;
506
507 // ----------------------------------------------------------------------
508 // Handlers to implement for typed input ports
509 // ----------------------------------------------------------------------
510
511 //! Handler for input port checkTimers
512 void checkTimers_handler(FwIndexType portNum, //!< The port number
513 U32 context //!< The call order
514 ) override;
515
516 //! Handler for input port cmdResponseIn
517 void cmdResponseIn_handler(FwIndexType portNum, //!< The port number
518 FwOpcodeType opCode, //!< Command Op Code
519 U32 cmdSeq, //!< Command Sequence
520 const Fw::CmdResponse& response //!< The command response argument
521 ) override;
522
523 //! Handler for input port seqRunIn
524 void seqRunIn_handler(FwIndexType portNum, const Fw::StringBase& filename, const Svc::SeqArgs& args) override;
525
526 //! Handler implementation for seqCancelIn
527 //!
528 //! port for requesting to cancel the currently running sequence
529 void seqCancelIn_handler(FwIndexType portNum //!< The port number
530 ) override;
531
532 //! Handler for input port pingIn
533 void pingIn_handler(FwIndexType portNum, //!< The port number
534 U32 key //!< Value to return to pinger
535 ) override;
536
537 //! Handler for input port tlmWrite
538 void tlmWrite_handler(FwIndexType portNum, //!< The port number
539 U32 context //!< The call order
540 ) override;
541
542 //! Internal interface handler for checkTimersInternal
543 void checkTimersInternal_internalInterfaceHandler() override;
544
545 //! Internal interface handler for tlmWriteInternal
546 void tlmWriteInternal_internalInterfaceHandler() override;
547
548 //! Overflow hook for tlmWriteInternal
549 void tlmWriteInternal_overflowHook() override;
550
551 //! Internal interface handler for directive_waitAbs
552 void directive_waitAbs_internalInterfaceHandler(const FpySequencer_WaitAbsDirective& directive,
553 U64 sequenceIndex) override;
554
555 //! Internal interface handler for directive_waitRel
556 void directive_waitRel_internalInterfaceHandler(const FpySequencer_WaitRelDirective& directive,
557 U64 sequenceIndex) override;
558
559 //! Internal interface handler for directive_goto
560 void directive_goto_internalInterfaceHandler(const Svc::FpySequencer_GotoDirective& directive,
561 U64 sequenceIndex) override;
562
563 //! Internal interface handler for directive_if
564 void directive_if_internalInterfaceHandler(const Svc::FpySequencer_IfDirective& directive,
565 U64 sequenceIndex) override;
566
567 //! Internal interface handler for directive_noOp
568 void directive_noOp_internalInterfaceHandler(const Svc::FpySequencer_NoOpDirective& directive,
569 U64 sequenceIndex) override;
570
571 //! Internal interface handler for directive_pushTlmVal
572 void directive_pushTlmVal_internalInterfaceHandler(const Svc::FpySequencer_PushTlmValDirective& directive,
573 U64 sequenceIndex) override;
574
575 //! Internal interface handler for directive_pushTlmValAndTime
576 void directive_pushTlmValAndTime_internalInterfaceHandler(
577 const Svc::FpySequencer_PushTlmValAndTimeDirective& directive,
578 U64 sequenceIndex) override;
579
580 //! Internal interface handler for directive_pushPrm
581 void directive_pushPrm_internalInterfaceHandler(const Svc::FpySequencer_PushPrmDirective& directive,
582 U64 sequenceIndex) override;
583
584 //! Internal interface handler for directive_constCmd
585 void directive_constCmd_internalInterfaceHandler(const Svc::FpySequencer_ConstCmdDirective& directive,
586 U64 sequenceIndex) override;
587
588 //! Internal interface handler for directive_stackOp
589 void directive_stackOp_internalInterfaceHandler(const Svc::FpySequencer_StackOpDirective& directive,
590 U64 sequenceIndex) override;
591
592 //! Internal interface handler for directive_exit
593 void directive_exit_internalInterfaceHandler(const Svc::FpySequencer_ExitDirective& directive,
594 U64 sequenceIndex) override;
595
596 //! Internal interface handler for directive_allocate
597 void directive_allocate_internalInterfaceHandler(const Svc::FpySequencer_AllocateDirective& directive,
598 U64 sequenceIndex) override;
599
600 //! Internal interface handler for directive_storeRelConstOffset
601 void directive_storeRelConstOffset_internalInterfaceHandler(
602 const Svc::FpySequencer_StoreRelConstOffsetDirective& directive,
603 U64 sequenceIndex) override;
604
605 //! Internal interface handler for directive_loadRel
606 void directive_loadRel_internalInterfaceHandler(const Svc::FpySequencer_LoadRelDirective& directive,
607 U64 sequenceIndex) override;
608
609 //! Internal interface handler for directive_pushVal
610 void directive_pushVal_internalInterfaceHandler(const Svc::FpySequencer_PushValDirective& directive,
611 U64 sequenceIndex) override;
612
613 //! Internal interface handler for directive_discard
614 void directive_discard_internalInterfaceHandler(const Svc::FpySequencer_DiscardDirective& directive,
615 U64 sequenceIndex) override;
616
617 //! Internal interface handler for directive_memCmp
618 void directive_memCmp_internalInterfaceHandler(const Svc::FpySequencer_MemCmpDirective& directive,
619 U64 sequenceIndex) override;
620
621 //! Internal interface handler for directive_stackCmd
622 void directive_stackCmd_internalInterfaceHandler(const Svc::FpySequencer_StackCmdDirective& directive,
623 U64 sequenceIndex) override;
624
625 //! Internal interface handler for directive_pushTime
626 void directive_pushTime_internalInterfaceHandler(const Svc::FpySequencer_PushTimeDirective& directive,
627 U64 sequenceIndex) override;
628
629 //! Internal interface handler for directive_setSeed
630 void directive_setSeed_internalInterfaceHandler(const Svc::FpySequencer_SetSeedDirective& directive,
631 U64 sequenceIndex) override;
632
633 //! Internal interface handler for directive_pushRand
634 void directive_pushRand_internalInterfaceHandler(const Svc::FpySequencer_PushRandDirective& directive,
635 U64 sequenceIndex) override;
636
637 //! Internal interface handler for directive_getField
638 void directive_getField_internalInterfaceHandler(const Svc::FpySequencer_GetFieldDirective& directive,
639 U64 sequenceIndex) override;
640
641 //! Internal interface handler for directive_peek
642 void directive_peek_internalInterfaceHandler(const Svc::FpySequencer_PeekDirective& directive,
643 U64 sequenceIndex) override;
644
645 //! Internal interface handler for directive_storeRel
646 void directive_storeRel_internalInterfaceHandler(const Svc::FpySequencer_StoreRelDirective& directive,
647 U64 sequenceIndex) override;
648
649 //! Internal interface handler for directive_call
650 void directive_call_internalInterfaceHandler(const Svc::FpySequencer_CallDirective& directive,
651 U64 sequenceIndex) override;
652
653 //! Internal interface handler for directive_return
654 void directive_return_internalInterfaceHandler(const Svc::FpySequencer_ReturnDirective& directive,
655 U64 sequenceIndex) override;
656
657 //! Internal interface handler for directive_loadAbs
658 void directive_loadAbs_internalInterfaceHandler(const Svc::FpySequencer_LoadAbsDirective& directive,
659 U64 sequenceIndex) override;
660
661 //! Internal interface handler for directive_storeAbs
662 void directive_storeAbs_internalInterfaceHandler(const Svc::FpySequencer_StoreAbsDirective& directive,
663 U64 sequenceIndex) override;
664
665 //! Internal interface handler for directive_storeAbsConstOffset
666 void directive_storeAbsConstOffset_internalInterfaceHandler(
667 const Svc::FpySequencer_StoreAbsConstOffsetDirective& directive,
668 U64 sequenceIndex) override;
669
670 //! Internal interface handler for directive_popEvent
671 void directive_popEvent_internalInterfaceHandler(const Svc::FpySequencer_PopEventDirective& directive,
672 U64 sequenceIndex) override;
673
674 //! Internal interface handler for directive_popSerializable
675 void directive_popSerializable_internalInterfaceHandler(const Svc::FpySequencer_PopSerializableDirective& directive,
676 U64 sequenceIndex) override;
677
678 void parametersLoaded() override;
679 void parameterUpdated(FwPrmIdType id) override;
680
681 public:
682 void allocateBuffer(FwEnumStoreType identifier, Fw::MemAllocator& allocator, FwSizeType bytes);
683
684 void deallocateBuffer(Fw::MemAllocator& allocator);
685
686 //! (Optional) Restrict file access to a directory.
687 //! Sequence files (RUN, VALIDATE and the seqRunIn port) and DUMP_STACK_TO_FILE output files
688 //! whose names resolve outside the directory are rejected with FileOutsideSandbox before the
689 //! file is opened. Until this is called, any path is allowed.
690 //! \param directory the allowed directory (absolute, or relative to CWD)
691 void configureSandbox(const char* directory);
692
693 private:
694 static constexpr U32 CRC_INITIAL_VALUE = 0xFFFFFFFFU;
695
696 //! Check a file name against the configured sandbox directory, if any.
697 //! Emits FileOutsideSandbox on rejection.
698 //! \return true if the file may be opened
699 bool checkSandbox(const Fw::StringBase& fileName);
700
701 // allocated at startup
702 Fw::ExternalSerializeBuffer m_sequenceBuffer;
703 // id of allocator that gave us m_sequenceBuffer
704 FwEnumStoreType m_allocatorId;
705
706 // assigned by the user via cmd
707 // length is FileNameStringSize
708 Fw::FileNameString m_sequenceFilePath;
709 // the sequence, loaded in memory
710 Fpy::Sequence m_sequenceObj;
711 // live running computation of CRC (updated as we read)
712 Utils::Hash m_computedCRC;
713
714 // Size of arguments read in current sequence. Used for validation between
715 // User provided arguments and what is requested of the sequence.
716 Fpy::StackSizeType m_totalExpectedArgSize;
717
718 // whether or not the sequence we're about to run should return immediately or
719 // block on completion
720 Svc::BlockState m_sequenceBlockState;
721 // if we are to block on completion, save the opCode and cmdSeq we should
722 // return
723 FwOpcodeType m_savedOpCode;
724 U32 m_savedCmdSeq;
725
726 // sequence arguments to push to stack when entering RUNNING state
727 Svc::SeqArgs m_sequenceArgs{};
728
729 // the goal state is the state that we're trying to reach in the sequencer
730 // if it's RUNNING, then we should promptly go to RUNNING once we validate the
731 // sequence. if it's VALID, we should wait after VALIDATING
732 FpySequencer_GoalState m_goalState;
733
734 // the total number of sequences this sequencer has started since construction
735 U64 m_sequencesStarted;
736 // the total number of statements this sequencer has dispatched, successfully or
737 // otherwise, since construction
738 U64 m_statementsDispatched;
739
740 const Fw::String NO_SEQ{"<no seq>"};
741
742 // true while a checkTimersInternal message is on the queue. set by the
743 // sync checkTimers handler, cleared by the internal handler
744 std::atomic<bool> m_checkTimersQueued;
745 // true while a tlmWriteInternal message is on the queue. set by the
746 // sync tlmWrite handler, cleared by the internal handler
747 std::atomic<bool> m_tlmWriteQueued;
748
749 // the runtime state of the sequence. encapsulates all state
750 // needed to run the sequence.
751 // this is distinct from the state of the sequencer. the
752 // sequencer and all its state is really just a shell to load
753 // and execute this runtime.
754 struct Runtime {
755 // the index of the next statement to be executed
756 U32 nextStatementIndex = 0;
757
758 // the opcode of the statement that is currently executing
759 U8 currentStatementOpcode = Fpy::DirectiveId::INVALID;
760 // the opcode of the command that we are currently awaiting, or 0 if we are executing a directive
761 FwOpcodeType currentCmdOpcode = 0;
762 // the time we dispatched the statement that is currently executing
763 Fw::Time currentStatementDispatchTime = Fw::Time();
764
765 // the absolute time we should wait for until returning
766 // a statement response
767 Fw::Time wakeupTime = Fw::Time();
768
769 // RNG state used by PUSH_RAND and SET_SEED directives during this run
770 std::mt19937 rng;
771 bool rngSeeded = false;
772
773 Stack stack = Stack();
774 } m_runtime;
775
776 // the state of the debugger. debugger is separate from runtime
777 // because it can be set up before running the sequence.
778 struct BreakpointInfo {
779 // whether or not to break at the debug breakpoint index
780 bool breakpointInUse = false;
781 // whether or not to remove the breakpoint after breaking on it
782 bool breakOnlyOnceOnBreakpoint = false;
783 // the statement index at which to break, before dispatching
784 U32 breakpointIndex = 0;
785 // whether or not to break before dispatching the next line,
786 // independent of what line it is.
787 // can be used in combination with breakpointIndex
788 bool breakBeforeNextLine = false;
789 } m_breakpoint;
790
791 // debug information about the sequence. only valid in the PAUSED state
792 // which you can access via BREAK or SET_BREAKPOINT cmds
793 struct DebugInfo {
794 // true if there are no statements remaining in the sequence file
795 bool reachedEndOfFile = false;
796 // true if we were able to deserialize the next statement successfully
797 bool nextStatementReadSuccess = false;
798 // the opcode of the next statement to dispatch.
799 U8 nextStatementOpcode = 0;
800 // if the next statement is a cmd directive, the opcode of that cmd
801 FwOpcodeType nextCmdOpcode = 0;
802 // the index of the next statement we're going to execute
803 U32 nextStatementIndex = 0;
804 // the size of the stack. store this separately from the real stack size
805 // so we can avoid changing this during runtime, only modify it during
806 // debug
807 Fpy::StackSizeType stackSize = 0;
808 } m_debug;
809
810 struct Telemetry {
811 // the number of statements that failed to execute
812 U64 statementsFailed = 0;
813 // the number of sequences successfully completed
814 U64 sequencesSucceeded = 0;
815 // the number of sequences that failed to validate or execute
816 U64 sequencesFailed = 0;
817 // the number of sequences that have been cancelled
818 U64 sequencesCancelled = 0;
819
820 // the error code of the last directive that ran
821 DirectiveError lastDirectiveError = DirectiveError::NO_ERROR;
822 // the index of the last directive that errored
823 U64 directiveErrorIndex = 0;
824 // the opcode of the last directive that errored
825 Fpy::DirectiveId directiveErrorId = Fpy::DirectiveId::INVALID;
826 } m_tlm;
827
828 // directory file access is restricted to (resolved, with trailing '/')
829 char m_sandboxDir[Os::FilePathUtils::MAX_PATH_LENGTH];
830 // whether configureSandbox() has been called; until then any path is allowed
831 bool m_sandboxConfigured;
832
833 // ----------------------------------------------------------------------
834 // Validation state
835 // ----------------------------------------------------------------------
836
837 // loads the sequence in memory, and does header/crc/integrity checks.
838 // return SUCCESS if sequence is valid, FAILURE otherwise
839 Fw::Success validate();
840 // reads and validates the header from the m_sequenceBuffer
841 // return SUCCESS if sequence is valid, FAILURE otherwise
842 Fw::Success readHeader();
843 // reads and validates the body from the m_sequenceBuffer
844 // return SUCCESS if sequence is valid, FAILURE otherwise
845 Fw::Success readBody();
846 // reads and validates the footer from the m_sequenceBuffer
847 // return SUCCESS if sequence is valid, FAILURE otherwise
848 Fw::Success readFooter();
849
850 // reads some bytes from the open file into the m_sequenceBuffer.
851 // updates the CRC by default, but can be turned off if the contents
852 // aren't included in CRC.
853 // return success if successful
854 Fw::Success readBytes(Os::File& file,
855 FwSizeType readLen,
856 const FpySequencer_FileReadStage& readStage,
857 bool updateCrc = true);
858
859 // ----------------------------------------------------------------------
860 // Run state
861 // ----------------------------------------------------------------------
862
863 // utility method for updating telemetry based on a directive error code
864 void handleDirectiveErrorCode(Fpy::DirectiveId id, DirectiveError err);
865
866 // dispatches the next statement
867 Signal dispatchStatement();
868
869 // deserializes a directive from bytes into the Fpy type
870 // returns success if able to deserialize, and returns the Fpy type object
871 // as a reference, in a union of all the possible directive type objects
872 Fw::Success deserializeDirective(const Fpy::Statement& stmt, DirectiveUnion& deserializedDirective);
873
874 // dispatches a deserialized sequencer directive to the right handler.
875 void dispatchDirective(const DirectiveUnion& directive, const Fpy::DirectiveId& id);
876
877 // checks whether the currently executing statement timed out
878 Signal checkStatementTimeout();
879
880 // checks whether the sequencer should wake from sleeping
881 Signal checkShouldWake();
882
883 // return true if state is a substate of RUNNING
884 bool isRunningState(State state);
885
886 // return true if a directive dispatched by the given sequence can execute in the current state.
887 // otherwise, log a warning
888 bool checkDirectiveExpected(Fpy::DirectiveId directive, U64 sequenceIndex);
889
890 // update a struct containing debug telemetry, or defaults if not in debug break
891 void updateDebugTelemetryStruct();
892
893 // ----------------------------------------------------------------------
894 // Directives
895 // ----------------------------------------------------------------------
896
897 // sends a signal based on a signal id
898 void sendSignal(Signal signal);
899
900 // dispatches a command, returns whether successful or not
901 Fw::Success sendCmd(FwOpcodeType opcode, const U8* argBuf, FwSizeType argBufSize);
902
903 // returns the index of the current statement
904 U32 currentStatementIdx();
905
906 // we split these functions up into the internalInterfaceInvoke and these custom member funcs
907 // so that we can unit test them easier
908 Signal waitRel_directiveHandler(const FpySequencer_WaitRelDirective& directive, DirectiveError& error);
909 Signal waitAbs_directiveHandler(const FpySequencer_WaitAbsDirective& directive, DirectiveError& error);
910 Signal goto_directiveHandler(const FpySequencer_GotoDirective& directive, DirectiveError& error);
911 Signal if_directiveHandler(const FpySequencer_IfDirective& directive, DirectiveError& error);
912 Signal noOp_directiveHandler(const FpySequencer_NoOpDirective& directive, DirectiveError& error);
913 Signal pushTlmVal_directiveHandler(const FpySequencer_PushTlmValDirective& directive, DirectiveError& error);
914 Signal pushTlmValAndTime_directiveHandler(const FpySequencer_PushTlmValAndTimeDirective& directive,
915 DirectiveError& error);
916 Signal pushPrm_directiveHandler(const FpySequencer_PushPrmDirective& directive, DirectiveError& error);
917 Signal constCmd_directiveHandler(const FpySequencer_ConstCmdDirective& directive, DirectiveError& error);
918 Signal stackOp_directiveHandler(const FpySequencer_StackOpDirective& directive, DirectiveError& error);
919
920 DirectiveError op_or();
921 DirectiveError op_and();
922 DirectiveError op_ieq();
923 DirectiveError op_ine();
924 DirectiveError op_ult();
925 DirectiveError op_ule();
926 DirectiveError op_ugt();
927 DirectiveError op_uge();
928 DirectiveError op_slt();
929 DirectiveError op_sle();
930 DirectiveError op_sgt();
931 DirectiveError op_sge();
932 DirectiveError op_feq();
933 DirectiveError op_fne();
934 DirectiveError op_flt();
935 DirectiveError op_fle();
936 DirectiveError op_fgt();
937 DirectiveError op_fge();
938 DirectiveError op_not();
939 DirectiveError op_fpext();
940 DirectiveError op_fptrunc();
941 DirectiveError op_fptoui();
942 DirectiveError op_fptosi();
943 DirectiveError op_sitofp();
944 DirectiveError op_uitofp();
945 DirectiveError op_add();
946 DirectiveError op_sub();
947 DirectiveError op_mul();
948 DirectiveError op_udiv();
949 DirectiveError op_sdiv();
950 DirectiveError op_umod();
951 DirectiveError op_smod();
952 DirectiveError op_fadd();
953 DirectiveError op_fsub();
954 DirectiveError op_fmul();
955 DirectiveError op_fdiv();
956 DirectiveError op_fpow();
957 DirectiveError op_flog();
958 DirectiveError op_fmod();
959 DirectiveError op_siext_8_64();
960 DirectiveError op_siext_16_64();
961 DirectiveError op_siext_32_64();
962 DirectiveError op_ziext_8_64();
963 DirectiveError op_ziext_16_64();
964 DirectiveError op_ziext_32_64();
965 DirectiveError op_itrunc_64_8();
966 DirectiveError op_itrunc_64_16();
967 DirectiveError op_itrunc_64_32();
968 DirectiveError op_ffloor();
969 DirectiveError op_iabs();
970 DirectiveError op_fabs();
971
972 Signal exit_directiveHandler(const FpySequencer_ExitDirective& directive, DirectiveError& error);
973 Signal allocate_directiveHandler(const FpySequencer_AllocateDirective& directive, DirectiveError& error);
974 //! Helper to pop value from stack top and store at destOffset
975 Signal storeHelper(Fpy::StackSizeType destOffset, Fpy::StackSizeType size, DirectiveError& error);
976 //! Helper to load value from srcOffset and push to stack top
977 Signal loadHelper(Fpy::StackSizeType srcOffset, Fpy::StackSizeType size, DirectiveError& error);
978 Signal storeRelConstOffset_directiveHandler(const FpySequencer_StoreRelConstOffsetDirective& directive,
979 DirectiveError& error);
980 Signal loadRel_directiveHandler(const FpySequencer_LoadRelDirective& directive, DirectiveError& error);
981 Signal pushVal_directiveHandler(const FpySequencer_PushValDirective& directive, DirectiveError& error);
982 Signal discard_directiveHandler(const FpySequencer_DiscardDirective& directive, DirectiveError& error);
983 Signal memCmp_directiveHandler(const FpySequencer_MemCmpDirective& directive, DirectiveError& error);
984 Signal stackCmd_directiveHandler(const FpySequencer_StackCmdDirective& directive, DirectiveError& error);
985 Signal pushTime_directiveHandler(const FpySequencer_PushTimeDirective& directive, DirectiveError& error);
986 Signal setSeed_directiveHandler(const FpySequencer_SetSeedDirective& directive, DirectiveError& error);
987 Signal pushRand_directiveHandler(const FpySequencer_PushRandDirective& directive, DirectiveError& error);
988 Signal getField_directiveHandler(const FpySequencer_GetFieldDirective& directive, DirectiveError& error);
989 Signal peek_directiveHandler(const FpySequencer_PeekDirective& directive, DirectiveError& error);
990 Signal storeRel_directiveHandler(const FpySequencer_StoreRelDirective& directive, DirectiveError& error);
991 Signal call_directiveHandler(const FpySequencer_CallDirective& directive, DirectiveError& error);
992 Signal return_directiveHandler(const FpySequencer_ReturnDirective& directive, DirectiveError& error);
993 Signal loadAbs_directiveHandler(const FpySequencer_LoadAbsDirective& directive, DirectiveError& error);
994 Signal storeAbs_directiveHandler(const FpySequencer_StoreAbsDirective& directive, DirectiveError& error);
995 Signal storeAbsConstOffset_directiveHandler(const FpySequencer_StoreAbsConstOffsetDirective& directive,
996 DirectiveError& error);
997 Signal popEvent_directiveHandler(const FpySequencer_PopEventDirective& directive, DirectiveError& error);
998 Signal popSerializable_directiveHandler(const FpySequencer_PopSerializableDirective& directive,
999 DirectiveError& error);
1000 };
1001
1002 } // namespace Svc
1003
1004 #endif
1005