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  memset(this->m_entryTable, 0, sizeof(this->m_entryTable));
24  memset(this->m_sequenceTracker, 0, sizeof(this->m_sequenceTracker));
25 }
26 
28 
29 void CommandDispatcherImpl::compCmdReg_handler(FwIndexType portNum, FwOpcodeType opCode) {
30  // search for an empty slot
31  bool slotFound = false;
32  for (FwOpcodeType slot = 0; slot < FW_NUM_ARRAY_ELEMENTS(this->m_entryTable); slot++) {
33  if ((not this->m_entryTable[slot].used) and (not slotFound)) {
34  this->m_entryTable[slot].opcode = opCode;
35  this->m_entryTable[slot].port = portNum;
36  this->m_entryTable[slot].used = true;
37  this->log_DIAGNOSTIC_OpCodeRegistered(opCode, portNum, static_cast<I32>(slot));
38  slotFound = true;
39  } else if ((this->m_entryTable[slot].used) && (this->m_entryTable[slot].opcode == opCode) &&
40  (this->m_entryTable[slot].port == portNum) && (not slotFound)) {
41  slotFound = true;
42  this->log_DIAGNOSTIC_OpCodeReregistered(opCode, portNum);
43  } else if (this->m_entryTable[slot].used) { // make sure no duplicates
44  FW_ASSERT(this->m_entryTable[slot].opcode != opCode, static_cast<FwAssertArgType>(opCode));
45  }
46  }
47  FW_ASSERT(slotFound, static_cast<FwAssertArgType>(opCode));
48 }
49 
50 void CommandDispatcherImpl::compCmdStat_handler(FwIndexType portNum,
51  FwOpcodeType opCode,
52  U32 cmdSeq,
53  const Fw::CmdResponse& response) {
54  // check response and log
55  if (Fw::CmdResponse::OK == response.e) {
56  this->log_COMMAND_OpCodeCompleted(opCode);
57  } else {
58  this->m_numCmdErrors++;
59  FW_ASSERT(response.e != Fw::CmdResponse::OK);
60  this->log_COMMAND_OpCodeError(opCode, response);
61  }
62  // look for command source
63  FwIndexType portToCall = -1;
64  U32 context;
65  for (U32 pending = 0; pending < FW_NUM_ARRAY_ELEMENTS(this->m_sequenceTracker); pending++) {
66  if ((this->m_sequenceTracker[pending].seq == cmdSeq) && (this->m_sequenceTracker[pending].used)) {
67  portToCall = this->m_sequenceTracker[pending].callerPort;
68  context = this->m_sequenceTracker[pending].context;
69  FW_ASSERT(opCode == this->m_sequenceTracker[pending].opCode);
70  FW_ASSERT(portToCall < this->getNum_seqCmdStatus_OutputPorts());
71  this->m_sequenceTracker[pending].used = false;
72  break;
73  }
74  }
75 
76  if (portToCall != -1) {
77  // call port to report status
78  if (this->isConnected_seqCmdStatus_OutputPort(portToCall)) {
79  // NOTE: seqCmdStatus port forwards three arguments: (opCode, cmdSeq, response).
80  // However, the cmdSeq value has no meaning for the calling sequencer.
81  // Instead, the context value is forwarded to allow the caller to utilize it if needed.
82  this->seqCmdStatus_out(portToCall, opCode, context, response);
83  }
84  }
85 }
86 
87 void CommandDispatcherImpl::seqCmdBuff_handler(FwIndexType portNum, Fw::ComBuffer& data, U32 context) {
88  Fw::CmdPacket cmdPkt;
89  Fw::SerializeStatus stat = cmdPkt.deserializeFrom(data);
90 
91  if (stat != Fw::FW_SERIALIZE_OK) {
92  Fw::DeserialStatus serErr(static_cast<Fw::DeserialStatus::t>(stat));
93  this->log_WARNING_HI_MalformedCommand(serErr);
94  if (this->isConnected_seqCmdStatus_OutputPort(portNum)) {
95  this->seqCmdStatus_out(portNum, cmdPkt.getOpCode(), context, Fw::CmdResponse::VALIDATION_ERROR);
96  }
97  return;
98  }
99 
100  // search for opcode in dispatch table
101  FwOpcodeType entry;
102  bool entryFound = false;
103 
104  for (entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_entryTable); entry++) {
105  if ((this->m_entryTable[entry].used) and (cmdPkt.getOpCode() == this->m_entryTable[entry].opcode)) {
106  entryFound = true;
107  break;
108  }
109  }
110  if (entryFound and this->isConnected_compCmdSend_OutputPort(this->m_entryTable[entry].port)) {
111  // register command in command tracker only if response port is connect
112  if (this->isConnected_seqCmdStatus_OutputPort(portNum)) {
113  bool pendingFound = false;
114 
115  for (U32 pending = 0; pending < FW_NUM_ARRAY_ELEMENTS(this->m_sequenceTracker); pending++) {
116  if (not this->m_sequenceTracker[pending].used) {
117  pendingFound = true;
118  this->m_sequenceTracker[pending].used = true;
119  this->m_sequenceTracker[pending].opCode = cmdPkt.getOpCode();
120  this->m_sequenceTracker[pending].seq = this->m_seq;
121  this->m_sequenceTracker[pending].context = context;
122  this->m_sequenceTracker[pending].callerPort = portNum;
123  break;
124  }
125  }
126 
127  // if we couldn't find a slot to track the command, quit
128  if (not pendingFound) {
130  if (this->isConnected_seqCmdStatus_OutputPort(portNum)) {
131  this->seqCmdStatus_out(portNum, cmdPkt.getOpCode(), context, Fw::CmdResponse::EXECUTION_ERROR);
132  }
133  return;
134  }
135  } // end if status port connected
136  // pass arguments to argument buffer
137  this->compCmdSend_out(this->m_entryTable[entry].port, cmdPkt.getOpCode(), this->m_seq, cmdPkt.getArgBuffer());
138  // log dispatched command
139  this->log_COMMAND_OpCodeDispatched(cmdPkt.getOpCode(), this->m_entryTable[entry].port);
140 
141  // increment command count
142  this->m_numCmdsDispatched++;
143  } else {
145  this->m_numCmdErrors++;
146  // Fail command back to port, if connected
147  if (this->isConnected_seqCmdStatus_OutputPort(portNum)) {
148  this->seqCmdStatus_out(portNum, cmdPkt.getOpCode(), context, Fw::CmdResponse::INVALID_OPCODE);
149  }
150  }
151 
152  // increment sequence number
153  this->m_seq++;
154 }
155 
156 void CommandDispatcherImpl ::run_handler(FwIndexType portNum, U32 context) {
157  this->tlmWrite_CommandsDropped(this->m_numCmdsDropped);
158  this->tlmWrite_CommandErrors(this->m_numCmdErrors);
159  this->tlmWrite_CommandsDispatched(this->m_numCmdsDispatched);
160 }
161 
162 void CommandDispatcherImpl::CMD_NO_OP_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
163  Fw::LogStringArg no_op_string("Hello, World!");
164  // Log event for NO_OP here.
166  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
167 }
168 
169 void CommandDispatcherImpl::CMD_NO_OP_STRING_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdStringArg& arg1) {
170  Fw::LogStringArg msg(arg1.toChar());
171  // Echo the NO_OP_STRING args here.
173  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
174 }
175 
176 void CommandDispatcherImpl::CMD_TEST_CMD_1_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, I32 arg1, F32 arg2, U8 arg3) {
177  this->log_ACTIVITY_HI_TestCmd1Args(arg1, arg2, arg3);
178  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
179 }
180 
181 void CommandDispatcherImpl::CMD_CLEAR_TRACKING_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
182  // clear tracking table
183  for (FwOpcodeType entry = 0; entry < CMD_DISPATCHER_SEQUENCER_TABLE_SIZE; entry++) {
184  this->m_sequenceTracker[entry].used = false;
185  }
186  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
187 }
188 
189 void CommandDispatcherImpl::pingIn_handler(FwIndexType portNum, U32 key) {
190  // respond to ping
191  this->pingOut_out(0, key);
192 }
193 
194 void CommandDispatcherImpl::seqCmdBuff_overflowHook(FwIndexType portNum, Fw::ComBuffer& data, U32 context) {
195  // Extract command opcode
196  Fw::CmdPacket cmdPkt;
197  Fw::SerializeStatus stat = cmdPkt.deserializeFrom(data);
198  FwOpcodeType opcode = 0; // Note: 0 = Reserved opcode
199 
200  if (stat == Fw::FW_SERIALIZE_OK) {
201  opcode = cmdPkt.getOpCode();
202  }
203 
204  // Log Cmd Buffer Overflow and increment CommandsDroppedBufOverflow counter
205  this->m_numCmdsDropped++;
206  this->log_WARNING_HI_CommandDroppedQueueOverflow(opcode, context);
207 }
208 
209 } // namespace Svc
Serialization/Deserialization operation was successful.
FwIdType FwOpcodeType
The type of a command opcode.
void log_WARNING_HI_CommandDroppedQueueOverflow(FwOpcodeType OpCode, U32 Context)
Invalid opcode dispatched.
Deserialization status.
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.
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())
SerializeStatus deserializeFrom(SerialBufferBase &buffer, Fw::Endianness mode=Fw::Endianness::BIG) override
Deserialize the contents of this object from a buffer.
Definition: CmdPacket.cpp:27
void log_WARNING_HI_MalformedCommand(Fw::DeserialStatus Status) const
void tlmWrite_CommandsDropped(U32 arg, Fw::Time _tlmTime=Fw::Time())
T e
The raw enum value.
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.
#define FW_NUM_ARRAY_ELEMENTS(a)
number of elements in an array
Definition: BasicTypes.h:90
Auto-generated base for CommandDispatcher component.
bool isConnected_seqCmdStatus_OutputPort(FwIndexType portNum)
Command failed validation.
RateGroupDivider component implementation.
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.
void log_COMMAND_OpCodeDispatched(FwOpcodeType Opcode, I32 port) const