Create Universal Driver Interface

The first step in creating a custom communication driver for OAS is to create the Driver Assembly. This .NET Assembly will be referenced by a .NET Hosting Application, and depending on the target deployment platforms, can be developed to be cross-platform compatible for use on Windows, Mac, Linux, Android, and iOS operating systems.

Choosing a Framework

If you would like the flexibility of being able to run your driver on multiple operating systems, your driver should target the .NET Standard 2.0+ framework. Yet, we understand that in some cases you must rely on other 3rd party libraries that are not compatible, or you cannot upgrade your infrastructure to the NET Framework 4.6.1+. In these cases, your driver must target the .NET 4.0 Framework, and will be limited to being run on a Windows platform.

In the OAS Platform distribution, we have provided Examples for any of these scenarios. In the installation directory, locate the Universal Drivers folder, to find all Example code for drivers and Hosting Apps, in both C# and VB.NET.

For cross-platform support, choose the examples under the Standard directory, and for .NET 4.0 or 4.5 only support, select examples under the Framework4 directory.

The Driver Architecture

Building a functional UDI Driver includes the development of your own Driver assembly following our example code, then running this within a Hosting Application. In this tutorial, we will be building a .NET Framework 4.0 Driver hosted within a Windows Service to be deployed on a Windows Server or PC.


You will need to be running Open Automation Software Version 11.00.0017 or greater to support Universal Drivers.  You can download the latest version at

You will also need Microsoft Visual Studio to work with any of these examples and to compile your custom driver. If you do not currently have Visual Studio installed, you can try out Visual Studio Community which is a fully functional, free version of the IDE.

Step 1

Copy the C# or VB Driver Code from the OAS installation path, typically C:\Program Files (x86)\Open Automation Software\OPC Systems.NET\Universal Drivers\Framework4\Driver\ to a location of your choosing, then open the project in Visual Studio.

NOTE: Under the project references, if you are getting a warning or if the OASDriverInterface (or OASDriverInterfaceFramework4 for a .NET Framwework 4.0 Driver project) assembly is missing, remove the reference and add it back in, locating it in the base OAS installation directory.


Step 2

Under the Project Properties set the Assembly name and Root namespace name to something unique for each driver you create. The default is ExampleDriver, so we’ll leave this as is but you should change this to uniquely identify your driver for each data source.

The Assembly Name will be the resulting DLL that is compiled. In this case, the assembly will compile to a file named ExampleDriver.dll.

The Default Namespace will only affect new classes and files added to your driver. You may also search and replace all references of ExampleDriver with your own custom driver name so that it displays properly in all other project references.


Step 3

Open the file DriverInterface.vb for the VB project or DriverInterface.cs for the C# project and set the m_DriverName variable to a unique name for each driver you create.

This string is the display name that will appear within the OAS Configuration application. The driver name will display in the following formats.

In the list of Drivers associated with the OAS Server, you will see UDI drivers in the left pane as:

   <Driver Name>-<MachineName>

The <Machine Name> will be defined in the host application configuration file (detailed in the Hosting App tutorial), so this can be changed upon deployment and will help with identifying instances of the same drivers hosted on different or remote machines.

In the dropdown lists of drivers, including the dropdowns used to select the data source of a Tag, the UDI Driver will be displayed as:

   UDI <Driver Name>

The Driver Name is set within the source code by setting the m_DriverName string.



The example below shows how the driver would be listed in the OAS Configuration app if the m_DriverName string was set to “Example Driver”.

The driver name also becomes an available selection for Data Source in the Tag parameters for Value and Alarm Limits.

Step 4

Define the Driver Interface properties you would like make adjustable in the function GetDefaultDriverConfig with a list of ClassProperty objects.

The collection of DriverProps returned in the GetDefaultDriverConfig defines the list of configurable properties for the driver which will be exposed in the OAS Configuration application.

Below is an example that adds several properties, including one called “Driver Type” that selectively triggers other property fields’ visibility depending on the value selected.

Each Driver property is an instance of a ClassProperty that can be one of many different types, including selectable options, input text fields and more.



The ClassProperty object is used to define both Driver Interface and Tag properties that you would like to appear in the OAS Framework for system setup.
Following is a list of the variables passed into the constructor for a ClassProperty object.

  • PropName
    A unique name that identifies the property. This will the be name used for CSV Import and Export and also for programmatic setup with the TagCSVImport and DriverInterfaceCSVImport methods.
  • PropDescription
    The text that will appear next to the property in the Configure OAS application.
  • PropHelp
    The text that will appear in the help window for this property in the Configure OAS application. If left blank the help icon will not appear next to the property.
  • PropType
    The data type of the property value. You can define enumerations or common data types.
  • PropValue
    This will be the default value of the property when a Driver Interface or Tag is created.
  • InputType
    This is the configuration input type to use for the property. Manual is the most commonly used input type, but there are also FileBrowse and other configuration input types that can be used to define a value in the Configure OAS application.
  • Binding
    This is an optional property that can be used to control the visibility of property in the Configure OAS application based on the values of other configuration properties. If left blank the property will always appear.
  • Units
    This is an optional property that defines the text that will appear after the property value. If left blank the text will not appear.

