Explorar o código

版本更新,完善三菱PLC采集

Shun %!s(int64=2) %!d(string=hai) anos
pai
achega
8b81a1264a

+ 1 - 1
src/YSAI.DAQ/YSAI.Beckhoff/YSAI.Beckhoff.csproj

@@ -14,7 +14,7 @@
 
 	<ItemGroup>
 		<PackageReference Include="Beckhoff.TwinCAT.Ads" Version="6.1.86" />
-		<PackageReference Include="YSAI.Core" Version="1.0.0.79" />
+		<PackageReference Include="YSAI.Core" Version="1.0.0.80" />
 	</ItemGroup>
 
 	<!--<ItemGroup>

+ 1 - 1
src/YSAI.DAQ/YSAI.Can/YSAI.Can.csproj

@@ -17,7 +17,7 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="YSAI.Core" Version="1.0.0.79" />
+    <PackageReference Include="YSAI.Core" Version="1.0.0.80" />
   </ItemGroup>
 
   <ItemGroup>

+ 1 - 1
src/YSAI.DAQ/YSAI.DB/YSAI.DB.csproj

@@ -18,7 +18,7 @@
 		<PackageReference Include="System.Data.OracleClient" Version="1.0.8" />
 		<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
 		<PackageReference Include="System.Data.SQLite" Version="1.0.118" />
-		<PackageReference Include="YSAI.Core" Version="1.0.0.79" />
+		<PackageReference Include="YSAI.Core" Version="1.0.0.80" />
 	</ItemGroup>
 	<!--<ItemGroup>
 		<ProjectReference Include="..\YSAI.Core\YSAI.Core.csproj" />

+ 1 - 1
src/YSAI.DAQ/YSAI.DaqManage/YSAI.DaqManage.csproj

@@ -7,7 +7,7 @@
   </PropertyGroup>
 	<ItemGroup>
 		<FrameworkReference Include="Microsoft.AspNetCore.App" />
-		<PackageReference Include="YSAI.Core" Version="1.0.0.79" />
+		<PackageReference Include="YSAI.Core" Version="1.0.0.80" />
 	</ItemGroup>
 
 	<!--<ItemGroup>

+ 1 - 1
src/YSAI.DAQ/YSAI.Kafka/YSAI.Kafka.csproj

@@ -14,7 +14,7 @@
 
   <ItemGroup>
     <PackageReference Include="Confluent.Kafka" Version="2.3.0" />
-    <PackageReference Include="YSAI.Core" Version="1.0.0.79" />
+    <PackageReference Include="YSAI.Core" Version="1.0.0.80" />
   </ItemGroup>
 	
 	<!--<ItemGroup>

+ 13 - 0
src/YSAI.DAQ/YSAI.Mitsubishi/MitsubishiData.cs

@@ -179,5 +179,18 @@ namespace YSAI.Mitsubishi
             /// </summary>
             public McDT DataType { get; set; }
         }
+
+        /// <summary>
+        /// 只用于连续读取的返回参数
+        /// </summary>
+        public class RetValue
+        {
+            /// <summary>
+            /// 地址
+            /// </summary>
+            public string? Address { get; set; }
+
+            public string? Value { get; set; }
+        }
     }
 }

+ 325 - 8
src/YSAI.DAQ/YSAI.Mitsubishi/MitsubishiOperate.cs

@@ -1,9 +1,12 @@
 using System.Collections.Concurrent;
 using System.Reflection;
+using System.Text;
 using YSAI.Core.attribute;
 using YSAI.Core.communication.net.tcp.client;
 using YSAI.Core.data;
 using YSAI.Core.@interface;
+using YSAI.Core.subscription;
+using YSAI.Core.virtualAddress;
 using YSAI.Unility;
 using static YSAI.Mitsubishi.MitsubishiData;
 
@@ -77,6 +80,11 @@ namespace YSAI.Mitsubishi
         /// </summary>
         private TcpClientOperate tcpClientOperate;
 
+        /// <summary>
+        /// 虚拟地址
+        /// </summary>
+        private VirtualAddressManage VAM = new VirtualAddressManage();
+
         #region 基础
         /// <summary>
         /// Qna_3E地址解析
@@ -571,8 +579,7 @@ namespace YSAI.Mitsubishi
                 //读取失败返回
                 return new byte[] { };
             }
-
-
+            return bytes;
         }
 
         /// <summary>
@@ -635,7 +642,21 @@ namespace YSAI.Mitsubishi
 
         public OperateResult Off()
         {
-            throw new NotImplementedException();
+            string SN = Depart("Off");
+            try
+            {
+                if (tcpClientOperate == null || !tcpClientOperate.GetStatus().State)
+                {
+                    return Break(SN, false, "未连接");
+                }
+                tcpClientOperate.Dispose();
+                tcpClientOperate = null;
+                return Break(SN, true);
+            }
+            catch (Exception ex)
+            {
+                return Break(SN, false, ex.Message, Exception: ex);
+            }
         }
 
         public Task<OperateResult> OffAsync()
@@ -688,17 +709,210 @@ namespace YSAI.Mitsubishi
 
         public OperateResult Read(Address address)
         {
-            throw new NotImplementedException();
+            string SN = Depart("Read");
+            try
+            {
+                if (tcpClientOperate == null || !tcpClientOperate.GetStatus().State)
+                {
+                    return Break(SN, false, "未连接");
+                }
+                //节点数据
+                ConcurrentDictionary<string, AddressValue> param = new ConcurrentDictionary<string, AddressValue>();
+                //循环添加项集合
+                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
+                    {
+                        (string addressName, int count) addressData = (string.Empty, 0);
+                        if (item.AddressName.Contains(","))
+                        {
+                            string[] strs = item.AddressName.Split(',');
+                            addressData.addressName = strs[0];
+                            addressData.count = int.Parse(strs[1]);
+                        }
+                        else
+                        {
+                            addressData.addressName = item.AddressName;
+                        }
+                        if (addressData.count.Equals(0))
+                        {
+                            switch (item.AddressDataType)
+                            {
+                                case Core.@enum.DataType.Short:
+                                    Value = BitConverter.ToInt16(R(addressData.addressName, 2), 0).ToString();
+                                    break;
+                                case Core.@enum.DataType.Bool:
+                                    Value = ((R(addressData.addressName, 1)[0] & 0b00010000) != 0).ToString();
+                                    break;
+                                case Core.@enum.DataType.Ushort:
+                                    Value = BitConverter.ToUInt16(R(addressData.addressName, 2), 0).ToString();
+                                    break;
+                                case Core.@enum.DataType.Int:
+                                    Value = BitConverter.ToInt32(R(addressData.addressName, 4), 0).ToString();
+                                    break;
+                                case Core.@enum.DataType.Uint:
+                                    Value = BitConverter.ToUInt32(R(addressData.addressName, 4), 0).ToString();
+                                    break;
+                                case Core.@enum.DataType.Long:
+                                    Value = BitConverter.ToInt64(R(addressData.addressName, 8), 0).ToString();
+                                    break;
+                                case Core.@enum.DataType.Ulong:
+                                    Value = BitConverter.ToUInt64(R(addressData.addressName, 8), 0).ToString();
+                                    break;
+                                case Core.@enum.DataType.Double:
+                                    Value = BitConverter.ToDouble(R(addressData.addressName, 8), 0).ToString();
+                                    break;
+                                case Core.@enum.DataType.Float:
+                                    Value = BitConverter.ToSingle(R(addressData.addressName, 4), 0).ToString();
+                                    break;
+                                default:
+                                    Value = $"不支持{item.AddressDataType}类型读取";
+                                    break;
+                            }
+                        }
+                        else
+                        {
+                            //数据长度
+                            int len = 0;
+                            //返回的字节数
+                            byte[] bytes;
+                            //连续读取返回的数据
+                            List<RetValue> DValue = new List<RetValue>();
+                            //数据类型
+                            string dbType = addressData.addressName.Substring(0, 1);
+                            //数据块地址
+                            int dbAddress = int.Parse(addressData.addressName.Substring(1));
+
+                            switch (item.AddressDataType)
+                            {
+                                case Core.@enum.DataType.Short:
+                                    len = 2;
+                                    bytes = R(addressData.addressName, Convert.ToUInt16(len * addressData.count));
+                                    for (int i = 0; i < addressData.count; i++)
+                                    {
+                                        DValue.Add(new RetValue
+                                        {
+                                            Address = $"{dbType}{dbAddress + i * len}",
+                                            Value = BitConverter.ToInt16(bytes, (addressData.count - 1 - i) * len).ToString()
+                                        });
+                                    }
+                                    Value = DValue.ToJson();
+                                    break;
+                                case Core.@enum.DataType.Bool:
+                                    len = 1;
+                                    bytes = R(addressData.addressName, Convert.ToUInt16(len * addressData.count));
+                                    for (int i = 0; i < addressData.count; i++)
+                                    {
+                                        var index = i / 2;
+                                        var isoffset = i % 2 == 0;
+                                        bool value;
+                                        if (isoffset)
+                                        {
+                                            value = (bytes[index] & 0b00010000) != 0;
+                                        }
+                                        else
+                                        {
+                                            value = (bytes[index] & 0b00000001) != 0;
+                                        }
+                                        DValue.Add(new RetValue
+                                        {
+                                            Address = $"{dbType}{dbAddress + i * len}",
+                                            Value = value.ToString()
+                                        });
+                                    }
+                                    Value = DValue.ToJson();
+                                    break;
+                                default:
+                                    Value = $"不支持{item.AddressDataType}类型批量读取";
+                                    break;
+                            }
+                        }
+                    }
+                    //数据处理
+                    AddressValue addressValue = Core.handler.AddressHandler.ExecuteDispose(item, Value);
+
+                    //数据添加
+                    param.AddOrUpdate(item.AddressName, addressValue, (k, v) => addressValue);
+
+                }
+                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));
         }
-
+        /// <summary>
+        /// 实现订阅功能
+        /// </summary>
+        private SubscribeOperate subscribeOperate;
         public OperateResult Subscribe(Address address)
         {
-            throw new NotImplementedException();
+            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 += SubscribeOperate_OnEvent;
+                    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);
+            }
+        }
+
+        /// <summary>
+        /// 事件抛出
+        /// </summary>
+        /// <param name="sender">自定义订阅对象</param>
+        /// <param name="e">返回的参数</param>
+        private void SubscribeOperate_OnEvent(object? sender, EventResult e)
+        {
+            OnEventHandler(this, e);
         }
 
         public Task<OperateResult> SubscribeAsync(Address address)
@@ -708,7 +922,23 @@ namespace YSAI.Mitsubishi
 
         public OperateResult UnSubscribe(Address address)
         {
-            throw new NotImplementedException();
+            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)
@@ -718,7 +948,94 @@ namespace YSAI.Mitsubishi
 
         public OperateResult Write<V>(ConcurrentDictionary<string, V> Values)
         {
-            throw new NotImplementedException();
+            string SN = Depart("Write");
+            try
+            {
+                if (tcpClientOperate == null || !tcpClientOperate.GetStatus().State)
+                {
+                    return Break(SN, false, "未连接");
+                }
+                //失败消息
+                List<string> FailMessage = new List<string>();
+
+                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;
+                        if (typeof(V).Name.Equals("String"))
+                        {
+                            var valueBytes = Encoding.ASCII.GetBytes(item.Value.ToString());
+                            var bytes = new byte[valueBytes.Length + 1];
+                            bytes[0] = (byte)valueBytes.Length;
+                            valueBytes.CopyTo(bytes, 1);
+                            Array.Reverse(bytes);
+                            RState = W(item.Key, bytes);
+                        }
+                        else if (typeof(V).Name.Equals("Boolean"))
+                        {
+                            byte[] valueByte = new byte[1];
+                            if (Convert.ToBoolean(item.Value)) valueByte[0] = 16;
+                            RState = W(item.Key, valueByte, true);
+                        }
+                        else
+                        {
+                            object obj = Param.Value;
+                            if (obj is byte)
+                            {
+                                RState = W(Param.Key, BitConverter.GetBytes((byte)obj));
+                            }
+                            else if (obj is Int16)
+                            {
+                                RState = W(Param.Key, BitConverter.GetBytes((Int16)obj));
+                            }
+                            else if (obj is UInt16)
+                            {
+                                RState = W(Param.Key, BitConverter.GetBytes((UInt16)obj));
+                            }
+                            else if (obj is Int32)
+                            {
+                                RState = W(Param.Key, BitConverter.GetBytes((Int32)obj));
+                            }
+                            else if (obj is Int64)
+                            {
+                                RState = W(Param.Key, BitConverter.GetBytes((Int64)obj));
+                            }
+                            else if (obj is float)
+                            {
+                                RState = W(Param.Key, BitConverter.GetBytes((float)obj));
+                            }
+                            else if (obj is double)
+                            {
+                                RState = W(Param.Key, BitConverter.GetBytes((double)obj));
+                            }
+                        }
+                        if (!RState)
+                        {
+                            FailMessage.Add($"{Param.Key},写入失败");
+                        }
+                    }
+                }
+                if (FailMessage.Count > 0)
+                {
+                    return Break("Write", false, FailMessage.ToJson());
+                }
+                return Break("Write", true, "写入成功");
+
+            }
+            catch (Exception ex)
+            {
+                return Break(SN, false, ex.Message, Exception: ex);
+            }
         }
 
         public Task<OperateResult> WriteAsync<V>(ConcurrentDictionary<string, V> Values)

+ 12 - 6
src/YSAI.DAQ/YSAI.Mitsubishi/YSAI.Mitsubishi.csproj

@@ -1,13 +1,19 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
-  <PropertyGroup>
-    <TargetFramework>net6.0</TargetFramework>
-    <ImplicitUsings>enable</ImplicitUsings>
-    <Nullable>enable</Nullable>
-  </PropertyGroup>
+	<PropertyGroup>
+		<TargetFramework>net6.0</TargetFramework>
+		<ImplicitUsings>enable</ImplicitUsings>
+		<Nullable>enable</Nullable>
+		<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
+		<Version>1.0.0.1</Version>
+		<Authors>Shun</Authors>
+		<Company>YSAI</Company>
+		<Product>SCADA</Product>
+		<GenerateDocumentationFile>True</GenerateDocumentationFile>
+	</PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="YSAI.Core" Version="1.0.0.79" />
+    <PackageReference Include="YSAI.Core" Version="1.0.0.80" />
   </ItemGroup>
 
 </Project>

+ 1 - 1
src/YSAI.DAQ/YSAI.Modbus/YSAI.Modbus.csproj

@@ -15,7 +15,7 @@
 	<ItemGroup>
     <PackageReference Include="NModbus" Version="3.0.81" />
     <PackageReference Include="NModbus.Serial" Version="3.0.81" />
-    <PackageReference Include="YSAI.Core" Version="1.0.0.79" />
+    <PackageReference Include="YSAI.Core" Version="1.0.0.80" />
   </ItemGroup>
 
 	<!--<ItemGroup>

+ 1 - 1
src/YSAI.DAQ/YSAI.Mqtt/YSAI.Mqtt.csproj

@@ -15,7 +15,7 @@
   <ItemGroup>
     <PackageReference Include="MQTTnet" Version="4.3.1.873" />
     <PackageReference Include="MQTTnet.AspNetCore" Version="4.3.1.873" />
-    <PackageReference Include="YSAI.Core" Version="1.0.0.79" />
+    <PackageReference Include="YSAI.Core" Version="1.0.0.80" />
   </ItemGroup>
 
 	<!--<ItemGroup>

+ 1 - 1
src/YSAI.DAQ/YSAI.Netty/YSAI.Netty.csproj

@@ -14,6 +14,6 @@
 	<ItemGroup>
 		<PackageReference Include="DotNetty.Handlers" Version="0.7.5" />
 		<PackageReference Include="DotNetty.Transport" Version="0.7.5" />
-		<PackageReference Include="YSAI.Core" Version="1.0.0.79" />
+		<PackageReference Include="YSAI.Core" Version="1.0.0.80" />
 	</ItemGroup>
 </Project>

+ 1 - 1
src/YSAI.DAQ/YSAI.Opc/YSAI.Opc.csproj

@@ -13,7 +13,7 @@
   </PropertyGroup>
   <ItemGroup>
     <PackageReference Include="OPCFoundation.NetStandard.Opc.Ua" Version="1.4.372.76" />
-	<PackageReference Include="YSAI.Core" Version="1.0.0.79" />
+	<PackageReference Include="YSAI.Core" Version="1.0.0.80" />
   </ItemGroup>
 
 

+ 1 - 1
src/YSAI.DAQ/YSAI.RabbitMQ/YSAI.RabbitMQ.csproj

@@ -14,7 +14,7 @@
 
   <ItemGroup>
     <PackageReference Include="RabbitMQ.Client" Version="6.6.0" />
-    <PackageReference Include="YSAI.Core" Version="1.0.0.79" />
+    <PackageReference Include="YSAI.Core" Version="1.0.0.80" />
   </ItemGroup>
 
   <ItemGroup>

+ 1 - 1
src/YSAI.DAQ/YSAI.RelayManage/YSAI.RelayManage.csproj

@@ -9,7 +9,7 @@
 	<ItemGroup>
 		<PackageReference Include="RabbitMQ.Client" Version="6.6.0" />
 		<PackageReference Include="Confluent.Kafka" Version="2.3.0" />
-		<PackageReference Include="YSAI.Core" Version="1.0.0.79" />
+		<PackageReference Include="YSAI.Core" Version="1.0.0.80" />
 		<FrameworkReference Include="Microsoft.AspNetCore.App" />
 	</ItemGroup>
 

+ 1 - 1
src/YSAI.DAQ/YSAI.S7/YSAI.S7.csproj

@@ -14,7 +14,7 @@
 
 	<ItemGroup>
     <PackageReference Include="S7netplus" Version="0.20.0" />
-    <PackageReference Include="YSAI.Core" Version="1.0.0.79" />
+    <PackageReference Include="YSAI.Core" Version="1.0.0.80" />
   </ItemGroup>
 
 	<!--<ItemGroup>

+ 1 - 1
src/YSAI.DAQ/YSAI.Test/YSAI.Test.csproj

@@ -17,7 +17,7 @@
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
-	<PackageReference Include="YSAI.Core" Version="1.0.0.79" />
+	<PackageReference Include="YSAI.Core" Version="1.0.0.80" />
   </ItemGroup>
 
   <ItemGroup>