Unsolicited Tags Callbacks

For unsolicited tags we use different callback functions at various stages.

Step 1
At collector start up, ihCollectorToolkitASyncInit and ihCollectorToolkitASyncInitCompleted callbacks are triggered and the details of all the unsolicited tags for the given collector is returned.
Step 2
If an unsolicited tag is added, ihCollectorToolkitASyncAddTag method is called and the details of the tag is entered in the collector tag list.
Step 3
If an unsolicited tag is deleted, ihCollectorToolkitASyncDeleteTag method is called and the tag details are removed from the collector tag list.

Example

The following sample helps you understand the given callback functions. The below sample code creates a thread for simulating the Unsolicited tag's collector behavior.

//This structure is the list of Unsolicited Tags. 
struct AsyncTagList : public CList<ihInterfaceTKASyncTagInfo*, ihInterfaceTKASyncTagInfo*>
{
virtual ~AsyncTagList()
{
FreeAll();
} 
void AddTag(ihInterfaceTKASyncTagInfo* tag)
{
ihInterfaceTKASyncTagInfo* info = new ihInterfaceTKASyncTagInfo;//need to allocate in delegator
memcpy(info, tag, sizeof(ihInterfaceTKASyncTagInfo));
AddTail(info);
}
void FreeAll()
{
while (!IsEmpty())
delete RemoveHead();
}
}; 
AsyncTagList g_AsyncTags; 
 
----------------------------------------------------------------------------
 
/// <summary>
/// Initializes unsolicited tags, by creating dedicated thread
/// <summary>
/// <returns></returns>
int    RandomValueSimulator::ihCollectorToolkitASyncInit(void)
{
       CSingleLock lock(&g_Sync, TRUE);
       g_AsyncTags.FreeAll();
       if (!g_AsyncThread)
              g_AsyncThread = AfxBeginThread(TKAsyncReadFunc, this);
       return TRUE;
}
 
----------------------------------------------------------------------------
 
/// <summary>
/// unsolicited tags initialization completed
/// <summary>
/// <returns>TRUE/FALSE</returns>
int    RandomValueSimulator::ihCollectorToolkitASyncInitCompleted(void)
{
       return TRUE;
}
 
------------------------------------------------------------------------------
 
/// <summary>
/// Custom Collector Initialization completed and is ready to read data from Source for unsolicited tag 
/// <summary>
/// <returns>TRUE/FALSE</returns>
int    RandomValueSimulator::ihCollectorToolkitASyncStartReading(void)
{
       InterlockedExchange(&g_DoAsyncRead, TRUE);
       return TRUE;
}
 
------------------------------------------------------------------------------
 
/// <summary>
/// Adds unsolicited tag to the historian
/// <summary>
/// <param name="ASyncTag">ihInterfaceTKAsyncTagInfo pointer</param>
/// <param name="IsCollectorStarting">Current Status of the Collector</param>
/// <returns>TRUE/FALSE</returns>
int    RandomValueSimulator::ihCollectorToolkitASyncAddTag(ihInterfaceTKASyncTagInfo *ASyncTag, int IsCollectorStarting)
{
       CSingleLock lock(&g_Sync, TRUE);
       g_AsyncTags.AddTag(ASyncTag);
       return TRUE;
}
 
-------------------------------------------------------------------------------
 
/// <summary>
/// From Clients tools/non-web admin/custom tools, if user deletes a tag, historian updates custom collector saying that tag got deleted.
/// So that, custom collector stops collecting data from source for that tag
/// <summary>
/// <param name="tagId">Tag Identifier</param>
/// <returns>TRUE/FALSE</returns>
int    RandomValueSimulator::ihCollectorToolkitASyncDeleteTag(int tagId)
{
       CSingleLock lock(&g_Sync, TRUE);
       POSITION pos = g_AsyncTags.GetHeadPosition();
       while (pos)
       {
              ihInterfaceTKASyncTagInfo * tagInfo = g_AsyncTags.GetAt(pos);
              if (tagInfo->TagId == tagId)
              {
                     g_AsyncTags.RemoveAt(pos);
                     return TRUE;
              }        
              g_AsyncTags.GetNext(pos);
       }
       return TRUE;
}
 
--------------------------------------------------------------------------------
 
/// <summary>
/// This method called by historian, if it needs to perform any calculations on source data. This method is only usefull in "calculation collector" way of collection for unsolicited tags
/// <summary>
/// <param name="StartTime"> start time for reload</param>
/// <param name="EndTime"> end time for reload</param>
/// <returns>TRUE/FALSE</returns>
int RandomValueSimulator::ihCollectorToolkitASyncReload(ihTKTimeStruct *StartTime, ihTKTimeStruct *EndTime)
{
       return CCollectorDelegator::ihCollectorToolkitASyncReload(StartTime, EndTime);
}
 
-------------------------------------------------------------------------------
 
/// <summary>
/// Unsolicited dedicated thread corresponding method. Here all unsolicited tags get data from source(usually, way should be source notification to historian) and sends to historian
/// <summary>
/// <param name="param"> Collector instance </param>
UINT RandomValueSimulator::TKAsyncReadFunc(void* param)
{
       POSITION pos = NULL;
       RandomValueSimulator* pColl = (RandomValueSimulator*) param;
       while (TRUE)
       {
              if (g_DoAsyncRead)
              {
                     CSingleLock lock(&g_Sync, TRUE);
                     if (!g_AsyncTags.IsEmpty())
                     {
                           // gets each unsolicited tag into ihInterfaceTKAsyncTagInfo object
                           if (!pos) 
                                  pos = g_AsyncTags.GetHeadPosition();
                           ihInterfaceTKASyncTagInfo* tag = g_AsyncTags.GetNext(pos);
                           int numTags = 1;
                           ihInterfaceTKDataInfo data;
                           memset(&data, 0, sizeof(ihInterfaceTKDataInfo));
                           data.Tag = pColl->TKStrdup(tag->Tag);
                           data.DataProp.ValueDataType = tag->DataType;                         
                           data.DataProp.TimeStamp = pColl->TKGetSystemTime();
                           // gets data for selected tag
                           pColl->ihCollectorToolkitGetData(0, 0, 0, numTags, NULL, &data);
                           unsigned long collectionTime = (unsigned long)time(0);
                           int tagId = tag->TagId;
                            ihInterfaceTKASyncData asyncData;
                           memset(&asyncData, 0, sizeof(ihInterfaceTKASyncData));
                           asyncData.NumValues = numTags;
                           asyncData.TagIds = &tagId;
                           asyncData.Values = &data.DataProp;
                           asyncData.CollectionTimes = &collectionTime;
                           // sends to historian
                           pColl->ihCollectorToolkitDataCallback(&asyncData);
                     }
                     else
                     {
                           pos = NULL;
                     }
              }
              else
              {
                     pos = NULL;
              }
              long sleepTimeInMs = 500 + (rand() % 46) * 100; // sleep from 0.5 to 5 seconds
              Sleep(sleepTimeInMs);
       }
       return 0;
}