diff --git a/Sharp7.Rx/Interfaces/IPlc.cs b/Sharp7.Rx/Interfaces/IPlc.cs index 31be636..b2c4aca 100644 --- a/Sharp7.Rx/Interfaces/IPlc.cs +++ b/Sharp7.Rx/Interfaces/IPlc.cs @@ -1,5 +1,4 @@ using JetBrains.Annotations; -using Microsoft.Extensions.Logging; using Sharp7.Rx.Enums; namespace Sharp7.Rx.Interfaces; @@ -7,12 +6,13 @@ namespace Sharp7.Rx.Interfaces; [NoReorder] public interface IPlc : IDisposable { - IObservable CreateNotification(string variableName, TransmissionMode transmissionMode); - Task SetValue(string variableName, TValue value, CancellationToken token = default); - Task GetValue(string variableName, CancellationToken token = default); IObservable ConnectionState { get; } + Task SetValue(string variableName, TValue value, CancellationToken token = default); + + Task GetValue(string variableName, CancellationToken token = default); Task GetValue(string variableName, CancellationToken token = default); - ILogger Logger { get; } + IObservable CreateNotification(string variableName, TransmissionMode transmissionMode); + IObservable CreateNotification(string variableName, TransmissionMode transmissionMode); } diff --git a/Sharp7.Rx/Sharp7.Rx.csproj b/Sharp7.Rx/Sharp7.Rx.csproj index 210e8d5..3067b4e 100644 --- a/Sharp7.Rx/Sharp7.Rx.csproj +++ b/Sharp7.Rx/Sharp7.Rx.csproj @@ -36,7 +36,7 @@ - + diff --git a/Sharp7.Rx/Sharp7Plc.cs b/Sharp7.Rx/Sharp7Plc.cs index 6cde0b2..3f0b839 100644 --- a/Sharp7.Rx/Sharp7Plc.cs +++ b/Sharp7.Rx/Sharp7Plc.cs @@ -11,6 +11,7 @@ using Sharp7.Rx.Enums; using Sharp7.Rx.Extensions; using Sharp7.Rx.Interfaces; using Sharp7.Rx.Settings; +using Sharp7.Rx.Utils; namespace Sharp7.Rx; @@ -21,13 +22,17 @@ public class Sharp7Plc : IPlc private static readonly MethodInfo getValueMethod = typeof(Sharp7Plc).GetMethods() .Single(m => m.Name == nameof(GetValue) && m.GetGenericArguments().Length == 1); - private IDisposable notificationSubscription; + private static readonly MethodInfo createNotificationMethod = typeof(Sharp7Plc).GetMethods() + .Single(m => m.Name == nameof(CreateNotification) && m.GetGenericArguments().Length == 1); + private readonly ConcurrentSubjectDictionary multiVariableSubscriptions = new(StringComparer.InvariantCultureIgnoreCase); private readonly List performanceCounter = new(1000); private readonly PlcConnectionSettings plcConnectionSettings; private readonly CacheVariableNameParser variableNameParser = new CacheVariableNameParser(new VariableNameParser()); private bool disposed; private int initialized; + + private IDisposable notificationSubscription; private Sharp7Connector s7Connector; /// @@ -135,10 +140,11 @@ public class Sharp7Plc : IPlc /// /// Read PLC variable as object. + /// The return type is automatically infered from the variable name. /// /// /// - /// + /// The actual return type is infered from the variable name. public async Task GetValue(string variableName, CancellationToken token = default) { var address = variableNameParser.Parse(variableName); @@ -191,6 +197,25 @@ public class Sharp7Plc : IPlc } } + /// + /// Creates an observable of object for a variable. + /// The return type is automatically infered from the variable name. + /// + /// + /// + /// The return type is infered from the variable name. + public IObservable CreateNotification(string variableName, TransmissionMode transmissionMode) + { + var address = variableNameParser.Parse(variableName); + var clrType = address.GetClrType(); + + var genericCreateNotification = createNotificationMethod!.MakeGenericMethod(clrType); + + var genericNotification = genericCreateNotification.Invoke(this, [variableName, transmissionMode]); + + return SignatureConverter.ConvertToObjectObservable(genericNotification, clrType); + } + /// /// Trigger PLC connection and start notification loop. /// diff --git a/Sharp7.Rx/Utils/SignatureConverter.cs b/Sharp7.Rx/Utils/SignatureConverter.cs new file mode 100644 index 0000000..64f4bf0 --- /dev/null +++ b/Sharp7.Rx/Utils/SignatureConverter.cs @@ -0,0 +1,21 @@ +using System.Reactive.Linq; +using System.Reflection; + +namespace Sharp7.Rx.Utils; + +internal static class SignatureConverter +{ + private static readonly MethodInfo convertToObjectObservableMethod = + typeof(SignatureConverter) + .GetMethods(BindingFlags.Public | BindingFlags.Static) + .Single(m => m.Name == nameof(ConvertToObjectObservable) && m.GetGenericArguments().Length == 1); + + public static IObservable ConvertToObjectObservable(IObservable obs) => obs.Select(o => (object) o); + + public static IObservable ConvertToObjectObservable(object observable, Type sourceType) + { + var convertGeneric = convertToObjectObservableMethod.MakeGenericMethod(sourceType); + + return convertGeneric.Invoke(null, [observable]) as IObservable; + } +}