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

📄 opcdrvitem.cpp

📁 基于Intellution开发包的开发的OPC服务器
💻 CPP
📖 第 1 页 / 共 3 页
字号:

			// Get the number of characters to read. It is in the Signal Cond slot
			m_wNumElements = (WORD)atoi((char *)LPCTSTR(strStringLength));

			// Initialize the read data with an empty buffer.
			CString	szEmpty;
			szEmpty.Empty();
			m_vReturnedData.vt = VT_BSTR;
			m_vReturnedData.bstrVal = szEmpty.AllocSysString();
		}
		else	// either analog or digital
		{
			// Parse out the string
			//
			HRESULT	hr = ParseItemIDOptions(strTmpID,
											strSignalCond,
											strLowEGU,
											strHighEGU,
											strHardwareOptions);
			m_wNumElements = 1;
		}
	}
	else if (EGU_X == m_EguRec.type)
	{
		// The user only entered "DRIVER:IOADDRESS", but the requested datatype
		// is string, so default the number of characters to read.
		//
		m_wNumElements			= g_wStringLength;

		// Initialize the read data with an empty buffer.
		CString	szEmpty;
		szEmpty.Empty();
		m_vReturnedData.vt = VT_BSTR;
		m_vReturnedData.bstrVal = szEmpty.AllocSysString();
	}
	else
	{
		// The user did not type the fields for SIGNAL,LOEGU,HIEGU,HWOPT, so set
		// the defaults.
		//
		strSignalCond		= g_strDefaultSignalConditioning;
		strLowEGU			= g_strDefaultLoEGU;
		strHighEGU			= g_strDefaultHiEGU;
		strHardwareOptions	= g_strDefaultHardwareOptions;
		m_wNumElements		= 1;
	}

	//
	// Save the Lo and Hi EGUs in the EGUREC member
	//
	if (EGU_A == m_EguRec.type)
	{
		//
		// This is an analog point
		//

		// Save away the LO EGU
		m_EguRec.urec.arec.lo = (float)atof((char *)LPCTSTR(strLowEGU));

		// Save away the span (High EGU - Lo EGU)
		m_EguRec.urec.arec.span = 
				(float)atof((char *)LPCTSTR(strHighEGU)) - m_EguRec.urec.arec.lo;
		
		// Save away the digits right of the decimal point
		if ((nIndex = strLowEGU.FindOneOf(g_psDecimalPoint)) == -1)
		{
			m_EguRec.urec.arec.ef = 0;
		}
		else
		{
			m_EguRec.urec.arec.ef = strLowEGU.GetLength() - (nIndex - 1);
		}
	}
	else if (EGU_D == m_EguRec.type)
	{
		//
		// This is a digital point
		//

		// Save away the OPEN contact string
		strcpy(m_EguRec.urec.drec.open, strLowEGU);

		// Save away the CLOSED contact string
		strcpy(m_EguRec.urec.drec.open, strHighEGU);

		// Clear out the signal cond for digital
		strSignalCond.Empty();
	}
	else
	{
		//
		// This is an ASCII point
		//
		
		// Make sure the read string isn't too big for ASCII.
		//
		if (m_wNumElements > MAX_STRING_LENGTH)
		{
			return OPC_E_INVALIDITEMID;
		}

		// Clear out the signal cond and hardware options
		strSignalCond.Empty();
		strHardwareOptions.Empty();
	}

	// 
	// Validate SIGNAL_COND through NIO for analog types only
	//
	memset(&IoStat, 0, sizeof(IOSTAT));
	nio_psig(&IoStat, &m_IovSpec, &m_EguRec, (char *)LPCTSTR(strSignalCond));

	if(IoStat.iostatus != FE_OK)
	{
		strMsg.Format("OPC DLL: Invalid signal conditioning passed to nio_psig() (%s)", strSignalCond);
		m_pParentGroup->m_pParentServer->SendMessageToDriver(strMsg, MSG_DEBUG);

		// The item id is not syntactically valid, so return an error
		return OPC_E_INVALIDITEMID; 
	}

	// 
	// Validate HARDWARE_OPTS
	// This will override the requested datatype set above!
	//
	memset(&IoStat, 0, sizeof(IOSTAT));
	//mvs11272000 - Check for Hardware options if not string NOT empty
	if (!strHardwareOptions.IsEmpty())
	{
		nio_popt(&IoStat, &m_IovSpec, &m_EguRec, (char *)LPCTSTR(strHardwareOptions));
		if(IoStat.iostatus != FE_OK)
		{
			strMsg.Format("OPC DLL: Invalid hardware options passed to nio_popt() (%s)", strHardwareOptions);
			m_pParentGroup->m_pParentServer->SendMessageToDriver(strMsg, MSG_DEBUG);

			// The item id is not syntactically valid, so return an error
			return OPC_E_INVALIDITEMID;
		}
	}

	// Copy other Itemdef info to Item object
	// (Note Blob stuff is not supported/required)
	//
	m_hServerItemHandle	= OPCHandle;
	m_hClientItemHandle	= pItemDef->hClient;
	this->SetActive(pItemDef->bActive);

	// Set ITEM RESULT
	//
	pItemResult->hServer				= m_hServerItemHandle;
	pItemResult->vtCanonicalDataType	= m_vtCanonical;
	pItemResult->dwAccessRights			= OPC_WRITEABLE | OPC_READABLE;
	pItemResult->pBlob					= NULL;
	pItemResult->dwBlobSize				= 0;

	// Do this last!
	// Mark data as 'changed' for OnDataChange
	//
	MarkAsChanged(OPC_ODC_ANY);

	return S_OK;
}


