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);
}