fprime/Svc/CmdDispatcher/CommandDispatcherImpl.hpp
Steven Doran 43ed537106
CWE 453 cmd buffer assert (#4198)
* Initial fix for CWE-453-CmdBufferAssert

* Added EVR throttle; updated ut

* Updated unit tests

* Updated UT to check for TLM update

* Implemented finding from pull request

* Removed Test Directory

* Update model and SDD

* Move telemetry to rate group to prevent flood

* Fix Ref topology

* Format

* sp

---------

Co-authored-by: bitWarrior <bitWarrior@protonmail.com>
Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-09-30 13:26:04 -07:00

192 lines
8.5 KiB
C++

/**
* \file
* \author T.Canham
* \brief Component responsible for dispatching incoming commands to registered components
*
* \copyright
* Copyright 2009-2015, by the California Institute of Technology.
* ALL RIGHTS RESERVED. United States Government Sponsorship
* acknowledged.
* <br /><br />
*/
#ifndef COMMANDDISPATCHERIMPL_HPP_
#define COMMANDDISPATCHERIMPL_HPP_
#include <Os/Mutex.hpp>
#include <Svc/CmdDispatcher/CommandDispatcherComponentAc.hpp>
#include <config/CommandDispatcherImplCfg.hpp>
namespace Svc {
//! \class CommandDispatcherImpl
//! \brief Command Dispatcher component class
//!
//! The command dispatcher takes incoming Fw::Com packets that contain
//! encoded commands. It extracts the opcode and looks it up in a table
//! that is populated by components at registration time. If a component
//! is connected to the seqCmdStatus port with the same number
//! as the port that submitted the command, the command status will be returned.
class CommandDispatcherImpl final : public CommandDispatcherComponentBase {
friend class CommandDispatcherTester;
public:
//! \brief Command Dispatcher constructor
//!
//! The constructor initializes the state of the component.
//! In this component, the opcode dispatch and tracking tables
//! are initialized.
//!
//! \param name the component instance name
CommandDispatcherImpl(const char* name);
//! \brief Component destructor
//!
//! The destructor for this component is empty
virtual ~CommandDispatcherImpl();
protected:
private:
//! \brief component command status handler
//!
//! The command status handler is called when a component
//! reports the completion of a command.
//!
//! \param portNum the number of the incoming port.
//! \param opCode the opcode of the completed command.
//! \param cmdSeq the sequence number assigned to the command when it was dispatched
//! \param response the completion status of the command
void compCmdStat_handler(FwIndexType portNum,
FwOpcodeType opCode,
U32 cmdSeq,
const Fw::CmdResponse& response) override;
//! \brief component command buffer handler
//!
//! The command buffer handler is called to submit a new
//! command packet to be decoded
//!
//! \param portNum the number of the incoming port.
//! \param data the buffer containing the command.
//! \param context a user value returned with the status
void seqCmdBuff_handler(FwIndexType portNum, Fw::ComBuffer& data, U32 context) override;
//! \brief component command registration handler
//!
//! The command registration handler is called to register
//! new opcodes. The port number called is used to indicate
//! which port should be used to dispatch the opcode.
//!
//! \param portNum the number of the incoming port.
//! \param opCode the opcode being registered.
void compCmdReg_handler(FwIndexType portNum, FwOpcodeType opCode) override;
//! \brief component ping handler
//!
//! The ping handler responds to messages to verify that the task
//! is still executing. Will call output ping port
//!
//! \param portNum the number of the incoming port.
//! \param opCode the opcode being registered.
//! \param key the key value that is returned with the ping response
void pingIn_handler(FwIndexType portNum, U32 key) override;
//! Handler implementation for run
//!
//! Run port used to emit telemetry. Specifically this port call emits the CommandsDropped telemetry channel.
void run_handler(FwIndexType portNum, //!< The port number
U32 context //!< The call order
) override;
//! \brief NO_OP command handler
//!
//! A test command that does nothing
//!
//! \param opCode the NO_OP opcode.
//! \param cmdSeq the assigned sequence number for the command
void CMD_NO_OP_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) override;
//! \brief NO_OP with string command handler
//!
//! A test command that receives a string and sends an event
//! with the string as an argument
//!
//! \param opCode the NO_OP_STRING opcode.
//! \param cmdSeq the assigned sequence number for the command
//! \param arg1 the string argument
void CMD_NO_OP_STRING_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdStringArg& arg1) override;
//! \brief A test command with different argument types
//!
//! A test command that receives a set of arguments of different types
//!
//! \param opCode the TEST_CMD_1 opcode.
//! \param cmdSeq the assigned sequence number for the command
//! \param arg1 the I32 argument
//! \param arg2 the F32 argument
//! \param arg3 the U8 argument
void CMD_TEST_CMD_1_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, I32 arg1, F32 arg2, U8 arg3) override;
//! \brief A command to clear the command tracking
//!
//! This command will clear the table tracking the completion of commands.
//! It is meant to be used if the tracking table has gotten full because of
//! a software failure. It is dangerous in that it can clear a command
//! that a sequencer is waiting for.
//!
//! \param opCode the CLEAR_TRACKING opcode.
//! \param cmdSeq the assigned sequence number for the command
void CMD_CLEAR_TRACKING_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) override;
//! \brief Called when the command sequence queue overflows
//!
//! Generate event to the user that the command queue overflowed and the
//! command will not be processed.
//!
//! \param portNum the number of the incoming port.
//! \param data the buffer containing the command.
//! \param context call value defined by user
void seqCmdBuff_overflowHook(FwIndexType portNum, Fw::ComBuffer& data, U32 context) override;
//! \struct DispatchEntry
//! \brief table used to store opcode to port mappings
//!
//! The DispatchEntry table is used to map incoming opcodes to the port
//! connected to the component that implements the opcode.
//! As each command opcode is registered, a new entry is found
//! in the table by checking for the "used" flag. The opcode
//! member is set to the opcode, and the port member set to the
//! port to dispatch to. When a new opcode is received for
//! execution, the table is traversed until the opcode is located.
struct DispatchEntry {
bool used; //!< if entry has been used yet
FwOpcodeType opcode; //!< opcode of entry
FwIndexType port; //!< which port the entry invokes
} m_entryTable[CMD_DISPATCHER_DISPATCH_TABLE_SIZE]; //!< table of dispatch entries
//! \struct SequenceTracker
//! \brief table used to store opcode that are being executed
//!
//! The SequenceTracker table is used to track commands that are being executed
//! but are not yet complete. When a new command opcode is received,
//! the status port that would be used to report the completion status
//! is checked. If it is connected, then an entry is placed in this table.
//! The "used" flag is set, and the "seq" member is set to the
//! assigned sequence number for the command. The "opCode" field is
//! used for the opcode, and the "callerPort" field is used to store
//! the port number of the caller so the status can be reported back to
//! correct port.
struct SequenceTracker {
bool used; //!< if this slot is used
U32 seq; //!< command sequence number
FwOpcodeType opCode; //!< opcode being tracked
U32 context; //!< context passed by user
FwIndexType callerPort; //!< port command source port
} m_sequenceTracker[CMD_DISPATCHER_SEQUENCER_TABLE_SIZE]; //!< sequence tracking port for command completions;
U32 m_seq; //!< current command sequence number
U32 m_numCmdsDispatched; //!< number of commands dispatched
U32 m_numCmdErrors; //!< number of commands with an error
U32 m_numCmdsDropped; //!< number of commands dropped due to buffer overflow
};
} // namespace Svc
#endif /* COMMANDDISPATCHERIMPL_HPP_ */