Quellcode durchsuchen

1. GE通用电气PLC集成,50%

Shun vor 2 Jahren
Ursprung
Commit
13c389a2e2

+ 3 - 0
README.md

@@ -582,3 +582,6 @@ while(true)
 3. 工具新增DB数据采集
 4. 采集转发版本更新
 
+#### 2024-1-5
+1. GE 通用电气 PLC 集成,百分之50
+

+ 7 - 0
src/YSAI.DAQ.sln

@@ -97,6 +97,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YSAI.Windows.Samples", "YSA
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YSAI.Windows.Anime.Samples", "YSAI.Windows.Anime.Samples\YSAI.Windows.Anime.Samples.csproj", "{A2F3A1D2-2165-403F-B0CE-311ECF807D33}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YSAI.GE", "YSAI.GE\YSAI.GE.csproj", "{9BEA4BCD-8C92-4B9C-8C8E-C2B56C3E3D3D}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -247,6 +249,10 @@ Global
 		{A2F3A1D2-2165-403F-B0CE-311ECF807D33}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{A2F3A1D2-2165-403F-B0CE-311ECF807D33}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{A2F3A1D2-2165-403F-B0CE-311ECF807D33}.Release|Any CPU.Build.0 = Release|Any CPU
+		{9BEA4BCD-8C92-4B9C-8C8E-C2B56C3E3D3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9BEA4BCD-8C92-4B9C-8C8E-C2B56C3E3D3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9BEA4BCD-8C92-4B9C-8C8E-C2B56C3E3D3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9BEA4BCD-8C92-4B9C-8C8E-C2B56C3E3D3D}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -292,6 +298,7 @@ Global
 		{ACE972C1-709F-4074-B085-300D80488AAC} = {8AB62EDF-2857-497A-889E-14A7CF88F107}
 		{8E8BFF57-ECC4-4D81-A483-A39ABF899838} = {ACE972C1-709F-4074-B085-300D80488AAC}
 		{A2F3A1D2-2165-403F-B0CE-311ECF807D33} = {ACE972C1-709F-4074-B085-300D80488AAC}
+		{9BEA4BCD-8C92-4B9C-8C8E-C2B56C3E3D3D} = {0A264424-1AD7-49FA-B813-D96498066479}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {5D5D3927-6714-40C0-84EA-44C5BA4C5E87}

+ 62 - 0
src/YSAI.GE/GEData.cs

@@ -0,0 +1,62 @@
+using System.ComponentModel;
+using YSAI.Core.subscription;
+using YSAI.Model.attribute;
+using YSAI.Model.data;
+using YSAI.Unility;
+
+namespace YSAI.GE
+{
+    public class GEData
+    {
+        /// <summary>
+        /// 基础数据
+        /// </summary>
+        public class Basics : SubscribeData.SCData
+        {
+            /// <summary>
+            /// 唯一标识符
+            /// </summary>
+            [Category("基础数据")]
+            [Description("唯一标识符")]
+            public string? SN { get; set; } = Guid.NewGuid().ToUpperNString();
+
+            /// <summary>
+            /// ip地址
+            /// </summary>
+            [Description("IP")]
+            [Verify(@"^(25[0-4]|2[0-4]\\d]|[01]?\\d{2}|[1-9])\\.(25[0-5]|2[0-4]\\d]|[01]?\\d?\\d)\\.(25[0-5]|2[0-4]\\d]|[01]?\\d?\\d)\\.(25[0-4]|2[0-4]\\d]|[01]?\\d{2}|[1-9])$", "输入有误")]
+            [Display(true, true, true, ParamStructure.dataCate.text)]
+            public string? Ip { get; set; } = "127.0.0.1";
+
+            /// <summary>
+            /// 端口
+            /// </summary>
+            [Description("端口")]
+            [Display(true, true, true, ParamStructure.dataCate.unmber)]
+            public int Port { get; set; } = 6688;
+
+            /// <summary>
+            /// 是否需要断开重新连接
+            /// </summary>
+            [Description("是否需要断开重新连接")]
+            [Display(true, true, true, ParamStructure.dataCate.radio)]
+            public bool InterruptReconnection { get; set; } = true;
+
+            /// <summary>
+            /// 重连间隔(毫秒)
+            /// </summary>
+            [Description("重连间隔")]
+            [Unit("ms")]
+            [Display(true, true, true, ParamStructure.dataCate.unmber)]
+            public int ReconnectionInterval { get; set; } = 2000;
+
+            /// <summary>
+            /// 超时时间
+            /// </summary>
+            [Description("超时时间")]
+            [Unit("ms")]
+            [Display(true, true, true, ParamStructure.dataCate.unmber)]
+            public int Timeout { get; set; } = 1000;
+        }
+    }
+}

