⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 opcdrvgroupdo.cpp

📁 基于Intellution开发包的开发的OPC服务器
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// 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 + -