General Information
This section provides general information about the OPC
Interfaces, and some background information about how the designers of
OPC expected these interfaces to be implemented and used.
Version Interoperability
Data Access Servers may be compatible with the requirements
of Version 1.0a of the specification or with Version 2.0 of the specification
or both. Data Access Clients may also be compatible with the requirements
of Version 1.0a of the specification or with Version 2.0 of the specification
or both.
The best migration strategy for server and client vendors
will depend on their particular business situation. For example a vendor
who mostly sells his own client and server components as a packaged system
and for whom OPC Compatability represents a long term strategy will have
less need to support multiple versions of the interfaces.
As a general guideline it is recommended that existing
server vendors add version 2.0 support and leave version 1.0 support in
place to support existing Version 1.0 Clients.
Data Access Server
Required Interfaces |
1.0 |
2.0 |
OPCServer |
|
|
IUnknown |
Required |
Required |
IOPCServer |
Required |
Required |
IOPCCommon |
N/A |
Required |
IConnectionPointContainer |
N/A |
Required |
IOPCItemProperties |
N/A |
Required |
IOPCServerPublicGroups |
Optional |
Optional |
IOPCBrowseServerAddressSpace |
Optional |
Optional |
|
|
|
OPCGroup |
|
|
IUnknown |
Required |
Required |
IOPCItemMgt |
Required |
Required |
IOPCGroupStateMgt |
Required |
Required |
IOPCPublicGroupStateMgt |
Optional |
Optional |
IOPCSyncIO |
Required |
Required |
IOPCAsyncIO2 |
N/A |
Required |
IConnectionPointContainer |
N/A |
Required |
IOPCAsyncIO |
Required |
N/A |
IDataObject |
Required |
N/A |
Ownership of memory
Per the COM specification, clients must free all memory
associated with out or in/out parameters. This includes memory that
is pointed to by elements within any structures. This is very important
for client writers to understand, otherwise they will experience memory
leaks that are difficult to find. See the IDL files to determine which
parameters are out parameters. The recommended approach is for a client
to create a subroutine that is used for freeing each type of structure
properly.
Independent of success/failure, the server must always
return well defined values for out parameters. Releasing the allocated
resources is the clients responsibility.
Note: If the error result is any FAILED error such
as E_OUTOFMEMORY , the OPC server should return NULL for all `out' pointers
(this is standard COM behavior). This rule also applies to the error
arrays (ppErrors) returned by many of the functions below. In general,
a robust OPC client should check each out or in/out pointer for NULL prior
to freeing it.
Standard Interfaces
Per the COM specification, all methods must be implemented
on each required interface.
Per the COM specification, any optional interfaces that
are supported must have all functions within that interface implemented,
even if the implementation is only a stub implementation returning E_NOTIMPL.
Null Strings and Null Pointers
Both of these terms are used below. They are NOT the
same thing. A NULL Pointer is an invalid pointer (0) which will cause an
exception if used. A NUL String is a valid (non zero) pointer to a 1 character
array where that character is a NUL (i.e. 0). If a NUL string is returned
from a method as an [out] parameter (or as an element of a structure) it
must be freed, otherwise the memory containing the NUL will be lost. Also
note that a NULL pointer cannot be passed for an [in,string] argument due
to COM marshalling restrictions. In this case a pointer to a NUL string
should be passed to indicate an omitted parameter.
Returned Arrays
You will note the syntax size_is(,dwCount) in
the IDL used in combination with pointers to pointers. This indicates that
the returned item is a pointer to an actual array of the indicated type,
rather than a pointer to an array of pointers to items of the indicated
type. This simplifies marshaling , creation, and access of the data by
the server and client.
Public Groups
Public groups are optional. The server vendor and the
client vendor may elect to support this behavior as appropriate for their
application. There are some specific rules that must be adhered to if the
public group capability is supported. This are discussed in detail later
in the method descriptions but in general:
A public group must have a unique name relative to all
other public groups. If a client adds a private group which will later
be converted to a public group, the client should insure that this name
is unique or an error will occur later in MoveToPublic.
Once a group has been made public, the items within that
group can not be changed. If changes need to be made to a public group,
a new group must be created with the items (e.g. through the use of CloneGroup),
and made public after the modifications to the items are in place
Once a client has connected to a public group, most of
that group properties (client handles, update rates, etc) will be maintained
as unique instance data for that client to group connection.
CACHE data, DEVICE data and TimeStamps
For the most part the terms CACHE and DEVICE are treated
as abstract within this specification. That is, reading CACHE or DEVICE
data simply affects the described behavior of various interfaces in a well
defined way. The implementation details of these capabilities is not dictated
by this specification.
In practice, however, it is expected that most servers
will read data into some sort of CACHE. Also, most clients will read data
from this cache via one of several mechanisms discussed later. Access to
DEVICE data is expected to be slow and is expected to be used primarily
for diagnostics or for particularly critical operations.
The CACHE should reflect the latest value of the data
(subject to update rate and deadband optimizations as discussed later)
as well as the quality and timestamp. The Timestamp should indicate the
time that the value and quality was obtained by the device (if this is
available) or the time the server updated or validated the value and quality
in its CACHE. Note that if a device or server is checking a value every
10 seconds then the expected behavior would be that the timestamp of that
value would be updated every 10 seconds (even if the value is not actually
changing). Thus the time stamp reflects the time at which the server knew
the corresponding value was accurate.
This is also true regardless of wether the physical device
to system interface is exception based. For example suppose it is known
that (a) an exception based device is checking values every 0.5 second
and that (b) the connection to the device is good and (c) that device sent
an update for item FIC101 three minutes ago with a value of 1.234. In this
case the value returned from a cache read would be 1.234 and more important,
the timestamp returned for this value would be the current time (within
0.5 second) since it is known that the value for the item is in fact still
1.234 as of 0.5 seconds ago.
Time Series Values
The OPC Data Access interfaces are designed primarily
to take snapshots of current real time process or automation data. The
Timestamp returned with those values is intended primarily as an indication
of the quality of that current data. These interfaces are not really
intended to deal with buffered time series data for a single point such
as historical data.
Asynchronous vs. Synchronous
Interfaces
Assuming that most clients want to access Cached data,
there are several ways for a client to obtain that data from a server.
-
It can perform a synchronous read from cache (simple and
reasonably efficient). This may be appropriate for fairly simple clients
that are reading relatively small amounts of data and where maximum efficiency
is not a concern. A client that operates in this way is essentially duplicating
the scanning that the server is already doing.
-
It can subscribe to cached data using IAdviseSink or IOPCDataCallback
which is more complex but very efficient. This is the recommended behavior
for clients because it will minimize use of CPU and NETWORK resources.
The ACTIVE flags, Deadband and
Update Rate
These attributes of groups and items can be used to
reduce resource use by clients and servers. They are discussed in more
detail later under GROUPS. In general, they affect how often the cached
data and quality information is updated and how often calls are made to
the clients IAdviseSink or IOPCDataCallback.
Errors and return codes
The OPC specification describes interfaces and corresponding
behavior that an OPC server implements, and an OPC client application depends
on. A list of OPC Specific errors and return codes is contained in the
summary of OPC error codes section in this specification. For each method
described below a list of all possible OPC error codes as well as the most
common OLE error codes is included. It is likely that clients will
encounter additional error codes such as RPC and Security related codes
in practice and they should be prepared to deal with them.
In two cases (Read and Write) it is also allowed for a
server to return Vendor Specific error codes. Such codes can be passed
to GetErrorString method. This is discussed in more detail later.
In all cases E error codes will indicate FAILED type
errors and S error codes will indicate at least partial success.
Startup Issues
After Items are added to a group, it may take some time
for the server to actually obtain values for these items. In such cases
the client might perform a read (from cache), or establish an AdviseSink
or ConnectionPoint based subscription and/or execute a Refresh on such
a subscription before the values are available. You will see in the later
discussions of subscriptions that an initial callback is expected which
contains all values in a Group. The expected behavior in this situation
is summarized by saying that as items are added to a group, their initial
state should be set to OPC_QUALITY_BAD with a NON_SPECIFIC (00) or optionally
a OPC_QUALITY_LAST_KNOWN (14) substate. Any client operation on the group
will then behave as it normally would for a group with a mixed set of GOOD
and BAD qualities. Note that in the case of the sync read and also asyncio2
operations the server can return vendor specific error information which
could indicate a vendor specific error such as "SERVER WAITING FOR INITIAL
DATA".
VARIANT Data Types and Interoperability
In order to promote interoperability, the following
rules and recommendations are presented.
Rules:
-
Servers are allowed to maintain and return any legal Canonical
Data Type (any legal permutation of VT_ flags).
-
Clients are allowed to request any legal Requested Data Type.
-
Servers should be prepared to deal in an elegant way with
requested types even when they are unable to convert their data to this
type. That is, they should not malfunction, return incorrect results or
lose memory. As mentioned elsewhere they may return a variety of errors
including any error returned by the Microsoft function: VariantChangeType.
-
Clients should always be prepared to deal with servers which
are unable to handle any requested datatype. That is, they should not malfunction
or lose memory when an error is returned.
-
Clients which request VT_EMPTY (which by convention indiciates
that the server should return it's canonical type) should likewise be prepared
to deal with any returned type. That is, even if they find that they are
not be able to use or display the returned data, they should properly free
the data (using VariantClear) and should probably indicate to the user
that a datatype was returned which is not usable by this client.
Recommendations:
-
The VARIANT types VT_I2, I4, R4, R8, CY, DATE, BSTR, BOOL,
UI1 as well as single arrays of these types (VT_ARRAY) are expected to
be most commonly used (in part because these are the legal types in Visual
Basic).
-
It is recommended that whenever possible, clients request
data in one of these formats and that whenever possible, servers be prepared
to return data in one of these formats.
-
It is expected that use of other extended types will most
likely occur where the Server and Client were written by the same vendor
and the server intends to pass some non-portable vendor specific data back
to the client. In the interests of interoperability, such transactions
should be minimized.