andreas

C++ and the PI System - Event Pipes

Blog Post created by andreas Employee on Feb 7, 2012

As promised here we will explore more of the PI SDK in C++. This time we are going to use an EventPipe (AKA sign up for events).

 

So we start with our preparation exactly as in this post (Note - the PI SDK has changed since that post, PITimeServer.DLL is now in the PISDK folder), but before we start with _tmain, we need something to handle our event pipe.

 

Here is a little function that takes all events from an EventPipe, counts them and prints them on the command line. We are going to use an EventPipe from a PointList - so the events we are receiving are PointValues, not PIValues.

 
double PrintEvents(EventPipePtr spEvPipe)
{
     // the number of events we are going to read
     long nEvent = 0;

     try 
     {
          while (spEvPipe->Count > 0) 
          {
               // loop through the events
               nEvent++;
               // pointer to the Event object
               _PIEventObjectPtr spEvObj = spEvPipe->Take();
               // the variant to the event data
               _variant_t vT = spEvObj->EventData;
               IDispatchPtr pDispatch = vT.pdispVal;
               // we are signed up for snapshot events, so we get PointValue objects
               PointValuePtr spPV = pDispatch;
               // print the tag, time, value we received in the event
               MyPIValue mPV(spPV->PIValue);
               std::cout << "Eventpipe: ";
               std::cout << spPV->PIPoint->Name << " ";
               std::cout << mPV.bstrTimeStamp << " ";
               std::cout << mPV.bstrValue << std::endl;
          } 
     }
     catch(_com_error Err)
     {
          std::cout << "Error in GetEvent: " 
                    << Err.Description()
                    << " : "
                       << Err.Error()
                      << std::endl
                      << "Unable to load PISDK."
                      << std::endl;
     }
     // return the number of events read
     return nEvent;
}

 Now we can continue with the main function. Similar to last time we initialize COM, check for the command line parameters and finally create the PISDK. After this has been done, we print out the PI SDK version:

 

 

 
int _tmain(int argc, _TCHAR* argv[])
{
     // Initialize COM
     ::CoInitializeEx(NULL,COINIT_APARTMENTTHREADED);
     // Check the command line switches
     if (argc < 3) {
          std::cout << "Command Line:" << std::endl
                      << (_bstr_t)argv[0] << " SERVERNAME TAGNAME(s)";
          return (1);
     }
     try                                    
     {
          // Create an instance of the PI SDK
          spPISDK.CreateInstance(__uuidof(PISDK));
          // Print out the PI SDK version
          spSDKVersion = spPISDK->PISDKVersion;
          std::cout << std::endl << "PI-SDK Version " 
                      << spSDKVersion->Version << " Build "
                      << spSDKVersion->BuildID << std::endl;
          // get the PI Server
          spServer = spPISDK->GetServers()->GetItem((_bstr_t)argv[1]);

 

 

So far everything is similar. But now we need to create a PointList and populate it by the tags we have supplied at the command line:

 
          // we want to use a pointlist
          _PointListPtr spPointList = NULL;
          spPointList.CreateInstance(__uuidof(PointList));
          
          // You can use more than just one tagname
          for (int i = 2; i< argc; i++) {
               // add tags one by one to a pointlist and print out the tags
               std::cout << "Adding " << (_bstr_t)argv [ i ]  << std::endl;
               spPIPoint = spServer->PIPoints->GetItem((_bstr_t)argv [ i ] );
               spPointList->Add(spPIPoint);
          }

          // Print out the number of tags
          std::cout << std::endl;
          std::cout << "Signed up for snapshot evenvts for ";
          std::cout << spPointList->Count;
          std::cout << " tags.";
          std::cout << std::endl;

 

 

Now let's have a look at the EventPipe:

 
          // the EventPipe will handle the events, 
          // the secondary interface is only required if we want to change the defaults
          // like the poll interval
          EventPipePtr     spEvPipe = NULL;             /* the event pipe */
          IEventPipe2Ptr     iep2 = NULL;                  /* Secondary interface */

          // get the eventpipe
          spEvPipe = spPointList->Data->EventPipe;
          // get the secondary interface 
          iep2 = spEvPipe;
          // set the poll intervall to 5000 ms
          iep2->PutPollInterval(5000);

 

 

to finish this simple example I am going to wait for the first ten events in my EventPipe and exit my little application:

 
          // for the sake of simplicity we just wait 
          // for some events in the eventpipe.
          double dblTotCnt = 0;
          while (dblTotCnt < 10)
          {
               Sleep (5000);
               dblTotCnt += PrintEvents (spEvPipe);
          }

     }
     catch( _com_error Err )
     {
          std::cout << "Error: " << Err.Description() << " : " << Err.Error() << std::endl;
          return (1);
     }

     return 0;
}

 

 

Done for this time. Stay tuned for more!

Outcomes