实例介绍
【实例简介】OPC Unified Automation client 源码
【实例截图】
【核心代码】
/******************************************************************************
** Copyright (c) 2006-2018 Unified Automation GmbH All rights reserved.
**
** Software License Agreement ("SLA") Version 2.7
**
** Unless explicitly acquired and licensed from Licensor under another
** license, the contents of this file are subject to the Software License
** Agreement ("SLA") Version 2.7, or subsequent versions
** as allowed by the SLA, and You may not copy or use this file in either
** source code or executable form, except in compliance with the terms and
** conditions of the SLA.
**
** All software distributed under the SLA is provided strictly on an
** "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
** AND LICENSOR HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
** LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
** PURPOSE, QUIET ENJOYMENT, OR NON-INFRINGEMENT. See the SLA for specific
** language governing rights and limitations under the SLA.
**
** Project: .NET based OPC UA Client Server SDK
**
** Description: OPC Unified Architecture Software Development Kit.
**
** The complete license agreement can be found here:
** http://unifiedautomation.com/License/SLA/2.7/
******************************************************************************/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using UnifiedAutomation.UaBase;
using UnifiedAutomation.UaClient;
namespace UnifiedAutomation.Sample
{
public partial class MainForm : Form
{
#region Connect and Disconnect Server
/// <summary>
/// Connect to the UA server and read the namespace table.
/// The connect is based on the Server URL entered in the Form
/// The read of the namespace table is used to detect the namespace index
/// of the namespace URI entered in the Form and used for the variables to read
/// </summary>
private void connect()
{
if (m_session == null)
{
// Create a session
m_session = new Session(m_application);
// attach to events
m_session.ConnectionStatusUpdate = new ServerConnectionStatusUpdateEventHandler(Session_ServerConnectionStatusUpdate);
}
m_session.UseDnsNameAndPortFromDiscoveryUrl = UseDnsNameAndPortFromDiscoveryUrl.Checked;
// Step 1 ----------------------------------------------------
// Connect to the server with no security
m_session.Connect(txtServerUrl.Text, SecuritySelection.None);
// Step 2 ----------------------------------------------------
// Search for the namespace URI entered in the user interface
// The namespace table is automatically read from the server and provided as property of the session
// Index in the namespace table is used as namespace index for the NodeIds in the example
ushort i;
for (i = 0; i < m_session.NamespaceUris.Count; i )
{
if (m_session.NamespaceUris[i] == txtNamespaceUri.Text)
{
m_NameSpaceIndex = i;
}
}
// Check if the namespace was found
if (m_NameSpaceIndex == 0)
{
throw new Exception("Namespace " txtNamespaceUri.Text " not found in server namespace table");
}
}
/// <summary>
/// Disconnect from the UA server.
/// </summary>
private void disconnect()
{
// Disconnect from Server
m_session.Disconnect();
m_subscription = null;
}
/// <summary>
/// receive updates about session state.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Session_ServerConnectionStatusUpdate(Session sender, ServerConnectionStatusUpdateEventArgs e)
{
if (InvokeRequired)
{
BeginInvoke(new ServerConnectionStatusUpdateEventHandler(Session_ServerConnectionStatusUpdate), sender, e);
return;
}
// check that the current session matches the session that raised the event.
if (!Object.ReferenceEquals(m_session, sender))
{
return;
}
lock (this)
{
bool allowEditing = true;
switch (e.Status)
{
case ServerConnectionStatus.Disconnected:
m_bConnected = false;
allowEditing = false;
// update status label
lblConnectionState.Text = "Disconnected";
// update buttons
btnConnect.Text = "Connect";
btnMonitor.Text = "Monitor";
break;
case ServerConnectionStatus.Connected:
m_bConnected = true;
allowEditing = true;
// update status label
lblConnectionState.Text = "Connected";
// update buttons
btnConnect.Text = "Disconnect";
break;
case ServerConnectionStatus.ConnectionWarningWatchdogTimeout:
// update status label
lblConnectionState.Text = "ConnectionWarningWatchdogTimeout";
break;
case ServerConnectionStatus.ConnectionErrorClientReconnect:
// update status label
lblConnectionState.Text = "ConnectionErrorClientReconnect";
break;
case ServerConnectionStatus.ServerShutdownInProgress:
// update status label
lblConnectionState.Text = "ServerShutdownInProgress";
break;
case ServerConnectionStatus.ServerShutdown:
// update status label
lblConnectionState.Text = "ServerShutdown";
break;
case ServerConnectionStatus.SessionAutomaticallyRecreated:
// update status label
lblConnectionState.Text = "SessionAutomaticallyRecreated";
break;
case ServerConnectionStatus.Connecting:
// update status label
lblConnectionState.Text = "Connecting";
break;
case ServerConnectionStatus.LicenseExpired:
// update status label
lblConnectionState.Text = "LicenseExpired";
break;
}
// Toggle Textboxes
txtServerUrl.Enabled = !m_bConnected;
txtNamespaceUri.Enabled = !m_bConnected;
// Toggle action buttons
btnMonitor.Enabled = allowEditing;
btnRead.Enabled = allowEditing;
btnReadAsync.Enabled = allowEditing;
btnWrite.Enabled = allowEditing;
btnWriteAsync.Enabled = allowEditing;
}
}
#endregion
#region Read and Write Variable Values
/// <summary>
/// Reads the values of the two variables entered in the From.
/// The NodeIds used for the Read are constructed from the identifier entered
/// in the Form and the namespace index detected in the connect method
/// </summary>
private void read()
{
// Step 1 --------------------------------------------------
// Prepare nodes to read
// Add the two variable NodeIds to the list of nodes to read
// NodeId is constructed from
// - the identifier text in the text box
// - the namespace index collected during the server connect
ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
nodesToRead.Add(new ReadValueId()
{
NodeId = new NodeId(txtIdentifier1.Text, m_NameSpaceIndex),
AttributeId = Attributes.Value
});
nodesToRead.Add(new ReadValueId()
{
NodeId = new NodeId(txtIdentifier2.Text, m_NameSpaceIndex),
AttributeId = Attributes.Value
});
// Step 2 --------------------------------------------------
// Read the values from the server
List<DataValue> results = m_session.Read(nodesToRead);
// Step 3 --------------------------------------------------
// Update GUI with results
// Print result for first variable - check first the result code
if (StatusCode.IsGood(results[0].StatusCode))
{
// The node succeeded - print the value as string
txtRead1.Text = results[0].WrappedValue.ToString();
txtRead1.BackColor = Color.White;
}
else
{
// The node failed - print the symbolic name of the status code
txtRead1.Text = results[0].StatusCode.ToString();
txtRead1.BackColor = Color.Red;
}
// Print result for second variable - check first the result code
if (StatusCode.IsGood(results[1].StatusCode))
{
// The node succeeded - print the value as string
txtRead2.Text = results[1].WrappedValue.ToString();
txtRead2.BackColor = Color.White;
}
else
{
// The node failed - print the symbolic name of the status code
txtRead2.Text = results[1].StatusCode.ToString();
txtRead2.BackColor = Color.Red;
}
}
/// <summary>
/// Write 2 values to the variables entered in the From.
/// The NodeId used for the Write is constructed from the identifier entered
/// in the Form and the namespace index detected in the connect method
/// </summary>
private void write()
{
// Step 1 --------------------------------------------------
// Get values to write and convert them to the right data type
if (m_TypeItem1 == BuiltInType.Null || m_TypeItem2 == BuiltInType.Null)
{
// Read variable data types from server
readDataTypes();
}
// Get values from GUI and convert them to the right data type
DataValue val1 = new DataValue();
val1.Value = TypeUtils.Cast(txtWrite1.Text, m_TypeItem1);
DataValue val2 = new DataValue();
val2.Value = TypeUtils.Cast(txtWrite2.Text, m_TypeItem2);
// Step 2 --------------------------------------------------
// Prepare nodes to write including the values to write
List<WriteValue> nodesToWrite = new List<WriteValue>();
nodesToWrite.Add(new WriteValue()
{
NodeId = new NodeId(txtIdentifier1.Text, m_NameSpaceIndex),
AttributeId = Attributes.Value,
Value = val1
});
nodesToWrite.Add(new WriteValue()
{
NodeId = new NodeId(txtIdentifier2.Text, m_NameSpaceIndex),
AttributeId = Attributes.Value,
Value = val2
});
// Step 3 --------------------------------------------------
// Write values to server
List<StatusCode> results = m_session.Write(nodesToWrite);
// Step 4 --------------------------------------------------
// Update GUI with results
// check results
if (StatusCode.IsGood(results[0]))
{
// write succeeded - reset background color
txtWrite1.BackColor = Color.White;
}
else
{
// write failed - print the symbolic name of the status code
txtWrite1.Text = results[0].ToString();
txtWrite1.BackColor = Color.Red;
}
if (StatusCode.IsGood(results[1]))
{
// write succeeded - reset background color
txtWrite2.BackColor = Color.White;
}
else
{
// write failed - print the symbolic name of the status code
txtWrite2.Text = results[1].ToString();
txtWrite2.BackColor = Color.Red;
}
}
#endregion
#region Monitoring of Variable Values
/// <summary>
/// Start monitoring by creating a subscription and monitored items
/// </summary>
private void startMonitoring()
{
// Step 1 --------------------------------------------------
// Create and initialize subscription
m_subscription = new Subscription(m_session);
m_subscription.PublishingEnabled = true;
m_subscription.PublishingInterval = 100;
// Data change events will be received through Subscription_DataChanged
m_subscription.DataChanged = new DataChangedEventHandler(Subscription_DataChanged);
// Create subscription on server
m_subscription.Create();
// Step 2 --------------------------------------------------
// Prepare variables to monitor as data monitored item
List<MonitoredItem> monitoredItems = new List<MonitoredItem>();
// The corresponding result text box gets assigned as user data
// Default is monitoring Value attributes
monitoredItems.Add(new DataMonitoredItem(new NodeId(txtIdentifier1.Text, m_NameSpaceIndex)) { UserData = txtMonitored1 });
monitoredItems.Add(new DataMonitoredItem(new NodeId(txtIdentifier2.Text, m_NameSpaceIndex)) { UserData = txtMonitored2 });
// Step 3 --------------------------------------------------
// Create monitored items on server
List<StatusCode> results = m_subscription.CreateMonitoredItems(monitoredItems);
// Step 4 --------------------------------------------------
// Display any errors.
for (int ii = 0; ii < results.Count; ii )
{
TextBox textBox = monitoredItems[ii].UserData as TextBox;
if (textBox != null)
{
if (StatusCode.IsBad(results[ii]))
{
textBox.Text = results[ii].ToString();
textBox.BackColor = Color.Red;
}
else
{
textBox.Text = String.Empty;
textBox.BackColor = Color.White;
}
}
}
}
/// <summary>
/// Stop monitoring by deleting the subscription
/// </summary>
private void stopMonitoring()
{
// Delete subscription from server
// Monitored items are deleted together with the subscription
m_subscription.Delete();
m_subscription = null;
}
/// <summary>
/// Receive datachange notifications.
/// </summary>
/// <param name="subscription"></param>
/// <param name="e"></param>
private void Subscription_DataChanged(Subscription subscription, DataChangedEventArgs e)
{
// Need to make sure this method is called on the UI thread because it updates UI controls.
if (InvokeRequired)
{
BeginInvoke(new DataChangedEventHandler(Subscription_DataChanged), subscription, e);
return;
}
try
{
// Check that the subscription has not changed.
if (!Object.ReferenceEquals(m_subscription, subscription))
{
return;
}
foreach (DataChange change in e.DataChanges)
{
// Get text box for displaying value from user data
TextBox textBox = change.MonitoredItem.UserData as TextBox;
if (textBox != null)
{
// Print result for variable - check first the result code
if (StatusCode.IsGood(change.Value.StatusCode))
{
// The node succeeded - print the value as string
textBox.Text = change.Value.WrappedValue.ToString();
textBox.BackColor = Color.White;
}
else
{
// The node failed - print the symbolic name of the status code
textBox.Text = change.Value.StatusCode.ToString();
textBox.BackColor = Color.Red;
}
}
}
}
catch (Exception exception)
{
ExceptionDlg.Show("Error in DataChanged callback", exception);
}
}
#endregion
#region Async Read Variable Values with callback
/// <summary>
/// Reads the values of the two variables entered in the From.
/// The NodeIds used for the Read are constructed from the identifier entered
/// in the Form and the namespace index detected in the connect method
/// using the async read method
/// </summary>
private void readAsync()
{
// Step 1 --------------------------------------------------
// Prepare nodes to read
// Add the two variable NodeIds to the list of nodes to read
// NodeId is constructed from
// - the identifier text in the text box
// - the namespace index collected during the server connect
ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
nodesToRead.Add(new ReadValueId()
{
NodeId = new NodeId(txtIdentifier1.Text, m_NameSpaceIndex),
AttributeId = Attributes.Value
});
nodesToRead.Add(new ReadValueId()
{
NodeId = new NodeId(txtIdentifier2.Text, m_NameSpaceIndex),
AttributeId = Attributes.Value
});
// use list of objects as user data - add the text fields
List<object> lstObjects = new List<object>();
lstObjects.Add(txtRead1);
lstObjects.Add(txtRead2);
// Step 2 --------------------------------------------------
// Read the values from the server
m_session.BeginRead(nodesToRead, 0, TimestampsToReturn.Both, null, OnReadComplete, lstObjects);
// Read results will be received through OnReadComplete
}
/// <summary>
/// Receive results from async read
/// </summary>
/// <param name="result"></param>
private void OnReadComplete(IAsyncResult result)
{
// Need to make sure this method is called on the UI thread because it updates UI controls.
if (this.InvokeRequired)
{
// Asynchronous execution of the AsyncCallback delegate.
this.BeginInvoke(new AsyncCallback(OnReadComplete), result);
return;
}
List<DataValue> results = null;
try
{
results = m_session.EndRead(result);
List<object> lstObjects = (List<object>)result.AsyncState;
if (lstObjects.Count == results.Count)
{
for (int i = 0; i < results.Count; i )
{
object obj = lstObjects[i];
if (obj.GetType() == typeof(TextBox))
{
// Get the according item
TextBox txtBox = (TextBox)obj;
if (StatusCode.IsGood(results[i].StatusCode))
{
// Reading the node succeeded - print the value as string
txtBox.Text = results[i].Value.ToString();
txtBox.BackColor = Color.White;
}
else
{
// Reading the node failed - print error code
txtBox.Text = results[i].StatusCode.ToString();
txtBox.BackColor = Color.Red;
}
}
else
{
// error
}
}
}
else
{
// error
}
}
catch (Exception exception)
{
ExceptionDlg.Show("OnReadComplete failed", exception);
}
}
#endregion
#region Async Write Variable Values with callback
/// <summary>
/// Write 2 values to the variables entered in the From.
/// The NodeId used for the Write is constructed from the identifier entered
/// in the Form and the namespace index detected in the connect method
/// using the async write method
/// </summary>
private void writeAsync()
{
// Step 1 --------------------------------------------------
// Get values to write and convert them to the right data type
if (m_TypeItem1 == BuiltInType.Null || m_TypeItem2 == BuiltInType.Null)
{
readDataTypes();
}
// Get values from GUI and convert them to the right data type
DataValue val1 = new DataValue();
val1.Value = TypeUtils.Cast(txtWrite1.Text, m_TypeItem1);
DataValue val2 = new DataValue();
val2.Value = TypeUtils.Cast(txtWrite2.Text, m_TypeItem2);
// Step 2 --------------------------------------------------
// Prepare nodes to write including the values to write
List<WriteValue> nodesToWrite = new List<WriteValue>();
nodesToWrite.Add(new WriteValue()
{
NodeId = new NodeId(txtIdentifier1.Text, m_NameSpaceIndex),
AttributeId = Attributes.Value,
Value = val1
});
nodesToWrite.Add(new WriteValue()
{
NodeId = new NodeId(txtIdentifier2.Text, m_NameSpaceIndex),
AttributeId = Attributes.Value,
Value = val2
});
// use list of objects as user data - add the text fields
List<object> lstObjects = new List<object>();
lstObjects.Add(txtRead2);
lstObjects.Add(txtRead1);
// Step 3 --------------------------------------------------
// Write values to server
m_session.BeginWrite(nodesToWrite, OnWriteComplete, lstObjects);
// Write results will be received through OnWriteComplete
}
/// <summary>
/// Receive results from async write
/// </summary>
/// <param name="result"></param>
private void OnWriteComplete(IAsyncResult result)
{
// Need to make sure this method is called on the UI thread because it updates UI controls.
if (this.InvokeRequired)
{
// Asynchronous execution of the AsyncCallback delegate.
this.BeginInvoke(new AsyncCallback(OnWriteComplete), result);
return;
}
List<StatusCode> results = null;
try
{
results = m_session.EndWrite(result);
List<object> lstObjects = (List<object>)result.AsyncState;
if (lstObjects.Count == results.Count)
{
for (int i = 0; i < results.Count; i )
{
object obj = lstObjects[i];
if (obj.GetType() == typeof(TextBox))
{
// Get the according item
TextBox txtBox = (TextBox)obj;
if (StatusCode.IsNotGood(results[i]))
{
// Writing the node failed - print error code
txtBox.Text = results[i].ToString();
txtBox.BackColor = Color.Red;
}
}
else
{
// error
}
}
}
else
{
// error
}
}
catch (Exception exception)
{
ExceptionDlg.Show("OnWriteComplete failed", exception);
}
}
#endregion
#region Read data types of variables from server
/// <summary>
/// Read the type informatin for both variables configured.
/// </summary>
private void readDataTypes()
{
// Add the two variable NodeIds to the list of nodes to read
// NodeId is constructed from
// - the identifier text in the text box
// - the namespace index collected during the server connect
ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
nodesToRead.Add(new ReadValueId()
{
NodeId = new NodeId(txtIdentifier1.Text, m_NameSpaceIndex),
AttributeId = Attributes.DataType
});
nodesToRead.Add(new ReadValueId()
{
NodeId = new NodeId(txtIdentifier2.Text, m_NameSpaceIndex),
AttributeId = Attributes.DataType
});
// Read the datatypes
List<DataValue> results = null;
try
{
results = m_session.Read(nodesToRead, 0, TimestampsToReturn.Neither, null);
// check the result code
if (StatusCode.IsGood(results[0].StatusCode))
{
// The node succeeded - save buildInType for later use
m_TypeItem1 = TypeUtils.GetBuiltInType((NodeId)results[0].Value);
}
else
{
throw new Exception("Read datatype failed for item " txtIdentifier1.Text);
}
// check the result code
if (StatusCode.IsGood(results[1].StatusCode))
{
// The node succeeded - save buildInType for later use
m_TypeItem2 = TypeUtils.GetBuiltInType((NodeId)results[1].Value);
}
else
{
throw new Exception("Read datatype failed for item " txtIdentifier1.Text);
}
}
catch (Exception exception)
{
ExceptionDlg.Show("Read datatype failed", exception);
throw exception;
}
}
#endregion
#region Construction
public MainForm(ApplicationInstance applicationInstance)
{
m_application = applicationInstance;
InitializeComponent();
Application.ApplicationExit = Application_ApplicationExit;
}
#endregion
#region Application EventHandlers
private void Application_ApplicationExit(object sender, EventArgs e)
{
if (m_session != null && m_session.ConnectionStatus == ServerConnectionStatus.Connected)
{
m_session.Disconnect();
}
}
#endregion
#region Fields
private ApplicationInstance m_application = null;
private Session m_session = null;
private bool m_bConnected = false;
private Subscription m_subscription = null;
private UInt16 m_NameSpaceIndex = 0;
private BuiltInType m_TypeItem1;
private BuiltInType m_TypeItem2;
#endregion
#region User actions
/// <summary>
/// Handle event for connect button
/// </summary>
private void btnConnect_Click(object sender, EventArgs e)
{
if (m_bConnected)
{
try
{
disconnect();
}
catch (Exception exception)
{
ExceptionDlg.Show(null, exception);
}
}
else
{
try
{
connect();
}
catch (Exception exception)
{
ExceptionDlg.Show("Connect failed", exception);
}
}
}
/// <summary>
/// Handle event for Read button
/// </summary>
private void btnRead_Click(object sender, EventArgs e)
{
try
{
read();
}
catch (Exception exception)
{
ExceptionDlg.Show(null, exception);
}
}
/// <summary>
/// Handle event for ReadAsync button
/// </summary>
private void btnReadAsync_Click(object sender, EventArgs e)
{
try
{
readAsync();
}
catch (Exception exception)
{
ExceptionDlg.Show("Read failed", exception);
}
}
/// <summary>
/// Handle event for Write button
/// </summary>
private void btnWrite_Click(object sender, EventArgs e)
{
try
{
write();
}
catch (Exception exception)
{
ExceptionDlg.Show("Write failed", exception);
}
}
/// <summary>
/// Handle event for WriteAsync button
/// </summary>
private void btnWriteAsync_Click(object sender, EventArgs e)
{
try
{
writeAsync();
}
catch (Exception exception)
{
ExceptionDlg.Show("Write failed", exception);
}
}
/// <summary>
/// Starts the monitoring of the values of the two variables entered in the From.
/// The NodeIds used for the monitoring are constructed from the identifier entered
/// in the Form and the namespace index detected in the connect method
/// </summary>
private void btnMonitor_Click(object sender, EventArgs e)
{
if (m_subscription == null)
{
// create the subscription
try
{
startMonitoring();
btnMonitor.Text = "Stop";
}
catch (Exception exception)
{
ExceptionDlg.Show("Create subscription failed", exception);
m_subscription = null;
btnMonitor.Text = "Monitor";
}
}
else
{
try
{
stopMonitoring();
btnMonitor.Text = "Monitor";
txtMonitored1.Text = "";
txtMonitored2.Text = "";
}
catch (Exception exception)
{
ExceptionDlg.Show("Stopping monitoring failed", exception);
}
}
}
#endregion
}
}
好例子网口号:伸出你的我的手 — 分享!
网友评论
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明


支持(0) 盖楼(回复)