As a follow up to this post, today I will write a value with annotations to PI.
In order to do this, we need the usual preparation. In other words, I need to get my imports:
//need to import sdk #pragma warning( disable : 4786 4146 ) #import "E:\PIPC\PISDK\PISDKCommon.dll" no_namespace #import "E:\PIPC\PISDK\PITimeServer.dll" no_namespace #import "E:\PIPC\PISDK\PISDK.dll" rename("Connected", "PISDKConnected") no_namespace
and some pointers and strings:
/* PISDK */ IPISDKPtr spPISDK = NULL; /* the PISDK */ ServerPtr spServer = NULL; /* the server */ PIPointPtr spPIPoint = NULL; /* the pi point */ _bstr_t bstrServer = "SCHREMMERAVMPI"; /* the pi servername*/ _bstr_t bstrPointName = "MyLabTag"; /* the tagname */
now let's start with the initialization:
// initialize the COM library ::CoInitializeEx(NULL,COINIT_APARTMENTTHREADED); // Create an instance of the PISDK spPISDK.CreateInstance(__uuidof(PISDK)); // get the PI server spServer = spPISDK->GetServers()->GetItem(bstrServer); // get the PI point spPIPoint = spServer->PIPoints->GetItem(bstrPointName);
to make my life easier I am going to use a Float32 tag, and I am assuming it does not have a bad value now. I get the snapshot:
// get the current value _PIValuePtr _pv = spPIPoint->Data->GetSnapshot();
and now I need some annotations:
// the PI Annotations _PIAnnotationsPtr spPIAnns; spPIAnns.CreateInstance(__uuidof(PIAnnotations)); // a string annotation spPIAnns->Add(L"Test",L"StringAnnotation",L"MyTest",false,VT_BSTR); // an integer annotation spPIAnns->Add(L"Test",L"IntegerAnnotation",(int)1,false,VT_I4); // a float annotation spPIAnns->Add(L"Test",L"FloatAnnotation",(float)1.23,false,VT_R4);
As usual we have to deal with VARIANTs:
// We need a variant to pass _variant_t vAnns; VariantInit (&vAnns); // the type is VT_DISPATCH V_VT (&vAnns) = VT_DISPATCH; // assign the annotations to the variant V_DISPATCH(&vAnns) = spPIAnns;
Now that there is a VARIANT that refers to my annotations. I am going to use UpdateValues to send my value to PI, and to pass the annotations I will need a named values collection, containing the VARIANT:
// named values :-) _NamedValuesPtr spNVValAttr; spNVValAttr.CreateInstance(__uuidof(NamedValues)); // add the annotations to the named values spNVValAttr->Add("Annotations", &vAnns);
almost there now. The remaining part is as simple as creating my PIValues collection, adding my PIValue to it, and sending it to PI. Remember, I am assuming my tag is a Float32 and has no bad value :
// PI Values _PIValuesPtr spPIValues; spPIValues.CreateInstance(__uuidof(PIValues)); // make the PI values writeable spPIValues->put_ReadOnly(false); // add a new value with current time, new float value and annotations spPIValues->Add("*",_pv->Value.fltVal + 1,spNVValAttr); // make the PI values readonly spPIValues->put_ReadOnly(true); // write the value to PI HRESULT hr = spPIPoint->Data->UpdateValues(spPIValues, dmInsertDuplicates, NULL);
cleaning up:
// we don't need the variant anymore V_VT (&vAnns) = VT_EMPTY; spNVValAttr.Release(); spPIAnns.Release(); _pv.Release();spPIPoint.Release(); spServer.Release(); spPISDK.Release(); // Closes the COM library ::CoUninitialize();
and leaving:
if (hr < 0) return hr; else return 0;
hope you had as much fun reading as I had writing !
Nice post, Andreas. I forgot how ugly C++ was, give me the prettier sister C# any day
Seriously, I remember a couple of years ago thrashing my way through some C++ to get PI SDK working (some posts on my RJK forum)...these posts certainly would have helped and I am sure will help those C++ developers in the community.