////////////////////////////////////////////////////////////////
// SetActive()
//
// Sets the active state for the item. If the item is going
// active and this is a 7x driver, then it will call the Start()
// method through the 7x driver's OLE Automation interface.
//
// Returns:
//	void
//
////////////////////////////////////////////////////////////////
void COPCDrvItem::SetActive(BOOL bSet)
{
	// Lock it
	this->Lock();

	m_bActive = bSet;

	// If going to active then also queue an OnDataChange
	// else if going inactive then clear DataChange
	//
	if (FALSE == m_bActive) 
	{
		ClearChanged(OPC_ODC_ANY);
		this->UnLock();
		return;
	}

	MarkAsChanged(OPC_ODC_ANY);

	if (TRUE == g_bAutoStart)
	{
		short nRunning = 0;

		// We just put an Item active, so if the driver is not running,
		// start it.
		//
		m_pParentGroup->m_pParentServer->m_pIDriver->get_Running(&nRunning);
		if (0 == nRunning)
		{
			m_pParentGroup->m_pParentServer->m_pIDriver->Start();
		}
	}

	// UnLock it
	this->UnLock();
}


////////////////////////////////////////////////////////////////
// GetActive()
//
// Returns the active state of the item.
//
// NOTE: This is an inline function defined in OpcDrv.h!!!
//
////////////////////////////////////////////////////////////////
//BOOL COPCDrvItem::GetActive(void)
//{
//	return m_bActive;
//}


////////////////////////////////////////////////////////////////
// SetHandle()
//
// Sets the client handle for the item.
//
// Returns:
//	void
//
////////////////////////////////////////////////////////////////
void COPCDrvItem::SetHandle(OPCHANDLE OPCClientHandle)
{
	m_hClientItemHandle = OPCClientHandle;
}


////////////////////////////////////////////////////////////////
// GetHandle()
//
// Returns the client handle for the item.
//
// Returns:
//	OPCHANDLE	-	Client handle for this item.
//
////////////////////////////////////////////////////////////////
OPCHANDLE COPCDrvItem::GetHandle(void)
{
	return m_hClientItemHandle;
}


////////////////////////////////////////////////////////////////
// SetDataType()
//
// This method allows the client to change the requested data
// type. It will compare the new datatype with the canonical to
// make sure that it is a valid change. For example, if we are
// getting back floats from the server, then it wouldn't be valid
// to change it to a date.
//
// Returns:
//	HRESULT	-	S_OK if the function was successful.
//			-	E_FAIL if the function failed.
//
////////////////////////////////////////////////////////////////
HRESULT COPCDrvItem::SetDatatype(VARTYPE	vtNewRequested,
								 BOOL		bInit)			/* = FALSE */
{
	VARIANT			vTemp;
	COPCDrvServer	*pServer = m_pParentGroup->m_pParentServer;


	// If this call didn't come from the initialize routine, then
	// we can't change from a string to analog and vice versa during
	// runtime
	//
	if (!bInit)
	{
		if (((VT_BSTR == vtNewRequested) && (VT_BSTR != m_vtRequested)) ||
			((VT_BSTR != vtNewRequested) && (VT_BSTR == m_vtRequested)))
		{
			return E_FAIL;
		}
	}

	// First, let's make sure that the driver supports this
	// datatype
	//
	if (!pServer->IsDataTypeSupported(vtNewRequested))
	{
		return E_FAIL;
	}

	// Inititialize the Variant for use
	//
	VariantInit(&vTemp);

	// Build up a temp variant that we can send to VariantChangeType()
	// for validation.
	//
	if (FAILED(VariantCopy(&vTemp, &m_vReturnedData)))
	{
		return E_FAIL;
	}

	// Change the temp type to see if it is a valid change
	//
	if (FAILED(VariantChangeType(&vTemp, &vTemp, 0, vtNewRequested)))
	{
		return E_FAIL;
	}

	// Ok, the change worked, so save the new requested datatype and
	// figure out the new NIO block type and canonical datatype.
	//
	Lock();

	m_vtRequested = vtNewRequested;
	GetNIOBlockType(m_vtRequested);

	UnLock();

	return S_OK;
}


