diff --git a/Modbus.Net/Modbus.Net.Core/ConfigurationManager.cs b/Modbus.Net/Modbus.Net.Core/ConfigurationManager.cs
index 55e5301..9fb6291 100644
--- a/Modbus.Net/Modbus.Net.Core/ConfigurationManager.cs
+++ b/Modbus.Net/Modbus.Net.Core/ConfigurationManager.cs
@@ -14,5 +14,7 @@ namespace Modbus.Net
private static IConfigurationRoot Configuration => builder.Build();
public static IConfigurationSection AppSettings => Configuration.GetSection("AppSettings");
+
+ public static IConfigurationSection ConnectionStrings => Configuration.GetSection("ConnectionStrings");
}
}
\ No newline at end of file
diff --git a/Modbus.Net/Modbus.Net.Core/Modbus.Net.Core.csproj b/Modbus.Net/Modbus.Net.Core/Modbus.Net.Core.csproj
index 3e7c4ae..c1c1818 100644
--- a/Modbus.Net/Modbus.Net.Core/Modbus.Net.Core.csproj
+++ b/Modbus.Net/Modbus.Net.Core/Modbus.Net.Core.csproj
@@ -48,12 +48,14 @@
+
+
diff --git a/Modbus.Net/Modbus.Net.OPC/OpcUtility.cs b/Modbus.Net/Modbus.Net.OPC/OpcUtility.cs
index 137637b..50ce8a5 100644
--- a/Modbus.Net/Modbus.Net.OPC/OpcUtility.cs
+++ b/Modbus.Net/Modbus.Net.OPC/OpcUtility.cs
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace Modbus.Net.OPC
{
- public abstract class OpcUtility : BaseUtility
+ public abstract class OpcUtility : BaseUtility>
{
protected OpcUtility(string connectionString) : base(0, 0)
{
diff --git a/Modbus.Net/Modbus.Net/Modbus.Net.csproj b/Modbus.Net/Modbus.Net/Modbus.Net.csproj
index 2d503be..00e6daa 100644
--- a/Modbus.Net/Modbus.Net/Modbus.Net.csproj
+++ b/Modbus.Net/Modbus.Net/Modbus.Net.csproj
@@ -47,6 +47,11 @@
+
+
+
+
+
diff --git a/Modbus.Net/src/Base.Common/BaseMachine.cs b/Modbus.Net/src/Base.Common/BaseMachine.cs
index 80d26c8..757df30 100644
--- a/Modbus.Net/src/Base.Common/BaseMachine.cs
+++ b/Modbus.Net/src/Base.Common/BaseMachine.cs
@@ -661,6 +661,11 @@ namespace Modbus.Net
{
return BaseUtility.Disconnect();
}
+
+ public string GetMachineIdString()
+ {
+ return Id.ToString();
+ }
}
internal class BaseMachineEqualityComparer : IEqualityComparer>
@@ -754,7 +759,7 @@ namespace Modbus.Net
///
/// 地址单元
///
- public class AddressUnit where TKey : IEquatable
+ public class AddressUnit : IEquatable> where TKey : IEquatable
{
///
/// 数据单元Id
@@ -815,31 +820,15 @@ namespace Modbus.Net
/// 扩展
///
public UnitExtend UnitExtend { get; set; }
- }
- internal struct AddressUnitEqualityComparer : IEqualityComparer> where TKey : IEquatable
- {
- public bool Equals(AddressUnit x, AddressUnit y)
+ public bool Equals(AddressUnit other)
{
- return (x.Area.ToUpper() == y.Area.ToUpper() && x.Address == y.Address) || x.Id.Equals(y.Id);
- }
-
- public int GetHashCode(AddressUnit obj)
- {
- return obj.GetHashCode();
+ return (Area.ToUpper() == other.Area.ToUpper() && Address == other.Address) || Id.Equals(other.Id);
}
}
- ///
- /// 设备的抽象
- ///
- public interface IMachineProperty where TKey : IEquatable
+ public interface IMachinePropertyWithoutKey
{
- ///
- /// Id
- ///
- TKey Id { get; set; }
-
///
/// 工程名
///
@@ -898,5 +887,18 @@ namespace Modbus.Net
///
/// 是否断开成功
bool Disconnect();
+
+ string GetMachineIdString();
+ }
+
+ ///
+ /// 设备的抽象
+ ///
+ public interface IMachineProperty : IMachinePropertyWithoutKey where TKey : IEquatable
+ {
+ ///
+ /// Id
+ ///
+ TKey Id { get; set; }
}
}
\ No newline at end of file
diff --git a/Modbus.Net/src/Base.Common/BaseProtocal.cs b/Modbus.Net/src/Base.Common/BaseProtocal.cs
index c4db1f3..627be11 100644
--- a/Modbus.Net/src/Base.Common/BaseProtocal.cs
+++ b/Modbus.Net/src/Base.Common/BaseProtocal.cs
@@ -10,11 +10,6 @@ namespace Modbus.Net
///
public abstract class BaseProtocal : BaseProtocal
{
- ///
- /// 协议的连接器
- ///
- public new ProtocalLinker ProtocalLinker { get; set; }
-
///
/// 构造器
///
diff --git a/Modbus.Net/src/Base.Common/BaseUtility.cs b/Modbus.Net/src/Base.Common/BaseUtility.cs
index 830b401..86172fb 100644
--- a/Modbus.Net/src/Base.Common/BaseUtility.cs
+++ b/Modbus.Net/src/Base.Common/BaseUtility.cs
@@ -28,7 +28,7 @@ namespace Modbus.Net
///
/// 基础Api入口
///
- public abstract class BaseUtility : BaseUtility
+ public abstract class BaseUtility : BaseUtility
{
///
/// 构造器
@@ -37,23 +37,17 @@ namespace Modbus.Net
{
}
-
- ///
- /// 协议收发主体
- ///
- protected new BaseProtocal Wrapper;
-
}
///
/// 基础Api入口
///
- public abstract class BaseUtility : IUtilityProperty, IUtilityMethodData
+ public abstract class BaseUtility : IUtilityProperty, IUtilityMethodData where TProtocalUnit : ProtocalUnit
{
///
/// 协议收发主体
///
- protected BaseProtocal> Wrapper;
+ protected BaseProtocal Wrapper;
///
/// 构造器
@@ -160,7 +154,7 @@ namespace Modbus.Net
return null;
}
}
-
+
///
/// 获取数据
///
@@ -296,7 +290,7 @@ namespace Modbus.Net
if (this is TUtilityMethod)
{
Type t = typeof(TUtilityMethod);
- object returnValue = t.GetRuntimeMethod(methodName, parameters.Select(p => p.GetType()).ToArray())
+ object returnValue = t.GetRuntimeMethod(methodName, parameters.Select(p => p.GetType()).ToArray(), false)
.Invoke(this, parameters);
return (TReturnType)returnValue;
}
diff --git a/Modbus.Net/src/Base.Common/ProtocalLinker.cs b/Modbus.Net/src/Base.Common/ProtocalLinker.cs
index 0d2bf45..3ec9995 100644
--- a/Modbus.Net/src/Base.Common/ProtocalLinker.cs
+++ b/Modbus.Net/src/Base.Common/ProtocalLinker.cs
@@ -9,11 +9,6 @@ namespace Modbus.Net
///
public abstract class ProtocalLinker : ProtocalLinker
{
- ///
- /// 传输连接器
- ///
- protected new BaseConnector BaseConnector;
-
///
/// 发送并接收数据
///
diff --git a/Modbus.Net/src/Base.Common/TaskManager.cs b/Modbus.Net/src/Base.Common/TaskManager.cs
index f6058ec..00ae740 100644
--- a/Modbus.Net/src/Base.Common/TaskManager.cs
+++ b/Modbus.Net/src/Base.Common/TaskManager.cs
@@ -8,34 +8,27 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Nito.AsyncEx;
namespace Modbus.Net
{
///
/// 返回结果的定义类
///
- public class TaskReturnDef : TaskReturnDef
+ public class DataReturnDef : DataReturnDef
{
-
+
}
///
/// 返回结果的定义类
///
- public class TaskReturnDef where TMachineKey : IEquatable
+ public class DataReturnDef where TMachineKey : IEquatable
{
public TMachineKey MachineId { get; set; }
public Dictionary ReturnValues { get; set; }
}
- ///
- /// 时间定义
- ///
- public static class TimeRestore
- {
- public static int Restore = 0;
- }
-
public class LimitedConcurrencyLevelTaskScheduler : TaskScheduler
{
///
@@ -105,7 +98,7 @@ namespace Modbus.Net
///
private void NotifyThreadPoolOfPendingWork()
{
-#if NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462
+#if NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47
ThreadPool.UnsafeQueueUserWorkItem(_ =>
#else
ThreadPool.QueueUserWorkItem(_ =>
@@ -199,51 +192,270 @@ namespace Modbus.Net
}
}
+ public class TaskMachine where TMachineKey : IEquatable
+ {
+ private TaskFactory _tasks { get; }
+
+ public TaskMachine(IMachineProperty machine, TaskFactory taskFactory)
+ {
+ Machine = machine;
+ _tasks = taskFactory;
+ }
+
+ public IMachineProperty Machine { get; }
+
+ public List TasksWithTimer { get; set; }
+
+ public bool InvokeTimer(TaskItem task)
+ {
+ task.DetectConnected = () => Machine.IsConnected;
+ task.GetMachine = () => Machine;
+ task.GetTaskFactory = () => _tasks;
+
+ if (!TasksWithTimer.Exists(taskCon => taskCon.Name == task.Name))
+ {
+ TasksWithTimer.Add(task);
+ task.StartTimer();
+ return true;
+ }
+ return false;
+ }
+
+ public bool StopTimer(string taskItemName)
+ {
+ if (TasksWithTimer.Exists(taskCon => taskCon.Name == taskItemName))
+ {
+ var task = TasksWithTimer.FirstOrDefault(taskCon => taskCon.Name == taskItemName);
+ task?.StopTimer();
+ TasksWithTimer.Remove(task);
+ return true;
+ }
+ return false;
+ }
+
+ public bool StopAllTimers()
+ {
+ bool ans = true;
+ foreach (var task in TasksWithTimer)
+ {
+ ans = ans && StopTimer(task.Name);
+ }
+ return ans;
+ }
+
+ public bool PauseTimer(string taskItemName)
+ {
+ if (TasksWithTimer.Exists(taskCon => taskCon.Name == taskItemName))
+ {
+ var task = TasksWithTimer.FirstOrDefault(taskCon => taskCon.Name == taskItemName);
+ task?.StopTimer();
+ return true;
+ }
+ return false;
+ }
+
+ public bool PauseAllTimers()
+ {
+ bool ans = true;
+ foreach (var task in TasksWithTimer)
+ {
+ ans = ans && PauseTimer(task.Name);
+ }
+ return ans;
+ }
+
+ public bool ContinueTimer(string taskItemName)
+ {
+ if (TasksWithTimer.Exists(taskCon => taskCon.Name == taskItemName))
+ {
+ var task = TasksWithTimer.FirstOrDefault(taskCon => taskCon.Name == taskItemName);
+ task?.StartTimer();
+ return true;
+ }
+ return false;
+ }
+
+ public bool ContinueAllTimers()
+ {
+ bool ans = true;
+ foreach (var task in TasksWithTimer)
+ {
+ ans = ans && ContinueTimer(task.Name);
+ }
+ return ans;
+ }
+
+ public async Task InvokeOnce(TaskItem task)
+ {
+ if (Machine.IsConnected)
+ {
+ var ans = await task.Invoke(Machine, _tasks, task.Params);
+ task.Return(ans);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ internal class TaskMachineEqualityComparer : IEqualityComparer>
+ where TKey : IEquatable
+ {
+ public bool Equals(TaskMachine x, TaskMachine y)
+ {
+ return x.Machine.Id.Equals(y.Machine.Id);
+ }
+
+ public int GetHashCode(TaskMachine obj)
+ {
+ return obj.GetHashCode();
+ }
+ }
+
+ public interface ITaskItem
+ {
+ string Name { get; set; }
+
+ bool StartTimer();
+
+ bool StopTimer();
+ }
+
+ public class TaskItemGetData : TaskItem
+ {
+ public TaskItemGetData(Action returnFunc, int getCycle, int sleepCycle)
+ {
+ Name = "GetDatas";
+ Invoke = async (machine, tasks, parameters) =>
+ {
+ var cts = new CancellationTokenSource();
+ cts.CancelAfter(TimeSpan.FromSeconds(100000));
+ var ans =
+ await tasks.Run(
+ async () => await machine.InvokeMachineMethod>>("GetDatasAsync",
+ MachineGetDataType.CommunicationTag).WithCancellation(cts.Token));
+ return new DataReturnDef
+ {
+ MachineId = machine.GetMachineIdString(),
+ ReturnValues = ans,
+ };
+ };
+ Params = null;
+ Return = returnFunc;
+ TimerDisconnectedTime = sleepCycle;
+ TimerTime = getCycle;
+ }
+ }
+
+ public class TaskItemSetData : TaskItem
+ {
+ public TaskItemSetData(Dictionary values)
+ {
+ Name = "SetDatas";
+ Invoke = Invoke = async (machine, tasks, parameters) =>
+ {
+ var cts = new CancellationTokenSource();
+ cts.CancelAfter(TimeSpan.FromSeconds(100000));
+ var ans =
+ await tasks.Run(
+ async () => await machine.InvokeMachineMethod>("SetDatasAsync", parameters[0],
+ MachineSetDataType.CommunicationTag).WithCancellation(cts.Token));
+ return ans;
+ };
+ Params = new object[]{values};
+ }
+ }
+
+ public class TaskItem : ITaskItem, IEquatable>
+ {
+ public string Name { get; set; }
+ private Timer Timer { get; set; }
+ public int TimerTime { get; set; }
+ private Timer TimerDisconnected { get; set; }
+ public int TimerDisconnectedTime { get; set; }
+ public Func> Invoke { get; set; }
+ internal Func DetectConnected { get; set; }
+ public object[] Params { get; set; }
+ public Action Return { get; set; }
+ internal Func GetMachine { get; set; }
+ internal Func GetTaskFactory { get; set; }
+
+ public bool Equals(TaskItem other)
+ {
+ return Name == other?.Name;
+ }
+
+ public bool StartTimer()
+ {
+ ActivateTimerDisconnected();
+ return true;
+ }
+
+ private void ActivateTimer()
+ {
+ Timer = new Timer(async state =>
+ {
+ if (!DetectConnected()) TimerChangeToDisconnect();
+ var ans = await Invoke(GetMachine(),GetTaskFactory(),Params);
+ Return(ans);
+ }, null, 0, TimerTime);
+ }
+
+ private void DeactivateTimer()
+ {
+ Timer.Dispose();
+ Timer = null;
+ }
+
+ private void ActivateTimerDisconnected()
+ {
+ TimerDisconnected = new Timer(async state =>
+ {
+ await GetMachine().ConnectAsync();
+ if (DetectConnected()) TimerChangeToConnect();
+ }, null, 0, TimerDisconnectedTime);
+ }
+
+ private void DeactivateTimerDisconnected()
+ {
+ TimerDisconnected.Dispose();
+ TimerDisconnected = null;
+ }
+
+ private bool TimerChangeToConnect()
+ {
+ DeactivateTimerDisconnected();
+ ActivateTimer();
+ return true;
+ }
+
+ private bool TimerChangeToDisconnect()
+ {
+ DeactivateTimer();
+ ActivateTimerDisconnected();
+ return true;
+ }
+
+ public bool StopTimer()
+ {
+ DeactivateTimer();
+ DeactivateTimerDisconnected();
+ return true;
+ }
+ }
+
///
/// 任务调度器
///
public class TaskManager : TaskManager
{
- public TaskManager(int maxRunningTask, int getCycle, bool keepConnect,
+ public TaskManager(int maxRunningTask, bool keepConnect,
MachineDataType dataType = MachineDataType.CommunicationTag)
- : base(maxRunningTask, getCycle, keepConnect, dataType)
+ : base(maxRunningTask, keepConnect, dataType)
{
}
- public new delegate void ReturnValuesDelegate(TaskReturnDef returnValue);
-
- public new event ReturnValuesDelegate ReturnValues;
-
- ///
- /// 执行对具体设备的数据更新
- ///
- /// 设备的实例
- ///
- protected override async Task RunTask(IMachineProperty machine)
- {
- try
- {
- var ans = await GetValue(machine);
- ReturnValues?.Invoke(new TaskReturnDef
- {
- MachineId = machine.Id,
- ReturnValues = ans
- });
- }
- catch (Exception e)
- {
- if (!machine.IsConnected)
- {
- MoveMachineToUnlinked(machine.Id);
- }
- ReturnValues?.Invoke(new TaskReturnDef
- {
- MachineId = machine.Id,
- ReturnValues = null
- });
- }
- }
-
public void AddMachine(BaseMachine machine)
{
base.AddMachine(machine);
@@ -271,29 +483,13 @@ namespace Modbus.Net
///
public class TaskManager where TMachineKey : IEquatable
{
- ///
- /// 返回数据代理
- ///
- ///
- public delegate void ReturnValuesDelegate(TaskReturnDef returnValue);
-
///
/// 正在运行的设备
///
- private readonly HashSet> _machines;
-
- ///
- /// 不在运行的设备
- ///
- private readonly HashSet> _unlinkedMachines;
+ private readonly HashSet> _machines;
private CancellationTokenSource _cts;
- ///
- /// 获取间隔
- ///
- private int _getCycle;
-
///
/// 保持连接
///
@@ -309,34 +505,32 @@ namespace Modbus.Net
///
private TaskFactory _tasks;
- ///
- /// 正常读取的计时器
- ///
- private Timer _timer;
-
- ///
- /// 重连计时器
- ///
- private Timer _timer2;
-
///
/// 构造一个TaskManager
///
/// 同时可以运行的任务数
- /// 读取数据的时间间隔(毫秒)
/// 读取数据后是否保持连接
/// 获取与设置数据的方式
- public TaskManager(int maxRunningTask, int getCycle, bool keepConnect,
+ public TaskManager(int maxRunningTask, bool keepConnect,
MachineDataType dataType = MachineDataType.CommunicationTag)
{
_scheduler = new LimitedConcurrencyLevelTaskScheduler(maxRunningTask);
_machines =
- new HashSet>(new BaseMachineEqualityComparer());
- _unlinkedMachines =
- new HashSet>(new BaseMachineEqualityComparer());
- _getCycle = getCycle;
+ new HashSet>(new TaskMachineEqualityComparer());
KeepConnect = keepConnect;
MachineDataType = dataType;
+ _cts = new CancellationTokenSource();
+ _tasks = new TaskFactory(_cts.Token, TaskCreationOptions.None, TaskContinuationOptions.None, _scheduler);
+ }
+
+ ///
+ /// 强制停止所有正在运行的任务
+ ///
+ public void TaskHalt()
+ {
+ _cts.Cancel();
+ _cts = new CancellationTokenSource();
+ _tasks = new TaskFactory(_cts.Token, TaskCreationOptions.None, TaskContinuationOptions.None, _scheduler);
}
///
@@ -347,61 +541,16 @@ namespace Modbus.Net
get { return _keepConnect; }
set
{
- TaskStop();
+ PauseTimerAll();
_keepConnect = value;
lock (_machines)
{
foreach (var machine in _machines)
{
- machine.KeepConnect = _keepConnect;
+ machine.Machine.KeepConnect = _keepConnect;
}
}
- }
- }
-
- ///
- /// 获取间隔,毫秒
- ///
- public int GetCycle
- {
- get { return _getCycle; }
- set
- {
- if (value == _getCycle) return;
-
- if (value == Timeout.Infinite)
- {
- if (_timer != null)
- {
- _timer.Change(Timeout.Infinite, Timeout.Infinite);
- _timer2.Change(Timeout.Infinite, Timeout.Infinite);
- _timer.Dispose();
- _timer2.Dispose();
- _timer = null;
- _timer2 = null;
- }
- }
- else if (value < 0) return;
- else
- {
- if (_timer != null)
- {
- _timer.Change(Timeout.Infinite, Timeout.Infinite);
- _timer2.Change(Timeout.Infinite, Timeout.Infinite);
- _timer.Dispose();
- _timer2.Dispose();
- _timer = null;
- _timer2 = null;
- }
- if (value > 0)
- {
- _getCycle = value;
- }
- _timer = new Timer(MaintainTasks, null, 0, _getCycle);
- _timer2 = new Timer(MaintainTasks2, null, _getCycle*2, _getCycle*2);
- //调试行,调试时请注释上面两行并取消下面一行的注释,每台设备只会执行一次数据获取。
- //MaintainTasks(null);
- }
+ ContinueTimerAll();
}
}
@@ -450,26 +599,23 @@ namespace Modbus.Net
get { return _scheduler.MaximumConcurrencyLevel; }
set
{
- TaskStop();
+ PauseTimerAll();
_scheduler = new LimitedConcurrencyLevelTaskScheduler(value);
+ ContinueTimerAll();
}
}
- ///
- /// 返回数据事件
- ///
- public event ReturnValuesDelegate ReturnValues;
-
///
/// 添加一台设备
///
/// 设备
- public void AddMachine(BaseMachine machine) where TUnitKey : IEquatable
+ public void AddMachine(BaseMachine machine)
+ where TUnitKey : IEquatable
{
machine.KeepConnect = KeepConnect;
lock (_machines)
{
- _machines.Add(machine);
+ _machines.Add(new TaskMachine(machine, _tasks) {TasksWithTimer = new List()});
}
}
@@ -477,7 +623,8 @@ namespace Modbus.Net
/// 添加多台设备
///
/// 设备的列表
- public void AddMachines(IEnumerable> machines) where TUnitKey : IEquatable
+ public void AddMachines(IEnumerable> machines)
+ where TUnitKey : IEquatable
{
lock (_machines)
{
@@ -493,17 +640,10 @@ namespace Modbus.Net
{
try
{
- IMachineProperty machine;
+ TaskMachine machine;
lock (_machines)
{
- machine = _machines.FirstOrDefault(p => p.Id.Equals(id));
- if (machine == null)
- {
- lock (_unlinkedMachines)
- {
- machine = _unlinkedMachines.FirstOrDefault(p => p.Id.Equals(id));
- }
- }
+ machine = _machines.FirstOrDefault(p => p.Machine.Id.Equals(id));
}
return machine as BaseMachine;
}
@@ -519,17 +659,10 @@ namespace Modbus.Net
{
try
{
- IMachineProperty machine;
+ TaskMachine machine;
lock (_machines)
{
- machine = _machines.FirstOrDefault(p => p.ConnectionToken == connectionToken);
- if (machine == null)
- {
- lock (_unlinkedMachines)
- {
- machine = _unlinkedMachines.FirstOrDefault(p => p.ConnectionToken == connectionToken);
- }
- }
+ machine = _machines.FirstOrDefault(p => p.Machine.ConnectionToken == connectionToken);
}
return machine as BaseMachine;
}
@@ -548,11 +681,7 @@ namespace Modbus.Net
{
lock (_machines)
{
- _machines.RemoveWhere(p => p.ConnectionToken == machineToken);
- }
- lock (_unlinkedMachines)
- {
- _unlinkedMachines.RemoveWhere(p => p.ConnectionToken == machineToken);
+ _machines.RemoveWhere(p => p.Machine.ConnectionToken == machineToken);
}
}
@@ -564,55 +693,7 @@ namespace Modbus.Net
{
lock (_machines)
{
- _machines.RemoveWhere(p => p.Id.Equals(id));
- }
- lock (_unlinkedMachines)
- {
- _unlinkedMachines.RemoveWhere(p => p.Id.Equals(id));
- }
- }
-
- ///
- /// 将设备指定为未连接
- ///
- /// 设备的id
- public void MoveMachineToUnlinked(TMachineKey id)
- {
- IEnumerable> machines;
- lock (_machines)
- {
- machines = _machines.Where(c => c.Id.Equals(id)).ToList();
- if (!machines.Any()) return;
- _machines.RemoveWhere(p => p.Id.Equals(id));
- }
- lock (_unlinkedMachines)
- {
- foreach (var machine in machines)
- {
- _unlinkedMachines.Add(machine);
- }
- }
- }
-
- ///
- /// 将设备指定为已连接
- ///
- /// 设备的id
- public void MoveMachineToLinked(TMachineKey id)
- {
- IEnumerable> machines;
- lock (_unlinkedMachines)
- {
- machines = _unlinkedMachines.Where(c => c.Id.Equals(id)).ToList();
- if (!machines.Any()) return;
- _unlinkedMachines.RemoveWhere(p => p.Id.Equals(id));
- }
- lock (_machines)
- {
- foreach (var machine in machines)
- {
- _machines.Add(machine);
- }
+ _machines.RemoveWhere(p => p.Machine.Id.Equals(id));
}
}
@@ -624,192 +705,161 @@ namespace Modbus.Net
{
lock (_machines)
{
- _machines.Remove(machine);
- }
- lock (_unlinkedMachines)
- {
- _unlinkedMachines.Remove(machine);
+ _machines.RemoveWhere(p=>p.Machine.Equals(machine));
}
}
- ///
- /// 已连接设备更新
- ///
- ///
- private void MaintainTasks(object sender)
- {
- AsyncHelper.RunSync(MaintainTasksAsync);
- }
-
- ///
- /// 未连接设备更新
- ///
- ///
- private void MaintainTasks2(object sender)
- {
- AsyncHelper.RunSync(MaintainTasks2Async);
- }
-
- ///
- /// 已连接设备更新
- ///
- ///
- private async Task MaintainTasksAsync()
- {
- try
- {
- var tasks = new List();
- var saveMachines = new HashSet>();
- IEnumerable> saveMachinesEnum;
- lock (_machines)
- {
- saveMachines.UnionWith(_machines);
- saveMachinesEnum = saveMachines.ToList();
- }
- foreach (var machine in saveMachinesEnum)
- {
- var cts = new CancellationTokenSource();
- cts.CancelAfter(TimeSpan.FromSeconds(_getCycle*10));
- var task = _tasks.StartNew(() => RunTask(machine).WithCancellation(cts.Token));
- tasks.Add(task);
- }
- await Task.WhenAll(tasks);
- }
- catch (Exception)
- {
- //ignore
- }
- }
-
- ///
- /// 未连接设备更新
- ///
- ///
- private async Task MaintainTasks2Async()
- {
- try
- {
- var tasks = new List();
- var saveMachines = new HashSet>();
- lock (_unlinkedMachines)
- {
- saveMachines.UnionWith(_unlinkedMachines);
- }
- foreach (var machine in saveMachines)
- {
- var cts = new CancellationTokenSource();
- cts.CancelAfter(TimeSpan.FromSeconds(_getCycle*10));
- var task = _tasks.StartNew(() => RunTask(machine).WithCancellation(cts.Token));
- tasks.Add(task);
- }
- await Task.WhenAll(tasks);
- }
- catch (Exception)
- {
- //ignore
- }
- }
-
- ///
- /// 设置数据
- ///
- /// 设备的连接标识
- /// 需要设置的数据
- /// 是否设置成功
- public async Task SetDatasAsync(string connectionToken,
- Dictionary values)
- {
- IMachineProperty machine = null;
- lock (_machines)
- {
- machine = _machines.FirstOrDefault(p => p.ConnectionToken == connectionToken);
- }
- if (machine == null) return false;
- return await machine.InvokeMachineMethod>("SetDatasAsync", SetDataType, values);
- }
-
- ///
- /// 启动TaskManager
- ///
- public void TaskStart()
- {
- TaskStop();
- _cts = new CancellationTokenSource();
- _tasks = new TaskFactory(_cts.Token, TaskCreationOptions.None, TaskContinuationOptions.None, _scheduler);
- GetCycle = TimeRestore.Restore;
- }
-
- ///
- /// 停止TaskManager
- ///
- public void TaskStop()
+ public bool InvokeTimerAll(TaskItem item)
{
lock (_machines)
{
- GetCycle = Timeout.Infinite;
- _cts?.Cancel();
- if (_machines != null)
+ foreach (var machine in _machines)
{
- foreach (var machine in _machines)
- {
- machine.Disconnect();
- }
+ machine.InvokeTimer(item);
}
- _tasks = null;
}
+ return true;
}
- ///
- /// 执行对具体设备的数据更新
- ///
- /// 设备的实例
- ///
- protected virtual async Task RunTask(IMachineProperty machine)
+ public bool StopTimerAll()
{
- try
+ lock (_machines)
{
- var ans = await GetValue(machine);
- ReturnValues?.Invoke(new TaskReturnDef
+ foreach (var machine in _machines)
{
- MachineId = machine.Id,
- ReturnValues = ans
- });
- }
- catch (Exception e)
- {
- if (!machine.IsConnected)
- {
- MoveMachineToUnlinked(machine.Id);
+ machine.StopAllTimers();
}
- ReturnValues?.Invoke(new TaskReturnDef
- {
- MachineId = machine.Id,
- ReturnValues = null
- });
}
+ return true;
}
- protected async Task> GetValue(IMachineProperty machine)
+ public bool StopTimerAll(string taskItemName)
{
- //调试代码,调试时取消下面一下代码的注释,会同步调用获取数据。
- //var ans = machine.GetDatas();
- //设置Cancellation Token
- var cts = new CancellationTokenSource();
- //超时后取消任务
- cts.CancelAfter(TimeSpan.FromSeconds(_getCycle));
- //读取数据
- var ans =
- await machine.InvokeMachineMethod>>("GetDatasAsync",
- GetDataType).WithCancellation(cts.Token);
- if (!machine.IsConnected)
+ lock (_machines)
{
- MoveMachineToUnlinked(machine.Id);
+ foreach (var machine in _machines)
+ {
+ machine.StopTimer(taskItemName);
+ }
}
- else
+ return true;
+ }
+
+ public bool PauseTimerAll()
+ {
+ lock (_machines)
{
- MoveMachineToLinked(machine.Id);
+ foreach (var machine in _machines)
+ {
+ machine.PauseAllTimers();
+ }
}
- return ans;
+ return true;
+ }
+
+ public bool PauseTimerAll(string taskItemName)
+ {
+ lock (_machines)
+ {
+ foreach (var machine in _machines)
+ {
+ machine.PauseTimer(taskItemName);
+ }
+ }
+ return true;
+ }
+
+ public bool ContinueTimerAll()
+ {
+ lock (_machines)
+ {
+ foreach (var machine in _machines)
+ {
+ machine.ContinueAllTimers();
+ }
+ }
+ return true;
+ }
+
+ public bool ConinueTimerAll(string taskItemName)
+ {
+ lock (_machines)
+ {
+ foreach (var machine in _machines)
+ {
+ machine.ContinueTimer(taskItemName);
+ }
+ }
+ return true;
+ }
+
+ public async Task InvokeOnceAll(TaskItem item)
+ {
+ var tasks = new List>();
+ lock (_machines)
+ {
+ foreach (var machine in _machines)
+ {
+ tasks.Add(machine.InvokeOnce(item));
+ }
+ }
+ var ans = await Task.WhenAll(tasks);
+ return ans.All(p=>p);
+ }
+
+ public async Task InvokeOnceForMachine(TMachineKey machineId, TaskItem item)
+ {
+ var machine = _machines.FirstOrDefault(p => p.Machine.Id.Equals(machineId));
+ if (machine != null)
+ {
+ await machine.InvokeOnce(item);
+ return true;
+ }
+ return false;
+ }
+
+ public bool InvokeTimerForMachine(TMachineKey machineId, TaskItem item)
+ {
+ var machine = _machines.FirstOrDefault(p => p.Machine.Id.Equals(machineId));
+ if (machine != null)
+ {
+ machine.InvokeTimer(item);
+ return true;
+ }
+ return false;
+ }
+
+ public bool StopTimerForMachine(TMachineKey machineId, string taskItemName)
+ {
+ var machine = _machines.FirstOrDefault(p => p.Machine.Id.Equals(machineId));
+ if (machine != null)
+ {
+ machine.StopTimer(taskItemName);
+ return true;
+ }
+ return false;
+ }
+
+ public bool PauseTimerForMachine(TMachineKey machineId, string taskItemName)
+ {
+ var machine = _machines.FirstOrDefault(p => p.Machine.Id.Equals(machineId));
+ if (machine != null)
+ {
+ machine.PauseTimer(taskItemName);
+ return true;
+ }
+ return false;
+ }
+
+ public bool ContinueTimerForMachine(TMachineKey machineId, string taskItemName)
+ {
+ var machine = _machines.FirstOrDefault(p => p.Machine.Id.Equals(machineId));
+ if (machine != null)
+ {
+ machine.ContinueTimer(taskItemName);
+ return true;
+ }
+ return false;
}
}
}
\ No newline at end of file
diff --git a/Modbus.Net/src/Base.Common/TypeExtensions.cs b/Modbus.Net/src/Base.Common/TypeExtensions.cs
new file mode 100644
index 0000000..282f839
--- /dev/null
+++ b/Modbus.Net/src/Base.Common/TypeExtensions.cs
@@ -0,0 +1,126 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Modbus.Net
+{
+ public static class TypeExtensions
+ {
+ #region Public Methods
+
+ ///
+ /// Looks for the method in the type matching the name and arguments.
+ ///
+ ///
+ ///
+ /// The name of the method to find.
+ ///
+ ///
+ /// The types of the method's arguments to match.
+ ///
+ ///
+ ///
+ /// Thrown if:
+ /// - The name of the method is not specified.
+ ///
+ public static MethodInfo GetRuntimeMethod(this Type type, string methodName, Type[] args, bool isGenericMethod)
+ {
+ if (ReferenceEquals(type, null))
+ throw new NullReferenceException("The type has not been specified.");
+
+ if (string.IsNullOrEmpty(methodName))
+ throw new ArgumentNullException("methodName", "The name of the method has not been specified.");
+
+
+ var methods = type.GetRuntimeMethods().Where(methodInfo => string.Equals(methodInfo.Name, methodName, StringComparison.OrdinalIgnoreCase)).ToList();
+
+ if (!methods.Any())
+ return null; // No methods have the specified name.
+
+ if (isGenericMethod)
+ {
+ methods = methods.Where(method => method.IsGenericMethod).ToList();
+ }
+ else
+ {
+ methods = methods.Where(method => !method.IsGenericMethod).ToList();
+ }
+
+ var ans = methods.Where(method => IsSignatureMatch(method, args));
+
+ if (ans.Count() <= 1)
+ {
+ return ans.Count() == 1 ? ans.Single() : null;
+ }
+
+ // Oh noes, don't make me go there.
+ throw new NotImplementedException("Resolving overloaded methods is not implemented as of now.");
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ ///
+ /// Finds out if the provided arguments matches the specified method's signature.
+ ///
+ ///
+ ///
+ ///
+ private static bool IsSignatureMatch(MethodBase methodInfo, Type[] args)
+ {
+ Debug.Assert(!ReferenceEquals(methodInfo, null), "The methodInfo has not been specified.");
+
+
+ // Gets the parameters of the method to analyze.
+ ParameterInfo[] parameters = methodInfo.GetParameters();
+
+ int currentArgId = 0;
+
+ foreach (ParameterInfo parameterInfo in parameters)
+ {
+ if (!ReferenceEquals(args, null) && currentArgId < args.Length)
+ {
+ // Find out if the types matchs.
+ if (parameterInfo.ParameterType == args[currentArgId])
+ {
+ currentArgId++;
+ continue; // Yeah! Try the next one.
+ }
+
+ // Is this a generic parameter?
+ if (parameterInfo.ParameterType.IsGenericParameter)
+ {
+ // Gets the base type of the generic parameter.
+ Type baseType = parameterInfo.ParameterType.GetTypeInfo().BaseType;
+
+
+ // TODO: This is not good v and works with the most simple situation.
+ // Does the base type match?
+ if (args[currentArgId].GetTypeInfo().BaseType == baseType)
+ {
+ currentArgId++;
+ continue; // Yeah! Go on to the next parameter.
+ }
+ }
+ }
+
+ // Is this parameter optional or does it have a default value?
+ if (parameterInfo.IsOptional || parameterInfo.HasDefaultValue)
+ continue; // Uhum. So let's ignore this parameter for now.
+
+ // No need to go further. It does not match :(
+ return false;
+ }
+
+ // Ye!
+ return true;
+ }
+
+ #endregion
+ }
+}
diff --git a/Samples/AnyType/Controllers/HomeController.cs b/Samples/AnyType/Controllers/HomeController.cs
index 93b730f..ad7d7de 100644
--- a/Samples/AnyType/Controllers/HomeController.cs
+++ b/Samples/AnyType/Controllers/HomeController.cs
@@ -55,38 +55,39 @@ namespace AnyType.Controllers
};
//初始化任务管理器
- task = new TaskManager(10, 300, true);
+ task = new TaskManager(10, true);
//向任务管理器中添加设备
task.AddMachine(new ModbusMachine(ModbusType.Tcp, "192.168.3.10", addressUnits,
true, 2, 0));
- //增加值返回时的处理函数
- task.ReturnValues += (returnValues) =>
+ //启动任务
+ task.InvokeTimerAll(new TaskItemGetData(returnValues =>
{
//唯一的参数包含返回值,是一个唯一标识符(machine的第二个参数),返回值(类型ReturnUnit)的键值对。
if (returnValues.ReturnValues != null)
{
lock (values)
{
- var unitValues = from val in returnValues.ReturnValues select new Tuple(addressUnits.FirstOrDefault(p => p.CommunicationTag == val.Key), val.Value.PlcValue);
+ var unitValues = from val in returnValues.ReturnValues
+ select
+ new Tuple(
+ addressUnits.FirstOrDefault(p => p.CommunicationTag == val.Key), val.Value.PlcValue);
values = from unitValue in unitValues
- select
- new TaskViewModel()
- {
- Id = unitValue.Item1.Id,
- Name = unitValue.Item1.Name,
- Address = unitValue.Item1.Address + "." + unitValue.Item1.SubAddress,
- Value = unitValue.Item2 ?? 0,
- Type = unitValue.Item1.DataType.Name
- };
+ select
+ new TaskViewModel()
+ {
+ Id = unitValue.Item1.Id,
+ Name = unitValue.Item1.Name,
+ Address = unitValue.Item1.Address + "." + unitValue.Item1.SubAddress,
+ Value = unitValue.Item2 ?? 0,
+ Type = unitValue.Item1.DataType.Name
+ };
}
}
else
{
Console.WriteLine($"ip {returnValues.MachineId} not return value");
}
- };
- //启动任务
- task.TaskStart();
+ }, 15000, 60000));
}
[HttpGet]
diff --git a/Samples/TaskManager/Controllers/HomeController.cs b/Samples/TaskManager/Controllers/HomeController.cs
index d34abc4..484df23 100644
--- a/Samples/TaskManager/Controllers/HomeController.cs
+++ b/Samples/TaskManager/Controllers/HomeController.cs
@@ -47,38 +47,39 @@ namespace TaskManager.Controllers
};
//初始化任务管理器
- task = new Modbus.Net.TaskManager(10, 300, true);
+ task = new Modbus.Net.TaskManager(10, true);
//向任务管理器中添加设备
task.AddMachine(new ModbusMachine(ModbusType.Tcp, "192.168.3.10", addressUnits,
true, 2, 0));
- //增加值返回时的处理函数
- task.ReturnValues += (returnValues) =>
+ //启动任务
+ task.InvokeTimerAll(new TaskItemGetData(returnValues =>
{
//唯一的参数包含返回值,是一个唯一标识符(machine的第二个参数),返回值(类型ReturnUnit)的键值对。
if (returnValues.ReturnValues != null)
- {
+ {
lock (values)
{
- var unitValues = from val in returnValues.ReturnValues select new Tuple(addressUnits.FirstOrDefault(p => p.CommunicationTag == val.Key), val.Value.PlcValue);
+ var unitValues = from val in returnValues.ReturnValues
+ select
+ new Tuple(
+ addressUnits.FirstOrDefault(p => p.CommunicationTag == val.Key), val.Value.PlcValue);
values = from unitValue in unitValues
select
- new TaskViewModel()
- {
- Id = unitValue.Item1.Id,
- Name = unitValue.Item1.Name,
- Address = unitValue.Item1.Address.ToString(),
- Value = unitValue.Item2 ?? 0,
- Type = unitValue.Item1.DataType.Name
- };
+ new TaskViewModel()
+ {
+ Id = unitValue.Item1.Id,
+ Name = unitValue.Item1.Name,
+ Address = unitValue.Item1.Address.ToString(),
+ Value = unitValue.Item2 ?? 0,
+ Type = unitValue.Item1.DataType.Name
+ };
}
}
else
{
Console.WriteLine($"ip {returnValues.MachineId} not return value");
}
- };
- //启动任务
- task.TaskStart();
+ }, 15000, 60000));
}
[HttpGet]
diff --git a/Tests/Modbus.Net.Tests/BaseTest.cs b/Tests/Modbus.Net.Tests/BaseTest.cs
index c6b1249..46cb258 100644
--- a/Tests/Modbus.Net.Tests/BaseTest.cs
+++ b/Tests/Modbus.Net.Tests/BaseTest.cs
@@ -142,7 +142,7 @@ namespace Modbus.Net.Tests
MachineName = "Test 2"
};
- _taskManager = new TaskManager(10, 3000, true);
+ _taskManager = new TaskManager(10, true);
_taskManager.AddMachine(_baseMachine);
_taskManager.AddMachine(_baseMachine2);