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;
}