|
|
@@ -1,10 +1,939 @@
|
|
|
-namespace YSAI.Mewtocol
|
|
|
+using MewtocolNet;
|
|
|
+using MewtocolNet.Registers;
|
|
|
+using System.Collections.Concurrent;
|
|
|
+using YSAI.Core.data;
|
|
|
+using YSAI.Core.handler;
|
|
|
+using YSAI.Core.@interface;
|
|
|
+using YSAI.Core.subscription;
|
|
|
+using YSAI.Core.virtualAddress;
|
|
|
+using YSAI.Log;
|
|
|
+using YSAI.Unility;
|
|
|
+
|
|
|
+namespace YSAI.Mewtocol
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 松下PLC 操作
|
|
|
/// </summary>
|
|
|
- public class MewtocolOperate
|
|
|
+ public class MewtocolOperate : IBaseAbstract, IDaq
|
|
|
{
|
|
|
+ protected override string TAG => "MewtocolOperate";
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 锁
|
|
|
+ /// </summary>
|
|
|
+ private static readonly object Lock = new object();
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 自身对象集合
|
|
|
+ /// </summary>
|
|
|
+ private static List<MewtocolOperate> ThisObjList = new List<MewtocolOperate>(); //自身对象集合
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 单例模式
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ public static MewtocolOperate Instance(MewtocolData.Basics basics)
|
|
|
+ {
|
|
|
+ if (ThisObjList.Count >= MaxInstanceCount)
|
|
|
+ {
|
|
|
+ throw new Exception(ExceedMaxInstanceCountTips);
|
|
|
+ }
|
|
|
+ MewtocolOperate? exp = ThisObjList.FirstOrDefault(c => c.basics.Comparer(basics).result);
|
|
|
+ if (exp == null)
|
|
|
+ {
|
|
|
+ lock (Lock)
|
|
|
+ {
|
|
|
+ if (ThisObjList.Count(c => c.basics.Comparer(basics).result) > 0)
|
|
|
+ {
|
|
|
+ return ThisObjList.First(c => c.basics.Comparer(basics).result);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ MewtocolOperate exp2 = new MewtocolOperate(basics);
|
|
|
+ ThisObjList.Add(exp2);
|
|
|
+ return exp2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return exp;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 构造函数
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="basics">基础数据</param>
|
|
|
+ public MewtocolOperate(MewtocolData.Basics basics)
|
|
|
+ {
|
|
|
+ this.basics = basics;
|
|
|
+ }
|
|
|
+
|
|
|
+ public MewtocolOperate()
|
|
|
+ { }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 基础数据
|
|
|
+ /// </summary>
|
|
|
+ private MewtocolData.Basics basics;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 松下PLC通信 网口
|
|
|
+ /// </summary>
|
|
|
+ private IPlcEthernet MTcp;
|
|
|
+ private MewtocolNet.Mewtocol.PostInit<IPlcEthernet> mmpi;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 松下PLC通信 串口
|
|
|
+ /// </summary>
|
|
|
+ private IPlcSerial MSerial;
|
|
|
+ private MewtocolNet.Mewtocol.PostInit<IPlcSerial> mmps;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 虚拟地址
|
|
|
+ /// </summary>
|
|
|
+ private VirtualAddressManage VAM = new VirtualAddressManage();
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 实现订阅功能
|
|
|
+ /// </summary>
|
|
|
+ private SubscribeOperate subscribeOperate;
|
|
|
+
|
|
|
+ public OperateResult Read(Address address)
|
|
|
+ {
|
|
|
+ string SN = Depart("Read");
|
|
|
+ try
|
|
|
+ {
|
|
|
+ //节点数据
|
|
|
+ ConcurrentDictionary<string, AddressValue> param = new ConcurrentDictionary<string, AddressValue>();
|
|
|
+ switch (basics.ProtocolType)
|
|
|
+ {
|
|
|
+ case MewtocolData.ProtocolType.Tcp:
|
|
|
+ if (MTcp == null)
|
|
|
+ {
|
|
|
+ return Break(SN, false, "未连接");
|
|
|
+ }
|
|
|
+ //循环添加项集合
|
|
|
+ foreach (var item in address.AddressArray)
|
|
|
+ {
|
|
|
+ if (!item.IsEnable) continue;
|
|
|
+ //是不是虚拟地址
|
|
|
+ bool IsVA = false;
|
|
|
+ //初始化虚拟地址
|
|
|
+ VAM.InitVirtualAddress(item, out IsVA);
|
|
|
+ //值
|
|
|
+ string? Value = string.Empty;
|
|
|
+
|
|
|
+ if (IsVA)
|
|
|
+ {
|
|
|
+ Value = VAM.Read(item);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ switch (item.AddressDataType)
|
|
|
+ {
|
|
|
+ case Core.@enum.DataType.String:
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ //字符串 必须放数据长度
|
|
|
+ //地址名,长度
|
|
|
+ string[] strings = item.AddressName.Split(',');
|
|
|
+ c.String(strings[0], int.Parse(strings[1])).AsArray(1).Build(out IArrayRegister<string>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case Core.@enum.DataType.Byte:
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<byte>(item.AddressName).Build(out IRegister<byte>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case Core.@enum.DataType.Bool:
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Bool(item.AddressName).Build(out IRegister<bool>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case Core.@enum.DataType.Short:
|
|
|
+ case Core.@enum.DataType.Int16:
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<short>(item.AddressName).Build(out IRegister<short>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case Core.@enum.DataType.Ushort:
|
|
|
+ case Core.@enum.DataType.UInt16:
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<ushort>(item.AddressName).Build(out IRegister<ushort>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case Core.@enum.DataType.Int:
|
|
|
+ case Core.@enum.DataType.Int32:
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<Word>(item.AddressName).Build(out IRegister<Word>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case Core.@enum.DataType.Uint:
|
|
|
+ case Core.@enum.DataType.UInt32:
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<DWord>(item.AddressName).Build(out IRegister<DWord>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case Core.@enum.DataType.Double:
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<double>(item.AddressName).Build(out IRegister<double>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case Core.@enum.DataType.Float:
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<float>(item.AddressName).Build(out IRegister<float>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ LogHelper.Error($"[ {item.AddressName} ]读取失败:不支持{item.AddressDataType}类型读取");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error($"[ {item.AddressName} ]读取异常:{ex.Message}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //数据处理
|
|
|
+ AddressValue addressValue = Core.handler.AddressHandler.ExecuteDispose(item, Value);
|
|
|
+
|
|
|
+ //数据添加
|
|
|
+ param.AddOrUpdate(item.AddressName, addressValue, (k, v) => addressValue);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case MewtocolData.ProtocolType.Serial:
|
|
|
+ if (MSerial == null)
|
|
|
+ {
|
|
|
+ return Break(SN, false, "未连接");
|
|
|
+ }
|
|
|
+
|
|
|
+ //循环添加项集合
|
|
|
+ foreach (var item in address.AddressArray)
|
|
|
+ {
|
|
|
+ if (!item.IsEnable) continue;
|
|
|
+ //是不是虚拟地址
|
|
|
+ bool IsVA = false;
|
|
|
+ //初始化虚拟地址
|
|
|
+ VAM.InitVirtualAddress(item, out IsVA);
|
|
|
+ //值
|
|
|
+ string? Value = string.Empty;
|
|
|
+
|
|
|
+ if (IsVA)
|
|
|
+ {
|
|
|
+ Value = VAM.Read(item);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ switch (item.AddressDataType)
|
|
|
+ {
|
|
|
+ case Core.@enum.DataType.String:
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ //字符串 必须放数据长度
|
|
|
+ //地址名,长度
|
|
|
+ string[] strings = item.AddressName.Split(',');
|
|
|
+ c.String(strings[0], int.Parse(strings[1])).AsArray(0).Build(out IArrayRegister<string>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case Core.@enum.DataType.Byte:
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<byte>(item.AddressName).Build(out IRegister<byte>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case Core.@enum.DataType.Bool:
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Bool(item.AddressName).Build(out IRegister<bool>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case Core.@enum.DataType.Short:
|
|
|
+ case Core.@enum.DataType.Int16:
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<short>(item.AddressName).Build(out IRegister<short>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case Core.@enum.DataType.Ushort:
|
|
|
+ case Core.@enum.DataType.UInt16:
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<ushort>(item.AddressName).Build(out IRegister<ushort>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case Core.@enum.DataType.Int:
|
|
|
+ case Core.@enum.DataType.Int32:
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<Word>(item.AddressName).Build(out IRegister<Word>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case Core.@enum.DataType.Uint:
|
|
|
+ case Core.@enum.DataType.UInt32:
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<DWord>(item.AddressName).Build(out IRegister<DWord>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case Core.@enum.DataType.Double:
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<double>(item.AddressName).Build(out IRegister<double>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case Core.@enum.DataType.Float:
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<float>(item.AddressName).Build(out IRegister<float>? mValue);
|
|
|
+ Value = mValue?.ValueStr ?? string.Empty;
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ LogHelper.Error($"[ {item.AddressName} ]读取失败:不支持{item.AddressDataType}类型读取");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.Error($"[ {item.AddressName} ]读取异常:{ex.Message}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //数据处理
|
|
|
+ AddressValue addressValue = Core.handler.AddressHandler.ExecuteDispose(item, Value);
|
|
|
+
|
|
|
+ //数据添加
|
|
|
+ param.AddOrUpdate(item.AddressName, addressValue, (k, v) => addressValue);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (param.Count > 0)
|
|
|
+ {
|
|
|
+ //返回读取的数据
|
|
|
+ return Break(SN, true, RData: param, RType: Core.@enum.ResultType.KeyValue);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return Break(SN, false, "读取失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ return Break(SN, false, ex.Message, Exception: ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Task<OperateResult> ReadAsync(Address address)
|
|
|
+ {
|
|
|
+ return Task.Run(() => Read(address));
|
|
|
+ }
|
|
|
+
|
|
|
+ public OperateResult Write<V>(ConcurrentDictionary<string, V> Values)
|
|
|
+ {
|
|
|
+ string SN = Depart("Write");
|
|
|
+ try
|
|
|
+ {
|
|
|
+ //失败消息
|
|
|
+ List<string> FailMessage = new List<string>();
|
|
|
+
|
|
|
+ switch (basics.ProtocolType)
|
|
|
+ {
|
|
|
+ case MewtocolData.ProtocolType.Tcp:
|
|
|
+ if (MTcp == null)
|
|
|
+ {
|
|
|
+ return Break(SN, false, "未连接");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ foreach (var item in Values)
|
|
|
+ {
|
|
|
+ KeyValuePair<string, V> Param = item;
|
|
|
+ //判断是不是虚拟点
|
|
|
+ if (VAM.IsVirtualAddress(Param.Key))
|
|
|
+ {
|
|
|
+ if (!VAM.Write(Param.Key, Param.Value.ToString()))
|
|
|
+ {
|
|
|
+ FailMessage.Add($"{Param.Key},写入失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ bool RState = false;
|
|
|
+ object obj = Param.Value;
|
|
|
+ if (obj is byte)
|
|
|
+ {
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<byte>(Param.Key).Build(out IRegister<byte>? mValue);
|
|
|
+ RState = mValue.WriteAsync((byte)obj).Wait(basics.Timeout);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (obj is bool)
|
|
|
+ {
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Bool(Param.Key).Build(out IRegister<bool>? mValue);
|
|
|
+ RState = mValue.WriteAsync((bool)obj).Wait(basics.Timeout);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (obj is string)
|
|
|
+ {
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ //字符串 必须放数据长度
|
|
|
+ //地址名,长度
|
|
|
+ string[] strings = Param.Key.Split(',');
|
|
|
+ c.String(strings[0], int.Parse(strings[1])).AsArray(1).Build(out IArrayRegister<string>? mValue);
|
|
|
+ RState = mValue.WriteAsync(new string[] { obj.ToString() }).Wait(basics.Timeout); ;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (obj is Int16)
|
|
|
+ {
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<short>(Param.Key).Build(out IRegister<short>? mValue);
|
|
|
+ RState = mValue.WriteAsync((short)obj).Wait(basics.Timeout);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (obj is UInt16)
|
|
|
+ {
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<ushort>(Param.Key).Build(out IRegister<ushort>? mValue);
|
|
|
+ RState = mValue.WriteAsync((ushort)obj).Wait(basics.Timeout);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (obj is Int32)
|
|
|
+ {
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<Word>(Param.Key).Build(out IRegister<Word>? mValue);
|
|
|
+ RState = mValue.WriteAsync((Word)obj).Wait(basics.Timeout);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (obj is UInt32)
|
|
|
+ {
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<DWord>(Param.Key).Build(out IRegister<DWord>? mValue);
|
|
|
+ RState = mValue.WriteAsync((DWord)obj).Wait(basics.Timeout);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (obj is float)
|
|
|
+ {
|
|
|
+ mmpi.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<float>(Param.Key).Build(out IRegister<float>? mValue);
|
|
|
+ RState = mValue.WriteAsync((float)obj).Wait(basics.Timeout);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (obj is double)
|
|
|
+ {
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<double>(Param.Key).Build(out IRegister<double>? mValue);
|
|
|
+ RState = mValue.WriteAsync((double)obj).Wait(basics.Timeout);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (!RState)
|
|
|
+ {
|
|
|
+ FailMessage.Add($"{Param.Key},写入失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case MewtocolData.ProtocolType.Serial:
|
|
|
+ if (MSerial == null)
|
|
|
+ {
|
|
|
+ return Break(SN, false, "未连接");
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach (var item in Values)
|
|
|
+ {
|
|
|
+ KeyValuePair<string, V> Param = item;
|
|
|
+ //判断是不是虚拟点
|
|
|
+ if (VAM.IsVirtualAddress(Param.Key))
|
|
|
+ {
|
|
|
+ if (!VAM.Write(Param.Key, Param.Value.ToString()))
|
|
|
+ {
|
|
|
+ FailMessage.Add($"{Param.Key},写入失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ bool RState = false;
|
|
|
+ object obj = Param.Value;
|
|
|
+ if (obj is byte)
|
|
|
+ {
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<byte>(Param.Key).Build(out IRegister<byte>? mValue);
|
|
|
+ RState = mValue.WriteAsync((byte)obj).Wait(basics.Timeout);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (obj is bool)
|
|
|
+ {
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Bool(Param.Key).Build(out IRegister<bool>? mValue);
|
|
|
+ RState = mValue.WriteAsync((bool)obj).Wait(basics.Timeout);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (obj is string)
|
|
|
+ {
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ //字符串 必须放数据长度
|
|
|
+ //地址名,长度
|
|
|
+ string[] strings = Param.Key.Split(',');
|
|
|
+ c.String(strings[0], int.Parse(strings[1])).AsArray(1).Build(out IArrayRegister<string>? mValue);
|
|
|
+ RState = mValue.WriteAsync(new string[] { obj.ToString() }).Wait(basics.Timeout); ;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (obj is Int16)
|
|
|
+ {
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<short>(Param.Key).Build(out IRegister<short>? mValue);
|
|
|
+ RState = mValue.WriteAsync((short)obj).Wait(basics.Timeout);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (obj is UInt16)
|
|
|
+ {
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<ushort>(Param.Key).Build(out IRegister<ushort>? mValue);
|
|
|
+ RState = mValue.WriteAsync((ushort)obj).Wait(basics.Timeout);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (obj is Int32)
|
|
|
+ {
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<Word>(Param.Key).Build(out IRegister<Word>? mValue);
|
|
|
+ RState = mValue.WriteAsync((Word)obj).Wait(basics.Timeout);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (obj is UInt32)
|
|
|
+ {
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<DWord>(Param.Key).Build(out IRegister<DWord>? mValue);
|
|
|
+ RState = mValue.WriteAsync((DWord)obj).Wait(basics.Timeout);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (obj is float)
|
|
|
+ {
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<float>(Param.Key).Build(out IRegister<float>? mValue);
|
|
|
+ RState = mValue.WriteAsync((float)obj).Wait(basics.Timeout);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if (obj is double)
|
|
|
+ {
|
|
|
+ mmps.WithRegisters(c =>
|
|
|
+ {
|
|
|
+ c.Struct<double>(Param.Key).Build(out IRegister<double>? mValue);
|
|
|
+ RState = mValue.WriteAsync((double)obj).Wait(basics.Timeout);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (!RState)
|
|
|
+ {
|
|
|
+ FailMessage.Add($"{Param.Key},写入失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (FailMessage.Count > 0)
|
|
|
+ {
|
|
|
+ return Break(SN, false, FailMessage.ToJson());
|
|
|
+ }
|
|
|
+ return Break(SN, true, "写入成功");
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ return Break(SN, false, ex.Message, Exception: ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Task<OperateResult> WriteAsync<V>(ConcurrentDictionary<string, V> Values)
|
|
|
+ {
|
|
|
+ return Task.Run(() => Write(Values));
|
|
|
+ }
|
|
|
+
|
|
|
+ public OperateResult Subscribe(Address address)
|
|
|
+ {
|
|
|
+ string SN = Depart("Subscribe");
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (subscribeOperate == null)
|
|
|
+ {
|
|
|
+ subscribeOperate = SubscribeOperate.Instance(new SubscribeData.Basics()
|
|
|
+ {
|
|
|
+ Address = address,
|
|
|
+ ChangeOut = basics.ChangeOut,
|
|
|
+ Function = Read,
|
|
|
+ AllOut = basics.AllOut,
|
|
|
+ HandleInterval = basics.HandleInterval,
|
|
|
+ SN = basics.SN,
|
|
|
+ TaskHandleInterval = basics.TaskHandleInterval,
|
|
|
+ TaskNumber = basics.TaskNumber
|
|
|
+ });
|
|
|
+ subscribeOperate.OnEvent += OnEventHandler;
|
|
|
+ OperateResult operateResult = subscribeOperate.On();
|
|
|
+ return Break(SN, operateResult.State, operateResult.Message);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ OperateResult operateResult = subscribeOperate.Subscribe(address);
|
|
|
+ return Break(SN, operateResult.State, operateResult.Message);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ return Break(SN, false, ex.Message, Exception: ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Task<OperateResult> SubscribeAsync(Address address)
|
|
|
+ {
|
|
|
+ return Task.Run(() => Subscribe(address));
|
|
|
+ }
|
|
|
+
|
|
|
+ public OperateResult UnSubscribe(Address address)
|
|
|
+ {
|
|
|
+ string SN = Depart("UnSubscribe");
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (subscribeOperate != null)
|
|
|
+ {
|
|
|
+ OperateResult operateResult = subscribeOperate.UnSubscribe(address);
|
|
|
+ return Break(SN, operateResult.State, operateResult.Message);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return Break(SN, false, "当前尚未订阅");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ return Break(SN, false, ex.Message, Exception: ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Task<OperateResult> UnSubscribeAsync(Address address)
|
|
|
+ {
|
|
|
+ return Task.Run(() => UnSubscribe(address));
|
|
|
+ }
|
|
|
+
|
|
|
+ public OperateResult On()
|
|
|
+ {
|
|
|
+ string SN = Depart("On");
|
|
|
+ try
|
|
|
+ {
|
|
|
+ switch (basics.ProtocolType)
|
|
|
+ {
|
|
|
+ case MewtocolData.ProtocolType.Tcp:
|
|
|
+ if (MTcp != null)
|
|
|
+ {
|
|
|
+ return Break(SN, false, "已连接");
|
|
|
+ }
|
|
|
+ mmpi = MewtocolNet.Mewtocol.Ethernet(basics.Ip, basics.Port, basics.StationNumber);
|
|
|
+ MTcp = mmpi.Build();
|
|
|
+ if (MTcp.ConnectAsync().Wait(basics.Timeout))
|
|
|
+ {
|
|
|
+ //没有超时
|
|
|
+ if (!MTcp.IsConnected)
|
|
|
+ {
|
|
|
+ return Break(SN, false, "连接失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //超时了
|
|
|
+ return Break(SN, false, "连接超时");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case MewtocolData.ProtocolType.Serial:
|
|
|
+ if (MSerial != null)
|
|
|
+ {
|
|
|
+ return Break(SN, false, "已连接");
|
|
|
+ }
|
|
|
+ mmps = MewtocolNet.Mewtocol.Serial(basics.PortName, basics.BaudRate, basics.DataBit, basics.ParityBit, basics.StopBit, basics.StationNumber);
|
|
|
+ MSerial = mmps.Build();
|
|
|
+ if (MSerial.ConnectAsync().Wait(basics.Timeout))
|
|
|
+ {
|
|
|
+ //没有超时
|
|
|
+ if (!MSerial.IsConnected)
|
|
|
+ {
|
|
|
+ return Break(SN, false, "连接失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //超时了
|
|
|
+ return Break(SN, false, "连接超时");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return Break(SN, true);
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ return Break(SN, false, ex.Message, Exception: ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Task<OperateResult> OnAsync()
|
|
|
+ {
|
|
|
+ return Task.Run(() => On());
|
|
|
+ }
|
|
|
+
|
|
|
+ public OperateResult Off()
|
|
|
+ {
|
|
|
+ string SN = Depart("Off");
|
|
|
+ try
|
|
|
+ {
|
|
|
+ switch (basics.ProtocolType)
|
|
|
+ {
|
|
|
+ case MewtocolData.ProtocolType.Tcp:
|
|
|
+ if (MTcp == null)
|
|
|
+ {
|
|
|
+ return Break(SN, false, "未连接");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (subscribeOperate != null)
|
|
|
+ {
|
|
|
+ OperateResult operateResult = subscribeOperate.Off();
|
|
|
+ if (!operateResult.State)
|
|
|
+ {
|
|
|
+ return Break(SN, false, operateResult.Message);
|
|
|
+ }
|
|
|
+ subscribeOperate = null;
|
|
|
+ }
|
|
|
+ if (MTcp.DisconnectAsync().Wait(basics.Timeout))
|
|
|
+ {
|
|
|
+ MTcp.Dispose();
|
|
|
+ MTcp = null;
|
|
|
+ mmpi = null;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return Break(SN, false, "关闭超时");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case MewtocolData.ProtocolType.Serial:
|
|
|
+ if (MSerial == null)
|
|
|
+ {
|
|
|
+ return Break(SN, false, "未连接");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (subscribeOperate != null)
|
|
|
+ {
|
|
|
+ OperateResult operateResult = subscribeOperate.Off();
|
|
|
+ if (!operateResult.State)
|
|
|
+ {
|
|
|
+ return Break(SN, false, operateResult.Message);
|
|
|
+ }
|
|
|
+ subscribeOperate = null;
|
|
|
+ }
|
|
|
+ if (MSerial.DisconnectAsync().Wait(basics.Timeout))
|
|
|
+ {
|
|
|
+ MSerial.Dispose();
|
|
|
+ MSerial = null;
|
|
|
+ mmps = null;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return Break(SN, false, "关闭超时");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return Break(SN, true);
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ return Break(SN, false, ex.Message, Exception: ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Task<OperateResult> OffAsync()
|
|
|
+ {
|
|
|
+ return Task.Run(() => Off());
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Dispose()
|
|
|
+ {
|
|
|
+ Off();
|
|
|
+ GC.Collect();
|
|
|
+ GC.SuppressFinalize(this);
|
|
|
+ ThisObjList.Remove(this);
|
|
|
+ }
|
|
|
+
|
|
|
+ public OperateResult GetStatus()
|
|
|
+ {
|
|
|
+ switch (basics.ProtocolType)
|
|
|
+ {
|
|
|
+ case MewtocolData.ProtocolType.Tcp:
|
|
|
+ return Break(Depart("GetStatus"), MTcp?.IsConnected ?? false, MTcp?.IsConnected ?? false ? "已连接" : "未连接");
|
|
|
+ case MewtocolData.ProtocolType.Serial:
|
|
|
+ return Break(Depart("GetStatus"), MSerial?.IsConnected ?? false, MSerial?.IsConnected ?? false ? "已连接" : "未连接");
|
|
|
+ default:
|
|
|
+ return Break(Depart("GetStatus"), false, "未连接");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Task<OperateResult> GetStatusAsync()
|
|
|
+ {
|
|
|
+ return Task.Run(() => GetStatus());
|
|
|
+ }
|
|
|
+
|
|
|
+ public OperateResult GetParam()
|
|
|
+ {
|
|
|
+ string SN = Depart("GetParam");
|
|
|
+ try
|
|
|
+ {
|
|
|
+ //名称
|
|
|
+ string name = TAG.Replace("Operate", string.Empty).Replace("Client", string.Empty);
|
|
|
+ //命名空间
|
|
|
+ string nameSpace = "YSAI.Mewtocol.MewtocolOperate";
|
|
|
+ //获取参数
|
|
|
+ OperateResult operateResult = ParamHandler.Get(new MewtocolData.Basics(), name, subclass: new List<ParamHandler.SubClass>
|
|
|
+ {
|
|
|
+ new ParamHandler.SubClass
|
|
|
+ {
|
|
|
+ Name= "Mewtocol-Tcp",
|
|
|
+ Properties=new List<ParamStructure.propertie>
|
|
|
+ {
|
|
|
+ new ParamStructure.propertie
|
|
|
+ {
|
|
|
+ PropertyName = "ServiceName",
|
|
|
+ Description = "命名空间",
|
|
|
+ Show = false,
|
|
|
+ Use = false,
|
|
|
+ Default = nameSpace,
|
|
|
+ DataCate = null
|
|
|
+ }
|
|
|
+ },
|
|
|
+ RGroups=new List<ParamHandler.RGroup>
|
|
|
+ {
|
|
|
+ new ParamHandler.RGroup
|
|
|
+ {
|
|
|
+ RIndex=2,
|
|
|
+ RCount=1
|
|
|
+ },
|
|
|
+ new ParamHandler.RGroup
|
|
|
+ {
|
|
|
+ RIndex=6,
|
|
|
+ RCount=5
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },new ParamHandler.SubClass
|
|
|
+ {
|
|
|
+ Name= "Mewtocol-Serial",
|
|
|
+ Properties=new List<ParamStructure.propertie>
|
|
|
+ {
|
|
|
+ new ParamStructure.propertie
|
|
|
+ {
|
|
|
+ PropertyName = "ServiceName",
|
|
|
+ Description = "命名空间",
|
|
|
+ Show = false,
|
|
|
+ Use = false,
|
|
|
+ Default = nameSpace,
|
|
|
+ DataCate = null
|
|
|
+ }
|
|
|
+ },
|
|
|
+ RGroups=new List<ParamHandler.RGroup>
|
|
|
+ {
|
|
|
+ new ParamHandler.RGroup
|
|
|
+ {
|
|
|
+ RIndex=2,
|
|
|
+ RCount=1
|
|
|
+ },
|
|
|
+ new ParamHandler.RGroup
|
|
|
+ {
|
|
|
+ RIndex=4,
|
|
|
+ RCount=2
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return Break(SN, operateResult);
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ return Break(SN, false, ex.Message, Exception: ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Task<OperateResult> GetParamAsync()
|
|
|
+ {
|
|
|
+ return Task.Run(() => GetParam());
|
|
|
+ }
|
|
|
+
|
|
|
+ public OperateResult CreateInstance<T>(T Basics)
|
|
|
+ {
|
|
|
+ string SN = Depart("CreateInstance");
|
|
|
+ try
|
|
|
+ {
|
|
|
+ //先判断对象类型是否一致
|
|
|
+ if (typeof(T).FullName.Equals(typeof(MewtocolData.Basics).FullName))
|
|
|
+ {
|
|
|
+ return Break(SN, true, RData: Instance(Basics as MewtocolData.Basics));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return Break(SN, false, "对象类型错误,无法创建实例");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ return Break(SN, false, ex.Message, Exception: ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Task<OperateResult> CreateInstanceAsync<T>(T Basics)
|
|
|
+ {
|
|
|
+ return Task.Run(() => CreateInstance(Basics));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
}
|
|
|
}
|