The Item definition (ItemID) used in the OPCITEMDEF and elsewhere is a nul-terminated string that uniquely identifies an OPC data item. The syntax of the identifier is server dependent (although it should include only printable UNICODE characters) and it provides a reference or key to an item in the data source. The item is anything that can be represented by a VARIANT although it is typically a single value such as an analog, digital or string value.
For example, an item such as FIC101 might represent an entire record such as a Fieldbus, Hart Foundation or ProfiBus data structure. Such behavior is specifically allowed but not required by OPC - the return of such structures is considered to be vendor specific behavior. Alternately FIC101.PV might represent one attribute of a record such as the process value. This would probably take the form of a double which could be used by any client.
As an extreme example, since the syntax of the item ID is server specific, additional information such as Counts, Engineering Units Scaling and Signal conditioning information could be embedded in the definition string (although this is not recommended).
Examples:
A server which supports access to an existing DCS might support a simple syntax such as
"TIC101.PV"
A server that supports low level access to a PLC might support a syntax such as
"COM1.STATION:42.REG:40001;0,4095,-100.0,+1234.0"
The ITEM ID provides all of the information needed to locate and process a data item. The Access Path is an optional piece of information that can be provided by the client. Its use is highly server specific but it is intended to allow the client to provide a recommendation to the server regarding how to get to the data. As an analogy, if the ItemID represented a phone number, the access path might represent a request to route the call via satellite (or transatlantic cable or microwave link). The call will go through regardless of whether you specify an access path and also whether or not the server is able to use that suggested path.
For example, suppose you wanted to access a value in an RTU and had a high speed modem on COM1 and a low speed modem on COM2. You might specify COM1 as the preferred access path. Either one will work, but you would prefer to use COM1 if it is available for better performance.
In any case, the use of access path by both the server and the client is optional. Servers need not provide the function and clients need not use it even if it is provided.
Servers which do not support access paths will completely
ignore any passed access path (and will not treat this as an error by the
client). Also, when queried, such servers will always return a null access
path for all items (i.e. a NUL string).
The Blob is basically a scratch area for the server to associate with items in order to speed up access to or processing of those items. The exact way in which it is used is server specific.
The idea is that clients refer to items via ASCII strings while internally, to speed up access, the server will probably need to resolve this string into some internal server specific address; a network address, a pointer into a table, a set of indices or files or register numbers, etc. This address resolution could take considerable time and the resulting internal address could take an arbitrary amount of space. This Blob allows the server to return this internal address and allows the client to save it and to provide the Blob back to the server for future references to this item. The server could use the Blob as a hint to help find the item more quickly the next time; "The Blob says that last time I looked for this tag I found it here - so lets see if its still in that location". However, in all cases, the ITEM ID is still the key to the data. Regardless of the contents of the Blob, the server needs to insure that it is in fact referencing the item referred to by the ITEM ID.
The behavior of the Blob is as follows.
Its use by both client and server is optional. Servers which can perform AddItems quickly based just on the item definition should generally not return a Blob. In cases where servers do return a Blob, clients are free to ignore these Blobs (although this will probably affect the performance of that server).
The Blob is passed to AddItems and ValidateItems and is also returned by the server any time an AddItems or ValidateItems or EnumItemAttributes is done. The returned Blob may differ in size and content from the one passed.
Note that the server can update the Blob for an item at any time entirely at the servers discretion (including, for example, whenever the client changes an attribute of an Item).
Proper behavior of a client that wishes to support the Blob is to Enumerate the item attributes to get a fresh copy of the Blobs for each item prior to deleting an item or group and to save that updated copy along with the other application data related to the items.
Comment:
The difference between the server handle and the Blob is that the server handle is fixed in size (DWORD), should not be stored between sessions by the client and that its implementation is required since it is the only way to identify items after they have been added. The Blob is variable in length, is optional and may be stored by the client between sessions.
The exact internal implementation of the server handles is entirely vendor specific. The client should never make any assumptions about the server handles and the server should never make any assumptions about the client handles.
The server group handle is unique across the server and must be returned when the group is created. The handle is then passed by the client to various methods. The server group handle can be assumed to remain valid until the client Removes the group and frees all of the interfaces.
It should not be persistently stored by the client as it may be different the next time the OPC group is created.
The client group handle is provided by the client to the server. It can be any value and does not need to be unique. It is included in the data stream sent to IAdviseSink in order to help the client identify the source of the data.
In practice it is expected that a client will assign a
unique value to its handle if it intends to use any of the asynchronous
functions of the OPC interfaces( including IOPCAsyncIO and IDataObject/IAdviseSink
interfaces), since this is the only key to the information that the server
gives back to the client via the IAdviseSink interface.
The server item handle is unique within the group and will be returned when the item is created. It is then passed by the client to various methods. The server item handle can be assumed to remain valid until the client Removes the items or Removes the Group containing the items.
It should not be persistently stored by the client as it may be different the next time the OPC Item is created.
The client item handle is provided by the client to the server. It can be any value and does not need to be unique. It is included in the data stream sent to IAdviseSink in order to help the client quickly identify which object in the client application is affected by the changed data.
In practice however it is expected that a client will
assign unique values its handles if it intends to use any of the asynchronous
functions of the OPC interfaces (including IOPCAsyncIO and IDataObject/IAdviseSink
interfaces), since this is the only key to the information that the server
gives back to the client via the IAdviseSink interface.
OPCHANDLE hClient;
FILETIME ftTimeStamp;
WORD wQuality;
WORD wReserved;
VARIANT vDataValue;
} OPCITEMSTATE;
Member | Description |
hClient | the client provided handle for this item |
ftTimeStamp | UTC TimeStamp for this item's value. If the device cannot provide a timestamp then the server should provide one. |
wQuality | The quality of this item. |
vDataValue | The value itself as a variant. |
Comments
Real values in the variant (VT_R4, VT_R8) will contain
IEEE floating point numbers. Note that the IEEE standard allows certain
non numeric values (called NANs) to be stored in this format. While use
of such values is rare, they are specifically allowed. If such a value
is returned it is required that the QUALITY flag be set to OPC_QUALITY_BAD.
typedef struct {
[string] LPWSTR szAccessPath;
[string] LPWSTR szItemID;
BOOL bActive ;
OPCHANDLE hClient;
DWORD dwBlobSize;
[size_is(dwBlobSize)] BYTE * pBlob;
VARTYPE vtRequestedDataType;
WORD wReserved;
} OPCITEMDEF;
This structure is used by IOPCItemMgt::AddItems and ValidateItems. The used by column below indicates which of these two functions use each member.
Member | Used by | Description |
szAccessPath | both | The access path the server should
associate with this item. By convention a pointer to a NUL string specifies
that the server should select the access path. Support for accesspath is
optional
NOTE: version 1 indicated that a NULL pointer would allow the server to pick the path however passing a NULL pointer will cause a fault in the proxy/stub code and thus is not allowed. |
szItemID | both | A null-terminated string that uniquely identifies the OPC data item. See the Item ID discussion and the AddItems function for specific information about the contents of this field. |
bActive | add | This Boolean value affects the behavior various methods as described elsewhere in this specification. |
hClient | add | The handle the client wishes to associate with the item. See the OPCHANDLE for more specific information about the contents of this field. |
dwBlobSize | both | The size of the pBlob for this item. |
pBlob | both | pBlob is a pointer to the Blob. |
vtRequestedDataType | both | The data type requested by the client. An error is returned (See Additems or ValidateItems) if the server cannot provide the item in this format. Passing VT_EMPTY means the client will accept the servers canonical datatype. |
Comments
typedef struct {
OPCHANDLE hServer;
VARTYPE vtCanonicalDataType;
WORD wReserved;
DWORD dwAccessRights;
DWORD dwBlobSize;
[size_is(dwBlobSize)] BYTE * pBlob;
} OPCITEMRESULT;
Member | Used by | Description |
hServer | add | The server handle used to refer to this item. |
vtCanonicalDataType | both | The native data type. The type of data maintained within the server for this item. |
dwAccessRights | both | Indicates if this item is read only, write only or read/write. This is NOT related to security but rather to the nature of the underlying hardware. See the Access Rights section below. |
dwBlobSize | both | The size of the Blob for this item. Note that this size may be 0 for servers that do not support or require this feature. |
pBlob | both | Pointer to the Blob. |
Comments
The client software must free the memory for the Blob before freeing the OPCITEMRESULT structure.
typedef struct {
[string] LPWSTR szAccessPath;
[string] LPWSTR szItemID;
BOOL bActive;
OPCHANDLE hClient;
OPCHANDLE hServer;
DWORD dwAccessRights;
DWORD dwBlobSize;
[size_is(dwBlobSize)] BYTE * pBlob;
VARTYPE vtRequestedDataType;
VARTYPE vtCanonicalDataType;
OPCEUTYPE dwEUType;
VARIANT vEUInfo;
} OPCITEMATTRIBUTES;
Member | Description |
szAccessPath | The access path specified by the client. A pointer to a NUL string is returned if the server does not support access paths. |
szItemID | The unique identifier for this item. |
bActive | FALSE if the item is not currently active, TRUE if the item is currently active |
hClient | The handle the client has associated with this item. |
hServer | The handle the server uses to reference this item. |
dwAccessRights | Indicates if this item is read only, write only or read/write. This is NOT related to security but rather to the nature of the underlying hardware. See the Access Rights section below. |
dwBlobSize | The size of the pBlob for this item. Note that this size may be 0 for servers that do not support or require this feature. |
pBlob | Pointer to the Blob. |
vtRequestedDataType | The data type in which the item's value will be returned. Note that if the requested data type was rejected then this field will return the canonical data type. |
vtCanonicalDataType | The data type in which the item's value is maintained within the server. |
dwEUType | Indicate the type of Engineering
Units (EU) information (if any) contained in vEUInfo.
0 - No EU information available (vEUInfo will be VT_EMPTY) 1 - Analog - vEUInfo will contain a SAFEARRAY of exactly two doubles (VT_ARRAY | VT_R8) corresponding to the LOW and HI EU range. 2 - Enumerated - vEUInfo will contain a SAFEARRAY of strings (VT_ARRAY | VT_BSTR) which contains a list of strings (Example: "OPEN", "CLOSE", "IN TRANSIT", etc.) corresponding to sequential numeric values (0, 1, 2, etc.) |
vEUInfo | The VARIANT containing the EU information. See Comments below. |
Comment:
EU information is provided by the server to the client and is essentially Read Only. OPC Does not provide the client with any control over the EU settings.
For analog EU the information returned represents the usual range of the item value. Sensor or instrument failure or deactivation can result in a returned item value which is actually outside this range. Client software must be prepared to deal with this. Similarly a client may attempt to write a value which is outside this range back to the server. The exact behavior (accept, reject, clamp, etc.) in this case is server dependent however in general servers must be prepared to handle this.
For enumerated EU the information returned represents string lookup table corresponding to sequential integer values starting with 0. The number of values represented is determined by the size of the SAFEARRAY. Again, robust clients should be prepared to handle item values outside the range of the list and robust servers should be prepared to handle writes of illegal values.
Servers may optionally support Localization of the enumeration. In this case the server should use the current locale ID of the group. See IOPCServer::AddGroup and IOPCGroupStateMgt::GetState and SetState.
The client is responsible for freeing the VARIANTs in the OPCITEMATTRIBUTES structure including all elements of any SAFEARRAYs.
Client writers may wish to create and use a common function such
as FreeOPCITEMATTRIBUTES(ptr) in order to minimize the chance of memory
leaks.
typedef struct {
FILETIME ftStartTime;
FILETIME ftCurrentTime;
FILETIME ftLastUpdateTime;
OPCSERVERSTATE dwServerState;
DWORD dwGroupCount;
DWORD dwBandWidth;
WORD wMajorVersion;
WORD wMinorVersion;
WORD wBuildNumber;
WORD wReserved;
[string] LPWSTR szVendorInfo;
} OPCSERVERSTATUS;
This structure used to communicate the status of the server
to the client. This information is provided by the server in the IOPCServer::GetStatus()
call.
Member | Description |
ftStartTime | Time (UTC) the server was started. This is constant for the server instance and is not reset when the server changes states. Each instance of a server should keep the time when the process started. |
ftCurrentTime | The current time (UTC) as known by the server. |
ftLastUpdateTime | The time (UTC) the server sent the last data value update to this client. This value is maintained on an instance basis. |
dwServerState | The current status of the server. Refer to OPC Server State values below. |
dwGroupCount | The total number of groups (all public and private) being managed by the server. This is mainly for diagnostic purposes. |
dwBandWidth | The behavior of this field is server specific. A suggested use is that it return the approximate Percent of Bandwidth currently in use by server. If multiple links are in use it could return the worst case link. Note that any value over 100% indicates that the aggregate combination of items and UpdateRate is too high. The server may also return 0xFFFFFFFF if this value is unknown. |
wMajorVersion | The major version of the server software |
wMinorVersion | The minor version of the server software |
wBuildNumber | The build number of the server software |
szVendorInfo | Vendor specific string providing additional information about the server. It is recommended that this mention the name of the company and the type of device(s) supported. |
OPCSERVERSTATE Values | Description |
OPC_STATUS_RUNNING | The server is running normally. This is the usual state for a server |
OPC_STATUS_FAILED | A vendor specific fatal error has occurred within the server. The server is no longer functioning. The recovery procedure from this situation is vendor specific. An error code of E_FAIL should generally be returned from any other server method. |
OPC_STATUS_NOCONFIG | The server is running but has no configuration information loaded and thus cannot function normally. Note this state implies that the server needs configuration information in order to function. Servers which do not require configuration information should not return this state. |
OPC_STATUS_SUSPENDED | The server has been temporarily suspended via some vendor specific method and is not getting or sending data. Note that Quality will be returned as OPC_QUALITY_OUT_OF_SERVICE. |
OPC_STATUS_TEST | The server is in Test Mode. The outputs are disconnected from the real hardware but the server will otherwise behave normally. Inputs may be real or may be simulated depending on the vendor implementation. Quality will generally be returned normally. |
AccessRights Values | Description |
OPC_READABLE | The client can read the data item's value. |
OPC_WRITEABLE | The client can change the data item's value. |
The low 8 bits of the Quality flags are currently defined in the form of three bit fields; Quality, Substatus and Limit status. The 8 Quality bits are arranged as follows:
QQSSSSLL
The high 8 bits of the Quality Word are available for vendor specific use. If these bits are used, the standard OPC Quality bits must still be set as accurately as possible to indicate what assumptions the client can make about the returned data. In addition it is the responsibility of any client interpreting vendor specific quality information to insure that the server providing it uses the same rules as the client. The details of such a negotiation are not specified in this standard although a QueryInterface call to the server for a vendor specific interface such as IMyQualityDefinitions is a possible approach.
Details of the OPC standard quality bits follow:
BIT VALUE | DEFINE | DESCRIPTION | |
0 | 00SSSSLL | Bad | Value is not useful for reasons indicated by the Substatus. |
1 | 01SSSSLL | Uncertain | The quality of the value is uncertain for reasons indicated by the Substatus. |
2 | 10SSSSLL | N/A | Not used by OPC |
3 | 11SSSSLL | Good | The Quality of the value is Good. |
Comment:
It is recommended that clients minimally check the Quality Bit field of all results (even if they do not check the substatus or limit fields).
Even when a BAD value is indicated, the contents of the value field must still be a well defined VARIANT even though it does not contain an accurate value. This is to simplify error handling in client applications. For example, clients are always expected to call VariantClear() on the results of a Sychronous Read. Similarly the IAdviseSink needs to be able to interpret and unpack the Value and Data included in the Stream even if that data is BAD.
If the server has no known value to return then some reasonable
default should be returned such as a NUL string or a 0 numeric value.
The Substatus BitField
The layout of this field depends on the value of the Quality Field.
Substatus for BAD Quality:
SSSS | BIT VALUE | DEFINE | DESCRIPTION |
0 | 000000LL | Non-specific | The value is bad but no specific reason is known |
1 | 000001LL | Configuration Error | There is some server specific problem with the configuration. For example the item is question has been deleted from the configuration. |
2 | 000010LL | Not Connected | The input is required to be logically connected to something but is not. This quality may reflect that no value is available at this time, for reasons like the value may have not been provided by the data source. |
3 | 000011LL | Device Failure | A device failure has been detected |
4 | 000100LL | Sensor Failure | A sensor failure had been detected (the Limits field can provide additional diagnostic information in some situations.) |
5 | 000101LL | Last Known Value | Communications have failed. However, the last known value is available. Note that the age of the value may be determined from the TIMESTAMP in the OPCITEMSTATE. |
6 | 000110LL | Comm Failure | Communications have failed. There is no last known value is available. |
7 | 000111LL | Out of Service | The block is off scan or otherwise locked This quality is also used when the active state of the item or the group containing the item is InActive. |
8-15 | N/A | Not used by OPC |
Comment
Substatus for UNCERTAIN Quality:
SSSS | BIT VALUE | DEFINE | DESCRIPTION |
0 | 010000LL | Non-specific | There is no specific reason why the value is uncertain. |
1 | 010001LL | Last Usable Value | Whatever was writing this value has stopped doing so. The returned value should be regarded as stale. Note that this differs from a BAD value with Substatus 5 (Last Known Value). That status is associated specifically with a detectable communications error on a fetched value. This error is associated with the failure of some external source to put something into the value within an acceptable period of time. Note that the age of the value can be determined from the TIMESTAMP in OPCITEMSTATE. |
2-3 | N/A | Not used by OPC | |
4 | 010100LL | Sensor Not Accurate | Either the value has pegged at one of the sensor limits (in which case the limit field should be set to 1 or 2) or the sensor is otherwise known to be out of calibration via some form of internal diagnostics (in which case the limit field should be 0). |
5 | 010101LL | Engineering Units Exceeded | The returned value is outside the limits defined for this parameter. Note that in this case (per the Fieldbus Specification) the Limits field indicates which limit has been exceeded but does NOT necessarily imply that the value cannot move farther out of range. |
6 | 010110LL | Sub-Normal | The value is derived from multiple sources and has less than the required number of Good sources. |
7-15 | N/A | Not used by OPC |
Comment
Substatus for GOOD Quality:
SSSS | BIT VALUE | DEFINE | DESCRIPTION |
0 | 110000LL | Non-specific | The value is good. There are no special conditions |
1-5 | N/A | Not used by OPC | |
6 | 110110LL | Local Override | The value has been Overridden. Typically this is means the input has been disconnected and a manually entered value has been forced. |
7-15 | N/A | Not used by OPC |
Comment
The Limit BitField
The Limit Field is valid regardless of the Quality and Substatus. In some cases such as Sensor Failure it can provide useful diagnostic information.
LL | BIT VALUE | DEFINE | DESCRIPTION |
0 | QQSSSS00 | Not Limited | The value is free to move up or down |
1 | QQSSSS01 | Low Limited | The value has pegged at some lower limit |
2 | QQSSSS10 | High Limited | The value has pegged at some high limit. |
3 | QQSSSS11 | Constant | The value is a constant and cannot move. |
Comment
Symbolic Equates are defined for values and masks for these BitFields in the "QUALITY" section of the OPC header files.