fprime/Svc/FpySequencer/FpySequencer.hpp
Zimri Leisher 6e2fb1fe4b
FpySequencer Version 0.1: Feature Parity (#3334)
* Add initiali fpy sequencer

* Get ready to use internal state machines

* Start modeling state machine in fpp

* Little more work on fpy sequencer

* Little more drafting on fpy sequencer

* State machine review with bocchino

* Remove unnecessary sm stuff

* Update docstgrings

* Start implementing actions for SM

* Little more work on fpy seq

* Get compiling again, rework how errors are handled, start actually reading header from disk

* Much more work on getting the state machine up and working

* Little more work

* More changes to SM. Mostly combine validation into one state

* A little more work on the readXYZ funcs

* Start working on the actual runtime!

* Little more work on sending out cmds

* Some work on handling statement results

* Get waits working hopefully. Also refactor cmd signals and responses

* remove the two states for cmd vs directive

* Some progress in converting to fprime types

* Get seq compiling with new fprime types

* refactor validation a little

* Fix final bugs with seq parsing. First seq rangits add to ref

* Add StatementARgBuf

* Add some tlm, get wait directives working

* Check timebase/ctx, increase allocated size

* Some fixes for removing NATIVE_X

* use handlestmt result

* Fix some types, clean up some errors, add tlm

* Move more stuff to RUN state

* Start pulling seq dirs into internal ports

* Use internal interfaces for directives

* Add timeout to dispatcher

* Fix a lil bug with seq too large

* Sequencer working! Passing all int tests

* Add seq path tlm, timeout, return signals in directives

* Fix several pr feedback items

* More pr feedback

* More fixes from PR feedback

* Remove printf

* Add basic unit tests

* Respond to more feedback

* Do most feedback from comments

* Little more event fixes, add more docs

* Some work on proper cmd response off nominal behavior

* Add all events and conditions to cmdresponsein

* Small fix to unexpected cmd repsonse, remove from ref

* Fix some small compiler warnings

* Fix one more warning

* Fix a comment

* spelling

* Remove unused types from test

* Cast  assert arg

---------

Co-authored-by: Zimri Leisher <zimri.leisher@fireflyspace.com>
2025-04-21 14:04:16 -07:00

403 lines
18 KiB
C++

// ======================================================================
// \title FpySequencer.hpp
// \author zimri.leisher
// \brief hpp file for FpySequencer component implementation class
// ======================================================================
#ifndef FpySequencer_HPP
#define FpySequencer_HPP
#include "FppConstantsAc.hpp"
#include "Fw/Types/MemAllocator.hpp"
#include "Fw/Types/StringBase.hpp"
#include "Fw/Types/WaitEnumAc.hpp"
#include "Fw/Types/SuccessEnumAc.hpp"
#include "Os/File.hpp"
#include "Svc/FpySequencer/DirectiveIdEnumAc.hpp"
#include "Svc/FpySequencer/FooterSerializableAc.hpp"
#include "Svc/FpySequencer/FpySequencerComponentAc.hpp"
#include "Svc/FpySequencer/FpySequencer_GoalStateEnumAc.hpp"
#include "Svc/FpySequencer/HeaderSerializableAc.hpp"
#include "Svc/FpySequencer/SequenceSerializableAc.hpp"
#include "Svc/FpySequencer/StatementSerializableAc.hpp"
static_assert(Svc::Fpy::MAX_SEQUENCE_ARG_COUNT <= std::numeric_limits<U8>::max(), "Sequence arg count must be below U8 max");
static_assert(Svc::Fpy::MAX_SEQUENCE_STATEMENT_COUNT <= std::numeric_limits<U16>::max(), "Sequence statement count must be below U16 max");
namespace Svc {
using Signal = FpySequencer_SequencerStateMachineStateMachineBase::Signal;
using State = FpySequencer_SequencerStateMachineStateMachineBase::State;
class FpySequencer : public FpySequencerComponentBase {
public:
// ----------------------------------------------------------------------
// Construction, initialization, and destruction
// ----------------------------------------------------------------------
//! Construct object FpySequencer
//!
FpySequencer(const char* const compName /*!< The component name*/
);
//! Destroy object FpySequencer
//!
~FpySequencer();
PRIVATE :
//! Handler for command RUN
//!
//! Loads, validates and runs a sequence
void
RUN_cmdHandler(FwOpcodeType opCode, //!< The opcode
U32 cmdSeq, //!< The command sequence number
const Fw::CmdStringArg& fileName, //!< The name of the sequence file
FpySequencer_BlockState block //!< Return command status when complete or not
) override;
//! Handler for command VALIDATE
//!
//! Loads and validates a sequence
void VALIDATE_cmdHandler(FwOpcodeType opCode, //!< The opcode
U32 cmdSeq, //!< The command sequence number
const Fw::CmdStringArg& fileName //!< The name of the sequence file
) override;
//! Handler for command RUN_VALIDATED
//!
//! Runs a previously validated sequence
void RUN_VALIDATED_cmdHandler(FwOpcodeType opCode, //!< The opcode
U32 cmdSeq, //!< The command sequence number
FpySequencer_BlockState block //!< Return command status when complete or not
) override;
//! Handler for command CANCEL
//!
//! Cancels a running or validated sequence
void CANCEL_cmdHandler(FwOpcodeType opCode, //!< The opcode
U32 cmdSeq //!< The command sequence number
) override;
// ----------------------------------------------------------------------
// Functions to implement for internal state machine actions
// ----------------------------------------------------------------------
//! Implementation for action signalEntered of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! simply raises the "entered" signal
void Svc_FpySequencer_SequencerStateMachine_action_signalEntered(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
//! Implementation for action setSequenceFilePath of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! sets the current sequence file path member var
void Svc_FpySequencer_SequencerStateMachine_action_setSequenceFilePath(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal, //!< The signal
const Svc::FpySequencer_SequenceExecutionArgs& value //!< The value
) override;
//! Implementation for action setSequenceBlockState of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! sets the block state of the sequence to be run
void Svc_FpySequencer_SequencerStateMachine_action_setSequenceBlockState(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal, //!< The signal
const Svc::FpySequencer_SequenceExecutionArgs& value //!< The value
) override;
//! Implementation for action validate of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! performs all steps necessary for sequence validation, and raises a signal result_success or result_failure
void Svc_FpySequencer_SequencerStateMachine_action_validate(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
//! Implementation for action report_seqSucceeded of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! reports that a sequence succeeded
void Svc_FpySequencer_SequencerStateMachine_action_report_seqSucceeded(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
//! Implementation for action report_seqCancelled of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! reports that a sequence was cancelled
void Svc_FpySequencer_SequencerStateMachine_action_report_seqCancelled(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
//! Implementation for action setGoalState_RUNNING of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! sets the goal state to RUNNING
void Svc_FpySequencer_SequencerStateMachine_action_setGoalState_RUNNING(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
//! Implementation for action setGoalState_VALID of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! sets the goal state to VALID
void Svc_FpySequencer_SequencerStateMachine_action_setGoalState_VALID(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
//! Implementation for action setGoalState_IDLE of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! sets the goal state to IDLE
void Svc_FpySequencer_SequencerStateMachine_action_setGoalState_IDLE(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
//! Implementation for action sendCmdResponse_OK of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! responds to the calling command with OK
void Svc_FpySequencer_SequencerStateMachine_action_sendCmdResponse_OK(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
//! Implementation for action sendCmdResponse_EXECUTION_ERROR of state machine
//! Svc_FpySequencer_SequencerStateMachine
//!
//! responds to the calling command with EXECUTION_ERROR
void Svc_FpySequencer_SequencerStateMachine_action_sendCmdResponse_EXECUTION_ERROR(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
//! Implementation for action dispatchStatement of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! iterates to the next statement and dispatches it
void Svc_FpySequencer_SequencerStateMachine_action_dispatchStatement(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
//! Implementation for action clearSequenceFile of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! clears all variables related to the loading/validating of the sequence file
void Svc_FpySequencer_SequencerStateMachine_action_clearSequenceFile(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
//! Implementation for action checkShouldWake of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! checks if sequencer should wake from sleep
void Svc_FpySequencer_SequencerStateMachine_action_checkShouldWake(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
//! Implementation for action resetRuntime of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! resets the sequence runtime
void Svc_FpySequencer_SequencerStateMachine_action_resetRuntime(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
//! Implementation for action checkStatementTimeout of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! checks if the current statement has timed out
void Svc_FpySequencer_SequencerStateMachine_action_checkStatementTimeout(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
//! Implementation for action incrementSequenceCounter of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! increments the m_sequencesStarted counter
void Svc_FpySequencer_SequencerStateMachine_action_incrementSequenceCounter(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
PROTECTED :
// ----------------------------------------------------------------------
// Functions to implement for internal state machine guards
// ----------------------------------------------------------------------
//! Implementation for guard goalStateIs_RUNNING of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! return true if the goal state is RUNNING
bool
Svc_FpySequencer_SequencerStateMachine_guard_goalStateIs_RUNNING(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) const override;
// ----------------------------------------------------------------------
// Handlers to implement for typed input ports
// ----------------------------------------------------------------------
//! Handler for input port checkTimers
void checkTimers_handler(FwIndexType portNum, //!< The port number
U32 context //!< The call order
) override;
//! Handler for input port cmdResponseIn
void cmdResponseIn_handler(FwIndexType portNum, //!< The port number
FwOpcodeType opCode, //!< Command Op Code
U32 cmdSeq, //!< Command Sequence
const Fw::CmdResponse& response //!< The command response argument
) override;
//! Handler for input port pingIn
void pingIn_handler(FwIndexType portNum, //!< The port number
U32 key //!< Value to return to pinger
) override;
//! Handler for input port tlmWrite
void tlmWrite_handler(FwIndexType portNum, //!< The port number
U32 context //!< The call order
) override;
//! Internal interface handler for directive_waitAbs
void directive_waitAbs_internalInterfaceHandler(const FpySequencer_WaitAbsDirective& directive) override;
//! Internal interface handler for directive_waitRel
void directive_waitRel_internalInterfaceHandler(const FpySequencer_WaitRelDirective& directive) override;
void parametersLoaded() override;
void parameterUpdated(FwPrmIdType id) override;
public:
void allocateBuffer(FwEnumStoreType identifier, Fw::MemAllocator& allocator, FwSizeType bytes);
void deallocateBuffer(Fw::MemAllocator& allocator);
PRIVATE :
static constexpr U32 CRC_INITIAL_VALUE = 0xFFFFFFFFU;
// allocated at startup
Fw::ExternalSerializeBuffer m_sequenceBuffer;
// id of allocator that gave us m_sequenceBuffer
FwEnumStoreType m_allocatorId;
// assigned by the user via cmd
Fw::String m_sequenceFilePath;
// the sequence, loaded in memory
Fpy::Sequence m_sequenceObj;
// live running computation of CRC (updated as we read)
U32 m_computedCRC;
// whether or not the sequence we're about to run should return immediately or
// block on completion
FpySequencer_BlockState m_sequenceBlockState;
// if we are to block on completion, save the opCode and cmdSeq we should
// return
FwOpcodeType m_savedOpCode;
U32 m_savedCmdSeq;
// the goal state is the state that we're trying to reach in the sequencer
// if it's RUNNING, then we should promptly go to RUNNING once we validate the
// sequence. if it's VALID, we should wait after VALIDATING
FpySequencer_GoalState m_goalState;
// the total number of sequences this sequencer has started since construction
U64 m_sequencesStarted;
// the total number of statements this sequencer has dispatched, successfully or
// otherwise, since construction
U64 m_statementsDispatched;
// the runtime state of the sequence. encapsulates all state
// needed to run the sequence.
// this is distinct from the state of the sequencer. the
// sequencer and all its state is really just a shell to load
// and execute this runtime.
struct Runtime {
// the index of the next statement to be executed
U32 nextStatementIndex = 0;
// the opcode of the statement that is currently executing
FwOpcodeType currentStatementOpcode = Fpy::DirectiveId::INVALID;
// the stmt type of the stmt currently executing (cmd or directive)
Fpy::StatementType currentStatementType = Fpy::StatementType::DIRECTIVE;
// the time we dispatched the statement that is currently executing
Fw::Time currentStatementDispatchTime = Fw::Time();
// the absolute time we should wait for until returning
// a statement response
Fw::Time wakeupTime = Fw::Time();
} m_runtime;
struct Telemetry {
// the number of statements that failed to execute
U64 statementsFailed = 0;
// the number of sequences successfully completed
U64 sequencesSucceeded = 0;
// the number of sequences that failed to validate or execute
U64 sequencesFailed = 0;
// the number of sequences that have been cancelled
U64 sequencesCancelled = 0;
} m_tlm;
// ----------------------------------------------------------------------
// Validation state
// ----------------------------------------------------------------------
void updateComputedCRC(const U8* buffer, //!< The buffer
FwSizeType bufferSize //!< The buffer size
);
// loads the sequence in memory, and does header/crc/integrity checks.
// return success if sequence is valid
Fw::Success validate();
// reads some bytes from the open file into the m_sequenceBuffer.
// updates the CRC by default, but can be turned off if the contents
// aren't included in CRC.
// return success if successful
Fw::Success readBytes(Os::File& file, FwSizeType readLen, bool updateCRC = true);
// ----------------------------------------------------------------------
// Run state
// ----------------------------------------------------------------------
// dispatches the next statement
Signal dispatchStatement();
// dispatches a command out via port.
// return success if successfully dispatched.
Fw::Success dispatchCommand(const Fpy::Statement& stmt);
// dispatches a sequencer directive to the right handler.
// return success if successfully handled.
Fw::Success dispatchDirective(const Fpy::Statement& stmt);
// checks whether the currently executing statement timed out
Signal checkStatementTimeout();
// checks whether the sequencer should wake from sleeping
Signal checkShouldWake();
// ----------------------------------------------------------------------
// Directives
// ----------------------------------------------------------------------
// sends a signal based on a signal id
void sendSignal(Signal signal);
// we split these functions up into the internalInterfaceInvoke and these custom member funcs
// so that we can unit test them easier
Signal waitRel_directiveHandler(const FpySequencer_WaitRelDirective& directive);
Signal waitAbs_directiveHandler(const FpySequencer_WaitAbsDirective& directive);
};
} // namespace Svc
#endif