From 091872422572949b98f852d05c309f27aae33f4d Mon Sep 17 00:00:00 2001 From: luosheng Date: Wed, 17 May 2023 11:21:07 +0800 Subject: [PATCH] Revert OPC --- Libraries/h-opc/ClientUtils.cs | 100 --- Libraries/h-opc/Common/ClientExtensions.cs | 34 - Libraries/h-opc/Common/IClient.cs | 103 --- Libraries/h-opc/Common/Node.cs | 46 -- Libraries/h-opc/Common/OpcException.cs | 70 -- Libraries/h-opc/Common/OpcStatus.cs | 18 - Libraries/h-opc/Common/Quality.cs | 28 - Libraries/h-opc/Common/ReadEvent.cs | 33 - Libraries/h-opc/NodeExtensions.cs | 24 - Libraries/h-opc/UaClient.cs | 646 ------------------ Libraries/h-opc/UaClientOptions.cs | 120 ---- Libraries/h-opc/UaNode.cs | 29 - Libraries/h-opc/h-opc.csproj | 30 - .../AddressTranslatorNA200H.cs | 2 +- .../Modbus.Net.Modbus.NA200H.csproj | 3 +- ...Modbus.Net.Modbus.SelfDefinedSample.csproj | 5 +- .../AddressTranslatorModbus.cs | 2 +- Modbus.Net/Modbus.Net.Modbus/Interfaces.cs | 2 +- .../Modbus.Net.Modbus.csproj | 3 +- .../ModbusAsciiProtocolLinker.cs | 3 +- .../Modbus.Net.Modbus/ModbusProtocol.cs | 20 +- Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs | 24 +- Modbus.Net/Modbus.Net.OPC/ClientExtend.cs | 22 +- .../Modbus.Net.OPC/FBox/FBoxOpcDaManchine.cs | 61 ++ .../Modbus.Net.OPC/Modbus.Net.OPC.csproj | 18 +- Modbus.Net/Modbus.Net.OPC/OpcConnector.cs | 17 +- Modbus.Net/Modbus.Net.OPC/OpcDaConnector.cs | 42 ++ Modbus.Net/Modbus.Net.OPC/OpcDaMachine.cs | 74 ++ Modbus.Net/Modbus.Net.OPC/OpcDaProtocal.cs | 38 ++ .../Modbus.Net.OPC/OpcDaProtocalLinker.cs | 28 + Modbus.Net/Modbus.Net.OPC/OpcDaUtility.cs | 18 + .../AddressTranslatorSiemens.cs | 2 +- .../Modbus.Net.Siemens.csproj | 3 +- .../SiemensPpiProtocolLinker.cs | 8 +- Modbus.Net/Modbus.Net.sln | 6 - .../Configuration/ConfigurationReader.cs | 4 +- .../Modbus.Net/Configuration/MachineReader.cs | 5 +- Modbus.Net/Modbus.Net/Helper/EnumHelper.cs | 65 ++ .../Modbus.Net/Linker/ComProtocolLinker.cs | 12 +- .../Machine/MachineMethodReflectionCall.cs | 8 +- Modbus.Net/Modbus.Net/Modbus.Net.csproj | 4 +- .../Utility/UtilityMethodReflectionCall.cs | 8 +- 42 files changed, 431 insertions(+), 1357 deletions(-) delete mode 100644 Libraries/h-opc/ClientUtils.cs delete mode 100644 Libraries/h-opc/Common/ClientExtensions.cs delete mode 100644 Libraries/h-opc/Common/IClient.cs delete mode 100644 Libraries/h-opc/Common/Node.cs delete mode 100644 Libraries/h-opc/Common/OpcException.cs delete mode 100644 Libraries/h-opc/Common/OpcStatus.cs delete mode 100644 Libraries/h-opc/Common/Quality.cs delete mode 100644 Libraries/h-opc/Common/ReadEvent.cs delete mode 100644 Libraries/h-opc/NodeExtensions.cs delete mode 100644 Libraries/h-opc/UaClient.cs delete mode 100644 Libraries/h-opc/UaClientOptions.cs delete mode 100644 Libraries/h-opc/UaNode.cs delete mode 100644 Libraries/h-opc/h-opc.csproj create mode 100644 Modbus.Net/Modbus.Net.OPC/FBox/FBoxOpcDaManchine.cs create mode 100644 Modbus.Net/Modbus.Net.OPC/OpcDaConnector.cs create mode 100644 Modbus.Net/Modbus.Net.OPC/OpcDaMachine.cs create mode 100644 Modbus.Net/Modbus.Net.OPC/OpcDaProtocal.cs create mode 100644 Modbus.Net/Modbus.Net.OPC/OpcDaProtocalLinker.cs create mode 100644 Modbus.Net/Modbus.Net.OPC/OpcDaUtility.cs create mode 100644 Modbus.Net/Modbus.Net/Helper/EnumHelper.cs diff --git a/Libraries/h-opc/ClientUtils.cs b/Libraries/h-opc/ClientUtils.cs deleted file mode 100644 index 493cc48..0000000 --- a/Libraries/h-opc/ClientUtils.cs +++ /dev/null @@ -1,100 +0,0 @@ -using Opc.Ua; -using Opc.Ua.Client; -using System; -using System.Linq; - -namespace Hylasoft.Opc.Ua -{ - /// - /// List of static utility methods - /// - internal static class ClientUtils - { - // TODO I didn't write these methods. I should rewrite it once I understand whtat it does, beacuse it looks crazy - - public static EndpointDescription SelectEndpoint(Uri discoveryUrl, bool useSecurity) - { - var configuration = EndpointConfiguration.Create(); - configuration.OperationTimeout = 5000; - EndpointDescription endpointDescription1 = null; - using (var discoveryClient = DiscoveryClient.Create(discoveryUrl, configuration)) - { - var endpoints = discoveryClient.GetEndpoints(null); - foreach (var endpointDescription2 in endpoints.Where(endpointDescription2 => endpointDescription2.EndpointUrl.StartsWith(discoveryUrl.Scheme))) - { - if (useSecurity) - { - if (endpointDescription2.SecurityMode == MessageSecurityMode.None) - continue; - } - else if (endpointDescription2.SecurityMode != MessageSecurityMode.None) - continue; - if (endpointDescription1 == null) - endpointDescription1 = endpointDescription2; - if (endpointDescription2.SecurityLevel > endpointDescription1.SecurityLevel) - endpointDescription1 = endpointDescription2; - } - if (endpointDescription1 == null) - { - if (endpoints.Count > 0) - endpointDescription1 = endpoints[0]; - } - } - var uri = Utils.ParseUri(endpointDescription1.EndpointUrl); - if (uri != null && uri.Scheme == discoveryUrl.Scheme) - endpointDescription1.EndpointUrl = new UriBuilder(uri) - { - Host = discoveryUrl.DnsSafeHost, - Port = discoveryUrl.Port - }.ToString(); - return endpointDescription1; - } - - public static ReferenceDescriptionCollection Browse(Session session, NodeId nodeId) - { - var desc = new BrowseDescription - { - NodeId = nodeId, - BrowseDirection = BrowseDirection.Forward, - IncludeSubtypes = true, - NodeClassMask = 0U, - ResultMask = 63U, - }; - return Browse(session, desc, true); - } - - public static ReferenceDescriptionCollection Browse(Session session, BrowseDescription nodeToBrowse, bool throwOnError) - { - try - { - var descriptionCollection = new ReferenceDescriptionCollection(); - var nodesToBrowse = new BrowseDescriptionCollection { nodeToBrowse }; - BrowseResultCollection results; - DiagnosticInfoCollection diagnosticInfos; - session.Browse(null, null, 0U, nodesToBrowse, out results, out diagnosticInfos); - ClientBase.ValidateResponse(results, nodesToBrowse); - ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToBrowse); - while (!StatusCode.IsBad(results[0].StatusCode)) - { - for (var index = 0; index < results[0].References.Count; ++index) - descriptionCollection.Add(results[0].References[index]); - if (results[0].References.Count == 0 || results[0].ContinuationPoint == null) - return descriptionCollection; - var continuationPoints = new ByteStringCollection(); - continuationPoints.Add(results[0].ContinuationPoint); - session.BrowseNext(null, false, continuationPoints, out results, out diagnosticInfos); - ClientBase.ValidateResponse(results, continuationPoints); - ClientBase.ValidateDiagnosticInfos(diagnosticInfos, continuationPoints); - } - throw new ServiceResultException(results[0].StatusCode); - } - catch (Exception ex) - { - if (throwOnError) - throw new ServiceResultException(ex, 2147549184U); - return null; - } - } - } -} - diff --git a/Libraries/h-opc/Common/ClientExtensions.cs b/Libraries/h-opc/Common/ClientExtensions.cs deleted file mode 100644 index 6ff6549..0000000 --- a/Libraries/h-opc/Common/ClientExtensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; - -namespace Hylasoft.Opc.Common -{ - /// - /// Useful extension methods for OPC Clients - /// - public static class ClientExtensions - { - /// - /// Reads a tag from the OPC. If for whatever reason the read fails (Tag doesn't exist, server not available) returns a default value - /// - /// the opc client to use for the read - /// The fully qualified identifier of the tag - /// the default value to read if the read fails - /// - public static ReadEvent ReadOrdefault(this IClient client, string tag, T defaultValue = default(T)) - { - try - { - return client.Read(tag); - } - catch (OpcException) - { - var readEvent = new ReadEvent(); - readEvent.Quality = Quality.Good; - readEvent.Value = defaultValue; - readEvent.SourceTimestamp = DateTime.Now; - readEvent.ServerTimestamp = DateTime.Now; - return readEvent; - } - } - } -} \ No newline at end of file diff --git a/Libraries/h-opc/Common/IClient.cs b/Libraries/h-opc/Common/IClient.cs deleted file mode 100644 index f09d405..0000000 --- a/Libraries/h-opc/Common/IClient.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Hylasoft.Opc.Common -{ - /// - /// Client interface to perform basic Opc tasks, like discovery, monitoring, reading/writing tags, - /// - public interface IClient : IDisposable - where TNode : Node - { - /// - /// Connect the client to the OPC Server - /// - Task Connect(); - - /// - /// Gets the current status of the OPC Client - /// - OpcStatus Status { get; } - - /// - /// Gets the datatype of an OPC tag - /// - /// Tag to get datatype of - /// System Type - System.Type GetDataType(string tag); - - /// - /// Read a tag - /// - /// The type of tag to read - /// The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name. - /// E.g: the tag `foo.bar` reads the tag `bar` on the folder `foo` - /// The value retrieved from the OPC - ReadEvent Read(string tag); - - /// - /// Write a value on the specified opc tag - /// - /// The type of tag to write on - /// The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name. - /// E.g: the tag `foo.bar` writes on the tag `bar` on the folder `foo` - /// - void Write(string tag, T item); - - /// - /// Monitor the specified tag for changes - /// - /// the type of tag to monitor - /// The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name. - /// E.g: the tag `foo.bar` monitors the tag `bar` on the folder `foo` - /// the callback to execute when the value is changed. - /// The first parameter is the new value of the node, the second is an `unsubscribe` function to unsubscribe the callback - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an async method.")] - void Monitor(string tag, Action, Action> callback); - - /// - /// Finds a node on the Opc Server - /// - /// The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name. - /// E.g: the tag `foo.bar` finds the tag `bar` on the folder `foo` - /// If there is a tag, it returns it, otherwise it throws an - TNode FindNode(string tag); - - /// - /// Gets the root node of the server - /// - TNode RootNode { get; } - - /// - /// Explore a folder on the Opc Server - /// - /// The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name. - /// E.g: the tag `foo.bar` finds the sub nodes of `bar` on the folder `foo` - /// The list of sub-nodes - IEnumerable ExploreFolder(string tag); - - /// - /// Read a tag asynchronusly - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an async method.")] - Task> ReadAsync(string tag); - - /// - /// Write a value on the specified opc tag asynchronously - /// - Task WriteAsync(string tag, T item); - - /// - /// Finds a node on the Opc Server asynchronously - /// - Task FindNodeAsync(string tag); - - /// - /// Explore a folder on the Opc Server asynchronously - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "Task")] - Task> ExploreFolderAsync(string tag); - } -} \ No newline at end of file diff --git a/Libraries/h-opc/Common/Node.cs b/Libraries/h-opc/Common/Node.cs deleted file mode 100644 index ae6750f..0000000 --- a/Libraries/h-opc/Common/Node.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace Hylasoft.Opc.Common -{ - /// - /// Base class representing a node on the OPC server - /// - public abstract class Node - { - /// - /// Gets the displayed name of the node - /// - public string Name { get; protected set; } - - /// - /// Gets the dot-separated fully qualified tag of the node - /// - public string Tag { get; protected set; } - - /// - /// Gets the parent node. If the node is root, returns null - /// - public Node Parent { get; private set; } - - /// - /// Creates a new node - /// - /// the name of the node - /// The parent node - protected Node(string name, Node parent = null) - { - Name = name; - Parent = parent; - if (parent != null && !string.IsNullOrEmpty(parent.Tag)) - Tag = parent.Tag + '.' + name; - else - Tag = name; - } - - /// - /// Overrides ToString() - /// - public override string ToString() - { - return Tag; - } - } -} diff --git a/Libraries/h-opc/Common/OpcException.cs b/Libraries/h-opc/Common/OpcException.cs deleted file mode 100644 index 67e0ae7..0000000 --- a/Libraries/h-opc/Common/OpcException.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Opc.Ua; -using System; -using System.Runtime.Serialization; - -namespace Hylasoft.Opc.Common -{ - /// - /// Identifies an exception occurred during OPC Communication - /// - [Serializable] - public class OpcException : Exception - { - /// - /// Initialize a new instance of the OpcException class - /// - public OpcException() - { - } - - /// - /// Initialize a new instance of the OpcException class - /// - public OpcException(string message) - : base(message) - { - } - - /// - /// Returns an (optional) associated OPC UA StatusCode for the exception. - /// - public StatusCode? Status { get; private set; } - - /// - /// Initialize a new instance of the OpcException class - /// - public OpcException(string message, StatusCode status) - : base(message) - { - Status = status; - } - - /// - /// Initialize a new instance of the OpcException class - /// - public OpcException(string message, Exception inner) - : base(message, inner) - { - } - - /// - /// Initialize a new instance of the OpcException class - /// - protected OpcException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Sets the System.Runtime.Serialization.SerializationInfo with information about the exception. - /// - /// The System.Runtime.Serialization.SerializationInfo that holds the serialized object data about the exception being thrown. - /// The System.Runtime.Serialization.StreamingContext that contains contextual information about the source or destination. - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - } - - } - -} \ No newline at end of file diff --git a/Libraries/h-opc/Common/OpcStatus.cs b/Libraries/h-opc/Common/OpcStatus.cs deleted file mode 100644 index 3534d4a..0000000 --- a/Libraries/h-opc/Common/OpcStatus.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Hylasoft.Opc.Common -{ - /// - /// Identifies the status of an OPC connector - /// - public enum OpcStatus - { - /// - /// The client is not connected - /// - NotConnected, - - /// - /// The client is connected - /// - Connected - } -} \ No newline at end of file diff --git a/Libraries/h-opc/Common/Quality.cs b/Libraries/h-opc/Common/Quality.cs deleted file mode 100644 index b9bfcc9..0000000 --- a/Libraries/h-opc/Common/Quality.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.ComponentModel; - -namespace Hylasoft.Opc.Common -{ - /// - /// Represents the quality of the value captured - /// - public enum Quality - { - /// - /// Quality: Unknown, the value of the quality could not be inferred by the library - /// - [Description("Unknown")] - Unknown, - - /// - /// Quality: Good - /// - [Description("Good")] - Good, - - /// - /// Quality: Bad - /// - [Description("Bad")] - Bad - } -} \ No newline at end of file diff --git a/Libraries/h-opc/Common/ReadEvent.cs b/Libraries/h-opc/Common/ReadEvent.cs deleted file mode 100644 index 78e8ffa..0000000 --- a/Libraries/h-opc/Common/ReadEvent.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.ComponentModel; - -namespace Hylasoft.Opc.Common -{ - /// - /// Base class representing a monitor event on the OPC server - /// - /// - public class ReadEvent - { - /// - /// Gets the value that was read from the server - /// - public T Value { get; set; } - - /// - /// Gets the quality of the signal from the server - /// - [DefaultValue(Common.Quality.Unknown)] - public Quality Quality { get; set; } - - /// - /// Gets the source timestamp on when the event ocurred - /// - public DateTime SourceTimestamp { get; set; } - - /// - /// Gets the server timestamp on when the event ocurred - /// - public DateTime ServerTimestamp { get; set; } - } -} diff --git a/Libraries/h-opc/NodeExtensions.cs b/Libraries/h-opc/NodeExtensions.cs deleted file mode 100644 index 8913f4b..0000000 --- a/Libraries/h-opc/NodeExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Hylasoft.Opc.Common; -using OpcF = Opc.Ua; - -namespace Hylasoft.Opc.Ua -{ - /// - /// Class with extension methods for OPC UA - /// - public static class NodeExtensions - { - /// - /// Converts an OPC Foundation node to an Hylasoft OPC UA Node - /// - /// The node to convert - /// the parent node (optional) - /// - internal static UaNode ToHylaNode(this OpcF.ReferenceDescription node, Node parent = null) - { - var name = node.DisplayName.ToString(); - var nodeId = node.NodeId.ToString(); - return new UaNode(name, nodeId, parent); - } - } -} \ No newline at end of file diff --git a/Libraries/h-opc/UaClient.cs b/Libraries/h-opc/UaClient.cs deleted file mode 100644 index 29b6100..0000000 --- a/Libraries/h-opc/UaClient.cs +++ /dev/null @@ -1,646 +0,0 @@ -using Hylasoft.Opc.Common; -using Opc.Ua; -using Opc.Ua.Client; -using Opc.Ua.Configuration; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Hylasoft.Opc.Ua -{ - /// - /// Client Implementation for UA - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", - Justification = "Doesn't make sense to split this class")] - public class UaClient : IClient - { - private readonly UaClientOptions _options = new UaClientOptions(); - private readonly Uri _serverUrl; - private Session _session; - - private readonly IDictionary _nodesCache = new Dictionary(); - private readonly IDictionary> _folderCache = new Dictionary>(); - - /// - /// Creates a server object - /// - /// the url of the server to connect to - public UaClient(Uri serverUrl) - { - _serverUrl = serverUrl; - Status = OpcStatus.NotConnected; - } - - /// - /// Creates a server object - /// - /// the url of the server to connect to - /// custom options to use with ua client - public UaClient(Uri serverUrl, UaClientOptions options) - { - _serverUrl = serverUrl; - _options = options; - Status = OpcStatus.NotConnected; - } - - /// - /// Options to configure the UA client session - /// - public UaClientOptions Options - { - get { return _options; } - } - - /// - /// OPC Foundation underlying session object - /// - protected Session Session - { - get - { - return _session; - } - } - - private void PostInitializeSession() - { - var node = _session.NodeCache.Find(ObjectIds.ObjectsFolder); - RootNode = new UaNode(string.Empty, node.NodeId.ToString()); - AddNodeToCache(RootNode); - Status = OpcStatus.Connected; - } - - /// - /// Connect the client to the OPC Server - /// - public async Task Connect() - { - if (Status == OpcStatus.Connected) - return; - _session = await InitializeSession(_serverUrl); - _session.KeepAlive += SessionKeepAlive; - _session.SessionClosing += SessionClosing; - PostInitializeSession(); - } - - /// - /// Gets the datatype of an OPC tag - /// - /// Tag to get datatype of - /// System Type - public System.Type GetDataType(string tag) - { - var nodesToRead = BuildReadValueIdCollection(tag, Attributes.Value); - DataValueCollection results; - DiagnosticInfoCollection diag; - _session.Read( - requestHeader: null, - maxAge: 0, - timestampsToReturn: TimestampsToReturn.Neither, - nodesToRead: nodesToRead, - results: out results, - diagnosticInfos: out diag); - var type = results[0].WrappedValue.TypeInfo.BuiltInType; - return System.Type.GetType("System." + type.ToString()); - } - - private void SessionKeepAlive(ISession session, KeepAliveEventArgs e) - { - if (e.CurrentState != ServerState.Running) - { - if (Status == OpcStatus.Connected) - { - Status = OpcStatus.NotConnected; - NotifyServerConnectionLost(); - } - } - else if (e.CurrentState == ServerState.Running) - { - if (Status == OpcStatus.NotConnected) - { - Status = OpcStatus.Connected; - NotifyServerConnectionRestored(); - } - } - } - - private void SessionClosing(object sender, EventArgs e) - { - Status = OpcStatus.NotConnected; - NotifyServerConnectionLost(); - } - - - /// - /// Reconnect the OPC session - /// - public void ReConnect() - { - Status = OpcStatus.NotConnected; - _session.Reconnect(); - Status = OpcStatus.Connected; - } - - /// - /// Create a new OPC session, based on the current session parameters. - /// - public void RecreateSession() - { - Status = OpcStatus.NotConnected; - _session = Session.Recreate(_session); - PostInitializeSession(); - } - - - /// - /// Gets the current status of the OPC Client - /// - public OpcStatus Status { get; private set; } - - - private ReadValueIdCollection BuildReadValueIdCollection(string tag, uint attributeId) - { - var n = FindNode(tag, RootNode); - var readValue = new ReadValueId - { - NodeId = n.NodeId, - AttributeId = attributeId - }; - return new ReadValueIdCollection { readValue }; - } - - /// - /// Read a tag - /// - /// The type of tag to read - /// The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name. - /// E.g: the tag `foo.bar` reads the tag `bar` on the folder `foo` - /// The value retrieved from the OPC - public ReadEvent Read(string tag) - { - var nodesToRead = BuildReadValueIdCollection(tag, Attributes.Value); - DataValueCollection results; - DiagnosticInfoCollection diag; - _session.Read( - requestHeader: null, - maxAge: 0, - timestampsToReturn: TimestampsToReturn.Neither, - nodesToRead: nodesToRead, - results: out results, - diagnosticInfos: out diag); - var val = results[0]; - - var readEvent = new ReadEvent(); - readEvent.Value = (T)val.Value; - readEvent.SourceTimestamp = val.SourceTimestamp; - readEvent.ServerTimestamp = val.ServerTimestamp; - if (StatusCode.IsGood(val.StatusCode)) readEvent.Quality = Quality.Good; - if (StatusCode.IsBad(val.StatusCode)) readEvent.Quality = Quality.Bad; - return readEvent; - } - - - /// - /// Read a tag asynchronously - /// - /// The type of tag to read - /// The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name. - /// E.g: the tag `foo.bar` reads the tag `bar` on the folder `foo` - /// The value retrieved from the OPC - public Task> ReadAsync(string tag) - { - var nodesToRead = BuildReadValueIdCollection(tag, Attributes.Value); - - // Wrap the ReadAsync logic in a TaskCompletionSource, so we can use C# async/await syntax to call it: - var taskCompletionSource = new TaskCompletionSource>(); - _session.BeginRead( - requestHeader: null, - maxAge: 0, - timestampsToReturn: TimestampsToReturn.Neither, - nodesToRead: nodesToRead, - callback: ar => - { - DataValueCollection results; - DiagnosticInfoCollection diag; - var response = _session.EndRead( - result: ar, - results: out results, - diagnosticInfos: out diag); - - try - { - CheckReturnValue(response.ServiceResult); - var val = results[0]; - var readEvent = new ReadEvent(); - readEvent.Value = (T)val.Value; - readEvent.SourceTimestamp = val.SourceTimestamp; - readEvent.ServerTimestamp = val.ServerTimestamp; - if (StatusCode.IsGood(val.StatusCode)) readEvent.Quality = Quality.Good; - if (StatusCode.IsBad(val.StatusCode)) readEvent.Quality = Quality.Bad; - taskCompletionSource.TrySetResult(readEvent); - } - catch (Exception ex) - { - taskCompletionSource.TrySetException(ex); - } - }, - asyncState: null); - - return taskCompletionSource.Task; - } - - - private WriteValueCollection BuildWriteValueCollection(string tag, uint attributeId, object dataValue) - { - var n = FindNode(tag, RootNode); - var writeValue = new WriteValue - { - NodeId = n.NodeId, - AttributeId = attributeId, - Value = { Value = dataValue } - }; - return new WriteValueCollection { writeValue }; - } - - /// - /// Write a value on the specified opc tag - /// - /// The type of tag to write on - /// The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name. - /// E.g: the tag `foo.bar` writes on the tag `bar` on the folder `foo` - /// The value for the item to write - public void Write(string tag, T item) - { - var nodesToWrite = BuildWriteValueCollection(tag, Attributes.Value, item); - - StatusCodeCollection results; - DiagnosticInfoCollection diag; - _session.Write( - requestHeader: null, - nodesToWrite: nodesToWrite, - results: out results, - diagnosticInfos: out diag); - - CheckReturnValue(results[0]); - } - - /// - /// Write a value on the specified opc tag asynchronously - /// - /// The type of tag to write on - /// The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name. - /// E.g: the tag `foo.bar` writes on the tag `bar` on the folder `foo` - /// The value for the item to write - public Task WriteAsync(string tag, T item) - { - var nodesToWrite = BuildWriteValueCollection(tag, Attributes.Value, item); - - // Wrap the WriteAsync logic in a TaskCompletionSource, so we can use C# async/await syntax to call it: - var taskCompletionSource = new TaskCompletionSource(); - _session.BeginWrite( - requestHeader: null, - nodesToWrite: nodesToWrite, - callback: ar => - { - StatusCodeCollection results; - DiagnosticInfoCollection diag; - var response = _session.EndWrite( - result: ar, - results: out results, - diagnosticInfos: out diag); - try - { - CheckReturnValue(response.ServiceResult); - CheckReturnValue(results[0]); - taskCompletionSource.SetResult(response.ServiceResult); - } - catch (Exception ex) - { - taskCompletionSource.TrySetException(ex); - } - }, - asyncState: null); - return taskCompletionSource.Task; - } - - - /// - /// Monitor the specified tag for changes - /// - /// the type of tag to monitor - /// The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name. - /// E.g: the tag `foo.bar` monitors the tag `bar` on the folder `foo` - /// the callback to execute when the value is changed. - /// The first parameter is a MonitorEvent object which represents the data point, the second is an `unsubscribe` function to unsubscribe the callback - public void Monitor(string tag, Action, Action> callback) - { - var node = FindNode(tag); - - var sub = new Subscription - { - PublishingInterval = _options.DefaultMonitorInterval, - PublishingEnabled = true, - LifetimeCount = _options.SubscriptionLifetimeCount, - KeepAliveCount = _options.SubscriptionKeepAliveCount, - DisplayName = tag, - Priority = byte.MaxValue - }; - - var item = new MonitoredItem - { - StartNodeId = node.NodeId, - AttributeId = Attributes.Value, - DisplayName = tag, - SamplingInterval = _options.DefaultMonitorInterval - }; - sub.AddItem(item); - _session.AddSubscription(sub); - sub.Create(); - sub.ApplyChanges(); - - item.Notification += (monitoredItem, args) => - { - var p = (MonitoredItemNotification)args.NotificationValue; - var t = p.Value.WrappedValue.Value; - Action unsubscribe = () => - { - sub.RemoveItems(sub.MonitoredItems); - sub.Delete(true); - _session.RemoveSubscription(sub); - sub.Dispose(); - }; - - var monitorEvent = new ReadEvent(); - monitorEvent.Value = (T)t; - monitorEvent.SourceTimestamp = p.Value.SourceTimestamp; - monitorEvent.ServerTimestamp = p.Value.ServerTimestamp; - if (StatusCode.IsGood(p.Value.StatusCode)) monitorEvent.Quality = Quality.Good; - if (StatusCode.IsBad(p.Value.StatusCode)) monitorEvent.Quality = Quality.Bad; - callback(monitorEvent, unsubscribe); - }; - } - - /// - /// Explore a folder on the Opc Server - /// - /// The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name. - /// E.g: the tag `foo.bar` finds the sub nodes of `bar` on the folder `foo` - /// The list of sub-nodes - public IEnumerable ExploreFolder(string tag) - { - IList nodes; - _folderCache.TryGetValue(tag, out nodes); - if (nodes != null) - return nodes; - - var folder = FindNode(tag); - nodes = ClientUtils.Browse(_session, folder.NodeId) - .GroupBy(n => n.NodeId) //this is to select distinct - .Select(n => n.First()) - .Where(n => n.NodeClass == NodeClass.Variable || n.NodeClass == NodeClass.Object) - .Select(n => n.ToHylaNode(folder)) - .ToList(); - - //add nodes to cache - if (!_folderCache.ContainsKey(tag)) - _folderCache.Add(tag, nodes); - foreach (var node in nodes) - AddNodeToCache(node); - - return nodes; - } - - /// - /// Explores a folder asynchronously - /// - public async Task> ExploreFolderAsync(string tag) - { - return await Task.Run(() => ExploreFolder(tag)); - } - - /// - /// Finds a node on the Opc Server - /// - /// The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name. - /// E.g: the tag `foo.bar` finds the tag `bar` on the folder `foo` - /// If there is a tag, it returns it, otherwise it throws an - public UaNode FindNode(string tag) - { - // if the tag already exists in cache, return it - if (_nodesCache.ContainsKey(tag)) - return _nodesCache[tag]; - - // try to find the tag otherwise - var found = FindNode(tag, RootNode); - if (found != null) - { - AddNodeToCache(found); - return found; - } - - // throws an exception if not found - throw new OpcException(string.Format("The tag \"{0}\" doesn't exist on the Server", tag)); - } - - /// - /// Find node asynchronously - /// - public async Task FindNodeAsync(string tag) - { - return await Task.Run(() => FindNode(tag)); - } - - /// - /// Gets the root node of the server - /// - public UaNode RootNode { get; private set; } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - if (_session != null) - { - _session.RemoveSubscriptions(_session.Subscriptions.ToList()); - _session.Close(); - _session.Dispose(); - } - GC.SuppressFinalize(this); - } - - private void CheckReturnValue(StatusCode status) - { - if (!StatusCode.IsGood(status)) - throw new OpcException(string.Format("Invalid response from the server. (Response Status: {0})", status), status); - } - - /// - /// Adds a node to the cache using the tag as its key - /// - /// the node to add - private void AddNodeToCache(UaNode node) - { - if (!_nodesCache.ContainsKey(node.Tag)) - _nodesCache.Add(node.Tag, node); - } - - /// - /// Return identity login object for a given URI. - /// - /// Login URI - /// AnonUser or User with name and password - private UserIdentity GetIdentity(Uri url) - { - if (_options.UserIdentity != null) - { - return _options.UserIdentity; - } - var uriLogin = new UserIdentity(); - if (!string.IsNullOrEmpty(url.UserInfo)) - { - var uis = url.UserInfo.Split(':'); - uriLogin = new UserIdentity(uis[0], uis[1]); - } - return uriLogin; - } - - /// - /// Crappy method to initialize the session. I don't know what many of these things do, sincerely. - /// - private async Task InitializeSession(Uri url) - { - var certificateValidator = new CertificateValidator(); - certificateValidator.CertificateValidation += (sender, eventArgs) => - { - if (ServiceResult.IsGood(eventArgs.Error)) - eventArgs.Accept = true; - else if ((eventArgs.Error.StatusCode.Code == StatusCodes.BadCertificateUntrusted) && _options.AutoAcceptUntrustedCertificates) - eventArgs.Accept = true; - else - throw new OpcException(string.Format("Failed to validate certificate with error code {0}: {1}", eventArgs.Error.Code, eventArgs.Error.AdditionalInfo), eventArgs.Error.StatusCode); - }; - // Build the application configuration - var appInstance = new ApplicationInstance - { - ApplicationType = ApplicationType.Client, - ConfigSectionName = _options.ConfigSectionName, - ApplicationConfiguration = new ApplicationConfiguration - { - ApplicationUri = url.ToString(), - ApplicationName = _options.ApplicationName, - ApplicationType = ApplicationType.Client, - CertificateValidator = certificateValidator, - ServerConfiguration = new ServerConfiguration - { - MaxSubscriptionCount = _options.MaxSubscriptionCount, - MaxMessageQueueSize = _options.MaxMessageQueueSize, - MaxNotificationQueueSize = _options.MaxNotificationQueueSize, - MaxPublishRequestCount = _options.MaxPublishRequestCount - }, - SecurityConfiguration = new SecurityConfiguration - { - AutoAcceptUntrustedCertificates = _options.AutoAcceptUntrustedCertificates - }, - TransportQuotas = new TransportQuotas - { - OperationTimeout = 600000, - MaxStringLength = 1048576, - MaxByteStringLength = 1048576, - MaxArrayLength = 65535, - MaxMessageSize = 4194304, - MaxBufferSize = 65535, - ChannelLifetime = 600000, - SecurityTokenLifetime = 3600000 - }, - ClientConfiguration = new ClientConfiguration - { - DefaultSessionTimeout = 60000, - MinSubscriptionLifetime = 10000 - }, - DisableHiResClock = true - } - }; - - // Assign a application certificate (when specified) - if (_options.ApplicationCertificate != null) - appInstance.ApplicationConfiguration.SecurityConfiguration.ApplicationCertificate = new CertificateIdentifier(_options.ApplicationCertificate); - - // Find the endpoint to be used - var endpoints = ClientUtils.SelectEndpoint(url, _options.UseMessageSecurity); - - // Create the OPC session: - var session = await Session.Create( - configuration: appInstance.ApplicationConfiguration, - endpoint: new ConfiguredEndpoint( - collection: null, - description: endpoints, - configuration: EndpointConfiguration.Create(applicationConfiguration: appInstance.ApplicationConfiguration)), - updateBeforeConnect: false, - checkDomain: false, - sessionName: _options.SessionName, - sessionTimeout: _options.SessionTimeout, - identity: GetIdentity(url), - preferredLocales: new string[] { }); - - return session; - } - - /// - /// Finds a node starting from the specified node as the root folder - /// - /// the tag to find - /// the root node - /// - private UaNode FindNode(string tag, UaNode node) - { - var folders = tag.Split('.'); - var head = folders.FirstOrDefault(); - UaNode found; - try - { - var subNodes = ExploreFolder(node.Tag); - found = subNodes.Single(n => n.Name == head); - } - catch (Exception ex) - { - throw new OpcException(string.Format("The tag \"{0}\" doesn't exist on folder \"{1}\"", head, node.Tag), ex); - } - - // remove an array element by converting it to a list - var folderList = folders.ToList(); - folderList.RemoveAt(0); // remove the first node - folders = folderList.ToArray(); - return folders.Length == 0 - ? found // last node, return it - : FindNode(string.Join(".", folders), found); // find sub nodes - } - - - private void NotifyServerConnectionLost() - { - if (ServerConnectionLost != null) - ServerConnectionLost(this, EventArgs.Empty); - } - - private void NotifyServerConnectionRestored() - { - if (ServerConnectionRestored != null) - ServerConnectionRestored(this, EventArgs.Empty); - } - - /// - /// This event is raised when the connection to the OPC server is lost. - /// - public event EventHandler ServerConnectionLost; - - /// - /// This event is raised when the connection to the OPC server is restored. - /// - public event EventHandler ServerConnectionRestored; - - } - -} diff --git a/Libraries/h-opc/UaClientOptions.cs b/Libraries/h-opc/UaClientOptions.cs deleted file mode 100644 index 5bb82a4..0000000 --- a/Libraries/h-opc/UaClientOptions.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System.Security.Cryptography.X509Certificates; -using OpcUa = Opc.Ua; - -namespace Hylasoft.Opc.Ua -{ - /// - /// This class defines the configuration options for the setup of the UA client session - /// - public class UaClientOptions - { - /// - /// Specifies the (optional) certificate for the application to connect to the server - /// - public X509Certificate2 ApplicationCertificate { get; set; } - - /// - /// Specifies the ApplicationName for the client application. - /// - public string ApplicationName { get; set; } - - /// - /// Should untrusted certificates be silently accepted by the client? - /// - public bool AutoAcceptUntrustedCertificates { get; set; } - - /// - /// Specifies the ConfigSectionName for the client configuration. - /// - public string ConfigSectionName { get; set; } - - /// - /// default monitor interval in Milliseconds. - /// - public int DefaultMonitorInterval { get; set; } - - /// - /// Specifies a name to be associated with the created sessions. - /// - public string SessionName { get; set; } - - /// - /// Specifies the timeout for the sessions. - /// - public uint SessionTimeout { get; set; } - - /// - /// Specify whether message exchange should be secured. - /// - public bool UseMessageSecurity { get; set; } - - /// - /// The maximum number of notifications per publish request. - /// The client’s responsibility is to send PublishRequests to the server, - /// in order to enable the server to send PublishResponses back. - /// The PublishResponses are used to deliver the notifications: but if there - /// are no PublishRequests, the server cannot send a notification to the client. - /// The server will also verify that the client is alive by checking that - /// new PublishRequests are received – LifeTimeCount defines the number of - /// PublishingIntervals to wait for a new PublishRequest, before realizing - /// that the client is no longer active.The Subscription is then removed from - /// the server. - /// - public uint SubscriptionLifetimeCount { get; set; } - - /// - /// If there is no data to send after the next PublishingInterval, - /// the server will skip it. But KeepAlive defines how many intervals may be skipped, - /// before an empty notification is sent anyway: to give the client a hint that - /// the subscription is still alive in the server and that there just has not been - /// any data arriving to the client. - /// - public uint SubscriptionKeepAliveCount { get; set; } - - /// - /// Gets or sets the max subscription count. - /// - public int MaxSubscriptionCount { get; set; } - - /// - /// The maximum number of messages saved in the queue for each subscription. - /// - public int MaxMessageQueueSize { get; set; } - - /// - /// The maximum number of notificates saved in the queue for each monitored item. - /// - public int MaxNotificationQueueSize { get; set; } - - /// - /// Gets or sets the max publish request count. - /// - public int MaxPublishRequestCount { get; set; } - - /// - /// The identity to connect to the OPC server as - /// - public OpcUa.UserIdentity UserIdentity { get; set; } - - /// - /// Creates a client options object - /// - public UaClientOptions() - { - // Initialize default values: - ApplicationName = "h-opc-client"; - AutoAcceptUntrustedCertificates = true; - ConfigSectionName = "h-opc-client"; - DefaultMonitorInterval = 100; - SessionName = "h-opc-client"; - SessionTimeout = 60000U; - UseMessageSecurity = false; - SubscriptionLifetimeCount = 0; - SubscriptionKeepAliveCount = 0; - MaxSubscriptionCount = 100; - MaxMessageQueueSize = 10; - MaxNotificationQueueSize = 100; - MaxPublishRequestCount = 20; - } - } -} diff --git a/Libraries/h-opc/UaNode.cs b/Libraries/h-opc/UaNode.cs deleted file mode 100644 index edaa021..0000000 --- a/Libraries/h-opc/UaNode.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Hylasoft.Opc.Common; - -namespace Hylasoft.Opc.Ua -{ - /// - /// Represents a node to be used specifically for OPC UA - /// - public class UaNode : Node - { - /// - /// The UA Id of the node - /// - public string NodeId { get; private set; } - - /// - /// Instantiates a UaNode class - /// - /// the name of the node - /// The UA Id of the node - /// The parent node - internal UaNode(string name, string nodeId, Node parent = null) - : base(name, parent) - { - NodeId = nodeId; - } - - } - -} diff --git a/Libraries/h-opc/h-opc.csproj b/Libraries/h-opc/h-opc.csproj deleted file mode 100644 index 4325c32..0000000 --- a/Libraries/h-opc/h-opc.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - - net6.0 - h-opc-ua - Hylasoft.Opc - h-opc-ua - 0.9.3 - Modbus.Net - Chris L.(Luo Sheng) - Hangzhou Delian Science Technology Co.,Ltd. - https://github.com/parallelbgls/Modbus.Net/tree/master/Modbus.Net - https://github.com/parallelbgls/Modbus.Net/ - High extensible hardware communication implementation platform. - Copyright 2023 Hangzhou Delian Science Technology Co.,Ltd. - hardware communicate protocol Delian - git - False - True - True - True - MIT - - - - - - - - diff --git a/Modbus.Net/Modbus.Net.Modbus.NA200H/AddressTranslatorNA200H.cs b/Modbus.Net/Modbus.Net.Modbus.NA200H/AddressTranslatorNA200H.cs index cc11251..8b75fd6 100644 --- a/Modbus.Net/Modbus.Net.Modbus.NA200H/AddressTranslatorNA200H.cs +++ b/Modbus.Net/Modbus.Net.Modbus.NA200H/AddressTranslatorNA200H.cs @@ -218,7 +218,7 @@ namespace Modbus.Net.Modbus.NA200H var head = splitString[0]; var tail = splitString[1]; string sub; - if (tail.Contains('.')) + if (tail.Contains(".")) { var splitString2 = tail.Split('.'); sub = splitString2[1]; diff --git a/Modbus.Net/Modbus.Net.Modbus.NA200H/Modbus.Net.Modbus.NA200H.csproj b/Modbus.Net/Modbus.Net.Modbus.NA200H/Modbus.Net.Modbus.NA200H.csproj index 081fb03..97d6f1e 100644 --- a/Modbus.Net/Modbus.Net.Modbus.NA200H/Modbus.Net.Modbus.NA200H.csproj +++ b/Modbus.Net/Modbus.Net.Modbus.NA200H/Modbus.Net.Modbus.NA200H.csproj @@ -1,7 +1,8 @@  - net6.0 + net6.0;net462 + 11.0 Modbus.Net.Modbus.NA200H Modbus.Net.Modbus.NA200H Modbus.Net.Modbus.NA200H diff --git a/Modbus.Net/Modbus.Net.Modbus.SelfDefinedSample/Modbus.Net.Modbus.SelfDefinedSample.csproj b/Modbus.Net/Modbus.Net.Modbus.SelfDefinedSample/Modbus.Net.Modbus.SelfDefinedSample.csproj index edf83a0..53eda87 100644 --- a/Modbus.Net/Modbus.Net.Modbus.SelfDefinedSample/Modbus.Net.Modbus.SelfDefinedSample.csproj +++ b/Modbus.Net/Modbus.Net.Modbus.SelfDefinedSample/Modbus.Net.Modbus.SelfDefinedSample.csproj @@ -1,7 +1,8 @@ - + - net6.0 + net6.0;net462 + 11.0 Modbus.Net.Modbus.SelfDefinedSample Modbus.Net.Modbus.SelfDefinedSample Modbus.Net.Modbus.SelfDefinedSample diff --git a/Modbus.Net/Modbus.Net.Modbus/AddressTranslatorModbus.cs b/Modbus.Net/Modbus.Net.Modbus/AddressTranslatorModbus.cs index 34edefc..bfd0f2f 100644 --- a/Modbus.Net/Modbus.Net.Modbus/AddressTranslatorModbus.cs +++ b/Modbus.Net/Modbus.Net.Modbus/AddressTranslatorModbus.cs @@ -126,7 +126,7 @@ namespace Modbus.Net.Modbus var head = splitString[0]; var tail = splitString[1]; string sub; - if (tail.Contains('.')) + if (tail.Contains(".")) { var splitString2 = tail.Split('.'); sub = splitString2[1]; diff --git a/Modbus.Net/Modbus.Net.Modbus/Interfaces.cs b/Modbus.Net/Modbus.Net.Modbus/Interfaces.cs index fde2fd6..1ef750d 100644 --- a/Modbus.Net/Modbus.Net.Modbus/Interfaces.cs +++ b/Modbus.Net/Modbus.Net.Modbus/Interfaces.cs @@ -203,7 +203,7 @@ namespace Modbus.Net.Modbus /// Task> GetMultipleRegister(ushort readStartingAddress, ushort quantityToRead, ushort writeStartingAddress, ushort[] writeValues); } - + /// /// FIFO队列读取方法 /// diff --git a/Modbus.Net/Modbus.Net.Modbus/Modbus.Net.Modbus.csproj b/Modbus.Net/Modbus.Net.Modbus/Modbus.Net.Modbus.csproj index 675d96e..d6cb0b9 100644 --- a/Modbus.Net/Modbus.Net.Modbus/Modbus.Net.Modbus.csproj +++ b/Modbus.Net/Modbus.Net.Modbus/Modbus.Net.Modbus.csproj @@ -1,7 +1,8 @@  - net6.0 + net6.0;net462 + 11.0 Modbus.Net.Modbus Modbus.Net.Modbus Modbus.Net.Modbus diff --git a/Modbus.Net/Modbus.Net.Modbus/ModbusAsciiProtocolLinker.cs b/Modbus.Net/Modbus.Net.Modbus/ModbusAsciiProtocolLinker.cs index bcc1cf5..c4457f2 100644 --- a/Modbus.Net/Modbus.Net.Modbus/ModbusAsciiProtocolLinker.cs +++ b/Modbus.Net/Modbus.Net.Modbus/ModbusAsciiProtocolLinker.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Text; +using System.Text; namespace Modbus.Net.Modbus { diff --git a/Modbus.Net/Modbus.Net.Modbus/ModbusProtocol.cs b/Modbus.Net/Modbus.Net.Modbus/ModbusProtocol.cs index 30c7bde..9b5e97f 100644 --- a/Modbus.Net/Modbus.Net.Modbus/ModbusProtocol.cs +++ b/Modbus.Net/Modbus.Net.Modbus/ModbusProtocol.cs @@ -389,7 +389,7 @@ namespace Modbus.Net.Modbus formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode, r_message.StartAddress, r_message.WriteCount, r_message.WriteByteCount, dataValue); } - + return formattingBytes; } @@ -493,7 +493,7 @@ namespace Modbus.Net.Modbus { var r_message = (ReadExceptionStatusModbusInputStruct)message; byte[] formattingBytes; - + formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode); return formattingBytes; @@ -613,10 +613,10 @@ namespace Modbus.Net.Modbus public override byte[] Format(IInputStruct message) { var r_message = (DiagnoticsModbusInputStruct)message; - + var formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode, r_message.SubFunction, r_message.Data); - + return formattingBytes; } @@ -1260,7 +1260,7 @@ namespace Modbus.Net.Modbus SlaveAddress = slaveAddress; FunctionCode = (byte)ModbusProtocolFunctionCode.WriteFileRecord; byte count = 0; - foreach(var writeRecord in writeRecords) + foreach (var writeRecord in writeRecords) { count += (byte)(writeRecord.RecordData.Length * 2 + 7); } @@ -1574,7 +1574,7 @@ namespace Modbus.Net.Modbus /// 读起始地址 /// public ushort ReadStartingAddress { get; } - + /// /// 读个数 /// @@ -1656,8 +1656,8 @@ namespace Modbus.Net.Modbus { var r_message = (ReadWriteMultipleRegistersModbusInputStruct)message; - var formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode, r_message.ReadStartingAddress, - r_message.QuantityToRead, r_message.WriteStartingAddress, r_message.QuantityToWrite, + var formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode, r_message.ReadStartingAddress, + r_message.QuantityToRead, r_message.WriteStartingAddress, r_message.QuantityToWrite, r_message.WriteByteCount, r_message.WriteValues); return formattingBytes; @@ -1674,8 +1674,8 @@ namespace Modbus.Net.Modbus var slaveAddress = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); var functionCode = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); var byteCount = ValueHelper.GetInstance(Endian).GetByte(messageBytes, ref flag); - ushort[] readValues= new ushort[byteCount / 2]; - for (int i = 0; i< byteCount / 2; i++) + ushort[] readValues = new ushort[byteCount / 2]; + for (int i = 0; i < byteCount / 2; i++) { readValues[i] = ValueHelper.GetInstance(Endian).GetUShort(messageBytes, ref flag); } diff --git a/Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs b/Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs index a19f62a..70e38fe 100644 --- a/Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs +++ b/Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs @@ -53,15 +53,15 @@ namespace Modbus.Net.Modbus /// /// Modbus基础Api入口 /// - public class ModbusUtility : BaseUtility, PipeUnit>, - IUtilityMethodExceptionStatus, - IUtilityMethodDiagnotics, - IUtilityMethodCommEventCounter, - IUtilityMethodCommEventLog, - IUtilityMethodSlaveId, - IUtilityMethodFileRecord, - IUtilityMethodMaskRegister, - IUtilityMethodMultipleRegister, + public class ModbusUtility : BaseUtility, PipeUnit>, + IUtilityMethodExceptionStatus, + IUtilityMethodDiagnotics, + IUtilityMethodCommEventCounter, + IUtilityMethodCommEventLog, + IUtilityMethodSlaveId, + IUtilityMethodFileRecord, + IUtilityMethodMaskRegister, + IUtilityMethodMultipleRegister, IUtilityMethodFIFOQueue { private static readonly ILogger logger = LogProvider.CreateLogger(); @@ -414,7 +414,7 @@ namespace Modbus.Net.Modbus inputStruct); return new ReturnStruct() { - Datas = new CommEventLogData() { Status = outputStruct.Status, Events = outputStruct.Events}, + Datas = new CommEventLogData() { Status = outputStruct.Status, Events = outputStruct.Events }, IsSuccess = true, ErrorCode = 0, ErrorMsg = null @@ -444,7 +444,7 @@ namespace Modbus.Net.Modbus inputStruct); return new ReturnStruct() { - Datas = new SlaveIdData() { SlaveId = outputStruct.SlaveId, IndicatorStatus = outputStruct.RunIndicatorStatus, AdditionalData = outputStruct.AdditionalData}, + Datas = new SlaveIdData() { SlaveId = outputStruct.SlaveId, IndicatorStatus = outputStruct.RunIndicatorStatus, AdditionalData = outputStruct.AdditionalData }, IsSuccess = true, ErrorCode = 0, ErrorMsg = null @@ -534,7 +534,7 @@ namespace Modbus.Net.Modbus inputStruct); return new ReturnStruct() { - Datas = new MaskRegisterData() { ReferenceAddress = outputStruct.ReferenceAddress, AndMask = outputStruct.AndMask, OrMask = outputStruct.OrMask}, + Datas = new MaskRegisterData() { ReferenceAddress = outputStruct.ReferenceAddress, AndMask = outputStruct.AndMask, OrMask = outputStruct.OrMask }, IsSuccess = true, ErrorCode = 0, ErrorMsg = null diff --git a/Modbus.Net/Modbus.Net.OPC/ClientExtend.cs b/Modbus.Net/Modbus.Net.OPC/ClientExtend.cs index 92ebb5f..fa3e3e9 100644 --- a/Modbus.Net/Modbus.Net.OPC/ClientExtend.cs +++ b/Modbus.Net/Modbus.Net.OPC/ClientExtend.cs @@ -1,4 +1,5 @@ using Hylasoft.Opc.Common; +using Hylasoft.Opc.Da; using Hylasoft.Opc.Ua; using System; using System.Collections.Generic; @@ -19,7 +20,7 @@ namespace Modbus.Net.OPC /// /// Connect the client to the OPC Server /// - Task Connect(); + void Connect(); /// /// Read a tag @@ -64,6 +65,25 @@ namespace Modbus.Net.OPC Task> ExploreFolderAsync(string tag); } + /// + /// UaClient Extend + /// + public class MyDaClient : DaClient, IClientExtend + { + /// + /// UaClient Extend + /// + /// Url address of Opc UA server + public MyDaClient(Uri serverUrl) : base(serverUrl) + { + } + + /// + /// Unified root node + /// + public Node RootNodeBase => RootNode; + } + /// /// DaClient Extend /// diff --git a/Modbus.Net/Modbus.Net.OPC/FBox/FBoxOpcDaManchine.cs b/Modbus.Net/Modbus.Net.OPC/FBox/FBoxOpcDaManchine.cs new file mode 100644 index 0000000..efb1810 --- /dev/null +++ b/Modbus.Net/Modbus.Net.OPC/FBox/FBoxOpcDaManchine.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using System.Configuration; + +namespace Modbus.Net.OPC.FBox +{ + /// + /// FBox的Opc服务设备 + /// + public class FBoxOpcDaMachine : OpcDaMachine + { + /// + /// 构造函数 + /// + /// 设备id + /// 页名称 + /// 设备名称 + /// 获取地址 + /// 是否保持连接 + public FBoxOpcDaMachine(string id, string localSequence, string linkerName, + IEnumerable getAddresses, bool keepConnect) + : base( + id, + ConfigurationManager.AppSettings["FBoxOpcDaHost"] ?? "opcda://localhost/FBoxOpcServer", getAddresses, + keepConnect, true) + { + LocalSequence = localSequence; + LinkerName = linkerName; + AddressFormater = + new AddressFormaterOpc( + (machine, unit) => + new[] + { + "(.*)", ((FBoxOpcDaMachine) machine).LinkerName, ((FBoxOpcDaMachine) machine).LocalSequence, + unit.Name + }, this, '.'); + } + + /// + /// 构造函数 + /// + /// 设备id + /// 页名称 + /// 设备名称 + /// 获取地址 + public FBoxOpcDaMachine(string id, string localSequence, string linkerName, + IEnumerable getAddresses) + : this(id, localSequence, linkerName, getAddresses, false) + { + } + + /// + /// 页名称 + /// + public string LocalSequence { get; set; } + + /// + /// 设备名称 + /// + public string LinkerName { get; set; } + } +} \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.OPC/Modbus.Net.OPC.csproj b/Modbus.Net/Modbus.Net.OPC/Modbus.Net.OPC.csproj index e16fe60..ccce17e 100644 --- a/Modbus.Net/Modbus.Net.OPC/Modbus.Net.OPC.csproj +++ b/Modbus.Net/Modbus.Net.OPC/Modbus.Net.OPC.csproj @@ -1,7 +1,8 @@  - net6.0 + net462 + 11.0 Modbus.Net.OPC Modbus.Net.OPC Modbus.Net.OPC @@ -29,15 +30,18 @@ - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.OPC/OpcConnector.cs b/Modbus.Net/Modbus.Net.OPC/OpcConnector.cs index 87ecc42..977b995 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcConnector.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcConnector.cs @@ -191,15 +191,11 @@ namespace Modbus.Net.OPC return null; } - /// - /// 连接PLC - /// - /// 是否连接成功 - public override async Task ConnectAsync() + private bool Connect() { try { - await Client.Connect(); + Client.Connect(); _connect = true; logger.LogInformation("opc client {ConnectionToken} connect success", ConnectionToken); return true; @@ -211,5 +207,14 @@ namespace Modbus.Net.OPC return false; } } + + /// + /// 连接PLC,异步 + /// + /// 是否连接成功 + public override Task ConnectAsync() + { + return Task.FromResult(Connect()); + } } } \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.OPC/OpcDaConnector.cs b/Modbus.Net/Modbus.Net.OPC/OpcDaConnector.cs new file mode 100644 index 0000000..4b30e81 --- /dev/null +++ b/Modbus.Net/Modbus.Net.OPC/OpcDaConnector.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; + +namespace Modbus.Net.OPC +{ + /// + /// Opc DA连接实现 + /// + public class OpcDaConnector : OpcConnector + { + /// + /// DA单例管理 + /// + protected static Dictionary _instances = new Dictionary(); + + /// + /// 构造函数 + /// + /// Opc DA 服务地址 + /// 是否开启正则匹配 + protected OpcDaConnector(string host, bool isRegexOn) : base(host, isRegexOn) + { + Client = new MyDaClient(new Uri(ConnectionToken)); + } + + /// + /// 根据服务地址生成DA单例 + /// + /// Opc DA 服务地址 + /// 是否开启正则匹配 + /// Opc DA 连接器实例 + public static OpcDaConnector Instance(string host, bool isRegexOn) + { + if (!_instances.ContainsKey(host)) + { + var connector = new OpcDaConnector(host, isRegexOn); + _instances.Add(host, connector); + } + return _instances[host]; + } + } +} \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.OPC/OpcDaMachine.cs b/Modbus.Net/Modbus.Net.OPC/OpcDaMachine.cs new file mode 100644 index 0000000..53eb504 --- /dev/null +++ b/Modbus.Net/Modbus.Net.OPC/OpcDaMachine.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; + +namespace Modbus.Net.OPC +{ + /// + /// Opc DA设备 + /// + /// 设备Id类型 + /// 设备包含的地址的Id类型 + public class OpcDaMachine : OpcMachine where TKey : IEquatable + where TUnitKey : IEquatable + { + /// + /// 构造函数 + /// + /// 设备的ID号 + /// 连接地址 + /// 需要读写的数据 + /// 是否保持连接 + /// 是否开启正则匹配 + public OpcDaMachine(TKey id, string connectionString, IEnumerable> getAddresses, bool keepConnect, bool isRegexOn = false) + : base(id, getAddresses, keepConnect) + { + BaseUtility = new OpcDaUtility(connectionString, isRegexOn); + ((OpcUtility)BaseUtility).GetSeperator += + () => ((AddressFormaterOpc)AddressFormater).Seperator; + } + + /// + /// 构造函数 + /// + /// 设备的ID号 + /// 连接地址 + /// 需要读写的数据 + public OpcDaMachine(TKey id, string connectionString, IEnumerable> getAddresses) + : this(id, connectionString, getAddresses, false) + { + } + } + + /// + /// Opc DA设备 + /// + public class OpcDaMachine : OpcMachine + { + /// + /// 构造函数 + /// + /// 设备的ID号 + /// 连接地址 + /// 需要读写的数据 + /// 是否保持连接 + /// 是否开启正则匹配 + public OpcDaMachine(string id, string connectionString, IEnumerable getAddresses, bool keepConnect, bool isRegexOn = false) + : base(id, getAddresses, keepConnect) + { + BaseUtility = new OpcDaUtility(connectionString, isRegexOn); + ((OpcUtility)BaseUtility).GetSeperator += + () => ((AddressFormaterOpc)AddressFormater).Seperator; + } + + /// + /// 构造函数 + /// + /// 设备的ID号 + /// 连接地址 + /// 需要读写的数据 + public OpcDaMachine(string id, string connectionString, IEnumerable getAddresses) + : this(id, connectionString, getAddresses, false) + { + } + } +} \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.OPC/OpcDaProtocal.cs b/Modbus.Net/Modbus.Net.OPC/OpcDaProtocal.cs new file mode 100644 index 0000000..f8bac5f --- /dev/null +++ b/Modbus.Net/Modbus.Net.OPC/OpcDaProtocal.cs @@ -0,0 +1,38 @@ +using System.Threading.Tasks; + +namespace Modbus.Net.OPC +{ + /// + /// Opc Da协议 + /// + public class OpcDaProtocol : OpcProtocol + { + private readonly string _host; + + private readonly bool _isRegexOn; + + /// + /// 构造函数 + /// + /// Opc DA服务地址 + /// 是否开启正则匹配 + public OpcDaProtocol(string host, bool isRegexOn) + { + _host = host; + _isRegexOn = isRegexOn; + } + + + /// + /// 连接设备 + /// + /// 是否连接成功 + public override async Task ConnectAsync() + { + ProtocolLinker = new OpcDaProtocolLinker(_host, _isRegexOn); + if (!await ProtocolLinker.ConnectAsync()) + return false; + return true; + } + } +} \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.OPC/OpcDaProtocalLinker.cs b/Modbus.Net/Modbus.Net.OPC/OpcDaProtocalLinker.cs new file mode 100644 index 0000000..4056f32 --- /dev/null +++ b/Modbus.Net/Modbus.Net.OPC/OpcDaProtocalLinker.cs @@ -0,0 +1,28 @@ +using System.Configuration; + +namespace Modbus.Net.OPC +{ + /// + /// Opc Da协议连接器 + /// + public class OpcDaProtocolLinker : OpcProtocolLinker + { + /// + /// 构造函数 + /// + /// 是否开启正则匹配 + public OpcDaProtocolLinker(bool isRegexOn) : this(ConfigurationManager.AppSettings["OpcDaHost"], isRegexOn) + { + } + + /// + /// 构造函数 + /// + /// Opc DA服务地址 + /// 是否开启正则匹配 + public OpcDaProtocolLinker(string host, bool isRegexOn) + { + BaseConnector = OpcDaConnector.Instance(host, isRegexOn); + } + } +} \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.OPC/OpcDaUtility.cs b/Modbus.Net/Modbus.Net.OPC/OpcDaUtility.cs new file mode 100644 index 0000000..a778185 --- /dev/null +++ b/Modbus.Net/Modbus.Net.OPC/OpcDaUtility.cs @@ -0,0 +1,18 @@ +namespace Modbus.Net.OPC +{ + /// + /// Opc Da协议Api入口 + /// + public class OpcDaUtility : OpcUtility + { + /// + /// 构造函数 + /// + /// 连接地址 + /// 是否开启正则匹配 + public OpcDaUtility(string connectionString, bool isRegexOn = false) : base(connectionString) + { + Wrapper = new OpcDaProtocol(ConnectionString, isRegexOn); + } + } +} \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.Siemens/AddressTranslatorSiemens.cs b/Modbus.Net/Modbus.Net.Siemens/AddressTranslatorSiemens.cs index 43e3126..0129773 100644 --- a/Modbus.Net/Modbus.Net.Siemens/AddressTranslatorSiemens.cs +++ b/Modbus.Net/Modbus.Net.Siemens/AddressTranslatorSiemens.cs @@ -48,7 +48,7 @@ namespace Modbus.Net.Siemens var head = splitString[0]; var tail = splitString[1]; string sub; - if (tail.Contains('.')) + if (tail.Contains(".")) { var splitString2 = tail.Split('.'); sub = splitString2[1]; diff --git a/Modbus.Net/Modbus.Net.Siemens/Modbus.Net.Siemens.csproj b/Modbus.Net/Modbus.Net.Siemens/Modbus.Net.Siemens.csproj index a347872..35a03ea 100644 --- a/Modbus.Net/Modbus.Net.Siemens/Modbus.Net.Siemens.csproj +++ b/Modbus.Net/Modbus.Net.Siemens/Modbus.Net.Siemens.csproj @@ -1,7 +1,8 @@  - net6.0 + net6.0;net462 + 11.0 Modbus.Net.Siemens Modbus.Net.Siemens Modbus.Net.Siemens diff --git a/Modbus.Net/Modbus.Net.Siemens/SiemensPpiProtocolLinker.cs b/Modbus.Net/Modbus.Net.Siemens/SiemensPpiProtocolLinker.cs index 46e922e..12f3782 100644 --- a/Modbus.Net/Modbus.Net.Siemens/SiemensPpiProtocolLinker.cs +++ b/Modbus.Net/Modbus.Net.Siemens/SiemensPpiProtocolLinker.cs @@ -1,4 +1,4 @@ -using System; +using FastEnumUtility; using System.Collections.Generic; using System.IO.Ports; using System.Threading; @@ -17,9 +17,9 @@ namespace Modbus.Net.Siemens /// 串口地址 /// 从站号 public SiemensPpiProtocolLinker(string com, int slaveAddress) - : base(com, slaveAddress, parity: - ConfigurationReader.GetValue("COM:Siemens", "Parity") != null - ? Enum.Parse(ConfigurationReader.GetValue("COM:Siemens", "Parity")) + : base(com, slaveAddress, parity: + ConfigurationReader.GetValue("COM:Siemens", "Parity") != null + ? FastEnum.Parse(ConfigurationReader.GetValue("COM:Siemens", "Parity")) : null ) { diff --git a/Modbus.Net/Modbus.Net.sln b/Modbus.Net/Modbus.Net.sln index ee00ca8..d15b9c9 100644 --- a/Modbus.Net/Modbus.Net.sln +++ b/Modbus.Net/Modbus.Net.sln @@ -28,8 +28,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnyType", "..\Samples\AnyTy EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Modbus.Net.OPC", "Modbus.Net.OPC\Modbus.Net.OPC.csproj", "{C854A379-C5EA-4CAC-9C5F-7291372D1D3F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "h-opc", "..\Libraries\h-opc\h-opc.csproj", "{347D0027-45F6-48C9-A917-1B1DF6C66DC5}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CrossLamp", "..\Samples\CrossLamp\CrossLamp.csproj", "{AA3A42D2-0502-41D3-929A-BAB729DF07D6}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TripleAdd", "..\Samples\TripleAdd\TripleAdd.csproj", "{414956B8-DBD4-414C-ABD3-565580739646}" @@ -74,10 +72,6 @@ Global {C854A379-C5EA-4CAC-9C5F-7291372D1D3F}.Debug|Any CPU.Build.0 = Debug|Any CPU {C854A379-C5EA-4CAC-9C5F-7291372D1D3F}.Release|Any CPU.ActiveCfg = Release|Any CPU {C854A379-C5EA-4CAC-9C5F-7291372D1D3F}.Release|Any CPU.Build.0 = Release|Any CPU - {347D0027-45F6-48C9-A917-1B1DF6C66DC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {347D0027-45F6-48C9-A917-1B1DF6C66DC5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {347D0027-45F6-48C9-A917-1B1DF6C66DC5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {347D0027-45F6-48C9-A917-1B1DF6C66DC5}.Release|Any CPU.Build.0 = Release|Any CPU {AA3A42D2-0502-41D3-929A-BAB729DF07D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AA3A42D2-0502-41D3-929A-BAB729DF07D6}.Debug|Any CPU.Build.0 = Debug|Any CPU {AA3A42D2-0502-41D3-929A-BAB729DF07D6}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/Modbus.Net/Modbus.Net/Configuration/ConfigurationReader.cs b/Modbus.Net/Modbus.Net/Configuration/ConfigurationReader.cs index 224d586..6829f81 100644 --- a/Modbus.Net/Modbus.Net/Configuration/ConfigurationReader.cs +++ b/Modbus.Net/Modbus.Net/Configuration/ConfigurationReader.cs @@ -13,7 +13,7 @@ namespace Modbus.Net private static readonly IConfigurationRoot configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.default.json", optional: false, reloadOnChange: true) - .AddJsonFile("appsettings.json", optional:false, reloadOnChange: true) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true, reloadOnChange: true) .Build(); @@ -26,7 +26,7 @@ namespace Modbus.Net /// 元素的值 public static string? GetValue(string path, string key) { - var split = path.Split(":"); + var split = path.Split(':'); string? ans = null; while (split.Length > 0) { diff --git a/Modbus.Net/Modbus.Net/Configuration/MachineReader.cs b/Modbus.Net/Modbus.Net/Configuration/MachineReader.cs index 9e0de8e..81f2082 100644 --- a/Modbus.Net/Modbus.Net/Configuration/MachineReader.cs +++ b/Modbus.Net/Modbus.Net/Configuration/MachineReader.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Configuration; +using FastEnumUtility; +using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.IO; @@ -66,7 +67,7 @@ namespace Modbus.Net } case "endian": { - paramsSet.Add(Enum.Parse(dic["endian"])); + paramsSet.Add(FastEnum.Parse(dic["endian"])); break; } default: diff --git a/Modbus.Net/Modbus.Net/Helper/EnumHelper.cs b/Modbus.Net/Modbus.Net/Helper/EnumHelper.cs new file mode 100644 index 0000000..86f677a --- /dev/null +++ b/Modbus.Net/Modbus.Net/Helper/EnumHelper.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Modbus.Net +{ +#if NET462 +#pragma warning disable 1591 + public static partial class EnumearbleExtensions + { + public static IEnumerable TakeLast(this IEnumerable source, int count) + { + if (null == source) + throw new ArgumentNullException(nameof(source)); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count)); + + if (0 == count) + yield break; + + // Optimization (see JonasH's comment) + if (source is ICollection) + { + foreach (T item in source.Skip(((ICollection)source).Count - count)) + yield return item; + + yield break; + } + + if (source is IReadOnlyCollection) + { + foreach (T item in source.Skip(((IReadOnlyCollection)source).Count - count)) + yield return item; + + yield break; + } + + // General case, we have to enumerate source + Queue result = new Queue(); + + foreach (T item in source) + { + if (result.Count == count) + result.Dequeue(); + + result.Enqueue(item); + } + + foreach (T item in result) + yield return result.Dequeue(); + } + + public static IEnumerable Append(this IEnumerable collection, T item) + { + if (collection == null) + { + throw new ArgumentNullException("Collection should not be null"); + } + + return collection.Concat(Enumerable.Repeat(item, 1)); + } + } +#pragma warning restore 1591 +#endif +} diff --git a/Modbus.Net/Modbus.Net/Linker/ComProtocolLinker.cs b/Modbus.Net/Modbus.Net/Linker/ComProtocolLinker.cs index 03e128d..0de006d 100644 --- a/Modbus.Net/Modbus.Net/Linker/ComProtocolLinker.cs +++ b/Modbus.Net/Modbus.Net/Linker/ComProtocolLinker.cs @@ -1,4 +1,4 @@ -using System; +using FastEnumUtility; using System.IO.Ports; namespace Modbus.Net @@ -63,11 +63,11 @@ namespace Modbus.Net protected ComProtocolLinker(string com, int slaveAddress, BaudRate? baudRate = null, Parity? parity = null, StopBits? stopBits = null, DataBits? dataBits = null, Handshake? handshake = null, int? connectionTimeout = null, bool? isFullDuplex = null) { - baudRate = Enum.Parse(baudRate != null ? baudRate.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "BaudRate")); - parity = Enum.Parse(parity != null ? parity.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "Parity")); - stopBits = Enum.Parse(stopBits != null ? stopBits.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "StopBits")); - dataBits = Enum.Parse(dataBits != null ? dataBits.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "DataBits")); - handshake = Enum.Parse(handshake != null ? handshake.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "Handshake")); + baudRate = FastEnum.Parse(baudRate != null ? baudRate.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "BaudRate")); + parity = FastEnum.Parse(parity != null ? parity.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "Parity")); + stopBits = FastEnum.Parse(stopBits != null ? stopBits.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "StopBits")); + dataBits = FastEnum.Parse(dataBits != null ? dataBits.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "DataBits")); + handshake = FastEnum.Parse(handshake != null ? handshake.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "Handshake")); connectionTimeout = int.Parse(connectionTimeout != null ? connectionTimeout.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "ConnectionTimeout")); isFullDuplex = bool.Parse(isFullDuplex != null ? isFullDuplex.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "FullDuplex")); BaseConnector = new ComConnector(com + ":" + slaveAddress, baudRate.Value, parity.Value, stopBits.Value, dataBits.Value, handshake.Value, connectionTimeout.Value, isFullDuplex.Value); diff --git a/Modbus.Net/Modbus.Net/Machine/MachineMethodReflectionCall.cs b/Modbus.Net/Modbus.Net/Machine/MachineMethodReflectionCall.cs index be24917..b6493a4 100644 --- a/Modbus.Net/Modbus.Net/Machine/MachineMethodReflectionCall.cs +++ b/Modbus.Net/Modbus.Net/Machine/MachineMethodReflectionCall.cs @@ -19,11 +19,11 @@ namespace Modbus.Net /// 返回的数据 public static Task> InvokeGet(this IMachineMethod machineMethod, object[] parameters) where TMachineMethod : IMachineMethod { - if (typeof(TMachineMethod).Name[..14] != "IMachineMethod") + if (typeof(TMachineMethod).Name.Substring(0, 14) != "IMachineMethod") { throw new NotSupportedException("IMachineMethod type name not begin with IMachineMethod"); } - var functionName = "Get" + typeof(TMachineMethod).Name[14..] + "Async"; + var functionName = "Get" + typeof(TMachineMethod).Name.Substring(14) + "Async"; return InvokeGet(machineMethod, functionName, parameters); } @@ -54,11 +54,11 @@ namespace Modbus.Net /// 设置是否成功 public static Task> InvokeSet(this IMachineMethod machineMethod, object[] parameters, T datas) where TMachineMethod : IMachineMethod { - if (typeof(TMachineMethod).Name[..14] != "IMachineMethod") + if (typeof(TMachineMethod).Name.Substring(0, 14) != "IMachineMethod") { throw new NotSupportedException("IMachineMethod type name not begin with IMachineMethod"); } - var functionName = "Set" + typeof(TMachineMethod).Name[14..] + "Async"; + var functionName = "Set" + typeof(TMachineMethod).Name.Substring(14) + "Async"; return InvokeSet(machineMethod, functionName, parameters, datas); } diff --git a/Modbus.Net/Modbus.Net/Modbus.Net.csproj b/Modbus.Net/Modbus.Net/Modbus.Net.csproj index 540b712..56915fa 100644 --- a/Modbus.Net/Modbus.Net/Modbus.Net.csproj +++ b/Modbus.Net/Modbus.Net/Modbus.Net.csproj @@ -1,7 +1,8 @@  - net6.0 + net6.0;net462 + 11.0 Modbus.Net Modbus.Net Modbus.Net @@ -30,6 +31,7 @@ + diff --git a/Modbus.Net/Modbus.Net/Utility/UtilityMethodReflectionCall.cs b/Modbus.Net/Modbus.Net/Utility/UtilityMethodReflectionCall.cs index 03ae572..609d818 100644 --- a/Modbus.Net/Modbus.Net/Utility/UtilityMethodReflectionCall.cs +++ b/Modbus.Net/Modbus.Net/Utility/UtilityMethodReflectionCall.cs @@ -18,11 +18,11 @@ namespace Modbus.Net /// 返回的数据 public static Task> InvokeGet(this IUtilityMethod utilityMethod, object[] parameters) where TUtilityMethod : IUtilityMethod { - if (typeof(TUtilityMethod).Name[..14] != "IUtilityMethod") + if (typeof(TUtilityMethod).Name.Substring(0, 14) != "IUtilityMethod") { throw new NotSupportedException("IUtilityMethod type name not begin with IUtilityMethod"); } - var functionName = "Get" + typeof(TUtilityMethod).Name[14..] + "Async"; + var functionName = "Get" + typeof(TUtilityMethod).Name.Substring(14) + "Async"; return InvokeGet(utilityMethod, functionName, parameters); } @@ -53,11 +53,11 @@ namespace Modbus.Net /// 设置是否成功 public static Task> InvokeSet(this IUtilityMethod utilityMethod, object[] parameters, T datas) where TUtilityMethod : IUtilityMethod { - if (typeof(TUtilityMethod).Name[..14] != "IUtilityMethod") + if (typeof(TUtilityMethod).Name.Substring(0, 14) != "IUtilityMethod") { throw new NotSupportedException("IUtilityMethod type name not begin with IUtilityMethod"); } - var functionName = "Set" + typeof(TUtilityMethod).Name[14..] + "Async"; + var functionName = "Set" + typeof(TUtilityMethod).Name.Substring(14) + "Async"; return InvokeSet(utilityMethod, functionName, parameters, datas); }