OPC Classic Concepts and Implementation

Before the OPC era, industrial applications had to carry the burden of maintaining their own communication drivers. The OPC standard provided a common method for accessing data. Consequently, OPC client applications can access all sorts of devices such as PLC, DCS, RTU…etc, using the same interfaces.

OPC classic is based on a Microsoft interprocess communications standard called COM. A COM component is identified by a CLSID or its user-friendly version called ProgID. COM components expose their services through interfaces that users can query then use to interact with the components. The interfaces are defined using the IDL language.

OPC Classic is a set of specifications, each one defines a set of COM interfaces. For example, Data Access Specification defines interfaces to access real-time data.

In order for an OPC client to connect to a server, it needs the server’s ProgID and hostname. Once connected, the client queries the interfaces from the server as shown in the code snippet below:

// retrieve CLSID from user friendly ProgID
Type opcServerType = Type.GetTypeFromProgID(progId, machine, false);
if (opcServerType != null)
{
  // connect to OPC server using CLSID
  opcServerObject = Activator.CreateInstance(opcServerType);
  // query IOPCServer interface using a simple cast
  opcServer = opcServerObject as IOPCServer;
  if (opcServer != null)
  {
     opcCommon = opcServerObject as IOPCCommon;
     opcBrowse = opcServer as IOPCBrowseServerAddressSpace;
     opcItemProperties = opcServer as IOPCItemProperties;
     opcConnectionPointContainer = opcServerObject as IConnectionPointContainer;
     // ...
     // do something useful with the interfaces
     // ...
  }
}

OPC Interfaces

The list below shows the main responsibilities of the most important OPC DA interfaces:

  • IOPCServer is used by a client to add/remove groups and retrieve the server status information
  • IOPCBrowseServerAddressSpace is used by a client to browse the server’s address space and provide the user with a graphical representation of the address space hierarchy
  • IOPCItemProperties retrieves item properties
  • IOPCItemMgt adds, validates and removes items
  • IOPCSyncIO allows the client to perform synchronous read and write requests
  • IOPCAsyncIO2 same as above except that the requests are non-blocking
  • IOPCDataCallback is a client interface used by the server to notify the client about changes in item values and qualities

OPC Item

An OPC item is the simplest unit of information provided by a server. An item might correspond to a physical I/O such as a relay state, a temperature or humidity value, a robotic arm position… or a value in memory such as the constants of a PID algorithm…

An OPC item has static properties, such as the canonical datatype, the description, the engineering unit…etc and runtime properties such as the value, the quality (level of confidence in the value provided), the timestamp of the latest change in value and/or quality and the item active state.

OPC Subscription

While it is possible for a client to make synchronous or asynchronous calls to read and write, creating a subscription is the most common and efficient way for a client to receive data. Basically, a subscription occurs when the client registers itself at the server in order to receive notifications when item values or qualities change. This method saves CPU/bandwidth by avoiding unnecessary read calls for items that didn’t necessarily change.

OPC Group

A group is a logical container for OPC items, the most important properties of a group are:

  • Active State: when a group is inactive the server stops sending change notifications for all the items that belong to the group
  • Update Rate: The server should not send change notifications to the client faster than the update rate (in milliseconds). When set to zero, the client requests data to be sent as quickly as possible

Be careful, when changing the value of this property, a small value may lead to a situation where data is oversampled which means an increase in the network traffic and eventually an overload of the end controller.

Subscriptions are made at the group level and they use a COM interface called IConnectionPointContainer as illustrated in the code snippet below:

// retrieve the connection point container interface from IOPCGroupStateMgt
// IOPCGroupStateMgt is returned from a call to IOPCServer::AddGroup
callbackConnectionPointContainer = opcGroupStateMgt as IConnectionPointContainer;
// retrieve the callbakc interface GUID
Guid riid = typeof(IOPCDataCallback).GUID;
// retrieve the connection point
callbackConnectionPointContainer.FindConnectionPoint(ref riid, out callbackConnectionPoint);
// use the connection point to register the caller object as recipient of change notifications
callbackConnectionPoint?.Advise(this, out callbackCookie);