fprime/Svc/CmdSequencer/CmdSequencerImpl.hpp
Joshua Anderson 3cccd731d9
Refactor FW_OBJECT_NAMES switches and fix building without object names
Instead of adding the name argument to a constructor when FW_OBJECT_NAMES
is enabled, always supply a name argument.

Add a marco that conditionally sets the name to "" if FW_OBJECT_NAMES is not set.
This cleans up a lot of the conditional compilation switches that weren't being tested
and would silently break, while still stripping the strings from the binary.
2020-10-07 17:19:05 -07:00

788 lines
22 KiB
C++

// ======================================================================
// \title CmdSequencerImpl.hpp
// \author Bocchino/Canham
// \brief hpp file for CmdSequencer component implementation class
//
// \copyright
// Copyright (C) 2009-2018 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship
// acknowledged.
//
// ======================================================================
#ifndef Svc_CmdSequencerImpl_HPP
#define Svc_CmdSequencerImpl_HPP
#include "Fw/Com/ComBuffer.hpp"
#include "Fw/Types/MemAllocator.hpp"
#include "Os/File.hpp"
#include "Os/ValidateFile.hpp"
#include "Svc/CmdSequencer/CmdSequencerComponentAc.hpp"
namespace Svc {
class CmdSequencerComponentImpl :
public CmdSequencerComponentBase
{
PRIVATE:
// ----------------------------------------------------------------------
// Private enumerations
// ----------------------------------------------------------------------
//! The run mode
enum RunMode {
STOPPED, RUNNING
};
//! The step mode
enum StepMode {
AUTO, MANUAL
};
public:
// ----------------------------------------------------------------------
// Public classes
// ----------------------------------------------------------------------
//! \class Sequence
//! \brief A sequence with unspecified binary format
class Sequence {
public:
//! \class Events
//! \brief Sequence event reporting
class Events {
public:
//! File read stage for error reporting
struct FileReadStage {
typedef enum {
READ_HEADER,
READ_HEADER_SIZE,
DESER_SIZE,
DESER_NUM_RECORDS,
DESER_TIME_BASE,
DESER_TIME_CONTEXT,
READ_SEQ_CRC,
READ_SEQ_DATA,
READ_SEQ_DATA_SIZE,
} t;
//! Convert FileReadStage::t to CmdSequencerComponentImpl::FileReadStage
static CmdSequencerComponentImpl::FileReadStage
toComponentEnum(
const t fileReadStage //!< The file read stage
);
};
public:
//! Construct an Events object
Events(
Sequence& sequence //!< The enclosing sequence
);
public:
//! File CRC failure
void fileCRCFailure(
const U32 storedCRC, //!< The CRC stored in the file
const U32 computedCRC //!< The CRC computed over the file
);
//! File invalid
void fileInvalid(
const FileReadStage::t stage, //!< The file read stage
const I32 error //!< The error
);
//! File not found
void fileNotFound(void);
//! File read error
void fileReadError(void);
//! File size error
void fileSizeError(
const U32 size //!< The size
);
//! Record invalid
void recordInvalid(
const U32 recordNumber, //!< The record number
const I32 error //!< The error
);
//! Record mismatch
void recordMismatch(
const U32 numRecords, //!< The number of records in the header
const U32 extraBytes //!< The number of bytes beyond last record
);
//! Time base mismatch
void timeBaseMismatch(
const FwTimeBaseStoreType currTimeBase, //!< The current time base
const FwTimeBaseStoreType seqTimeBase //!< The sequence file time base
);
//! Time context mismatch
void timeContextMismatch(
const FwTimeContextStoreType currTimeContext, //!< The current time context
const FwTimeContextStoreType seqTimeContext //!< The sequence file time context
);
PRIVATE:
//! The enclosing component
Sequence& m_sequence;
};
public:
//! Construct a Sequence object
Sequence(
CmdSequencerComponentImpl& component //!< The enclosing component
);
//! Destroy a Sequence object
virtual ~Sequence(void);
public:
//! \class Header
//! \brief A sequence header
class Header {
public:
enum Constants {
//! Serialized size of header
SERIALIZED_SIZE =
sizeof(U32) +
sizeof(U32) +
sizeof(FwTimeBaseStoreType) +
sizeof(FwTimeContextStoreType)
};
public:
//! Construct a Header object
Header(void);
public:
//! Validate the time field of the sequence header
//! \return Success or failure
bool validateTime(
CmdSequencerComponentImpl& component //!< Component for time and events
);
public:
//! The file size
U32 m_fileSize;
//! The number of records in the sequence
U32 m_numRecords;
//! The time base of the sequence
TimeBase m_timeBase;
//! The context of the sequence
FwTimeContextStoreType m_timeContext;
};
public:
//! \class Record
//! \brief A sequence record
class Record {
public:
enum Descriptor {
ABSOLUTE, //!< Absolute time
RELATIVE, //!< Relative time
END_OF_SEQUENCE //!< end of sequence
};
public:
//! Construct a Record object
Record(void) :
m_descriptor(END_OF_SEQUENCE)
{
}
public:
//! The descriptor
Descriptor m_descriptor;
//! The time tag. NOTE: timeBase and context not filled in
Fw::Time m_timeTag;
//! The command
Fw::ComBuffer m_command;
};
public:
//! Give the sequence representation a memory buffer
void allocateBuffer(
const NATIVE_INT_TYPE identifier, //!< The identifier
Fw::MemAllocator& allocator, //!< The allocator
const NATIVE_UINT_TYPE bytes //!< The number of bytes
);
//! Deallocate the buffer
void deallocateBuffer(
Fw::MemAllocator& allocator //!< The allocator
);
//! Set the file name. Also sets the log file name.
void setFileName(const Fw::CmdStringArg& fileName);
//! Get the file name
//! \return The file name
Fw::CmdStringArg& getFileName(void);
//! Get the log file name
//! \return The log file name
Fw::LogStringArg& getLogFileName(void);
//! Get the sequence header
const Header& getHeader(void) const;
//! Load a sequence file
//! \return Success or failure
virtual bool loadFile(
const Fw::CmdStringArg& fileName //!< The file name
) = 0;
//! Query whether the sequence has any more records
//! \return Yes or no
virtual bool hasMoreRecords(void) const = 0;
//! Get the next record in the sequence
//! Asserts on failure
virtual void nextRecord(
Record& record //!< The returned record
) = 0;
//! Reset the sequence to the beginning.
//! After calling this, hasMoreRecords should return true,
//! unless the sequence has no records
virtual void reset(void) = 0;
//! Clear the sequence records.
//! After calling this, hasMoreRecords should return false
virtual void clear(void) = 0;
PROTECTED:
//! The enclosing component
CmdSequencerComponentImpl& m_component;
//! Event reporting
Events m_events;
//! The sequence file name
Fw::CmdStringArg m_fileName;
//! Copy of file name for events
Fw::LogStringArg m_logFileName;
//! Serialize buffer to hold the binary sequence data
Fw::ExternalSerializeBuffer m_buffer;
//! The allocator ID
NATIVE_INT_TYPE m_allocatorId;
//! The sequence header
Header m_header;
};
//! \class FPrimeSequence
//! \brief A sequence that uses the F Prime binary format
class FPrimeSequence :
public Sequence
{
PRIVATE:
enum Constants {
INITIAL_COMPUTED_VALUE = 0xFFFFFFFFU
};
public:
//! \class CRC
//! \brief Container for computed and stored CRC values
struct CRC {
//! Construct a CRC
CRC(void);
//! Initialize computed CRC
void init(void);
//! Update computed CRC
void update(
const BYTE* buffer, //!< The buffer
NATIVE_UINT_TYPE bufferSize //!< The buffer size
);
//! Finalize computed CRC
void finalize(void);
//! Computed CRC
U32 m_computed;
//! Stored CRC
U32 m_stored;
};
public:
//! Construct an FPrimeSequence
FPrimeSequence(
CmdSequencerComponentImpl& component //!< The enclosing component
);
public:
//! Load a sequence file
//! \return Success or failure
bool loadFile(
const Fw::CmdStringArg& fileName //!< The file name
);
//! Query whether the sequence has any more records
//! \return Yes or no
bool hasMoreRecords(void) const;
//! Get the next record in the sequence.
//! Asserts on failure
void nextRecord(
Record& record //!< The returned record
);
//! Reset the sequence to the beginning.
//! After calling this, hasMoreRecords should return true, unless
//! the sequence has no records.
void reset(void);
//! Clear the sequence records.
//! After calling this, hasMoreRecords should return false.
void clear(void);
PRIVATE:
//! Read a sequence file
//! \return Success or failure
bool readFile(void);
//! Read an open sequence file
//! \return Success or failure
bool readOpenFile(void);
//! Read a binary sequence header from the sequence file
//! into the buffer
//! \return Success or failure
bool readHeader(void);
//! Deserialize the binary sequence header from the buffer
//! \return Success or failure
bool deserializeHeader(void);
//! Read records and CRC into buffer
//! \return Success or failure
bool readRecordsAndCRC(void);
//! Extract CRC from record data
//! \return Success or failure
bool extractCRC(void);
//! Validate the CRC
//! \return Success or failure
bool validateCRC(void);
//! Deserialize a record from a buffer
//! \return Serialize status
Fw::SerializeStatus deserializeRecord(
Record& record //!< The record
);
//! Deserialize a record descriptor
//! \return Serialize status
Fw::SerializeStatus deserializeDescriptor(
Record::Descriptor& descriptor //!< The descriptor
);
//! Deserialize a time tag
//! \return Serialize status
Fw::SerializeStatus deserializeTimeTag(
Fw::Time& timeTag //!< The time tag
);
//! Deserialize the record size
//! \return Serialize status
Fw::SerializeStatus deserializeRecordSize(
U32& recordSize //!< The record size
);
//! Copy the serialized command into a com buffer
//! \return Serialize status
Fw::SerializeStatus copyCommand(
Fw::ComBuffer& comBuffer, //!< The com buffer
const U32 recordSize //!< The record size
);
//! Validate the sequence records in the buffer
//! \return Success or failure
bool validateRecords(void);
PRIVATE:
//! The CRC values
CRC m_crc;
//! The sequence file
Os::File m_sequenceFile;
};
PRIVATE:
// ----------------------------------------------------------------------
// Private classes
// ----------------------------------------------------------------------
//! \class Timer
//! \brief A class representing a timer
class Timer {
PRIVATE:
//! The timer state
typedef enum {
SET, CLEAR
} State;
public:
//! Construct a Timer object
Timer(void) :
m_state(CLEAR)
{
}
//! Set the expiration time
void set(
Fw::Time time //!< The time
) {
this->m_state = SET;
this->expirationTime = time;
}
//! Clear the timer
void clear(void) {
this->m_state = CLEAR;
}
//! Determine whether the timer is expired at a given time
//! \return Yes or no
bool isExpiredAt(
Fw::Time time //!< The time
) {
if (this->m_state == CLEAR) {
return false;
} else if (
Fw::Time::compare(this->expirationTime, time) == Fw::Time::GT
) {
return false;
}
return true;
}
PRIVATE:
//! The timer state
State m_state;
//! The expiration time
Fw::Time expirationTime;
};
public:
// ----------------------------------------------------------------------
// Construction, initialization, and destruction
// ----------------------------------------------------------------------
//! Construct a CmdSequencer
CmdSequencerComponentImpl(
const char* compName //!< The component name
);
//! Initialize a CmdSequencer
void init(
const NATIVE_INT_TYPE queueDepth, //!< The queue depth
const NATIVE_INT_TYPE instance //!< The instance number
);
//! (Optional) Set a timeout.
//! Sequence will quit if a command takes longer than the number of
//! seconds in the timeout value.
void setTimeout(
NATIVE_UINT_TYPE seconds //!< The number of seconds
);
//! (Optional) Set the sequence format.
//! CmdSequencer will use the sequence object you pass in
//! to load and run sequences. By default, it uses an FPrimeSequence
//! object.
void setSequenceFormat(
Sequence& sequence //!< The sequence object
);
//! Give the sequence a memory buffer.
//! Call this after constructor and init, and after setting
//! the sequence format, but before task is spawned.
void allocateBuffer(
const NATIVE_INT_TYPE identifier, //!< The identifier
Fw::MemAllocator& allocator, //!< The allocator
const NATIVE_UINT_TYPE bytes //!< The number of bytes
);
//! (Optional) Load a sequence to run later.
//! When you call this function, the event ports must be connected.
void loadSequence(
const Fw::EightyCharString& fileName //!< The file name
);
//! Return allocated buffer. Call during shutdown.
void deallocateBuffer(
Fw::MemAllocator& allocator //!< The allocator
);
//! Destroy a CmdDispatcherComponentBase
~CmdSequencerComponentImpl(void);
PRIVATE:
// ----------------------------------------------------------------------
// Handler implementations for input ports
// ----------------------------------------------------------------------
//! Handler for input port cmdResponseIn
void cmdResponseIn_handler(
NATIVE_INT_TYPE portNum, //!< The port number
FwOpcodeType opcode, //!< The command opcode
U32 cmdSeq, //!< The command sequence number
Fw::CommandResponse response //!< The command response
);
//! Handler for input port schedIn
void schedIn_handler(
NATIVE_INT_TYPE portNum, //!< The port number
NATIVE_UINT_TYPE order //!< The call order
);
//! Handler for input port seqRunIn
void seqRunIn_handler(
NATIVE_INT_TYPE portNum, //!< The port number
Fw::EightyCharString &filename //!< The sequence file
);
//! Handler for ping port
void pingIn_handler(
NATIVE_INT_TYPE portNum, //!< The port number
U32 key //!< Value to return to pinger
);
PRIVATE:
// ----------------------------------------------------------------------
// Command handler implementations
// ----------------------------------------------------------------------
//! Handler for command CS_AUTO
//! Set the run mode to AUTO.
void CS_AUTO_cmdHandler(
FwOpcodeType opcode, //!< The opcode
U32 cmdSeq //!< The command sequence number
);
//! Handler for command CS_CANCEL
//! Validate a command sequence file
void CS_CANCEL_cmdHandler(
FwOpcodeType opCode, //!< The opcode
U32 cmdSeq //!< The command sequence number
);
//! Handler for command CS_MANUAL
//! Set the run mode to MANUAL.
void CS_MANUAL_cmdHandler(
FwOpcodeType opcode, //!< The opcode
U32 cmdSeq //!< The command sequence number
);
//! Handler for command CS_RUN
void CS_RUN_cmdHandler(
FwOpcodeType opCode, //!< The opcode
U32 cmdSeq, //!< The command sequence number
const Fw::CmdStringArg& fileName //!< The file name
);
//! Handler for command CS_START
//! Start running a command sequence
void CS_START_cmdHandler(
FwOpcodeType opcode, //!< The opcode
U32 cmdSeq //!< The command sequence number
);
//! Handler for command CS_STEP
//! Perform one step in a command sequence.
//! Valid only if SequenceRunner is in MANUAL run mode.
void CS_STEP_cmdHandler(
FwOpcodeType opcode, //!< The opcode
U32 cmdSeq //!< The command sequence number
);
//! Handler for command CS_VALIDATE
//! Run a command sequence file
void CS_VALIDATE_cmdHandler(
FwOpcodeType opCode, //!< The opcode
U32 cmdSeq, //!< The command sequence number
const Fw::CmdStringArg& fileName //!< The name of the sequence file
);
PRIVATE:
// ----------------------------------------------------------------------
// Private helper methods
// ----------------------------------------------------------------------
//! Load a sequence file
//! \return Success or failure
bool loadFile(
const Fw::CmdStringArg& fileName //!< The file name
);
//! Perform a Cancel command
void performCmd_Cancel(void);
//! Perform a Step command
void performCmd_Step(void);
//! Perform a Step command with a relative time
void performCmd_Step_RELATIVE(
Fw::Time& currentTime //!< The time
);
//! Perform a Step command with an absolute time
void performCmd_Step_ABSOLUTE(
Fw::Time& currentTime //!< The time
);
//! Record a completed command
void commandComplete(
const U32 opCode //!< The opcode
);
//! Record a sequence complete event
void sequenceComplete(void);
//! Record an error
void error(void);
//! Record an error in executing a sequence command
void commandError(
const U32 number, //!< The command number
const U32 opCode, //!< The command opcode
const U32 error //!< The error code
);
//! Require a run mode
//! \return Whether we are in the correct mode
bool requireRunMode(
RunMode mode //!< The required mode
);
//! Set command timeout timer
void setCmdTimeout(
const Fw::Time &currentTime //!< The current time
);
PRIVATE:
// ----------------------------------------------------------------------
// Private member variables
// ----------------------------------------------------------------------
//! The F Prime sequence
FPrimeSequence m_FPrimeSequence;
//! The abstract sequence
Sequence *m_sequence;
//! The number of Load commands executed
U32 m_loadCmdCount;
//! The number of Cancel commands executed
U32 m_cancelCmdCount;
//! The number of errors
U32 m_errorCount;
//! The run mode
RunMode m_runMode;
//! The step mode
StepMode m_stepMode;
//! The sequence record currently being processed
Sequence::Record m_record;
//! The command time timer
Timer m_cmdTimer;
//! The number of commands executed in this sequence
U32 m_executedCount;
//! The total number of commands executed across all sequences
U32 m_totalExecutedCount;
//! The total number of sequences completed
U32 m_sequencesCompletedCount;
//! timeout value
NATIVE_UINT_TYPE m_timeout;
//! timeout timer
Timer m_cmdTimeoutTimer;
};
};
#endif