F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
CommandDispatcherImpl.cpp
Go to the documentation of this file.
1 /*
2  * CommandDispatcherImpl.cpp
3  *
4  * Created on: May 13, 2014
5  * Author: Timothy Canham
6  */
7 
8 #include <Fw/Cmd/CmdPacket.hpp>
9 #include <Fw/Types/Assert.hpp>
11 #include <cstdio>
12 #include <cstring>
13 
14 // Check the CMD_DISPATCHER_DISPATCH_TABLE_SIZE and CMD_DISPATCHER_SEQUENCER_TABLE_SIZE for overflow
15 static_assert(CMD_DISPATCHER_DISPATCH_TABLE_SIZE <= std::numeric_limits<FwOpcodeType>::max(),
16  "Opcode table limited to opcode range");
17 static_assert(CMD_DISPATCHER_SEQUENCER_TABLE_SIZE <= std::numeric_limits<U32>::max(),
18  "Sequencer table limited to range of U32");
19 
20 namespace Svc {
22  : CommandDispatcherComponentBase(name), m_seq(0), m_numCmdsDispatched(0), m_numCmdErrors(0), m_numCmdsDropped(0) {}
23 
25 
26 void CommandDispatcherImpl::compCmdReg_handler(FwIndexType portNum, FwOpcodeType opCode) {
27  FwIndexType existingPort;
28  if (this->m_entryTable.find(opCode, existingPort) == Fw::Success::SUCCESS) {
29  // Opcode already present — must be the same port (re-registration)
30  FW_ASSERT(existingPort == portNum, static_cast<FwAssertArgType>(opCode));
31  this->log_DIAGNOSTIC_OpCodeReregistered(opCode, portNum);
32  } else {
33  const I32 slot = static_cast<I32>(this->m_entryTable.getSize());
34  const Fw::Success status = this->m_entryTable.insert(opCode, portNum);
35  FW_ASSERT(status == Fw::Success::SUCCESS, static_cast<FwAssertArgType>(opCode));
36  this->log_DIAGNOSTIC_OpCodeRegistered(opCode, portNum, slot);
37  }
38 }
39 
40 void CommandDispatcherImpl::compCmdStat_handler(FwIndexType portNum,
41  FwOpcodeType opCode,
42  U32 cmdSeq,
43  const Fw::CmdResponse& response) {
44  // check response and log
45  if (Fw::CmdResponse::OK == response.e) {
46  this->log_COMMAND_OpCodeCompleted(opCode);
47  } else {
48  this->m_numCmdErrors++;
49  FW_ASSERT(response.e != Fw::CmdResponse::OK);
50  this->log_COMMAND_OpCodeError(opCode, response);
51  }
52  // look for command source
53  SequenceTrackerEntry trackedCmd;
54  const Fw::Success removeStatus = this->m_sequenceTracker.remove(cmdSeq, trackedCmd);
55  if (removeStatus == Fw::Success::SUCCESS) {
56  const FwIndexType portToCall = trackedCmd.callerPort;
57  const U32 context = trackedCmd.context;
58  FW_ASSERT(opCode == trackedCmd.opCode);
59  FW_ASSERT(portToCall < this->getNum_seqCmdStatus_OutputPorts());
60 
61  // call port to report status
62  if (this->isConnected_seqCmdStatus_OutputPort(portToCall)) {
63  // NOTE: seqCmdStatus port forwards three arguments: (opCode, cmdSeq, response).
64  // However, the cmdSeq value has no meaning for the calling sequencer.
65  // Instead, the context value is forwarded to allow the caller to utilize it if needed.
66  this->seqCmdStatus_out(portToCall, opCode, context, response);
67  }
68  }
69 }
70 
71 void CommandDispatcherImpl::seqCmdBuff_handler(FwIndexType portNum, Fw::ComBuffer& data, U32 context) {
72  Fw::CmdPacket cmdPkt;
73  Fw::SerializeStatus stat = cmdPkt.deserializeFrom(data);
74 
75  if (stat != Fw::FW_SERIALIZE_OK) {
76  Fw::DeserialStatus serErr(static_cast<Fw::DeserialStatus::t>(stat));
77  this->log_WARNING_HI_MalformedCommand(serErr);
78  if (this->isConnected_seqCmdStatus_OutputPort(portNum)) {
79  this->seqCmdStatus_out(portNum, cmdPkt.getOpCode(), context, Fw::CmdResponse::VALIDATION_ERROR);
80  }
81  return;
82  }
83 
84  // look up opcode in dispatch map
85  FwIndexType entryPort;
86  Fw::Success findStatus = this->m_entryTable.find(cmdPkt.getOpCode(), entryPort);
87  if (findStatus == Fw::Success::SUCCESS and this->isConnected_compCmdSend_OutputPort(entryPort)) {
88  // register command in command tracker only if response port is connect
89  if (this->isConnected_seqCmdStatus_OutputPort(portNum)) {
90  SequenceTrackerEntry pendingCmd;
91  pendingCmd.opCode = cmdPkt.getOpCode();
92  pendingCmd.context = context;
93  pendingCmd.callerPort = portNum;
94 
95  const Fw::Success pendingInsertStatus = this->m_sequenceTracker.insert(this->m_seq, pendingCmd);
96 
97  // if we couldn't find a slot to track the command, quit
98  if (pendingInsertStatus != Fw::Success::SUCCESS) {
100  if (this->isConnected_seqCmdStatus_OutputPort(portNum)) {
101  this->seqCmdStatus_out(portNum, cmdPkt.getOpCode(), context, Fw::CmdResponse::EXECUTION_ERROR);
102  }
103  return;
104  }
105  } // end if status port connected
106  // pass arguments to argument buffer
107  this->compCmdSend_out(entryPort, cmdPkt.getOpCode(), this->m_seq, cmdPkt.getArgBuffer());
108  // log dispatched command
109  this->log_COMMAND_OpCodeDispatched(cmdPkt.getOpCode(), entryPort);
110 
111  // increment command count
112  this->m_numCmdsDispatched++;
113  } else {
115  this->m_numCmdErrors++;
116  // Fail command back to port, if connected
117  if (this->isConnected_seqCmdStatus_OutputPort(portNum)) {
118  this->seqCmdStatus_out(portNum, cmdPkt.getOpCode(), context, Fw::CmdResponse::INVALID_OPCODE);
119  }
120  }
121 
122  // increment sequence number
123  this->m_seq++;
124 }
125 
126 void CommandDispatcherImpl ::run_handler(FwIndexType portNum, U32 context) {
127  this->tlmWrite_CommandsDropped(this->m_numCmdsDropped);
128  this->tlmWrite_CommandErrors(this->m_numCmdErrors);
129  this->tlmWrite_CommandsDispatched(this->m_numCmdsDispatched);
130 }
131 
132 void CommandDispatcherImpl::CMD_NO_OP_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
133  Fw::LogStringArg no_op_string("Hello, World!");
134  // Log event for NO_OP here.
136  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
137 }
138 
139 void CommandDispatcherImpl::CMD_NO_OP_STRING_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdStringArg& arg1) {
140  Fw::LogStringArg msg(arg1.toChar());
141  // Echo the NO_OP_STRING args here.
143  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
144 }
145 
146 void CommandDispatcherImpl::CMD_TEST_CMD_1_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, I32 arg1, F32 arg2, U8 arg3) {
147  this->log_ACTIVITY_HI_TestCmd1Args(arg1, arg2, arg3);
148  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
149 }
150 
151 void CommandDispatcherImpl::CMD_CLEAR_TRACKING_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
152  // clear tracking table
153  this->m_sequenceTracker.clear();
154  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
155 }
156 
157 void CommandDispatcherImpl::pingIn_handler(FwIndexType portNum, U32 key) {
158  // respond to ping
159  this->pingOut_out(0, key);
160 }
161 
162 void CommandDispatcherImpl::seqCmdBuff_overflowHook(FwIndexType portNum, Fw::ComBuffer& data, U32 context) {
163  // Extract command opcode
164  Fw::CmdPacket cmdPkt;
165  Fw::SerializeStatus stat = cmdPkt.deserializeFrom(data);
166  FwOpcodeType opcode = 0; // Note: 0 = Reserved opcode
167 
168  if (stat == Fw::FW_SERIALIZE_OK) {
169  opcode = cmdPkt.getOpCode();
170  }
171 
172  // Log Cmd Buffer Overflow and increment CommandsDroppedBufOverflow counter
173  this->m_numCmdsDropped++;
174  this->log_WARNING_HI_CommandDroppedQueueOverflow(opcode, context);
175 }
176 
177 } // namespace Svc
Serialization/Deserialization operation was successful.
FwIdType FwOpcodeType
The type of a command opcode.
Representing success.
void log_WARNING_HI_CommandDroppedQueueOverflow(FwOpcodeType OpCode, U32 Context)
Invalid opcode dispatched.
Deserialization status.
enum T e
The raw enum value.
FwSizeType getSize() const override
void log_ACTIVITY_HI_TestCmd1Args(I32 arg1, F32 arg2, U8 arg3) const
void pingOut_out(FwIndexType portNum, U32 key)
Invoke output port pingOut.
Enum representing a command response.
Success find(const K &key, V &value) const override
void compCmdSend_out(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, Fw::CmdArgBuffer &args)
Invoke output port compCmdSend.
void log_DIAGNOSTIC_OpCodeReregistered(FwOpcodeType Opcode, I32 port) const
SerializeStatus
forward declaration for string
float F32
32-bit floating point
Definition: BasicTypes.h:83
void log_COMMAND_OpCodeCompleted(FwOpcodeType Opcode) const
void log_ACTIVITY_HI_NoOpStringReceived(const Fw::StringBase &message) const
void tlmWrite_CommandsDispatched(U32 arg, Fw::Time _tlmTime=Fw::Time())
Success insert(const K &key, const V &value) override
Definition: ArrayMap.hpp:97
SerializeStatus deserializeFrom(SerialBufferBase &buffer, Fw::Endianness mode=Fw::Endianness::BIG) override
Deserialize the contents of this object from a buffer.
Definition: CmdPacket.cpp:27
Success remove(const K &key, V &value) override
Definition: ArrayMap.hpp:105
void clear() override
Clear the map.
Definition: ArrayMap.hpp:73
void log_WARNING_HI_MalformedCommand(Fw::DeserialStatus Status) const
void tlmWrite_CommandsDropped(U32 arg, Fw::Time _tlmTime=Fw::Time())
Component responsible for dispatching incoming commands to registered components. ...
virtual ~CommandDispatcherImpl()
Component destructor.
void tlmWrite_CommandErrors(U32 arg, Fw::Time _tlmTime=Fw::Time())
CommandDispatcherImpl(const char *name)
Command Dispatcher constructor.
FwOpcodeType getOpCode() const
Definition: CmdPacket.cpp:52
void log_WARNING_HI_InvalidCommand(FwOpcodeType Opcode) const
Command successfully executed.
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:53
void log_COMMAND_OpCodeError(FwOpcodeType Opcode, Fw::CmdResponse error) const
CmdArgBuffer & getArgBuffer()
Definition: CmdPacket.cpp:56
Command had execution error.
const char * toChar() const
Convert to a C-style char*.
Definition: CmdString.hpp:50
void seqCmdStatus_out(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response)
Invoke output port seqCmdStatus.
PlatformIndexType FwIndexType
void log_DIAGNOSTIC_OpCodeRegistered(FwOpcodeType Opcode, I32 port, I32 slot) const
Log event OpCodeRegistered.
Auto-generated base for CommandDispatcher component.
bool isConnected_seqCmdStatus_OutputPort(FwIndexType portNum)
Command failed validation.
RateGroupDivider component implementation.
Success insert(const K &key, const V &value) override
static constexpr FwIndexType getNum_seqCmdStatus_OutputPorts()
void log_WARNING_HI_TooManyCommands(FwOpcodeType Opcode) const
bool isConnected_compCmdSend_OutputPort(FwIndexType portNum)
#define FW_ASSERT(...)
Definition: Assert.hpp:14
void cmdResponse_out(FwOpcodeType opCode, U32 cmdSeq, Fw::CmdResponse response)
Emit command response.
Success/Failure.
void log_COMMAND_OpCodeDispatched(FwOpcodeType Opcode, I32 port) const