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