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 
9 #include <Fw/Cmd/CmdPacket.hpp>
10 #include <Fw/Types/Assert.hpp>
11 #include <cstdio>
12 
13 // Check the CMD_DISPATCHER_DISPATCH_TABLE_SIZE and CMD_DISPATCHER_SEQUENCER_TABLE_SIZE for overflow
14 static_assert(CMD_DISPATCHER_DISPATCH_TABLE_SIZE <= std::numeric_limits<FwOpcodeType>::max(), "Opcode table limited to opcode range");
15 static_assert(CMD_DISPATCHER_SEQUENCER_TABLE_SIZE <= std::numeric_limits<U32>::max(), "Sequencer table limited to range of U32");
16 
17 namespace Svc {
20  m_seq(0),
21  m_numCmdsDispatched(0),
22  m_numCmdErrors(0)
23  {
24  memset(this->m_entryTable,0,sizeof(this->m_entryTable));
25  memset(this->m_sequenceTracker,0,sizeof(this->m_sequenceTracker));
26  }
27 
29  }
30 
31  void CommandDispatcherImpl::compCmdReg_handler(FwIndexType portNum, FwOpcodeType opCode) {
32  // search for an empty slot
33  bool slotFound = false;
34  for (FwOpcodeType slot = 0; slot < FW_NUM_ARRAY_ELEMENTS(this->m_entryTable); slot++) {
35  if ((not this->m_entryTable[slot].used) and (not slotFound)) {
36  this->m_entryTable[slot].opcode = opCode;
37  this->m_entryTable[slot].port = portNum;
38  this->m_entryTable[slot].used = true;
39  this->log_DIAGNOSTIC_OpCodeRegistered(opCode,portNum,static_cast<I32>(slot));
40  slotFound = true;
41  } else if ((this->m_entryTable[slot].used) &&
42  (this->m_entryTable[slot].opcode == opCode) &&
43  (this->m_entryTable[slot].port == portNum) &&
44  (not slotFound)) {
45  slotFound = true;
46  this->log_DIAGNOSTIC_OpCodeReregistered(opCode,portNum);
47  } else if (this->m_entryTable[slot].used) { // make sure no duplicates
48  FW_ASSERT(this->m_entryTable[slot].opcode != opCode, static_cast<FwAssertArgType>(opCode));
49  }
50  }
51  FW_ASSERT(slotFound,static_cast<FwAssertArgType>(opCode));
52  }
53 
54  void CommandDispatcherImpl::compCmdStat_handler(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response) {
55  // check response and log
56  if (Fw::CmdResponse::OK == response.e) {
57  this->log_COMMAND_OpCodeCompleted(opCode);
58  } else {
59  this->m_numCmdErrors++;
60  this->tlmWrite_CommandErrors(this->m_numCmdErrors);
61  FW_ASSERT(response.e != Fw::CmdResponse::OK);
62  this->log_COMMAND_OpCodeError(opCode,response);
63  }
64  // look for command source
65  FwIndexType portToCall = -1;
66  U32 context;
67  for (U32 pending = 0; pending < FW_NUM_ARRAY_ELEMENTS(this->m_sequenceTracker); pending++) {
68  if (
69  (this->m_sequenceTracker[pending].seq == cmdSeq) &&
70  (this->m_sequenceTracker[pending].used)
71  ) {
72  portToCall = this->m_sequenceTracker[pending].callerPort;
73  context = this->m_sequenceTracker[pending].context;
74  FW_ASSERT(opCode == this->m_sequenceTracker[pending].opCode);
75  FW_ASSERT(portToCall < this->getNum_seqCmdStatus_OutputPorts());
76  this->m_sequenceTracker[pending].used = false;
77  break;
78  }
79  }
80 
81  if (portToCall != -1) {
82  // call port to report status
83  if (this->isConnected_seqCmdStatus_OutputPort(portToCall)) {
84  this->seqCmdStatus_out(portToCall,opCode,context,response);
85  }
86  }
87  }
88 
89  void CommandDispatcherImpl::seqCmdBuff_handler(FwIndexType portNum, Fw::ComBuffer &data, U32 context) {
90 
91  Fw::CmdPacket cmdPkt;
92  Fw::SerializeStatus stat = cmdPkt.deserialize(data);
93 
94  if (stat != Fw::FW_SERIALIZE_OK) {
95  Fw::DeserialStatus serErr(static_cast<Fw::DeserialStatus::t>(stat));
96  this->log_WARNING_HI_MalformedCommand(serErr);
97  if (this->isConnected_seqCmdStatus_OutputPort(portNum)) {
98  this->seqCmdStatus_out(portNum,cmdPkt.getOpCode(),context,Fw::CmdResponse::VALIDATION_ERROR);
99  }
100  return;
101  }
102 
103  // search for opcode in dispatch table
104  FwOpcodeType entry;
105  bool entryFound = false;
106 
107  for (entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_entryTable); entry++) {
108  if ((this->m_entryTable[entry].used) and (cmdPkt.getOpCode() == this->m_entryTable[entry].opcode)) {
109  entryFound = true;
110  break;
111  }
112  }
113  if (entryFound and this->isConnected_compCmdSend_OutputPort(this->m_entryTable[entry].port)) {
114  // register command in command tracker only if response port is connect
115  if (this->isConnected_seqCmdStatus_OutputPort(portNum)) {
116  bool pendingFound = false;
117 
118  for (U32 pending = 0; pending < FW_NUM_ARRAY_ELEMENTS(this->m_sequenceTracker); pending++) {
119  if (not this->m_sequenceTracker[pending].used) {
120  pendingFound = true;
121  this->m_sequenceTracker[pending].used = true;
122  this->m_sequenceTracker[pending].opCode = cmdPkt.getOpCode();
123  this->m_sequenceTracker[pending].seq = this->m_seq;
124  this->m_sequenceTracker[pending].context = context;
125  this->m_sequenceTracker[pending].callerPort = portNum;
126  break;
127  }
128  }
129 
130  // if we couldn't find a slot to track the command, quit
131  if (not pendingFound) {
133  if (this->isConnected_seqCmdStatus_OutputPort(portNum)) {
134  this->seqCmdStatus_out(portNum,cmdPkt.getOpCode(),context,Fw::CmdResponse::EXECUTION_ERROR);
135  }
136  return;
137  }
138  } // end if status port connected
139  // pass arguments to argument buffer
140  this->compCmdSend_out(
141  this->m_entryTable[entry].port,
142  cmdPkt.getOpCode(),
143  this->m_seq,
144  cmdPkt.getArgBuffer());
145  // log dispatched command
146  this->log_COMMAND_OpCodeDispatched(cmdPkt.getOpCode(),this->m_entryTable[entry].port);
147 
148  // increment command count
149  this->m_numCmdsDispatched++;
150  // write telemetry channel for dispatched commands
151  this->tlmWrite_CommandsDispatched(this->m_numCmdsDispatched);
152  } else {
154  this->m_numCmdErrors++;
155  // Fail command back to port, if connected
156  if (this->isConnected_seqCmdStatus_OutputPort(portNum)) {
157  this->seqCmdStatus_out(portNum,cmdPkt.getOpCode(),context,Fw::CmdResponse::INVALID_OPCODE);
158  }
159  this->tlmWrite_CommandErrors(this->m_numCmdErrors);
160  }
161 
162  // increment sequence number
163  this->m_seq++;
164  }
165 
166  void CommandDispatcherImpl::CMD_NO_OP_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
167  Fw::LogStringArg no_op_string("Hello, World!");
168  // Log event for NO_OP here.
170  this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK);
171  }
172 
173  void CommandDispatcherImpl::CMD_NO_OP_STRING_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdStringArg& arg1) {
174  Fw::LogStringArg msg(arg1.toChar());
175  // Echo the NO_OP_STRING args here.
177  this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK);
178  }
179 
180  void CommandDispatcherImpl::CMD_TEST_CMD_1_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, I32 arg1, F32 arg2, U8 arg3) {
181  this->log_ACTIVITY_HI_TestCmd1Args(arg1,arg2,arg3);
182  this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK);
183  }
184 
185  void CommandDispatcherImpl::CMD_CLEAR_TRACKING_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
186  // clear tracking table
187  for (FwOpcodeType entry = 0; entry < CMD_DISPATCHER_SEQUENCER_TABLE_SIZE; entry++) {
188  this->m_sequenceTracker[entry].used = false;
189  }
190  this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK);
191  }
192 
193  void CommandDispatcherImpl::pingIn_handler(FwIndexType portNum, U32 key) {
194  // respond to ping
195  this->pingOut_out(0,key);
196  }
197 
198 }
Serialization/Deserialization operation was successful.
SerializeStatus deserialize(SerializeBufferBase &buffer)
deserialize to contents
Definition: CmdPacket.cpp:29
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.
SerializeStatus
forward declaration for string
float F32
32-bit floating point
Definition: BasicTypes.h:86
void log_ACTIVITY_HI_NoOpStringReceived(const Fw::StringBase &message) const
void tlmWrite_CommandsDispatched(U32 arg, Fw::Time _tlmTime=Fw::Time())
U32 FwOpcodeType
The type of a command opcode.
void log_WARNING_HI_MalformedCommand(Fw::DeserialStatus Status) const
void log_COMMAND_OpCodeDispatched(U32 Opcode, I32 port) const
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:55
Command successfully executed.
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:56
void log_DIAGNOSTIC_OpCodeReregistered(U32 Opcode, I32 port) const
CmdArgBuffer & getArgBuffer()
Definition: CmdPacket.cpp:59
Command had execution error.
const char * toChar() const
Definition: CmdString.hpp:50
void seqCmdStatus_out(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response)
Invoke output port seqCmdStatus.
PlatformIndexType FwIndexType
#define FW_NUM_ARRAY_ELEMENTS(a)
number of elements in an array
Definition: BasicTypes.h:93
Auto-generated base for CommandDispatcher component.
bool isConnected_seqCmdStatus_OutputPort(FwIndexType portNum)
Command failed validation.
RateGroupDivider component implementation.
void log_COMMAND_OpCodeError(U32 Opcode, Fw::CmdResponse error) 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_DIAGNOSTIC_OpCodeRegistered(U32 Opcode, I32 port, I32 slot) const
Log event OpCodeRegistered.