Example of what will appear in Configure-Drivers with this example code:

Step 5

Add code to the Connect method to be executed when the driver instance enters runtime mode.

This method is where you would do one or more of the following:

  • Execute initialization code for connecting to your data source
  • Read driver configuration properties for initialization using the GetPropValue function
  • Set up timers to trigger polling activities

In this example, we read some of the persisted properties for the driver as it was configured. Then we check a flag (m_Connected) to determine if the driver has already executed Connect, and if not, start a local Timer to begin triggering.



Step 6

Add code to the Disconnect method to be executed when the driver instance exits runtime mode. This should be used to shut down any connections and undo any initialization that was performed during the Connect method.

In this example, we set the m_Connected flag to false, stop the local Timer, and clear out any tag data using the m_Tags.Clear method.



Step 7

Define the Tag properties you would like make adjustable in the function GetDefaultTagConfig with a list of ClassProperty objects.

These are properties that will be displayed and associated with a Tag configuration when the tag source uses your Driver. These properties will be added to the Value tab in the OAS Configuration app.

These properties are also defined using the ClassProperty object and added to the m_TagProps collection.

In this example, we are adding two Tag properties for Simulation Type and Dynamic Simulation Type.



Example of what will appear in Configure-Tags with this example code:

Step 8

Add code to the AddTags method that passes the tags to be monitored with continuous polling.

All Tag Properties defined in the driver will be available at this point and additionally TagName and PollingRate and can be inspected using the GetPropValue method.

This example demonstrates pulling the TagName, and PollingRate. To add a Tag to the continuous polling routines, the tag is then added to the m_Tags collection. We further reset the timestamp stored in the m_LastUpdateTime for the Tag which is used to track the last time the Tag value has been updated.


Step 9

Add code to the RemoveTags method that passes the tags to be removed from continuous polling. This should reverse the code added to the AddTags method by removing tags from continuous polling.

This example demonstrates the removal of all Tags from the m_Tags collection and clears out the associated timestamps from the m_LastUpdateTime collection.


Step 10

Optionally, you can have your custom Driver create and configure Tags on the server in which it is installed by implementing the GetTagsToAdd method. This example demonstrates adding tags to the configuration so that data will begin flowing as soon as the Driver is activated.

As you can see, we are also using the ClassProperty to define all of the Tags’ configuration properties and even ensure that they connect using the custom Driver as a source. However, you can configure any other Tags that you choose, truly making the deployment of a Driver a hands-off operation.




Step 11

Optionally add code to the SyncRead method that passes a tags list, each containing properties. This is for one time read of values based on a trigger in OAS for a Device Read. If you do not need support for the Device Read feature this method can be left blank. For continuous monitoring refer to Step 13 with the AsyncReadCallback method.

If you are connecting to a data source or application, this is where you may pull values from an API or memory cache just once on each call made to the method for the Tags requested.


Step 12

Add code to the WriteValues method that passes a list Tag name, values to be written, and a list of property values for each Tag. This section of code is where you would receive tag names, values, and properties defined in the OAS Platform for each tag for tags that are to be written.

In this example simulation the values are added to the m_StaticTagValues collection for persistence in this simulation, most likely they would be sent back to the data source of you are implementing a writeable interface to your source.


Step 13

Add code for continuous polling that will obtain values for the tags and call the method AsyncReadCallback on the OAS Driver Interface object which will pass an array of tag values.

This code is triggered by the Timer that is started and stopped in the Connect and Disconnect methods. In this routine, you would perform periodic updates on your Tags and mark them as updated by recording an associated timestamp in the m_LastUpdateTime collection.

You can also see in this example that our Tags marked as “Dynamic” are provided calculated values, and “Static” tags pull values from the m_StaticTagValues collection which is set in the WriteValues routine.


Step 14

To post a System Error to OAS call the method UpdateSystemError on the OAS Driver Interface object.
Set the first parameter to true to post the System Error as active and false to clear the System Error that has been previously posted.
Specify a Category to group the error along with a unique MessageID.





Creating a Hosting App

Once you have compiled the custom Driver assembly, your next step will be to Create a Hosting Application that will load the assembly and run it. This application can be any .NET app, but for most deployments, you will be creating a .NET Windows Service or a Console Application. Services are perfect for deployment on a Windows platform, and Console Applications, when written using .NET Core, can be hosted on non-Windows operating systems like Linux and Mac. Additionally, you can create an Android or iOS app using the Xamarin development tools within Visual Studio.