+ 726 - 0
src/YSAI.GE/GEOperate.cs

@@ -0,0 +1,726 @@
+using System.Collections.Concurrent;
+using YSAI.Core.communication.net.tcp.client;
+using YSAI.Core.subscription;
+using YSAI.Core.virtualAddress;
+using YSAI.Model.data;
+using YSAI.Model.@enum;
+using YSAI.Model.@interface;
+using YSAI.Model.tool;
+using YSAI.Unility;
+
+namespace YSAI.GE
+{
+    /// <summary>
+    /// 通用电气 PLC通信
+    /// </summary>
+    public sealed class GEOperate : IBaseAbstract, IDaq
+    {
+        protected override string TAG => "GEOperate";
+
+        /// <summary>
+        /// 锁
+        /// </summary>
+        private static readonly object Lock = new object();
+
+        /// <summary>
+        /// 自身对象集合
+        /// </summary>
+        private static List<GEOperate> ThisObjList = new List<GEOperate>(); //自身对象集合
+
+        /// <summary>
+        /// 单例模式
+        /// </summary>
+        /// <returns></returns>
+        public static GEOperate Instance(GEData.Basics basics)
+        {
+            if (ThisObjList.Count >= MaxInstanceCount)
+            {
+                throw new Exception(ExceedMaxInstanceCountTips);
+            }
+            GEOperate? 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
+                    {
+                        GEOperate exp2 = new GEOperate(basics);
+                        ThisObjList.Add(exp2);
+                        return exp2;
+                    }
+                }
+            }
+            return exp;
+        }
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="basics">基础数据</param>
+        public GEOperate(GEData.Basics basics)
+        {
+            this.basics = basics;
+        }
+
+        public GEOperate()
+        { }
+
+        /// <summary>
+        /// 基础数据
+        /// </summary>
+        private GEData.Basics basics;
+
+        /// <summary>
+        ///SOCKET TCP Client
+        /// </summary>
+        private TcpClientOperate tcpClientOperate;
+
+        /// <summary>
+        /// 虚拟地址
+        /// </summary>
+        private VirtualAddressManage VAM = new VirtualAddressManage();
+
+        /// <summary>
+        /// 实现订阅功能
+        /// </summary>
+        private SubscribeOperate subscribeOperate;
+
+        public void Dispose()
+        {
+            Off();
+            GC.Collect();
+            GC.SuppressFinalize(this);
+            ThisObjList.Remove(this);
+        }
+
+        public OperateResult GetStatus()
+        {
+            string SN = Depart("GetStatus");
+            if (tcpClientOperate == null)
+            {
+                return Break(SN, false, "未连接", OutputLog: false);
+            }
+            else
+            {
+                return Break(SN, tcpClientOperate.GetStatus().State, tcpClientOperate.GetStatus().State ? "已连接" : "未连接", OutputLog: 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.GE.GEOperate";
+                //对象实例
+                GEData.Basics basics = new GEData.Basics();
+                //参数处理
+                OperateResult operateResult = ParamTool.Get(new GEData.Basics(), name, Properties: new List<ParamStructure.propertie>
+                {
+                    new ParamStructure.propertie
+                    {
+                        PropertyName = "ServiceName",
+                        Description = "命名空间",
+                        Show = false,
+                        Use = false,
+                        Default = nameSpace,
+                        DataCate = null
+                    }
+                });
+                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(GEData.Basics).FullName))
+                {
+                    return Break(SN, true, RData: Instance(Basics as GEData.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));
+        }
+
+        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 Off()
+        {
+            string SN = Depart("Off");
+            try
+            {
+                if (tcpClientOperate == null || !tcpClientOperate.GetStatus().State)
+                {
+                    return Break(SN, false, "未连接");
+                }
+                if (subscribeOperate != null)
+                {
+                    OperateResult operateResult = subscribeOperate.Off();
+                    if (!operateResult.State)
+                    {
+                        return Break(SN, false, operateResult.Message);
+                    }
+                    subscribeOperate = null;
+                }
+                tcpClientOperate.Dispose();
+                tcpClientOperate = null;
+                return Break(SN, true);
+            }
+            catch (Exception ex)
+            {
+                return Break(SN, false, ex.Message, Exception: ex);
+            }
+        }
+
+        public Task<OperateResult> OffAsync()
+        {
+            return Task.Run(() => Off());
+        }
+
+        public OperateResult On()
+        {
+            string SN = Depart("On");
+            try
+            {
+                if (tcpClientOperate != null && tcpClientOperate.GetStatus().State)
+                {
+                    return Break(SN, false, "已连接");
+                }
+                if (tcpClientOperate != null && !tcpClientOperate.GetStatus().State)
+                {
+                    tcpClientOperate.Dispose();
+                }
+                //先实例化底层 socket 通信
+                tcpClientOperate = TcpClientOperate.Instance(new TcpClientData.Basics
+                {
+                    InterruptReconnection = basics.InterruptReconnection,
+                    Ip = basics.Ip,
+                    Port = basics.Port,
+                    ReconnectionInterval = basics.ReconnectionInterval,
+                    SN = basics.SN,
+                    Timeout = basics.Timeout,
+                    SendWait = true,
+                    SendWaitInterval = basics.Timeout
+                });
+                OperateResult operateResult = tcpClientOperate.On();
+                if (operateResult.State)
+                {
+                    //发送基础命令
+                    operateResult = tcpClientOperate.SendWait(msg_init);
+                    if (operateResult.State)
+                    {
+                        byte[]? bytes = operateResult.GetRData<byte[]>();
+                        if (bytes != null)
+                        {
+                            if (bytes[0] == 0x01)
+                            {
+                                return Break(SN, true);
+                            }
+                        }
+                    }
+                }
+                tcpClientOperate.Off();
+                return Break(SN, false, operateResult.Message);
+            }
+            catch (Exception ex)
+            {
+                return Break(SN, false, ex.Message, Exception: ex);
+            }
+        }
+
+        public Task<OperateResult> OnAsync()
+        {
+            return Task.Run(() => On());
+        }
+
+        public OperateResult Read(Address address)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Task<OperateResult> ReadAsync(Address address)
+        {
+            throw new NotImplementedException();
+        }
+
+        public OperateResult Write<V>(ConcurrentDictionary<string, V> Values)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Task<OperateResult> WriteAsync<V>(ConcurrentDictionary<string, V> Values)
+        {
+            throw new NotImplementedException();
+        }
+
+
+        #region 基础
+
+        /// <summary>
+        /// 先发送56字节,给PLC;
+        /// 它将响应:0x01 0x00...
+        /// </summary>
+        private byte[] msg_init = new byte[56];
+
+        /// <summary>
+        /// 这是标准的消息格式,你需要更新;
+        /// 发送前的一些字段;
+        /// PC发送请求开始:0x02 0x00…;
+        /// PLC响应消息:0x03 0x00…;
+        /// </summary>
+        private byte[] msg_base = {
+              0x02,        // 00 - Type (x03:=ReceiveOK, x02:=Transmit, x08:=Something just after msg_init - maybe kind of exception interruption?)
+              0x00,        // 01 - Unknown
+              0x00,        // 02 - Seq Number (x00 works, x06 also works, x05 also according referenced document)
+              0x00,        // 03 - Unknown
+              0x00,        // 04 - Text Length
+              0x00,        // 05 - Unknown / Text character?
+              0x00,        // 06 - Unknown / Text character?
+              0x00,        // 07 - Unknown / Text character?
+              0x00,        // 08 - Unknown / Text character?
+              0x01,        // 09 - Unknown / Text character?
+              0x00,        // 10 - Unknown / Text character?
+              0x00,        // 11 - Unknown / Text character?
+              0x00,        // 12 - Unknown / Text character?
+              0x00,        // 13 - Unknown / Text character?
+              0x00,        // 14 - Unknown / Text character?
+              0x00,        // 15 - Unknown / Text character?
+              0x00,        // 16 - Unknown / Text character?
+              0x01,        // 17 - Unknown / Always x01
+              0x00,        // 18 - Unknown
+              0x00,        // 19 - Unknown
+              0x00,        // 20 - Unknown
+              0x00,        // 21 - Unknown
+              0x00,        // 22 - Unknown
+              0x00,        // 23 - Unknown
+              0x00,        // 24 - Unknown
+              0x00,        // 25 - Unknown
+              0x00,        // 26 - Time Seconds
+              0x00,        // 27 - Time Minutes
+              0x00,        // 28 - Time Hours
+              0x00,        // 29 - Reserved / Always x01
+              0x06,        // 30 - Seq Number (Repeated) (0x06) - meaning in responces from PLC
+              0xc0,        // 31 - Message Type
+              0x00,        // 32 - Mailbox Source
+              0x00,        // 33 - Mailbox Source
+              0x00,        // 34 - Mailbox Source
+              0x00,        // 35 - Mailbox Source
+              0x10,        // 36 - Mailbox Destination // dec: 3600
+              0x0e,        // 37 - Mailbox Destination
+              0x00,        // 38 - Mailbox Destination
+              0x00,        // 39 - Mailbox Destination
+              0x01,        // 40 - Packet Number // to check
+              0x01,        // 41 - Total Packet Number
+              0x00,        // 42 - Service Request Code - (Operation Type SERVICE_REQUEST_CODE)
+              0x00,        // 43 - Request Dependent Space (Ex. MEMORY_TYPE_CODE)
+              0x00,        // 44 - Request Dependent Space (Ex. Address:LSB)
+              0x00,        // 45 - Request Dependent Space (Ex. Address:MSB)
+              0x00,        // 46 - Request Dependent Space (Ex. Data Size Words:LSB)
+              0x00,        // 47 - Request Dependent Space (Ex. Data Size Words:MSB)
+              0x00,        // 48 - Request Dependent Space (Ex. Write Value:LSB)
+              0x00,        // 49 - Request Dependent Space (Ex. Write Value:MSB)
+              0x00,        // 50 - Request Dependent Space (Ex. Write Value Part 2 for LONG:LSB)
+              0x00,        // 51 - Request Dependent Space (Ex. Write Value Part 2 for LONG:MSB)
+              0x00,        // 52 - Dependent of "Data Size" - byte 46, 47 / PLC status in other Service Request
+              0x00,        // 53 - Dependent of "Data Size" - byte 46, 47 / PLC status in other Service Request
+              0x00,        // 54 - Dependent of "Data Size" - byte 46, 47 / PLC status in other Service Request
+              0x00         // 55 - Dependent of "Data Size" - byte 46, 47 / PLC status in other Service Request
+          };
+
+        /// <summary>
+        /// 功能码
+        /// </summary>
+        private enum FCode
+        {
+            R,
+            AI,
+            AQ,
+            I,
+            Q,
+            T,
+            M,
+            SA,
+            SB,
+            SC,
+            G
+        }
+
+        /// <summary>
+        /// 解析地址,返回功能码与下标
+        /// </summary>
+        /// <param name="address">地址</param>
+        /// <param name="isBit">是否是bit</param>
+        /// <returns></returns>
+        private (FCode fc, byte fCode, int index) ParseAddress(string address, bool isBit = false)
+        {
+            byte retCode = 0x00;
+            string code = string.Empty;
+            string[] rStrs = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", };
+            foreach (string str in rStrs)
+            {
+                code = address.Replace(str, string.Empty);
+            }
+            int retIndex = int.Parse(address.Replace(code, string.Empty));
+            FCode retFc = (FCode)Enum.Parse(typeof(FCode), code);
+            if (!isBit)
+            {
+                switch (code)
+                {
+                    case "R":
+                        retCode = 0x08;
+                        break;
+                    case "AI":
+                        retCode = 0x0a;
+                        break;
+                    case "AQ":
+                        retCode = 0x0c;
+                        break;
+                    case "I":
+                        retCode = 0x10;
+                        break;
+                    case "Q":
+                        retCode = 0x12;
+                        break;
+                    case "T":
+                        retCode = 0x14;
+                        break;
+                    case "M":
+                        retCode = 0x16;
+                        break;
+                    case "SA":
+                        retCode = 0x18;
+                        break;
+                    case "SB":
+                        retCode = 0x20;
+                        break;
+                    case "SC":
+                        retCode = 0x22;
+                        break;
+                    case "G":
+                        retCode = 0x38;
+                        break;
+                }
+            }
+            else
+            {
+                switch (code)
+                {
+                    case "I":
+                        retCode = 0x46;
+                        break;
+                    case "Q":
+                        retCode = 0x48;
+                        break;
+                    case "T":
+                        retCode = 0x4a;
+                        break;
+                    case "M":
+                        retCode = 0x4c;
+                        break;
+                    case "SA":
+                        retCode = 0x4e;
+                        break;
+                    case "SB":
+                        retCode = 0x50;
+                        break;
+                    case "SC":
+                        retCode = 0x52;
+                        break;
+                    case "G":
+                        retCode = 0x56;
+                        break;
+                }
+            }
+
+            return (retFc, retCode, retIndex);
+        }
+
+
+        /// <summary>
+        /// 解析读取的包头数据
+        /// </summary>
+        /// <param name="address"></param>
+        /// <param name=""></param>
+        /// <returns></returns>
+        private byte[] R(string address, DataType dataType)
+        {
+            byte[] msg_send = new byte[56];
+            byte[] msg_read = new byte[512];
+            this.msg_base.CopyTo(msg_send, 0);
+            (FCode fc, byte fCode, int index) pa = ParseAddress(address);
+            switch (dataType)
+            {
+                case DataType.Byte:
+                    switch (pa.fc)
+                    {
+                        case FCode.R:
+                            msg_send[42] = 0x04;  //请求类型
+                            msg_send[43] = pa.fCode;  //功能码
+                            byte[] byteArrayAddress = BitConverter.GetBytes((Int16)(pa.index / 8));
+                            msg_send[44] = byteArrayAddress[0];
+                            msg_send[45] = byteArrayAddress[1];
+                            msg_send[46] = 0x01;
+                            break;
+                        case FCode.AI:
+                            break;
+                        case FCode.AQ:
+                            break;
+                        case FCode.I:
+                            break;
+                        case FCode.Q:
+                            break;
+                        case FCode.T:
+                            break;
+                        case FCode.M:
+                            break;
+                        case FCode.SA:
+                            break;
+                        case FCode.SB:
+                            break;
+                        case FCode.SC:
+                            break;
+                        case FCode.G:
+                            break;
+                    }
+                    break;
+                case DataType.Bool:
+
+
+
+                    break;
+                case DataType.Short:
+                case DataType.Int16:
+                    switch (pa.fc)
+                    {
+                        case FCode.R:
+                            msg_send[42] = 0x04;  //请求类型
+                            msg_send[43] = pa.fCode;  //功能码
+                            msg_send[44] = (byte)(pa.index & 0xFF);
+                            msg_send[45] = (byte)(pa.index >> 8);
+                            msg_send[46] = 0x01;
+                            break;
+                        case FCode.AI:
+                            break;
+                        case FCode.AQ:
+                            break;
+                        case FCode.I:
+                            break;
+                        case FCode.Q:
+                            break;
+                        case FCode.T:
+                            break;
+                        case FCode.M:
+                            break;
+                        case FCode.SA:
+                            break;
+                        case FCode.SB:
+                            break;
+                        case FCode.SC:
+                            break;
+                        case FCode.G:
+                            break;
+                    }
+                    break;
+                case DataType.Ushort:
+                case DataType.UInt16:
+
+                    break;
+                case DataType.Int:
+                case DataType.Int32:
+                    switch (pa.fc)
+                    {
+                        case FCode.R:
+                            msg_send[42] = 0x04;  //请求类型
+                            msg_send[43] = pa.fCode;  //功能码
+                            int ad = pa.index - 1;
+                            msg_send[44] = (byte)(ad & 0xFF);
+                            msg_send[45] = (byte)(ad >> 8);
+                            msg_send[46] = 0x02;
+                            break;
+                        case FCode.AI:
+                            break;
+                        case FCode.AQ:
+                            break;
+                        case FCode.I:
+                            break;
+                        case FCode.Q:
+                            break;
+                        case FCode.T:
+                            break;
+                        case FCode.M:
+                            break;
+                        case FCode.SA:
+                            break;
+                        case FCode.SB:
+                            break;
+                        case FCode.SC:
+                            break;
+                        case FCode.G:
+                            break;
+                    }
+                    break;
+                case DataType.Uint:
+                case DataType.UInt32:
+
+                    break;
+                case DataType.Long:
+                case DataType.Int64:
+
+                    break;
+                case DataType.Ulong:
+                case DataType.UInt64:
+
+                    break;
+                case DataType.Double:
+
+                    break;
+                case DataType.Float:
+                    switch (pa.fc)
+                    {
+                        case FCode.R:
+                            msg_send[42] = 0x04;  //请求类型
+                            msg_send[43] = pa.fCode;  //功能码
+                            int ad = pa.index - 1;
+                            msg_send[44] = (byte)(ad & 0xFF);
+                            msg_send[45] = (byte)(ad >> 8);
+                            msg_send[46] = 0x02;
+                            break;
+                        case FCode.AI:
+                            break;
+                        case FCode.AQ:
+                            break;
+                        case FCode.I:
+                            break;
+                        case FCode.Q:
+                            break;
+                        case FCode.T:
+                            break;
+                        case FCode.M:
+                            break;
+                        case FCode.SA:
+                            break;
+                        case FCode.SB:
+                            break;
+                        case FCode.SC:
+                            break;
+                        case FCode.G:
+                            break;
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        /// <summary>
+        /// 解析写入的包头数据
+        /// </summary>
+        /// <param name="address">地址</param>
+        /// <param name="value">值</param>
+        /// <returns></returns>
+        private byte[] W(string address, object value)
+        {
+
+        }
+
+        #endregion
+    }
+}

+ 22 - 0
src/YSAI.GE/YSAI.GE.csproj

@@ -0,0 +1,22 @@
+<Project Sdk="Microsoft.NET.Sdk">
+	<PropertyGroup>
+		<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
+		<ImplicitUsings>enable</ImplicitUsings>
+		<Nullable>enable</Nullable>
+		<Version>24.4.7470</Version>
+		<PackageOutputPath Condition="'$(Configuration)' == 'Release'">../YSAI.Publish/Release</PackageOutputPath>
+		<PackageOutputPath Condition="'$(Configuration)' == 'Debug'">../YSAI.Publish/Debug</PackageOutputPath>
+		<Authors>Shun</Authors>
+		<Company>YSAI</Company>
+		<Product>SCADA</Product>
+		<GenerateDocumentationFile>True</GenerateDocumentationFile>
+		<DescriptionType>采集协议</DescriptionType>
+		<DescriptionName>GE</DescriptionName>
+		<DescriptionDetails>通用电气 - Tcp</DescriptionDetails>
+		<Description>$(DescriptionType):$(DescriptionName) ( $(DescriptionDetails) )</Description>
+	</PropertyGroup>
+	<ItemGroup>
+		<PackageReference Include="YSAI.Core" Version="23.360.5156" />
+	</ItemGroup>
+</Project>
+

+ 1 - 0
src/YSAI.Omron/OmronOperate.cs

@@ -670,6 +670,7 @@ namespace YSAI.Omron
                         }
                     }
                 }
+                tcpClientOperate.Off();
                 return Break(SN, false, operateResult.Message);
             }
             catch (Exception ex)

+ 1 - 1
src/YSAI.Tool.Wpf/Main.xaml.cs

@@ -32,7 +32,7 @@ namespace YSAI.Tool.Wpf
                     if (navigationViews.Count > 0)
                     {
                         //第一次打开显示的界面
-                        navigationViews[0].Navigate(typeof(YSAI.Tool.Wpf.views.DB));
+                        navigationViews[0].Navigate(typeof(YSAI.Tool.Wpf.views.UaClient));
                     }
                 });
             });