📄 opcdrvitem.cpp
字号:
// 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 + -