Using Multiport in RH

 

Introduction

The default behavior for a Redhawk port connection is for each connection to get all of the data. However, there are times when the output port of a component is connected to a group of follow on components, and you want each component receive different output data. This post will provide an easy example of how to pick which data goes to each connection on the output port. The source code for the entire component can be obtained by sending us a request.

Header File

The header file for this example is shown below:

class MultiportExample_i : public MultiportExample_base
{
    ENABLE_LOGGING
    public:
        MultiportExample_i(const char *uuid, const char *label);
        ~MultiportExample_i();
        void start() throw (CF::Resource::StartError, CORBA::SystemException);
        int serviceFunction();

    protected:
        std::vector<bulkio::connection_descriptor_struct> connectionTable;
};

The important addition here is the connectionTable. The connectionTable is used to represent the multi-port setup. Each connection_descriptor_struct has a port_name, stream_id, and connection_id. When pushPacket is called, the port and streamID are provided in the call, and using that information the packet is sent out on the corresponding connection_id based on what the table says.

Start Function

The next step is to set up the connectionTable once the connections are made by the framework. This example is using a static number of connections and so it is set up only once, but the same paradigm can be used when dynamic connections to device are a possibility. In this case the start() function was chosen for the table setup, but this can be done anywhere once the connections have been made. The start function is shown here:

void MultiportExample_i::start() throw (CF::Resource::StartError, CORBA::SystemException){

  for(unsigned int loop = 0; loop < dataShort_out->getConnections().size(); loop++){
    bulkio::connection_descriptor_struct newConnection;
    newConnection.port_name = dataShort_out->getName();
    newConnection.connection_id = dataShort_out->getConnections().at(loop).second;
    newConnection.stream_id = dataShort_out->getConnections().at(loop).second;
    connectionTable.push_back(newConnection);
  }

  dataShort_out->updateConnectionFilter(connectionTable);
  MultiportExample_base::start();
}

The function loops through each connection to an output port, and each time through creates a connection_descriptor_struct. In this example the stream ID is made the same as the connection ID, but it can be set to whatever is desired. Once each structure has all of its needed information it is stored for future lookup or modification. The last step passes the vector of connections to the port so it will be able to utilize the information during each pushPacket() call.

Service Function

The serviceFunction in this example takes in a packet of data, and for each connection number, it adds that amount to the data. This operation may not be of much use but the intention here is only to show how the multi-port works. Here is the serviceFunction:

int MultiportExample_i::serviceFunction()
{
  bulkio::InShortPort::dataTransfer *packetIn = dataShort_in->getPacket(0);
  if (not packetIn) {
    return NOOP;
  }

  outputData.resize(packetIn->dataBuffer.size());
  for(unsigned int outerLoop = 0; outerLoop < connectionTable.size(); outerLoop++){
    for(unsigned int innerLoop = 0; innerLoop < packetIn->dataBuffer.size(); innerLoop++){
      outputData[innerLoop] = packetIn->dataBuffer[innerLoop] + outerLoop;
    }

    if(packetIn->sriChanged){
      BULKIO::StreamSRI outSri = packetIn->SRI;
      outSri.streamID = connectionTable[outerLoop].stream_id.c_str();
      dataShort_out->pushSRI(packetIn->SRI);
    }
    dataShort_out->pushPacket(outputData, packetIn->T, packetIn->EOS, 
      connectionTable[outerLoop].stream_id);
  }

  delete packetIn;
  return NORMAL;
}

The outside for loop is set to run for each connection. The inner for loop is where the data modification occurs. In this case, the connection index value is added to each data element. Once that has completed the normal sriChanged check is performed and the data is pushed out. Note that the stream ID that is used in the call is what the port uses in its table to determine which connections to push the data to.

Other Applications

While this particular application is a fairly useless one, there are many use cases where this would work well. A few possible designs are:

  • Division of labor: if each RH packet could be considered a ‘request’ and each output component can operate on that request, then a master/slave relation can be made where the master can determine where to send each request
  • Multiple streams of data: a single component can perform an operation on many different streams of data, and then send the data to a corresponding component connected to its output
  • Router: a component can receive from many input streams and route to many output streams
  • Channelizer: if the component were a channelizer this would provide the capability of sending each narrowband stream to a different follow on component

 

If you have suggestions on what else you would like to see or any questions or comments please contact us:
Contact Us

Recent Posts

Ready for an exciting change?

Work with US!