Rimesso adapter in proj da Ref Client
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.32510.428
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MP.MONO.ADAPTER.OPC", "MP.MONO.ADAPTER.OPC\MP.MONO.ADAPTER.OPC.csproj", "{458FD824-7804-4CF9-8C43-463C1F5659DA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{458FD824-7804-4CF9-8C43-463C1F5659DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{458FD824-7804-4CF9-8C43-463C1F5659DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{458FD824-7804-4CF9-8C43-463C1F5659DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{458FD824-7804-4CF9-8C43-463C1F5659DA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3811E8B4-1DD3-4841-9840-1B1A08782CD3}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,382 @@
|
||||
/* ========================================================================
|
||||
* Copyright (c) 2005-2021 The OPC Foundation, Inc. All rights reserved.
|
||||
*
|
||||
* OPC Foundation MIT License 1.00
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The complete license agreement can be found here:
|
||||
* http://opcfoundation.org/License/MIT/1.00/
|
||||
* ======================================================================*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Mono.Options;
|
||||
using Opc.Ua;
|
||||
using Opc.Ua.Configuration;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
using Serilog.Templates;
|
||||
using static Opc.Ua.Utils;
|
||||
|
||||
namespace MP.MONO.ADAPTER.OPC
|
||||
{
|
||||
/// <summary>
|
||||
/// The log output implementation of a TextWriter.
|
||||
/// </summary>
|
||||
public class LogWriter : TextWriter
|
||||
{
|
||||
private StringBuilder m_builder = new StringBuilder();
|
||||
|
||||
public override void Write(char value)
|
||||
{
|
||||
m_builder.Append(value);
|
||||
}
|
||||
|
||||
public override void WriteLine(char value)
|
||||
{
|
||||
m_builder.Append(value);
|
||||
LogInfo("{0}", m_builder.ToString());
|
||||
m_builder.Clear();
|
||||
}
|
||||
|
||||
public override void WriteLine()
|
||||
{
|
||||
LogInfo("{0}", m_builder.ToString());
|
||||
m_builder.Clear();
|
||||
}
|
||||
|
||||
public override void WriteLine(string format, object arg0)
|
||||
{
|
||||
m_builder.Append(format);
|
||||
LogInfo(m_builder.ToString(), arg0);
|
||||
m_builder.Clear();
|
||||
}
|
||||
|
||||
public override void WriteLine(string format, object arg0, object arg1)
|
||||
{
|
||||
m_builder.Append(format);
|
||||
LogInfo(m_builder.ToString(), arg0, arg1);
|
||||
m_builder.Clear();
|
||||
}
|
||||
|
||||
public override void WriteLine(string format, params object[] arg)
|
||||
{
|
||||
m_builder.Append(format);
|
||||
LogInfo(m_builder.ToString(), arg);
|
||||
m_builder.Clear();
|
||||
}
|
||||
|
||||
public override void Write(string value)
|
||||
{
|
||||
m_builder.Append(value);
|
||||
}
|
||||
|
||||
public override void WriteLine(string value)
|
||||
{
|
||||
m_builder.Append(value);
|
||||
LogInfo("{0}", m_builder.ToString());
|
||||
m_builder.Clear();
|
||||
}
|
||||
|
||||
public override Encoding Encoding
|
||||
{
|
||||
get { return Encoding.Default; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The error code why the application exit.
|
||||
/// </summary>
|
||||
public enum ExitCode : int
|
||||
{
|
||||
Ok = 0,
|
||||
ErrorNotStarted = 0x80,
|
||||
ErrorRunning = 0x81,
|
||||
ErrorException = 0x82,
|
||||
ErrorStopping = 0x83,
|
||||
ErrorCertificate = 0x84,
|
||||
ErrorInvalidCommandLine = 0x100
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// An exception that occured and caused an exit of the application.
|
||||
/// </summary>
|
||||
public class ErrorExitException : Exception
|
||||
{
|
||||
public ExitCode ExitCode { get; }
|
||||
|
||||
public ErrorExitException(ExitCode exitCode)
|
||||
{
|
||||
ExitCode = exitCode;
|
||||
}
|
||||
|
||||
public ErrorExitException()
|
||||
{
|
||||
ExitCode = ExitCode.Ok;
|
||||
}
|
||||
|
||||
public ErrorExitException(string message) : base(message)
|
||||
{
|
||||
ExitCode = ExitCode.Ok;
|
||||
}
|
||||
|
||||
public ErrorExitException(string message, ExitCode exitCode) : base(message)
|
||||
{
|
||||
ExitCode = exitCode;
|
||||
}
|
||||
|
||||
public ErrorExitException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
ExitCode = ExitCode.Ok;
|
||||
}
|
||||
|
||||
public ErrorExitException(string message, Exception innerException, ExitCode exitCode) : base(message, innerException)
|
||||
{
|
||||
ExitCode = exitCode;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A dialog which asks for user input.
|
||||
/// </summary>
|
||||
public class ApplicationMessageDlg : IApplicationMessageDlg
|
||||
{
|
||||
private TextWriter m_output;
|
||||
private string m_message = string.Empty;
|
||||
private bool m_ask;
|
||||
|
||||
public ApplicationMessageDlg(TextWriter output)
|
||||
{
|
||||
m_output = output;
|
||||
}
|
||||
|
||||
public override void Message(string text, bool ask)
|
||||
{
|
||||
m_message = text;
|
||||
m_ask = ask;
|
||||
}
|
||||
|
||||
public override async Task<bool> ShowAsync()
|
||||
{
|
||||
if (m_ask)
|
||||
{
|
||||
var message = new StringBuilder(m_message);
|
||||
message.Append(" (y/n, default y): ");
|
||||
m_output.Write(message.ToString());
|
||||
|
||||
try
|
||||
{
|
||||
ConsoleKeyInfo result = Console.ReadKey();
|
||||
m_output.WriteLine();
|
||||
return await Task.FromResult((result.KeyChar == 'y') ||
|
||||
(result.KeyChar == 'Y') || (result.KeyChar == '\r')).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// intentionally fall through
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_output.WriteLine(m_message);
|
||||
}
|
||||
|
||||
return await Task.FromResult(true).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper functions shared in various console applications.
|
||||
/// </summary>
|
||||
public static class ConsoleUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Process a command line of the console sample application.
|
||||
/// </summary>
|
||||
public static string ProcessCommandLine(
|
||||
TextWriter output,
|
||||
string[] args,
|
||||
Mono.Options.OptionSet options,
|
||||
ref bool showHelp,
|
||||
bool noExtraArgs = true)
|
||||
{
|
||||
IList<string> extraArgs = null;
|
||||
try
|
||||
{
|
||||
extraArgs = options.Parse(args);
|
||||
if (noExtraArgs)
|
||||
{
|
||||
foreach (string extraArg in extraArgs)
|
||||
{
|
||||
output.WriteLine("Error: Unknown option: {0}", extraArg);
|
||||
showHelp = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OptionException e)
|
||||
{
|
||||
output.WriteLine(e.Message);
|
||||
showHelp = true;
|
||||
}
|
||||
|
||||
if (showHelp)
|
||||
{
|
||||
options.WriteOptionDescriptions(output);
|
||||
throw new ErrorExitException("Invalid Commandline or help requested.", ExitCode.ErrorInvalidCommandLine);
|
||||
}
|
||||
|
||||
return extraArgs.FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure the logging providers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Replaces the Opc.Ua.Core default ILogger with a
|
||||
/// Microsoft.Extension.Logger with a Serilog file, debug and console logger.
|
||||
/// The debug logger is only enabled for debug builds.
|
||||
/// The console logger is enabled by the logConsole flag at the consoleLogLevel.
|
||||
/// The file logger uses the setting in the ApplicationConfiguration.
|
||||
/// The Trace logLevel is chosen if required by the Tracemasks.
|
||||
/// </remarks>
|
||||
/// <param name="configuration">The application configuration.</param>
|
||||
/// <param name="context">The context name for the logger. </param>
|
||||
/// <param name="logConsole">Enable logging to the console.</param>
|
||||
/// <param name="consoleLogLevel">The LogLevel to use for the console/debug.<
|
||||
/// /param>
|
||||
public static void ConfigureLogging(
|
||||
ApplicationConfiguration configuration,
|
||||
string context,
|
||||
bool logConsole,
|
||||
LogLevel consoleLogLevel)
|
||||
{
|
||||
var loggerConfiguration = new LoggerConfiguration()
|
||||
.Enrich.FromLogContext();
|
||||
|
||||
if (logConsole)
|
||||
{
|
||||
loggerConfiguration.WriteTo.Console(
|
||||
restrictedToMinimumLevel: (LogEventLevel)consoleLogLevel
|
||||
);
|
||||
}
|
||||
#if DEBUG
|
||||
else
|
||||
{
|
||||
loggerConfiguration
|
||||
.WriteTo.Debug(restrictedToMinimumLevel: (LogEventLevel)consoleLogLevel);
|
||||
}
|
||||
#endif
|
||||
LogLevel fileLevel = LogLevel.Information;
|
||||
|
||||
// switch for Trace/Verbose output
|
||||
var traceMasks = configuration.TraceConfiguration.TraceMasks;
|
||||
if ((traceMasks & ~(TraceMasks.Information | TraceMasks.Error |
|
||||
TraceMasks.Security | TraceMasks.StartStop | TraceMasks.StackTrace)) != 0)
|
||||
{
|
||||
fileLevel = LogLevel.Trace;
|
||||
}
|
||||
|
||||
// add file logging if configured
|
||||
var outputFilePath = configuration.TraceConfiguration.OutputFilePath;
|
||||
if (!string.IsNullOrWhiteSpace(outputFilePath))
|
||||
{
|
||||
loggerConfiguration.WriteTo.File(
|
||||
new ExpressionTemplate("{UtcDateTime(@t):yyyy-MM-dd HH:mm:ss.fff} [{@l:u3}] {@m}\n{@x}"),
|
||||
ReplaceSpecialFolderNames(outputFilePath),
|
||||
restrictedToMinimumLevel: (LogEventLevel)fileLevel,
|
||||
rollOnFileSizeLimit: true);
|
||||
}
|
||||
|
||||
// adjust minimum level
|
||||
if (fileLevel < LogLevel.Information || consoleLogLevel < LogLevel.Information)
|
||||
{
|
||||
loggerConfiguration.MinimumLevel.Verbose();
|
||||
}
|
||||
|
||||
// create the serilog logger
|
||||
var serilogger = loggerConfiguration
|
||||
.CreateLogger();
|
||||
|
||||
// create the ILogger for Opc.Ua.Core
|
||||
var logger = LoggerFactory.Create(builder => builder.SetMinimumLevel(LogLevel.Trace))
|
||||
.AddSerilog(serilogger)
|
||||
.CreateLogger(context);
|
||||
|
||||
// set logger interface, disables TraceEvent
|
||||
SetLogger(logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Output log messages.
|
||||
/// </summary>
|
||||
public static void LogTest()
|
||||
{
|
||||
// print legacy logging output, for testing
|
||||
Trace(TraceMasks.Error, "This is an Error message: {0}", TraceMasks.Error);
|
||||
Trace(TraceMasks.Information, "This is a Information message: {0}", TraceMasks.Information);
|
||||
Trace(TraceMasks.StackTrace, "This is a StackTrace message: {0}", TraceMasks.StackTrace);
|
||||
Trace(TraceMasks.Service, "This is a Service message: {0}", TraceMasks.Service);
|
||||
Trace(TraceMasks.ServiceDetail, "This is a ServiceDetail message: {0}", TraceMasks.ServiceDetail);
|
||||
Trace(TraceMasks.Operation, "This is a Operation message: {0}", TraceMasks.Operation);
|
||||
Trace(TraceMasks.OperationDetail, "This is a OperationDetail message: {0}", TraceMasks.OperationDetail);
|
||||
Trace(TraceMasks.StartStop, "This is a StartStop message: {0}", TraceMasks.StartStop);
|
||||
Trace(TraceMasks.ExternalSystem, "This is a ExternalSystem message: {0}", TraceMasks.ExternalSystem);
|
||||
Trace(TraceMasks.Security, "This is a Security message: {0}", TraceMasks.Security);
|
||||
|
||||
// print ILogger logging output
|
||||
LogTrace("This is a Trace message: {0}", LogLevel.Trace);
|
||||
LogDebug("This is a Debug message: {0}", LogLevel.Debug);
|
||||
LogInfo("This is a Info message: {0}", LogLevel.Information);
|
||||
LogWarning("This is a Warning message: {0}", LogLevel.Warning);
|
||||
LogError("This is a Error message: {0}", LogLevel.Error);
|
||||
LogCritical("This is a Critical message: {0}", LogLevel.Critical);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an event which is set if a user
|
||||
/// enters the Ctrl-C key combination.
|
||||
/// </summary>
|
||||
public static ManualResetEvent CtrlCHandler()
|
||||
{
|
||||
var quitEvent = new ManualResetEvent(false);
|
||||
try
|
||||
{
|
||||
Console.CancelKeyPress += (_, eArgs) => {
|
||||
quitEvent.Set();
|
||||
eArgs.Cancel = true;
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
// intentionally left blank
|
||||
}
|
||||
return quitEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<AssemblyName>MP.MONO.ADAPTER.OPC</AssemblyName>
|
||||
<OutputType>Exe</OutputType>
|
||||
<PackageId>MP.MONO.ADAPTER.OPC</PackageId>
|
||||
<Company>EgalWare</Company>
|
||||
<Description>OPC UA Console Client</Description>
|
||||
<Copyright>Copyright © 2020+ EgalWare</Copyright>
|
||||
<RootNamespace>MP.MONO.ADAPTER.OPC</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||
<PackageReference Include="Mono.Options" Version="6.12.0.148" />
|
||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="1.4.368.58" />
|
||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Configuration" Version="1.4.368.58" />
|
||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Core" Version="1.4.368.58" />
|
||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Security.Certificates" Version="1.4.368.58" />
|
||||
<PackageReference Include="Serilog" Version="2.11.0" />
|
||||
<PackageReference Include="Serilog.Expressions" Version="3.4.0" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="Quickstarts.ReferenceClient.Config.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -36,7 +36,7 @@ using Microsoft.Extensions.Logging;
|
||||
using Opc.Ua;
|
||||
using Opc.Ua.Configuration;
|
||||
|
||||
namespace Quickstarts.ConsoleReferenceClient
|
||||
namespace MP.MONO.ADAPTER.OPC
|
||||
{
|
||||
/// <summary>
|
||||
/// The program.
|
||||
@@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ApplicationConfiguration
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:ua="http://opcfoundation.org/UA/2008/02/Types.xsd"
|
||||
xmlns="http://opcfoundation.org/UA/SDK/Configuration.xsd"
|
||||
>
|
||||
<ApplicationName>Egalware Console Adapter OPC Client</ApplicationName>
|
||||
<ApplicationUri>urn:localhost:UA:Egalware:MP:MONO:ADAPTER</ApplicationUri>
|
||||
<ProductUri>uri:egalware.com:MP:MONO:ADAPTER</ProductUri>
|
||||
<ApplicationType>Client_1</ApplicationType>
|
||||
|
||||
<SecurityConfiguration>
|
||||
|
||||
<!-- Where the application instance certificate is stored (MachineDefault) -->
|
||||
<ApplicationCertificate>
|
||||
<StoreType>Directory</StoreType>
|
||||
<StorePath>%LocalApplicationData%/EgalWare/pki/own</StorePath>
|
||||
<SubjectName>CN=EgalWare Adapter Client, C=IT, S=Bergamo, O=EgalWare, DC=localhost</SubjectName>
|
||||
</ApplicationCertificate>
|
||||
|
||||
<!-- Where the issuer certificate are stored (certificate authorities) -->
|
||||
<TrustedIssuerCertificates>
|
||||
<StoreType>Directory</StoreType>
|
||||
<StorePath>%LocalApplicationData%/EgalWare/pki/issuer</StorePath>
|
||||
</TrustedIssuerCertificates>
|
||||
|
||||
<!-- Where the trust list is stored -->
|
||||
<TrustedPeerCertificates>
|
||||
<StoreType>Directory</StoreType>
|
||||
<StorePath>%LocalApplicationData%/EgalWare/pki/trusted</StorePath>
|
||||
</TrustedPeerCertificates>
|
||||
|
||||
<!-- The directory used to store invalid certficates for later review by the administrator. -->
|
||||
<RejectedCertificateStore>
|
||||
<StoreType>Directory</StoreType>
|
||||
<StorePath>%LocalApplicationData%/EgalWare/pki/rejected</StorePath>
|
||||
</RejectedCertificateStore>
|
||||
|
||||
<!-- WARNING: The following setting (to automatically accept untrusted certificates) should be used
|
||||
for easy debugging purposes ONLY and turned off for production deployments! -->
|
||||
<AutoAcceptUntrustedCertificates>false</AutoAcceptUntrustedCertificates>
|
||||
|
||||
</SecurityConfiguration>
|
||||
|
||||
<TransportConfigurations></TransportConfigurations>
|
||||
|
||||
<TransportQuotas>
|
||||
<OperationTimeout>600000</OperationTimeout>
|
||||
<MaxStringLength>1048576</MaxStringLength>
|
||||
<MaxByteStringLength>1048576</MaxByteStringLength>
|
||||
<MaxArrayLength>65535</MaxArrayLength>
|
||||
<MaxMessageSize>4194304</MaxMessageSize>
|
||||
<MaxBufferSize>65535</MaxBufferSize>
|
||||
<ChannelLifetime>300000</ChannelLifetime>
|
||||
<SecurityTokenLifetime>3600000</SecurityTokenLifetime>
|
||||
</TransportQuotas>
|
||||
|
||||
<ClientConfiguration>
|
||||
<DefaultSessionTimeout>60000</DefaultSessionTimeout>
|
||||
<WellKnownDiscoveryUrls>
|
||||
<ua:String>opc.tcp://{0}:4840</ua:String>
|
||||
<ua:String>http://{0}:52601/UADiscovery</ua:String>
|
||||
<ua:String>http://{0}/UADiscovery/Default.svc</ua:String>
|
||||
</WellKnownDiscoveryUrls>
|
||||
<DiscoveryServers></DiscoveryServers>
|
||||
<MinSubscriptionLifetime>10000</MinSubscriptionLifetime>
|
||||
</ClientConfiguration>
|
||||
|
||||
<Extensions>
|
||||
</Extensions>
|
||||
|
||||
<TraceConfiguration>
|
||||
<OutputFilePath>%LocalApplicationData%/EgalWare/Logs/MP.MONO.ADAPTER.OPC.log.txt</OutputFilePath>
|
||||
<DeleteOnLoad>true</DeleteOnLoad>
|
||||
<!-- Show Only Errors -->
|
||||
<!-- <TraceMasks>1</TraceMasks> -->
|
||||
<!-- Show Only Security and Errors -->
|
||||
<!-- <TraceMasks>513</TraceMasks> -->
|
||||
<!-- Show Only Security, Errors and Trace -->
|
||||
<!-- <TraceMasks>515</TraceMasks> -->
|
||||
<!-- Show Only Security, COM Calls, Errors and Trace -->
|
||||
<!-- <TraceMasks>771</TraceMasks> -->
|
||||
<!-- Show Only Security, Service Calls, Errors and Trace -->
|
||||
<!-- <TraceMasks>523</TraceMasks> -->
|
||||
<!-- Show Only Security, ServiceResultExceptions, Errors and Trace -->
|
||||
<!-- <TraceMasks>519</TraceMasks> -->
|
||||
</TraceConfiguration>
|
||||
|
||||
</ApplicationConfiguration>
|
||||
@@ -35,7 +35,7 @@ using System.Threading.Tasks;
|
||||
using Opc.Ua;
|
||||
using Opc.Ua.Client;
|
||||
|
||||
namespace Quickstarts
|
||||
namespace MP.MONO.ADAPTER.OPC
|
||||
{
|
||||
/// <summary>
|
||||
/// OPC UA Client with examples of basic functionality.
|
||||
+7
-7
@@ -2,13 +2,13 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(AppTargetFrameWorks)</TargetFrameworks>
|
||||
<AssemblyName>ConsoleReferenceClient</AssemblyName>
|
||||
<AssemblyName>MP.MONO.ADAPTER.OPC</AssemblyName>
|
||||
<OutputType>Exe</OutputType>
|
||||
<PackageId>ConsoleReferenceClient</PackageId>
|
||||
<Company>OPC Foundation</Company>
|
||||
<Description>.NET Console Reference Client</Description>
|
||||
<Copyright>Copyright © 2004-2022 OPC Foundation, Inc</Copyright>
|
||||
<RootNamespace>Quickstarts.ConsoleReferenceClient</RootNamespace>
|
||||
<PackageId>MP.MONO.ADAPTER.OPC</PackageId>
|
||||
<Company>EgalWare</Company>
|
||||
<Description>OPC UA Console Client</Description>
|
||||
<Copyright>Copyright © 2020+ EgalWare</Copyright>
|
||||
<RootNamespace>MP.MONO.ADAPTER.OPC</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(NoHttps)' != 'true' ">
|
||||
@@ -37,7 +37,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Quickstarts.ReferenceClient.Config.xml">
|
||||
<None Update="MP.MONO.ADAPTER.OPC.Config.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
@@ -0,0 +1,45 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(AppTargetFrameWorks)</TargetFrameworks>
|
||||
<AssemblyName>MP.MONO.ADAPTER.OPC</AssemblyName>
|
||||
<OutputType>Exe</OutputType>
|
||||
<PackageId>MP.MONO.ADAPTER.OPC</PackageId>
|
||||
<Company>EgalWare</Company>
|
||||
<Description>OPC UA Console Client</Description>
|
||||
<Copyright>Copyright © 2020+ EgalWare</Copyright>
|
||||
<RootNamespace>MP.MONO.ADAPTER.OPC</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(NoHttps)' != 'true' ">
|
||||
<ProjectReference Include="..\..\Stack\Opc.Ua.Bindings.Https\Opc.Ua.Bindings.Https.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\ConsoleReferenceServer\ConsoleUtils.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||
<PackageReference Include="Mono.Options" Version="6.12.0.148" />
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Serilog.Expressions" Version="3.3.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Stack\Opc.Ua.Core\Opc.Ua.Core.csproj" />
|
||||
<ProjectReference Include="..\..\Libraries\Opc.Ua.Configuration\Opc.Ua.Configuration.csproj" />
|
||||
<ProjectReference Include="..\..\Libraries\Opc.Ua.Client\Opc.Ua.Client.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="MP.MONO.ADAPTER.OPC.Config.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,186 @@
|
||||
/* ========================================================================
|
||||
* Copyright (c) 2005-2021 The OPC Foundation, Inc. All rights reserved.
|
||||
*
|
||||
* OPC Foundation MIT License 1.00
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The complete license agreement can be found here:
|
||||
* http://opcfoundation.org/License/MIT/1.00/
|
||||
* ======================================================================*/
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Opc.Ua;
|
||||
using Opc.Ua.Configuration;
|
||||
|
||||
namespace MP.MONO.ADAPTER.OPC
|
||||
{
|
||||
/// <summary>
|
||||
/// The program.
|
||||
/// </summary>
|
||||
public static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// Main entry point.
|
||||
/// </summary>
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
TextWriter output = Console.Out;
|
||||
output.WriteLine("OPC UA Console Reference Client");
|
||||
|
||||
output.WriteLine("OPC UA library: {0} @ {1} -- {2}",
|
||||
Utils.GetAssemblyBuildNumber(),
|
||||
Utils.GetAssemblyTimestamp().ToString("G", CultureInfo.InvariantCulture),
|
||||
Utils.GetAssemblySoftwareVersion());
|
||||
|
||||
// The application name and config file names
|
||||
var applicationName = "ConsoleReferenceClient";
|
||||
var configSectionName = "Quickstarts.ReferenceClient";
|
||||
var usage = $"Usage: dotnet {applicationName}.dll [OPTIONS]";
|
||||
|
||||
// command line options
|
||||
bool showHelp = false;
|
||||
bool autoAccept = false;
|
||||
bool logConsole = false;
|
||||
bool appLog = false;
|
||||
bool renewCertificate = false;
|
||||
string password = null;
|
||||
int timeout = Timeout.Infinite;
|
||||
|
||||
Mono.Options.OptionSet options = new Mono.Options.OptionSet {
|
||||
usage,
|
||||
{ "h|help", "show this message and exit", h => showHelp = h != null },
|
||||
{ "a|autoaccept", "auto accept certificates (for testing only)", a => autoAccept = a != null },
|
||||
{ "c|console", "log to console", c => logConsole = c != null },
|
||||
{ "l|log", "log app output", c => appLog = c != null },
|
||||
{ "p|password=", "optional password for private key", (string p) => password = p },
|
||||
{ "r|renew", "renew application certificate", r => renewCertificate = r != null },
|
||||
{ "t|timeout=", "timeout in seconds to exit application", (int t) => timeout = t * 1000 },
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// parse command line and set options
|
||||
var extraArg = ConsoleUtils.ProcessCommandLine(output, args, options, ref showHelp, false);
|
||||
|
||||
// connect Url?
|
||||
Uri serverUrl = new Uri("opc.tcp://localhost:62541/Quickstarts/ReferenceServer");
|
||||
if (!string.IsNullOrEmpty(extraArg))
|
||||
{
|
||||
serverUrl = new Uri(extraArg);
|
||||
}
|
||||
|
||||
// log console output to logger
|
||||
if (logConsole && appLog)
|
||||
{
|
||||
output = new LogWriter();
|
||||
}
|
||||
|
||||
// Define the UA Client application
|
||||
ApplicationInstance.MessageDlg = new ApplicationMessageDlg(output);
|
||||
CertificatePasswordProvider PasswordProvider = new CertificatePasswordProvider(password);
|
||||
ApplicationInstance application = new ApplicationInstance {
|
||||
ApplicationName = applicationName,
|
||||
ApplicationType = ApplicationType.Client,
|
||||
ConfigSectionName = configSectionName,
|
||||
CertificatePasswordProvider = PasswordProvider
|
||||
};
|
||||
|
||||
// load the application configuration.
|
||||
var config = await application.LoadApplicationConfiguration(silent: false);
|
||||
|
||||
// setup the logging
|
||||
ConsoleUtils.ConfigureLogging(config, applicationName, logConsole, LogLevel.Information);
|
||||
|
||||
// delete old certificate
|
||||
if (renewCertificate)
|
||||
{
|
||||
await application.DeleteApplicationInstanceCertificate().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// check the application certificate.
|
||||
bool haveAppCertificate = await application.CheckApplicationInstanceCertificate(false, minimumKeySize: 0).ConfigureAwait(false);
|
||||
if (!haveAppCertificate)
|
||||
{
|
||||
throw new ErrorExitException("Application instance certificate invalid!", ExitCode.ErrorCertificate);
|
||||
}
|
||||
|
||||
// wait for timeout or Ctrl-C
|
||||
var quitEvent = ConsoleUtils.CtrlCHandler();
|
||||
|
||||
// connect to a server until application stopped
|
||||
bool quit = false;
|
||||
DateTime start = DateTime.UtcNow;
|
||||
int waitTime = int.MaxValue;
|
||||
do
|
||||
{
|
||||
if (timeout > 0)
|
||||
{
|
||||
waitTime = timeout - (int)DateTime.UtcNow.Subtract(start).TotalMilliseconds;
|
||||
if (waitTime <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// create the UA Client object and connect to configured server.
|
||||
UAClient uaClient = new UAClient(application.ApplicationConfiguration, output, ClientBase.ValidateResponse) {
|
||||
AutoAccept = autoAccept
|
||||
};
|
||||
|
||||
bool connected = await uaClient.ConnectAsync(serverUrl.ToString());
|
||||
if (connected)
|
||||
{
|
||||
// Run tests for available methods.
|
||||
uaClient.ReadNodes();
|
||||
uaClient.WriteNodes();
|
||||
uaClient.Browse();
|
||||
uaClient.CallMethod();
|
||||
|
||||
uaClient.SubscribeToDataChanges();
|
||||
|
||||
// Wait for some DataChange notifications from MonitoredItems
|
||||
quit = quitEvent.WaitOne(Math.Min(30_000, waitTime));
|
||||
|
||||
uaClient.Disconnect();
|
||||
}
|
||||
else
|
||||
{
|
||||
output.WriteLine("Could not connect to server! Retry in 10 seconds or Ctrl-C to quit.");
|
||||
quit = quitEvent.WaitOne(Math.Min(10_000, waitTime));
|
||||
}
|
||||
|
||||
} while (!quit);
|
||||
|
||||
output.WriteLine("\nClient stopped.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
output.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,501 @@
|
||||
/* ========================================================================
|
||||
* Copyright (c) 2005-2020 The OPC Foundation, Inc. All rights reserved.
|
||||
*
|
||||
* OPC Foundation MIT License 1.00
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The complete license agreement can be found here:
|
||||
* http://opcfoundation.org/License/MIT/1.00/
|
||||
* ======================================================================*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Opc.Ua;
|
||||
using Opc.Ua.Client;
|
||||
|
||||
namespace MP.MONO.ADAPTER.OPC
|
||||
{
|
||||
/// <summary>
|
||||
/// OPC UA Client with examples of basic functionality.
|
||||
/// </summary>
|
||||
class UAClient
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the UAClient class.
|
||||
/// </summary>
|
||||
public UAClient(ApplicationConfiguration configuration, TextWriter writer, Action<IList, IList> validateResponse)
|
||||
{
|
||||
m_validateResponse = validateResponse;
|
||||
m_output = writer;
|
||||
m_configuration = configuration;
|
||||
m_configuration.CertificateValidator.CertificateValidation += CertificateValidation;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
/// <summary>
|
||||
/// Gets the client session.
|
||||
/// </summary>
|
||||
public Session Session => m_session;
|
||||
|
||||
/// <summary>
|
||||
/// Auto accept untrusted certificates.
|
||||
/// </summary>
|
||||
public bool AutoAccept { get; set; } = false;
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Creates a session with the UA server
|
||||
/// </summary>
|
||||
public async Task<bool> ConnectAsync(string serverUrl)
|
||||
{
|
||||
if (serverUrl == null) throw new ArgumentNullException(nameof(serverUrl));
|
||||
|
||||
try
|
||||
{
|
||||
if (m_session != null && m_session.Connected == true)
|
||||
{
|
||||
m_output.WriteLine("Session already connected!");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_output.WriteLine("Connecting to... {0}", serverUrl);
|
||||
|
||||
// Get the endpoint by connecting to server's discovery endpoint.
|
||||
// Try to find the first endopint with security.
|
||||
EndpointDescription endpointDescription = CoreClientUtils.SelectEndpoint(m_configuration, serverUrl, true);
|
||||
EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(m_configuration);
|
||||
ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);
|
||||
|
||||
// Create the session
|
||||
Session session = await Session.Create(
|
||||
m_configuration,
|
||||
endpoint,
|
||||
false,
|
||||
false,
|
||||
m_configuration.ApplicationName,
|
||||
30 * 60 * 1000,
|
||||
new UserIdentity(),
|
||||
null
|
||||
);
|
||||
|
||||
// Assign the created session
|
||||
if (session != null && session.Connected)
|
||||
{
|
||||
m_session = session;
|
||||
}
|
||||
|
||||
// Session created successfully.
|
||||
m_output.WriteLine("New Session Created with SessionName = {0}", m_session.SessionName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log Error
|
||||
m_output.WriteLine("Create Session Error : {0}", ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnects the session.
|
||||
/// </summary>
|
||||
public void Disconnect()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (m_session != null)
|
||||
{
|
||||
m_output.WriteLine("Disconnecting...");
|
||||
|
||||
m_session.Close();
|
||||
m_session.Dispose();
|
||||
m_session = null;
|
||||
|
||||
// Log Session Disconnected event
|
||||
m_output.WriteLine("Session Disconnected.");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_output.WriteLine("Session not created!");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log Error
|
||||
m_output.WriteLine($"Disconnect Error : {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a list of nodes from Server
|
||||
/// </summary>
|
||||
public void ReadNodes()
|
||||
{
|
||||
if (m_session == null || m_session.Connected == false)
|
||||
{
|
||||
m_output.WriteLine("Session not connected!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
#region Read a node by calling the Read Service
|
||||
|
||||
// build a list of nodes to be read
|
||||
ReadValueIdCollection nodesToRead = new ReadValueIdCollection()
|
||||
{
|
||||
// Value of ServerStatus
|
||||
new ReadValueId() { NodeId = Variables.Server_ServerStatus, AttributeId = Attributes.Value },
|
||||
// BrowseName of ServerStatus_StartTime
|
||||
new ReadValueId() { NodeId = Variables.Server_ServerStatus_StartTime, AttributeId = Attributes.BrowseName },
|
||||
// Value of ServerStatus_StartTime
|
||||
new ReadValueId() { NodeId = Variables.Server_ServerStatus_StartTime, AttributeId = Attributes.Value }
|
||||
};
|
||||
|
||||
// Read the node attributes
|
||||
m_output.WriteLine("Reading nodes...");
|
||||
|
||||
// Call Read Service
|
||||
m_session.Read(
|
||||
null,
|
||||
0,
|
||||
TimestampsToReturn.Both,
|
||||
nodesToRead,
|
||||
out DataValueCollection resultsValues,
|
||||
out DiagnosticInfoCollection diagnosticInfos);
|
||||
|
||||
// Validate the results
|
||||
m_validateResponse(resultsValues, nodesToRead);
|
||||
|
||||
// Display the results.
|
||||
foreach (DataValue result in resultsValues)
|
||||
{
|
||||
m_output.WriteLine("Read Value = {0} , StatusCode = {1}", result.Value, result.StatusCode);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Read the Value attribute of a node by calling the Session.ReadValue method
|
||||
// Read Server NamespaceArray
|
||||
m_output.WriteLine("Reading Value of NamespaceArray node...");
|
||||
DataValue namespaceArray = m_session.ReadValue(Variables.Server_NamespaceArray);
|
||||
// Display the result
|
||||
m_output.WriteLine($"NamespaceArray Value = {namespaceArray}");
|
||||
#endregion
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log Error
|
||||
m_output.WriteLine($"Read Nodes Error : {ex.Message}.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a list of nodes to the Server
|
||||
/// </summary>
|
||||
public void WriteNodes()
|
||||
{
|
||||
if (m_session == null || m_session.Connected == false)
|
||||
{
|
||||
m_output.WriteLine("Session not connected!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Write the configured nodes
|
||||
WriteValueCollection nodesToWrite = new WriteValueCollection();
|
||||
|
||||
// Int32 Node - Objects\CTT\Scalar\Scalar_Static\Int32
|
||||
WriteValue intWriteVal = new WriteValue();
|
||||
intWriteVal.NodeId = new NodeId("ns=2;s=Scalar_Static_Int32");
|
||||
intWriteVal.AttributeId = Attributes.Value;
|
||||
intWriteVal.Value = new DataValue();
|
||||
intWriteVal.Value.Value = (int)100;
|
||||
nodesToWrite.Add(intWriteVal);
|
||||
|
||||
// Float Node - Objects\CTT\Scalar\Scalar_Static\Float
|
||||
WriteValue floatWriteVal = new WriteValue();
|
||||
floatWriteVal.NodeId = new NodeId("ns=2;s=Scalar_Static_Float");
|
||||
floatWriteVal.AttributeId = Attributes.Value;
|
||||
floatWriteVal.Value = new DataValue();
|
||||
floatWriteVal.Value.Value = (float)100.5;
|
||||
nodesToWrite.Add(floatWriteVal);
|
||||
|
||||
// String Node - Objects\CTT\Scalar\Scalar_Static\String
|
||||
WriteValue stringWriteVal = new WriteValue();
|
||||
stringWriteVal.NodeId = new NodeId("ns=2;s=Scalar_Static_String");
|
||||
stringWriteVal.AttributeId = Attributes.Value;
|
||||
stringWriteVal.Value = new DataValue();
|
||||
stringWriteVal.Value.Value = "String Test";
|
||||
nodesToWrite.Add(stringWriteVal);
|
||||
|
||||
// Write the node attributes
|
||||
StatusCodeCollection results = null;
|
||||
DiagnosticInfoCollection diagnosticInfos;
|
||||
m_output.WriteLine("Writing nodes...");
|
||||
|
||||
// Call Write Service
|
||||
m_session.Write(null,
|
||||
nodesToWrite,
|
||||
out results,
|
||||
out diagnosticInfos);
|
||||
|
||||
// Validate the response
|
||||
m_validateResponse(results, nodesToWrite);
|
||||
|
||||
// Display the results.
|
||||
m_output.WriteLine("Write Results :");
|
||||
|
||||
foreach (StatusCode writeResult in results)
|
||||
{
|
||||
m_output.WriteLine(" {0}", writeResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log Error
|
||||
m_output.WriteLine($"Write Nodes Error : {ex.Message}.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Browse Server nodes
|
||||
/// </summary>
|
||||
public void Browse()
|
||||
{
|
||||
if (m_session == null || m_session.Connected == false)
|
||||
{
|
||||
m_output.WriteLine("Session not connected!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Create a Browser object
|
||||
Browser browser = new Browser(m_session);
|
||||
|
||||
// Set browse parameters
|
||||
browser.BrowseDirection = BrowseDirection.Forward;
|
||||
browser.NodeClassMask = (int)NodeClass.Object | (int)NodeClass.Variable;
|
||||
browser.ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences;
|
||||
|
||||
NodeId nodeToBrowse = ObjectIds.Server;
|
||||
|
||||
// Call Browse service
|
||||
m_output.WriteLine("Browsing {0} node...", nodeToBrowse);
|
||||
ReferenceDescriptionCollection browseResults = browser.Browse(nodeToBrowse);
|
||||
|
||||
// Display the results
|
||||
m_output.WriteLine("Browse returned {0} results:", browseResults.Count);
|
||||
|
||||
foreach (ReferenceDescription result in browseResults)
|
||||
{
|
||||
m_output.WriteLine(" DisplayName = {0}, NodeClass = {1}", result.DisplayName.Text, result.NodeClass);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log Error
|
||||
m_output.WriteLine($"Browse Error : {ex.Message}.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call UA method
|
||||
/// </summary>
|
||||
public void CallMethod()
|
||||
{
|
||||
if (m_session == null || m_session.Connected == false)
|
||||
{
|
||||
m_output.WriteLine("Session not connected!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Define the UA Method to call
|
||||
// Parent node - Objects\CTT\Methods
|
||||
// Method node - Objects\CTT\Methods\Add
|
||||
NodeId objectId = new NodeId("ns=2;s=Methods");
|
||||
NodeId methodId = new NodeId("ns=2;s=Methods_Add");
|
||||
|
||||
// Define the method parameters
|
||||
// Input argument requires a Float and an UInt32 value
|
||||
object[] inputArguments = new object[] { (float)10.5, (uint)10 };
|
||||
IList<object> outputArguments = null;
|
||||
|
||||
// Invoke Call service
|
||||
m_output.WriteLine("Calling UAMethod for node {0} ...", methodId);
|
||||
outputArguments = m_session.Call(objectId, methodId, inputArguments);
|
||||
|
||||
// Display results
|
||||
m_output.WriteLine("Method call returned {0} output argument(s):", outputArguments.Count);
|
||||
|
||||
foreach (var outputArgument in outputArguments)
|
||||
{
|
||||
m_output.WriteLine(" OutputValue = {0}", outputArgument.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_output.WriteLine("Method call error: {0}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create Subscription and MonitoredItems for DataChanges
|
||||
/// </summary>
|
||||
public void SubscribeToDataChanges()
|
||||
{
|
||||
if (m_session == null || m_session.Connected == false)
|
||||
{
|
||||
m_output.WriteLine("Session not connected!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Create a subscription for receiving data change notifications
|
||||
|
||||
// Define Subscription parameters
|
||||
Subscription subscription = new Subscription(m_session.DefaultSubscription);
|
||||
|
||||
subscription.DisplayName = "Console ReferenceClient Subscription";
|
||||
subscription.PublishingEnabled = true;
|
||||
subscription.PublishingInterval = 1000;
|
||||
|
||||
m_session.AddSubscription(subscription);
|
||||
|
||||
// Create the subscription on Server side
|
||||
subscription.Create();
|
||||
m_output.WriteLine("New Subscription created with SubscriptionId = {0}.", subscription.Id);
|
||||
|
||||
// Create MonitoredItems for data changes (Reference Server)
|
||||
|
||||
MonitoredItem intMonitoredItem = new MonitoredItem(subscription.DefaultItem);
|
||||
// Int32 Node - Objects\CTT\Scalar\Simulation\Int32
|
||||
intMonitoredItem.StartNodeId = new NodeId("ns=2;s=Scalar_Simulation_Int32");
|
||||
intMonitoredItem.AttributeId = Attributes.Value;
|
||||
intMonitoredItem.DisplayName = "Int32 Variable";
|
||||
intMonitoredItem.SamplingInterval = 1000;
|
||||
intMonitoredItem.Notification += OnMonitoredItemNotification;
|
||||
|
||||
subscription.AddItem(intMonitoredItem);
|
||||
|
||||
MonitoredItem floatMonitoredItem = new MonitoredItem(subscription.DefaultItem);
|
||||
// Float Node - Objects\CTT\Scalar\Simulation\Float
|
||||
floatMonitoredItem.StartNodeId = new NodeId("ns=2;s=Scalar_Simulation_Float");
|
||||
floatMonitoredItem.AttributeId = Attributes.Value;
|
||||
floatMonitoredItem.DisplayName = "Float Variable";
|
||||
floatMonitoredItem.SamplingInterval = 1000;
|
||||
floatMonitoredItem.Notification += OnMonitoredItemNotification;
|
||||
|
||||
subscription.AddItem(floatMonitoredItem);
|
||||
|
||||
MonitoredItem stringMonitoredItem = new MonitoredItem(subscription.DefaultItem);
|
||||
// String Node - Objects\CTT\Scalar\Simulation\String
|
||||
stringMonitoredItem.StartNodeId = new NodeId("ns=2;s=Scalar_Simulation_String");
|
||||
stringMonitoredItem.AttributeId = Attributes.Value;
|
||||
stringMonitoredItem.DisplayName = "String Variable";
|
||||
stringMonitoredItem.SamplingInterval = 1000;
|
||||
stringMonitoredItem.Notification += OnMonitoredItemNotification;
|
||||
|
||||
subscription.AddItem(stringMonitoredItem);
|
||||
|
||||
// Create the monitored items on Server side
|
||||
subscription.ApplyChanges();
|
||||
m_output.WriteLine("MonitoredItems created for SubscriptionId = {0}.", subscription.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_output.WriteLine("Subscribe error: {0}", ex.Message);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Handle DataChange notifications from Server
|
||||
/// </summary>
|
||||
private void OnMonitoredItemNotification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Log MonitoredItem Notification event
|
||||
MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification;
|
||||
m_output.WriteLine("Notification Received for Variable \"{0}\" and Value = {1}.", monitoredItem.DisplayName, notification.Value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_output.WriteLine("OnMonitoredItemNotification error: {0}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the certificate validation event.
|
||||
/// This event is triggered every time an untrusted certificate is received from the server.
|
||||
/// </summary>
|
||||
private void CertificateValidation(CertificateValidator sender, CertificateValidationEventArgs e)
|
||||
{
|
||||
bool certificateAccepted = false;
|
||||
|
||||
// ****
|
||||
// Implement a custom logic to decide if the certificate should be
|
||||
// accepted or not and set certificateAccepted flag accordingly.
|
||||
// The certificate can be retrieved from the e.Certificate field
|
||||
// ***
|
||||
|
||||
ServiceResult error = e.Error;
|
||||
m_output.WriteLine(error);
|
||||
if (error.StatusCode == StatusCodes.BadCertificateUntrusted && AutoAccept)
|
||||
{
|
||||
certificateAccepted = true;
|
||||
}
|
||||
|
||||
if (certificateAccepted)
|
||||
{
|
||||
m_output.WriteLine("Untrusted Certificate accepted. Subject = {0}", e.Certificate.Subject);
|
||||
e.Accept = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_output.WriteLine("Untrusted Certificate rejected. Subject = {0}", e.Certificate.Subject);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
private ApplicationConfiguration m_configuration;
|
||||
private Session m_session;
|
||||
private readonly TextWriter m_output;
|
||||
private readonly Action<IList, IList> m_validateResponse;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
REM collect a trace using the EventSource provider OPC-UA-Core
|
||||
dotnet tool install --global dotnet-trace
|
||||
dotnet-trace collect --name consolereferenceclient --providers OPC-UA-Core,OPC-UA-Client
|
||||
@@ -0,0 +1,44 @@
|
||||
<Project>
|
||||
<!-- Uncomment to suppress warning that .NET Core 2.1 is used with .NET 6 library. -->
|
||||
<!--
|
||||
<PropertyGroup>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
</PropertyGroup>
|
||||
-->
|
||||
<Choose>
|
||||
<!-- Note: .NET Core 2.x is end of life, removed netcoreapp2.1 from any target. -->
|
||||
<!-- Visual Studio 2022, supports .NET Framework 4.6.2, .NET Core 3.1 and .NET 6 -->
|
||||
<When Condition="'$(VisualStudioVersion)' == '17.0'">
|
||||
<PropertyGroup>
|
||||
<AppTargetFrameworks>net6.0;netcoreapp3.1;net462</AppTargetFrameworks>
|
||||
<AppTargetFramework>net6.0</AppTargetFramework>
|
||||
<TestsTargetFrameworks>net462;netcoreapp3.1;net6.0</TestsTargetFrameworks>
|
||||
<LibTargetFrameworks>net462;netstandard2.0;netstandard2.1;net6.0</LibTargetFrameworks>
|
||||
<LibxTargetFrameworks>net462;netstandard2.1;net6.0</LibxTargetFrameworks>
|
||||
<HttpsTargetFrameworks>net462;netstandard2.0;netcoreapp3.1;net6.0</HttpsTargetFrameworks>
|
||||
</PropertyGroup>
|
||||
</When>
|
||||
<!-- Visual Studio 2019, supports .NET Framework 4.6.2 and .NET Core 3.1 -->
|
||||
<When Condition="'$(VisualStudioVersion)' == '16.0'">
|
||||
<PropertyGroup>
|
||||
<AppTargetFrameworks>netcoreapp3.1;net462</AppTargetFrameworks>
|
||||
<AppTargetFramework>netcoreapp3.1</AppTargetFramework>
|
||||
<TestsTargetFrameworks>net462;netcoreapp3.1</TestsTargetFrameworks>
|
||||
<LibTargetFrameworks>net462;netstandard2.0;netstandard2.1</LibTargetFrameworks>
|
||||
<LibxTargetFrameworks>net462;netstandard2.1</LibxTargetFrameworks>
|
||||
<HttpsTargetFrameworks>net462;netstandard2.0;netcoreapp3.1</HttpsTargetFrameworks>
|
||||
</PropertyGroup>
|
||||
</When>
|
||||
<!-- Visual Studio 2017 and earlier, support only .NET Framework 4.6.2 because .NET Core 2.x is end of life. -->
|
||||
<Otherwise>
|
||||
<PropertyGroup>
|
||||
<AppTargetFrameworks>net462</AppTargetFrameworks>
|
||||
<AppTargetFramework>net462</AppTargetFramework>
|
||||
<TestsTargetFrameworks>net462</TestsTargetFrameworks>
|
||||
<LibTargetFrameworks>net462</LibTargetFrameworks>
|
||||
<LibxTargetFrameworks>net462</LibxTargetFrameworks>
|
||||
<HttpsTargetFrameworks>net462</HttpsTargetFrameworks>
|
||||
</PropertyGroup>
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
</Project>
|
||||
@@ -15,8 +15,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MP.MONO.DECODER", "MP.MONO.
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MP.MONO.ANALYZER", "MP.MONO.ANALYZER\MP.MONO.ANALYZER.csproj", "{4C9BEAED-1A33-41A7-B9D6-7C173A43FDB8}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MP.MONO.ADAPTER", "MP.MONO.ADAPTER\MP.MONO.ADAPTER.csproj", "{873736BA-CDB6-4CE5-A340-6D904C11C07C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -99,18 +97,6 @@ Global
|
||||
{4C9BEAED-1A33-41A7-B9D6-7C173A43FDB8}.Release|x64.Build.0 = Release|x64
|
||||
{4C9BEAED-1A33-41A7-B9D6-7C173A43FDB8}.Release|x86.ActiveCfg = Release|x86
|
||||
{4C9BEAED-1A33-41A7-B9D6-7C173A43FDB8}.Release|x86.Build.0 = Release|x86
|
||||
{873736BA-CDB6-4CE5-A340-6D904C11C07C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{873736BA-CDB6-4CE5-A340-6D904C11C07C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{873736BA-CDB6-4CE5-A340-6D904C11C07C}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{873736BA-CDB6-4CE5-A340-6D904C11C07C}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{873736BA-CDB6-4CE5-A340-6D904C11C07C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{873736BA-CDB6-4CE5-A340-6D904C11C07C}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{873736BA-CDB6-4CE5-A340-6D904C11C07C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{873736BA-CDB6-4CE5-A340-6D904C11C07C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{873736BA-CDB6-4CE5-A340-6D904C11C07C}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{873736BA-CDB6-4CE5-A340-6D904C11C07C}.Release|x64.Build.0 = Release|Any CPU
|
||||
{873736BA-CDB6-4CE5-A340-6D904C11C07C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{873736BA-CDB6-4CE5-A340-6D904C11C07C}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Platforms>AnyCPU;x86;x64</Platforms>
|
||||
<Version>1.12206.1319</Version>
|
||||
<Version>1.12206.1411</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>MAPO-MONO</i>
|
||||
<h4>Version: 1.12206.1319</h4>
|
||||
<h4>Version: 1.12206.1411</h4>
|
||||
<br /> Release Note:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.12206.1319
|
||||
1.12206.1411
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>1.12206.1319</version>
|
||||
<version>1.12206.1411</version>
|
||||
<url>http://nexus.steamware.net/repository/SWS/MP.MONO.UI/stable/LAST/MP.Mon.zip</url>
|
||||
<changelog>http://nexus.steamware.net/repository/SWS/MP.MONO.UI/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
Reference in New Issue
Block a user