📄 opcdrvgroupdo.cpp
字号:
// OPCDrvGroupDO.cpp
//
// This file contains the implementation of
// the COPCDrvGroup Object's IDataObject Async Logic
// for the OPC server.
//
//
// (c) COPYRIGHT 1996-1998, INTELLUTION INC.
// ALL RIGHTS RESERVED
//
// Functions defined in this module:
//
// COPCDrvGroup::CheckDataObjectOnDataTimeChange()
// COPCDrvGroup::CheckDataObjectOnDataChange()
// COPCDrvGroup::CheckDataObjectAsyncRead()
// COPCDrvGroup::CheckDataObjectAsyncWrite()
// COPCDrvGroup::CheckDataObjectRefresh()
// COPCDrvGroup::SendStreamWithTime()
// COPCDrvGroup::SendStream()
// COPCDrvGroup::SendWriteStream()
// COPCDrvGroup::ComputeSize()
//
//
//
// Note - this logic supports independent subscriptions for
// data with and without timestamp (although it is not likely
// that this would ever be used)
//
// Note - this logic CANNOT be used at the same time as ConnectionPoints.
// The client must use one or the other but not both.
//
// Modification Log:
// Vers Date By Notes
// ---- -------- --- -----
// 1.0 08/26/97 jra Created
// 1.3 03/10/98 jra Modified to be wizard generated and driver specific.
// 7.11 10/02/98 jra Modified CheckDataObjectAsyncRead() to check the read type of
// the transaction, not the trans type for device reads.
//
//
#define WIN32_LEAN_AND_MEAN
#define NOCOMM
#include "OPCDrv.h"
#include "OPCVariantPack.h"
////////////////////////////////////////////////////////////////
// COPCDrvGroup::CheckDataObjectOnDataTimeChange()
//
// @desc Handle IDataObject Callbacks for OnDataChange (WITH TimeStamp)
//
// @parm none
//
// @retval void
//
// @devnote We don't lock the group object here because it is
// already locked in the parent server's
// UpdateDataCache() call.
//
////////////////////////////////////////////////////////////////
void COPCDrvGroup::CheckDataObjectOnDataTimeChange(void)
{
// If group is active
//
if(FALSE == m_bActive)
{
return;
}
// And if there is a Data object
//
if(NULL == m_pCImpIDataObject)
{
return;
}
// And if the DataObject has a callback
//
if(m_pCImpIDataObject->m_datatimeCallback)
{
int i,
nCount = 0,
nDataSize,
nNumItems = this->GetNumItemHandles();
POSITION ItemPosition = this->GetFirstItemPosition();
COPCDrvItem *pItem = NULL;
OPCHANDLE OPCHandle;
// Build a list of the things that changed
//
OPCHANDLE *ItemHandleList = new OPCHANDLE[nNumItems];
for(i = 0; i < nNumItems; i++)
{
this->GetNextItem(ItemPosition, OPCHandle, pItem);
if(pItem->Changed(OPC_ODC_DOT)) // with time
{
ItemHandleList[nCount] = OPCHandle;
nCount++;
}
}
// And if anything changed
//
if(nCount)
{
// compute the size needed to send them
//
nDataSize = ComputeSize(nCount, ItemHandleList);
// Given the item list, build and send the callback
//
SendStreamWithTime(nCount,
ItemHandleList,
nDataSize,
OPC_ODC_DOT,
0);
}
// Free the itemhandlelist
//
delete [] ItemHandleList;
}
}
////////////////////////////////////////////////////////////////
// COPCDrvGroup::CheckDataObjectOnDataChange()
//
// @desc Handle IDataObject Callbacks for OnDataChange (WITHOUT TimeStamp)
//
// @parm none
//
// @retval void
//
// @devnote We don't lock the group object here because it is
// already locked in the parent server's
// UpdateDataCache() call.
//
////////////////////////////////////////////////////////////////
void COPCDrvGroup::CheckDataObjectOnDataChange(void)
{
// If group is active
//
if(FALSE == m_bActive)
{
return;
}
// And if there is a Data object
//
if(NULL == m_pCImpIDataObject)
{
return;
}
// And if the DataObject point has a callback
//
if(m_pCImpIDataObject->m_dataCallback)
{
int i,
nCount = 0,
nDataSize,
nNumItems = this->GetNumItemHandles();
POSITION ItemPosition = this->GetFirstItemPosition();
COPCDrvItem *pItem;
OPCHANDLE OPCHandle;
// Build a list of the things that changed
//
OPCHANDLE *ItemHandleList = new OPCHANDLE[nNumItems];
for(i = 0; i < nNumItems; i++)
{
this->GetNextItem(ItemPosition, OPCHandle, pItem);
if(pItem->Changed(OPC_ODC_DO))
{
ItemHandleList[nCount] = OPCHandle;
nCount++;
}
}
// And if anything changed
//
if(nCount)
{
// compute the size needed to send them
//
nDataSize = ComputeSize(nCount, ItemHandleList);
// Given the item list, build and send the callback
// without time
//
SendStream(nCount,
ItemHandleList,
nDataSize,
OPC_ODC_DO,
0);
}
// Free the itemhandlelist
//
delete [] ItemHandleList;
}
}
////////////////////////////////////////////////////////////////
// COPCDrvGroup::CheckDataObjectAsyncRead()
//
// @desc Checks to see if there is a pending Async->Read()
//
// @parm none
//
// @retval void
//
////////////////////////////////////////////////////////////////
void COPCDrvGroup::CheckDataObjectAsyncRead(void)
{
POSITION posTrans = NULL;
int nNumReads = 0,
nDataSize = 0;
COPCDrvAsyncTrans *pTrans = NULL;
OPCHANDLE *pReadList = NULL;
DWORD dwNumHandles = 0;
// If reads are pending
//
if((nNumReads = m_AsyncReadQueue.GetCount()) > 0)
{
posTrans = m_AsyncReadQueue.GetHeadPosition();
while (posTrans != NULL)
{
// Get the info for the next transaction in the read queue
//
pTrans = (COPCDrvAsyncTrans *)m_AsyncReadQueue.GetNext(posTrans);
pTrans->GetListInfo(&dwNumHandles, &pReadList);
// Do the read for each handle (if from device)
//
if(OPC_DS_DEVICE == pTrans->m_dwReadType) // jra 100298 - Changed from m_dwTransType to m_dwReadType
{
for (DWORD i = 0; i < dwNumHandles; i++)
{
GetItemPtr(pReadList[i])->ReadValue();
}
}
if(m_pCImpIDataObject)
{
// Compute data size for stream
//
nDataSize = ComputeSize(dwNumHandles, pReadList);
// And if the DataObject has a callback
//
if(m_pCImpIDataObject->m_dataCallback)
{
SendStream(dwNumHandles,
pReadList,
nDataSize,
0,
pTrans->GetTransactionID(),
pTrans->m_dwReadType);
}
if(m_pCImpIDataObject->m_datatimeCallback)
{
SendStreamWithTime(dwNumHandles,
pReadList,
nDataSize,
0,
pTrans->GetTransactionID(),
pTrans->m_dwReadType);
}
}
// In any case the read is complete, so remove it from the queue
//
pTrans->RemoveFromQueue(TRUE);
} // while(...)
} // (else read not active)
}
////////////////////////////////////////////////////////////////
// COPCDrvGroup::CheckDataObjectAsyncWrite()
//
// @desc Checks to see if there is a pending Async->WriteComplete()
//
// @parm none
//
// @retval void
//
////////////////////////////////////////////////////////////////
void COPCDrvGroup::CheckDataObjectAsyncWrite(void)
{
POSITION posTrans = NULL;
int nNumWrites = NULL;
COPCDrvAsyncTrans *pTrans = NULL;
OPCHANDLE *pWriteList = NULL;
DWORD dwNumHandles = 0;
VARIANT *pWriteData = NULL;
// If writes are pending
//
if((nNumWrites = m_AsyncWriteQueue.GetCount()) > 0)
{
posTrans = m_AsyncWriteQueue.GetHeadPosition();
while (posTrans != NULL)
{
// Get the info for the next transaction in the write queue
//
pTrans = (COPCDrvAsyncTrans *)m_AsyncWriteQueue.GetNext(posTrans);
pTrans->GetListInfo(&dwNumHandles, &pWriteList, &pWriteData);
// Do the write for each handle
//
for (DWORD i = 0; i < dwNumHandles; i++)
{
GetItemPtr(pWriteList[i])->WriteValue(&pWriteData[i]);
}
if(m_pCImpIDataObject)
{
// If the DataObject has a callback
//
if(m_pCImpIDataObject->m_writeCallback)
{
SendWriteStream(dwNumHandles,
pWriteList,
pTrans->GetTransactionID());
}
}
// In any case the write is complete, so remove it from the queue
//
pTrans->RemoveFromQueue(TRUE);
} // while(...)
} // (else Write not active)
}
////////////////////////////////////////////////////////////////
// COPCDrvGroup::SendStreamWithTime()
//
// @desc This function is used to build the stream for OnDataChange
// and also for async operations such as Read and Refresh.
// The two cases are 'almost' the same except for
// a small bit of 'mask' and quality logic as you can see below
//
// Create the Stream which consists of:
// GroupHeader
// ItemHeaders
// Variants and Related Data.
//
// @parm IN int | nCount | Count of items to send
// @parm IN OPCHANDLE * | ItemHandleList| Item handle list
// @parm IN DWORD | dwDataSize | Data size
// @parm IN WORD | wMask | Mask to clear
// @parm IN DWORD | tid | Transaction ID
// @parm IN OPTIONAL OPCDATASOURCE | dwSource | Data source (cache or device)
//
// @retval void
//
// @devnote We use exception handling around the call to OnDataChange()
// since this is an open architecture and we have no control
// over the client's implementation. We want to make sure we
// don't crash.
//
////////////////////////////////////////////////////////////////
void COPCDrvGroup::SendStreamWithTime(IN int nCount,
IN OPCHANDLE *ItemHandleList,
IN DWORD dwDataSize,
IN WORD wMask,
IN DWORD tid,
IN OPCDATASOURCE dwSource) /* = OPC_DS_DEVICE */
{
int j,
nHdrSize,
nTotalSize;
OPCHANDLE OPCHandle;
HRESULT hr;
// Allocate the Data Stream
//
nHdrSize = sizeof(OPCGROUPHEADER) + nCount * sizeof(OPCITEMHEADER1); // with time
nTotalSize = nHdrSize + dwDataSize;
char *gp;
HGLOBAL gh;
gh = GlobalAlloc( GMEM_FIXED, nTotalSize );
if(NULL == gh)
{
// If no memory, For now we just give up and return;
// But a better error handler would be nice
//
return;
}
gp = (char*)GlobalLock(gh);
OPCGROUPHEADER *pGrpPtr;
OPCITEMHEADER1 *pItemHdr1; // With Time
char *pcDataPtr;
pGrpPtr = (OPCGROUPHEADER *) gp;
pItemHdr1 = (OPCITEMHEADER1 *) (gp + sizeof(OPCGROUPHEADER)); // with Time
pcDataPtr = gp + nHdrSize;
// Fill in the Group header
//
pGrpPtr->dwSize = nTotalSize;
pGrpPtr->dwItemCount = nCount;
pGrpPtr->hClientGroup = m_ClientGroupHandle;
pGrpPtr->hrStatus = S_OK;
pGrpPtr->dwTransactionID = tid;
// Now fill in the Item Information
//
COPCDrvItem *pItem = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -