| 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 |