////////////////////////////////////////////////////////////////
// GetDataType()
//
////////////////////////////////////////////////////////////////
VARTYPE COPCDrvItem::GetDatatype(void)
{
	return m_vtRequested;
}


////////////////////////////////////////////////////////////////
// Clone()
// 
// Clone an item
// (this is similar to a copy constructor)
//
// Returns:
//	COPCDrvItem*	-	Pointer to the newly cloned item.
//
////////////////////////////////////////////////////////////////
COPCDrvItem *COPCDrvItem::Clone(COPCDrvGroup	*pParentGroup)
{
	COPCDrvItem *pNewItem = new COPCDrvItem(pParentGroup);
	if (NULL == pNewItem)
	{
		return NULL;
	}

	// Copy over all the data
	//
	*pNewItem = *this;

	// Set the new group inactive and give it a unique server handle. 
	// This is per the OPC spec!! Everything else gets copied.
	//
	pNewItem->m_bActive				= FALSE;
	pNewItem->m_hServerItemHandle	= (OPCHANDLE)pNewItem;

	return pNewItem;
}


////////////////////////////////////////////////////////////////
// IAGet()
// 
// Fill in an OPCITEMATTRIBUTE
// This is similar to IAClone() in itemutil.cpp
// Caller should delete contents of the IA 
// using IAFree()
//
// Returns:
//	void
//
////////////////////////////////////////////////////////////////
void COPCDrvItem::IAGet(OPCITEMATTRIBUTES *pItemAttrib)
{
	if (NULL == pItemAttrib)
	{
		return;
	}

	// Note Blob and EUInfo not supported at present

	//
	// the easy stuff...
	//
	pItemAttrib->bActive				= m_bActive;
	pItemAttrib->hServer				= m_hServerItemHandle;
	pItemAttrib->hClient				= m_hClientItemHandle;
	pItemAttrib->dwAccessRights			= OPC_READABLE | OPC_WRITEABLE;
	pItemAttrib->dwBlobSize				= 0;				// not supported
	pItemAttrib->pBlob					= NULL;
	pItemAttrib->vtRequestedDataType	= m_vtRequested;
	pItemAttrib->vtCanonicalDataType	= m_vtCanonical;
	pItemAttrib->dwEUType				= OPC_NOENUM;		// not supported
	pItemAttrib->vEUInfo.vt				= VT_EMPTY;

	// jra 012299
	// Verify that the pointers are good before cloning

	// strings...
	// Use local memory
	//
	if (m_szAccessPath)
	{
		pItemAttrib->szAccessPath = WSTRClone(m_szAccessPath, NULL);
		if (NULL == pItemAttrib->szAccessPath)
		{
			// Return some kind of error?
		}
	}

	if (m_szItemID)
	{
		pItemAttrib->szItemID = WSTRClone(m_szItemID, NULL);
		if (NULL == pItemAttrib->szItemID)
		{
			// Return some kind of error?
		}
	}
}


////////////////////////////////////////////////////////////////
// GetValue()
//
// Get Item Value from cache.
//
// Returns:
//	HRESULT	-	S_OK if the function was successful.
//			-	E_FAIL if the function failed.
//			-	E_POINTER if the function was passed a bad 
//				pointer value.
// 
////////////////////////////////////////////////////////////////
HRESULT COPCDrvItem::GetValue(OPCDATASOURCE		dwSource, 
							  VARIANT			*pvData, 
							  WORD				*pwQuality, 
							  FILETIME			*pftTime)
{
	// Sanity checks...
	//
	if (NULL == pvData)
	{
		return E_POINTER;
	}

	// If this is a device read, then get the data.
	//
	if (OPC_DS_DEVICE == dwSource)
	{
		ReadValue();
	}

	Lock();

	// First handle Quality...
	//
	if (pwQuality) 
	{
		switch(dwSource)
		{
		case OPC_DS_CACHE:
			// The OPC spec states that if either the item or device are
			// not active for CACHE reads, then the quality should reflect
			// that state.
			//
			if(m_bActive) 
			{
				*pwQuality = m_wQuality;
			}
			else 
			{
				((QUALITY_STATE *)pwQuality)->nQuality = QUALITY_BAD;
				((QUALITY_STATE *)pwQuality)->nSubStatus = SS_OUT_OF_SERVICE;
			}
			break;

		case OPC_DS_DEVICE:
			*pwQuality = m_wQuality;
			break;
		}
	}

	// Then the Timestamp...
	//
	if (pftTime) 
	{
		*pftTime = m_ftLastReadTime;
	}

	// Then the Data...
	//
	VariantCopy(pvData, &m_vReturnedData);

	UnLock();
	return S_OK;
}


////////////////////////////////////////////////////////////////
// SetValue()
//
// Writes a value to the driver for an item. Used for synch 
// writes.
//
// Returns:
//	HRESULT	-	S_OK if the function was successful.
//			-	E_FAIL if the function failed.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -