user_lt 1 rok temu
rodzic
commit
56ccd325bf

+ 6 - 0
BlankApp1/BlankApp1.sln

@@ -13,6 +13,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common", "Common\Common.csp
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "Model\Model.csproj", "{70C6DE58-70FF-453F-96DB-5F254129FE37}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OmronFinsTCP.Net", "OmronFinsTCP.Net\OmronFinsTCP.Net.csproj", "{C5497625-00CA-41EC-8428-021143D7EEA9}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -39,6 +41,10 @@ Global
 		{70C6DE58-70FF-453F-96DB-5F254129FE37}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{70C6DE58-70FF-453F-96DB-5F254129FE37}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{70C6DE58-70FF-453F-96DB-5F254129FE37}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C5497625-00CA-41EC-8428-021143D7EEA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C5497625-00CA-41EC-8428-021143D7EEA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C5497625-00CA-41EC-8428-021143D7EEA9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C5497625-00CA-41EC-8428-021143D7EEA9}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 2 - 1
BlankApp1/BlankApp1/App.config

@@ -3,7 +3,8 @@
 	<appSettings>
 		<!--连接字符串 SQL Server-->
 		<add key="MySql" value="Data Source=localhost;Database=plc_point_db;User Id='root';Password='Lt,100186';port=3306;charset=utf8mb4;"/>
-	
+		<add key="PLCIp" value="192.168.0.1"/>
+		<add key="PLCPort" value="5000"/>
 
 	</appSettings>
 </configuration>

+ 226 - 0
BlankApp1/BlankApp1/Common/PLCCom.cs

@@ -0,0 +1,226 @@
+using OmronFinsTCP.Net;
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PLCTool.Common
+{
+    public class PLCCom
+    {
+        private static string plcIp = ConfigurationManager.AppSettings["PLCIp"];
+        private static string plcPort = ConfigurationManager.AppSettings["PLCPort"];
+        private EtherNetPLC ENT;//plc连接
+        private static PLCCom instance;
+        private bool isConnect = false; 
+
+        private PLCCom() 
+        {
+            ConnectPLC();
+        }
+
+
+        public static PLCCom GetInstance()
+        {
+            if (instance == null)
+            {
+               instance = new PLCCom();
+            }
+            return instance;
+
+        }
+
+        private bool ConnectPLC()
+        {
+            ENT = new EtherNetPLC();
+            short re = ENT.Link(plcIp, short.Parse(plcPort), 500);
+            if (re == 0)
+            {
+                //_logger.Info("PLC连接成功!");
+                return true;
+            }
+            else
+            {
+                //_logger.Info("PLC连接失败!");
+                return false;
+            }
+
+        }
+        public string ReadPlcObject(string address, VarType valueType)
+        {
+            string value = string.Empty; ;
+            short rb;
+            short reSuc = -1;
+            if (isConnect== false)
+            {
+                return string.Empty;
+            }
+           
+            switch (valueType)
+            {
+                case VarType.Bit:
+           
+                    reSuc = ENT.GetBitState(PlcMemory.DM, address, out rb);
+                    //读取成功
+                    if (reSuc == 0)
+                    {
+                        value = rb.ToString();
+                    }
+                    break;
+                case VarType.Byte:
+                    break;
+                case VarType.Word:
+                    reSuc = ENT.ReadWord(PlcMemory.DM, short.Parse(address), out rb);
+                    //读取成功
+                    if(reSuc==0)
+                    {
+                        value = rb.ToString();
+                    }
+                    break;
+                case VarType.DWord:
+                    break;
+                case VarType.Int:
+                    break;
+                case VarType.DInt:
+                    break;
+                case VarType.Real:
+                    break;
+
+                default:
+                    return null;
+            }
+            return value;
+        }
+        public bool WritePlcObject(string address, VarType valueType,string writeValue)
+        {
+            bool isSuccess=false;
+            
+            short reSuc = -1;
+            if (isConnect == false)
+            {
+                return false;
+            }
+
+            switch (valueType)
+            {
+                case VarType.Bit:
+                    BitState bit= BitState.OFF;
+                    if(writeValue.Trim()=="1")
+                    {
+                        bit = BitState.ON;
+                    }
+                    else
+                    {
+                        if (writeValue.Trim() == "0")
+                        {
+                            bit = BitState.OFF;
+                        }
+
+                    }
+                    reSuc = ENT.SetBitState(PlcMemory.DM, address,bit);
+                    //写成功
+                    if (reSuc == 0)
+                    {
+                        isSuccess = true;
+                    }
+                    break;
+                case VarType.Byte:
+                    break;
+                case VarType.Word:
+                    short wValue = Convert.ToInt16(writeValue);
+                    reSuc = ENT.WriteWord(PlcMemory.DM, short.Parse(address), wValue);
+                    //写成功
+                    if (reSuc == 0)
+                    {
+                        isSuccess = true;
+                    }
+                    break;
+                case VarType.DWord:
+                    break;
+                case VarType.Int:
+                    break;
+                case VarType.DInt:
+                    break;
+                case VarType.Real:
+                    break;
+
+            }
+            return isSuccess;
+        }
+
+        private static object GetVariableValue(VarType varType, object var)
+        {
+            switch (varType)
+            {
+                case VarType.Bit:
+                    return (bool)var;
+                case VarType.Byte:
+                    return (byte)var;
+                case VarType.Word:
+                    return (ushort)var;
+                case VarType.DWord:
+                    return (uint)var;
+                case VarType.Int:
+                    return (short)var;
+                case VarType.DInt:
+                    return (int)var;
+                case VarType.Real:
+                    return (float)var;
+             
+                default:
+                    return null;
+            }
+        }
+
+    }
+
+    public enum VarType
+    {
+        /// <summary>
+        ///  Bit variable type (bool)
+        /// </summary>
+        Bit,
+
+        /// <summary>
+        ///  Byte variable type (8 bits)
+        /// </summary>
+        Byte,
+
+        /// <summary>
+        /// Word variable type (16 bits, 2 bytes)
+        /// </summary>
+        Word,
+
+        /// <summary>
+        /// 
+        /// </summary>
+        DWord,
+
+        /// <summary>
+        ///  Int variable type (16 bits, 2 bytes)
+        /// </summary>
+        Int,
+
+        /// <summary>
+        /// DInt variable type (32 bits, 4 bytes)
+        /// </summary>
+        DInt,
+
+        /// <summary>
+        /// Real variable type (32 bits, 4 bytes)
+        /// </summary>
+        Real,
+
+        
+
+        /// <summary>
+        /// Char Array / C-String variable type (variable)
+        /// </summary>
+        String,
+
+      
+    }
+}

+ 1 - 0
BlankApp1/BlankApp1/PLCTool.csproj

@@ -33,6 +33,7 @@
     <ProjectReference Include="..\BizService\BizService.csproj" />
     <ProjectReference Include="..\Common\Common.csproj" />
     <ProjectReference Include="..\Model\Model.csproj" />
+    <ProjectReference Include="..\OmronFinsTCP.Net\OmronFinsTCP.Net.csproj" />
   </ItemGroup>
   <ItemGroup>
     <Resource Include="Assets\Fonts\iconfont.ttf">

+ 5 - 4
BlankApp1/BlankApp1/ViewModels/BusinessManageViewModel/AutoTestViewModel.cs

@@ -1,9 +1,10 @@
 using AutoMapper;
 using BizService;
+using Microsoft.Extensions.Logging;
 using Model.Dto;
 using Model.Entities;
 using Newtonsoft.Json;
-using NLog;
+
 using PLCTool.Common;
 using Prism.Commands;
 using Prism.Events;
@@ -40,7 +41,7 @@ namespace PLCTool.ViewModels.BusinessManageViewModel
         private long schDetailId = 0; //测试方案明细ID
 
         private const string TestMode = "自动测试";
-        public AutoTestViewModel(IDialogService dialog, IEventAggregator aggregator, IOptionConfigService optionConfigService, IBasicPlcTestSchemeService basicPlcTestSchemeService, IBasicPlcTestSchemeDtlService basicPlcTestSchemeDtlService, IBizTestRecordService iBizTestRecordService, IBizTestRecordDtlService iBizTestRecordDtlService, IMapper mapper)
+        public AutoTestViewModel(IDialogService dialog, IEventAggregator aggregator, IOptionConfigService optionConfigService, IBasicPlcTestSchemeService basicPlcTestSchemeService, IBasicPlcTestSchemeDtlService basicPlcTestSchemeDtlService, IBizTestRecordService iBizTestRecordService, IBizTestRecordDtlService iBizTestRecordDtlService, IMapper mapper, ILogger logger)
         {
             _dialog = dialog;
             _aggregator = aggregator;
@@ -50,7 +51,7 @@ namespace PLCTool.ViewModels.BusinessManageViewModel
             _iBizTestRecordDtlService = iBizTestRecordDtlService;
             _iBizTestRecordService = iBizTestRecordService;
             _mapper = mapper;
-            //_logger = logger;
+            _logger = logger;
             CloseCommand = new DelegateCommand(Close);
             StartCommand = new DelegateCommand<object>(Start);
             DoneCommand = new DelegateCommand<object>(Done);
@@ -64,7 +65,7 @@ namespace PLCTool.ViewModels.BusinessManageViewModel
 
 
         #region idialog接口实现
-        public string Title { set; get; } = "动测试";
+        public string Title { set; get; } = "动测试";
 
         public event Action<IDialogResult> RequestClose;
 

+ 58 - 4
BlankApp1/BlankApp1/ViewModels/BusinessManageViewModel/ManualTestViewModel.cs

@@ -1,9 +1,10 @@
 using AutoMapper;
 using BizService;
+using Microsoft.Extensions.Logging;
 using Model.Dto;
 using Model.Entities;
 using Newtonsoft.Json;
-using NLog;
+using OmronFinsTCP.Net;
 using PLCTool.Common;
 using Prism.Commands;
 using Prism.Events;
@@ -12,6 +13,7 @@ using Prism.Services.Dialogs;
 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
+using System.Configuration;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
@@ -42,7 +44,8 @@ namespace PLCTool.ViewModels.BusinessManageViewModel
         private long schDetailId = 0; //测试方案明细ID
 
         private const string TestMode = "手动测试";
-        public ManualTestViewModel(IDialogService dialog, IEventAggregator aggregator, IOptionConfigService optionConfigService, IBasicPlcTestSchemeService basicPlcTestSchemeService, IBasicPlcTestSchemeDtlService basicPlcTestSchemeDtlService, IBizTestRecordService iBizTestRecordService, IBizTestRecordDtlService iBizTestRecordDtlService,IMapper mapper)
+    
+        public ManualTestViewModel(IDialogService dialog, IEventAggregator aggregator, IOptionConfigService optionConfigService, IBasicPlcTestSchemeService basicPlcTestSchemeService, IBasicPlcTestSchemeDtlService basicPlcTestSchemeDtlService, IBizTestRecordService iBizTestRecordService, IBizTestRecordDtlService iBizTestRecordDtlService,IMapper mapper,ILogger logger)
         {
             _dialog = dialog;
             _aggregator = aggregator;
@@ -52,7 +55,7 @@ namespace PLCTool.ViewModels.BusinessManageViewModel
             _iBizTestRecordDtlService = iBizTestRecordDtlService;
             _iBizTestRecordService= iBizTestRecordService;
             _mapper = mapper;
-            //_logger = logger;
+            _logger = logger;
             CloseCommand = new DelegateCommand(Close);
             StartCommand = new DelegateCommand<object>(Start);
             PreviousCommand = new DelegateCommand<object>(Previous);
@@ -62,6 +65,7 @@ namespace PLCTool.ViewModels.BusinessManageViewModel
             InConList = new ObservableCollection<BasPlcItemConfigDto>();
             OutConList = new ObservableCollection<BasPlcItemConfigDto>();
             GetConfigOption();
+           
         }
 
     
@@ -179,7 +183,8 @@ namespace PLCTool.ViewModels.BusinessManageViewModel
         #endregion
 
         #region 私有发方法
-
+        
+     
 
         /// <summary>
         /// 完成时间
@@ -265,7 +270,56 @@ namespace PLCTool.ViewModels.BusinessManageViewModel
         {
             //开始时间
             startTime = DateTime.Now;
+            
+            
+            //前置项
+            switch(BeforeSelectJudge)
+            {
+                case "人工判定":
+                    //弹出确认的对话框
+                    MessageBox.Show(BeforeDetail, "确认", MessageBoxButton.OKCancel, MessageBoxImage.Information);
+                    StepIndex = 1;
+                    break;
+                case "自动判定":
+                    //读取plc的值
+                    switch(SelectLogic)
+                    {
+                        case "NULL":
+                            break;
+                        case "AND":
+                            int countCond = 0;
+                            foreach(var item in BeforeConList)
+                            {
+                                string plcAddress = item.PlcAddress;
+                                string plcAddType = item.plcAddType;
+                                string plcValue = item.PlcValue;
+                                switch(plcAddType) 
+                                {
+                                    case "bool":
+                                        string readResult=PLCCom.GetInstance().ReadPlcObject(plcAddress, VarType.Bit);
+                                        if(readResult== plcValue)
+                                        {
+                                            countCond++;
+                                        }
+                                        break;
+                                    case "word":
+                                        break;
+                                }
+                            }
+                            if(countCond > 0)
+                            {
 
+                            }
+                            break;
+                        case "OR":
+                            break;
+                        case "ONLY":
+                            break;
+                        case "ORDER":
+                            break;
+                    }
+                    break;
+            }
         }
 
         /// <summary>

+ 3 - 0
BlankApp1/BlankApp1/Views/BusinessManageView/AutoTestView.xaml

@@ -109,6 +109,7 @@
                         <DataGridTextColumn Header="PLC变量名" Binding="{Binding PlcItem}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTextColumn Header="判定值" Binding="{Binding PlcValue}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTextColumn Header="结果" Binding="{Binding RealValue}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
+                        <DataGridTextColumn Header="描述" Binding="{Binding Remark}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTemplateColumn Header="操作" Width="160"  CellStyle="{StaticResource MyDataGridCellStyle}">
                             <DataGridTemplateColumn.CellTemplate>
                                 <DataTemplate>
@@ -198,6 +199,7 @@
                         <DataGridTextColumn Header="PLC变量名" Binding="{Binding PlcItem}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTextColumn Header="判定值" Binding="{Binding PlcValue}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTextColumn Header="结果" Binding="{Binding RealValue}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
+                        <DataGridTextColumn Header="描述" Binding="{Binding Remark}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTemplateColumn Header="操作" Width="160"  CellStyle="{StaticResource MyDataGridCellStyle}">
                             <DataGridTemplateColumn.CellTemplate>
                                 <DataTemplate>
@@ -287,6 +289,7 @@
                         <DataGridTextColumn Header="PLC变量名" Binding="{Binding PlcItem}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTextColumn Header="判定值" Binding="{Binding PlcValue}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTextColumn Header="结果" Binding="{Binding RealValue}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
+                        <DataGridTextColumn Header="描述" Binding="{Binding Remark}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTemplateColumn Header="操作" Width="160"  CellStyle="{StaticResource MyDataGridCellStyle}">
                             <DataGridTemplateColumn.CellTemplate>
                                 <DataTemplate>

+ 5 - 1
BlankApp1/BlankApp1/Views/BusinessManageView/ManualTestView.xaml

@@ -4,7 +4,7 @@
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
              xmlns:local="clr-namespace:PLCTool.Views.BusinessManageView"
-                         xmlns:hc="https://handyorg.github.io/handycontrol"
+             xmlns:hc="https://handyorg.github.io/handycontrol"
              xmlns:prism="http://prismlibrary.com/" 
              BorderBrush="#CBCBCB" BorderThickness="1"
              Height="600" Width="1000" >
@@ -109,6 +109,7 @@
                         <DataGridTextColumn Header="PLC变量名" Binding="{Binding PlcItem}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTextColumn Header="判定值" Binding="{Binding PlcValue}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTextColumn Header="结果" Binding="{Binding RealValue}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
+                        <DataGridTextColumn Header="描述" Binding="{Binding Remark}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTemplateColumn Header="操作" Width="160"  CellStyle="{StaticResource MyDataGridCellStyle}">
                             <DataGridTemplateColumn.CellTemplate>
                                 <DataTemplate>
@@ -198,6 +199,7 @@
                         <DataGridTextColumn Header="PLC变量名" Binding="{Binding PlcItem}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTextColumn Header="判定值" Binding="{Binding PlcValue}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTextColumn Header="结果" Binding="{Binding RealValue}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
+                        <DataGridTextColumn Header="描述" Binding="{Binding Remark}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTemplateColumn Header="操作" Width="160"  CellStyle="{StaticResource MyDataGridCellStyle}">
                             <DataGridTemplateColumn.CellTemplate>
                                 <DataTemplate>
@@ -287,6 +289,7 @@
                         <DataGridTextColumn Header="PLC变量名" Binding="{Binding PlcItem}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTextColumn Header="判定值" Binding="{Binding PlcValue}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTextColumn Header="结果" Binding="{Binding RealValue}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
+                        <DataGridTextColumn Header="描述" Binding="{Binding Remark}" CellStyle="{StaticResource MyDataGridCellStyle}"/>
                         <DataGridTemplateColumn Header="操作" Width="160"  CellStyle="{StaticResource MyDataGridCellStyle}">
                             <DataGridTemplateColumn.CellTemplate>
                                 <DataTemplate>
@@ -320,6 +323,7 @@
         <Border Grid.Row="3"  BorderBrush="#CBCBCB" BorderThickness="0,1,0,0" />
         <Grid Grid.Row="4">
             <hc:StepBar  StepIndex="{Binding StepIndex}" VerticalAlignment="Center" x:Name="ProSetpBar"  >
+                <hc:StepBarItem Content="开始"/>
                 <hc:StepBarItem Content="前置条件满足"/>
                 <hc:StepBarItem Content="输入明细完成"/>
                 <hc:StepBarItem Content="结果判定完成"/>

+ 73 - 0
BlankApp1/OmronFinsTCP.Net/BasicClass.cs

@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Net.Sockets;
+using System.Net.NetworkInformation;
+
+namespace OmronFinsTCP.Net
+{
+    class BasicClass
+    {
+        internal static TcpClient Client;
+        internal static NetworkStream Stream;
+        internal static byte pcNode, plcNode;
+
+        //检查PLC链接状况
+        internal static bool PingCheck(string ip,int timeOut)
+        {
+            Ping ping = new Ping();
+            PingReply pr = ping.Send(ip, timeOut);
+            if (pr.Status == IPStatus.Success)
+                return true;
+            else
+                return false;
+        }
+
+        //内部方法,发送数据
+        internal static short SendData(byte[] sd)
+        {
+            try
+            {
+                Stream.Write(sd, 0, sd.Length);
+                return 0;
+            }
+            catch
+            {
+                return -1;
+            }
+        }
+
+        //内部方法,接收数据
+        internal static short ReceiveData(byte[] rd)
+        {
+            try
+            {
+                //等待可读数据到底指定的长度,自己想的方法,下面的另一写法参考网络。
+                //突然发现,此方法在数据量达不到指定长度时会死循环!
+                //while (true)
+                //{
+                //    Thread.Sleep(1);
+                //    if (Client.Available >= rd.Length && Stream.DataAvailable)
+                //        break;
+                //}
+                //this.Stream.Read(rd, 0, rd.Length);
+                //另一写法:
+                int index = 0;
+                do
+                {
+                    int len = Stream.Read(rd, index, rd.Length - index);
+                    if (len == 0)
+                        return -1;//这里控制读取不到数据时就跳出,网络异常断开,数据读取不完整。
+                    else
+                        index += len;
+                } while (index < rd.Length);
+                return 0;
+            }
+            catch
+            {
+                return -1;
+            }
+        }
+    }
+}

+ 66 - 0
BlankApp1/OmronFinsTCP.Net/EnumClass.cs

@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace OmronFinsTCP.Net
+{
+    /// <summary>
+    /// 寄存器类型,十六进制表示形式
+    /// </summary>
+    public enum PlcMemory
+    {
+        //CIO_Word = 0xB0,
+        //CIO_Bit = 0x30,
+        //WR_Word = 0xB1,
+        //WR_Bit = 0x31,
+        //HR_Word =0xB2,
+        //HR_Bit = 0x32,
+        //AR_Word =0xB3,
+        //AR_Bit = 0x33,
+        //DM_Word = 0x82,
+        //DM_Bit = 0x02
+        CIO,
+        WR,
+        HR,
+        AR,
+        DM
+    }
+
+    /// <summary>
+    /// 地址类型
+    /// </summary>
+    public enum MemoryType
+    {
+        Bit,
+        Word
+    }
+
+    /// <summary>
+    /// 数据类型,PLC字为16位数,最高位为符号位,负数表现形式为“取反加一”
+    /// </summary>
+    public enum DataType
+    {
+        BIT,
+        INT16,
+        REAL
+    }
+
+    /// <summary>
+    /// bit位开关状态,on=1,off=0
+    /// </summary>
+    public enum BitState
+    {
+        ON = 1,
+        OFF = 0
+    }
+
+    /// <summary>
+    /// 区分指令的读写类型
+    /// </summary>
+    public enum RorW
+    {
+        Read,
+        Write
+    }
+}

+ 230 - 0
BlankApp1/OmronFinsTCP.Net/ErrorCode.cs

@@ -0,0 +1,230 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace OmronFinsTCP.Net
+{
+    class ErrorCode
+    {        
+        /// <summary>
+        /// (若返回的头指令为3)检查命令头中的错误代码
+        /// </summary>
+        /// <param name="Code">错误代码</param>
+        /// <returns>指示程序是否可以继续进行</returns>
+        internal static bool CheckHeadError(byte Code)
+        {
+            switch (Code)
+            {
+                case 0x00: return true;
+                case 0x01: return false;//RaiseException("the head is not 'FINS'");
+                case 0x02: return false;//RaiseException("the data length is too long");
+                case 0x03: return false;//RaiseException("the command is not supported");
+            }
+            //no hit
+            return false;//RaiseException("unknown exception");
+        }
+
+        /// <summary>
+        /// 检查命令帧中的EndCode
+        /// </summary>
+        /// <param name="Main">主码</param>
+        /// <param name="Sub">副码</param>
+        /// <returns>指示程序是否可以继续进行</returns>
+        internal static bool CheckEndCode(byte Main, byte Sub)
+        {
+            switch (Main)
+            {
+                case 0x00:
+                    switch (Sub)
+                    {
+                        case 0x00: return true;//the only situation of success
+                        case 0x40: return true;//错误码64,是因为PLC中产生了报警,但是数据还是能正常读到的,屏蔽64报警或清除plc错误可解决
+                        case 0x01: return false;//RaiseException("service canceled");
+                    }
+                    break;
+
+                case 0x01:
+                    switch (Sub)
+                    {
+                        case 0x01: return false;//RaiseException("local node not in network");
+                        case 0x02: return false;//RaiseException("token timeout");
+                        case 0x03: return false;//RaiseException("retries failed");
+                        case 0x04: return false;//RaiseException("too many send frames");
+                        case 0x05: return false;//RaiseException("node address range error");
+                        case 0x06: return false;//RaiseException("node address duplication");
+                    }
+                    break;
+
+                case 0x02:
+                    switch (Sub)
+                    {
+                        case 0x01: return false;//RaiseException("destination node not in network");
+                        case 0x02: return false;//RaiseException("unit missing");
+                        case 0x03: return false;//RaiseException("third node missing");
+                        case 0x04: return false;//RaiseException("destination node busy");
+                        case 0x05: return false;//RaiseException("response timeout");
+                    }
+                    break;
+
+                case 0x03:
+                    switch (Sub)
+                    {
+                        case 0x01: return false;//RaiseException("communications controller error");
+                        case 0x02: return false;//RaiseException("CPU unit error");
+                        case 0x03: return false;//RaiseException("controller error");
+                        case 0x04: return false;//RaiseException("unit number error");
+                    }
+                    break;
+
+                case 0x04:
+                    switch (Sub)
+                    {
+                        case 0x01: return false;//RaiseException("undefined command");
+                        case 0x02: return false;//RaiseException("not supported by model/version");
+                    }
+                    break;
+
+                case 0x05:
+                    switch (Sub)
+                    {
+                        case 0x01: return false;//RaiseException("destination address setting error");
+                        case 0x02: return false;//RaiseException("no routing tables");
+                        case 0x03: return false;//RaiseException("routing table error");
+                        case 0x04: return false;//RaiseException("too many relays");
+                    }
+                    break;
+
+                case 0x10:
+                    switch (Sub)
+                    {
+                        case 0x01: return false;//RaiseException("command too long");
+                        case 0x02: return false;//RaiseException("command too short");
+                        case 0x03: return false;//RaiseException("elements/data don't match");
+                        case 0x04: return false;//RaiseException("command format error");
+                        case 0x05: return false;//RaiseException("header error");
+                    }
+                    break;
+
+                case 0x11:
+                    switch (Sub)
+                    {
+                        case 0x01: return false;//RaiseException("area classification missing");
+                        case 0x02: return false;//RaiseException("access size error");
+                        case 0x03: return false;//RaiseException("address range error");
+                        case 0x04: return false;//RaiseException("address range exceeded");
+                        case 0x06: return false;//RaiseException("program missing");
+                        case 0x09: return false;//RaiseException("relational error");
+                        case 0x0a: return false;//RaiseException("duplicate data access");
+                        case 0x0b: return false;//RaiseException("response too long");
+                        case 0x0c: return false;//RaiseException("parameter error");
+                    }
+                    break;
+
+                case 0x20:
+                    switch (Sub)
+                    {
+                        case 0x02: return false;//RaiseException("protected");
+                        case 0x03: return false;//RaiseException("table missing");
+                        case 0x04: return false;//RaiseException("data missing");
+                        case 0x05: return false;//RaiseException("program missing");
+                        case 0x06: return false;//RaiseException("file missing");
+                        case 0x07: return false;//RaiseException("data mismatch");
+                    }
+                    break;
+
+                case 0x21:
+                    switch (Sub)
+                    {
+                        case 0x01: return false;//RaiseException("read-only");
+                        case 0x02: return false;//RaiseException("protected , cannot write data link table");
+                        case 0x03: return false;//RaiseException("cannot register");
+                        case 0x05: return false;//RaiseException("program missing");
+                        case 0x06: return false;//RaiseException("file missing");
+                        case 0x07: return false;//RaiseException("file name already exists");
+                        case 0x08: return false;//RaiseException("cannot change");
+                    }
+                    break;
+
+                case 0x22:
+                    switch (Sub)
+                    {
+                        case 0x01: return false;//RaiseException("not possible during execution");
+                        case 0x02: return false;//RaiseException("not possible while running");
+                        case 0x03: return false;//RaiseException("wrong PLC mode");
+                        case 0x04: return false;//RaiseException("wrong PLC mode");
+                        case 0x05: return false;//RaiseException("wrong PLC mode");
+                        case 0x06: return false;//RaiseException("wrong PLC mode");
+                        case 0x07: return false;//RaiseException("specified node not polling node");
+                        case 0x08: return false;//RaiseException("step cannot be executed");
+                    }
+                    break;
+
+                case 0x23:
+                    switch (Sub)
+                    {
+                        case 0x01: return false;//RaiseException("file device missing");
+                        case 0x02: return false;//RaiseException("memory missing");
+                        case 0x03: return false;//RaiseException("clock missing");
+                    }
+                    break;
+
+                case 0x24:
+                    switch (Sub)
+                    {
+                        case 0x01: return false;//RaiseException("table missing");
+                    }
+                    break;
+
+                case 0x25:
+                    switch (Sub)
+                    {
+                        case 0x02: return false;//RaiseException("memory error");
+                        case 0x03: return false;//RaiseException("I/O setting error");
+                        case 0x04: return false;//RaiseException("too many I/O points");
+                        case 0x05: return false;//RaiseException("CPU bus error");
+                        case 0x06: return false;//RaiseException("I/O duplication");
+                        case 0x07: return false;//RaiseException("CPU bus error");
+                        case 0x09: return false;//RaiseException("SYSMAC BUS/2 error");
+                        case 0x0a: return false;//RaiseException("CPU bus unit error");
+                        case 0x0d: return false;//RaiseException("SYSMAC BUS No. duplication");
+                        case 0x0f: return false;//RaiseException("memory error");
+                        case 0x10: return false;//RaiseException("SYSMAC BUS terminator missing");
+                    }
+                    break;
+
+                case 0x26:
+                    switch (Sub)
+                    {
+                        case 0x01: return false;//RaiseException("no protection");
+                        case 0x02: return false;//RaiseException("incorrect password");
+                        case 0x04: return false;//RaiseException("protected");
+                        case 0x05: return false;//RaiseException("service already executing");
+                        case 0x06: return false;//RaiseException("service stopped");
+                        case 0x07: return false;//RaiseException("no execution right");
+                        case 0x08: return false;//RaiseException("settings required before execution");
+                        case 0x09: return false;//RaiseException("necessary items not set");
+                        case 0x0a: return false;//RaiseException("number already defined");
+                        case 0x0b: return false;//RaiseException("error will not clear");
+                    }
+                    break;
+
+                case 0x30:
+                    switch (Sub)
+                    {
+                        case 0x01: return false;//RaiseException("no access right");
+                    }
+                    break;
+
+                case 0x40:
+                    switch (Sub)
+                    {
+                        case 0x01: return false;//RaiseException("service aborted");
+                    }
+                    break;
+            }
+            //no hit
+            return false;//RaiseException("unknown exception");
+        }
+    }
+}

+ 416 - 0
BlankApp1/OmronFinsTCP.Net/EtherNetPLC.cs

@@ -0,0 +1,416 @@
+using System;
+using System.Net.Sockets;
+using System.Threading;
+
+namespace OmronFinsTCP.Net
+{
+    public class EtherNetPLC
+    {
+        /// <summary>
+        /// PLC节点号,调试方法,一般不需要使用
+        /// </summary>
+        public string PLCNode
+        {
+            get { return BasicClass.plcNode.ToString(); }
+        }
+
+        /// <summary>
+        /// PC节点号,调试方法,一般不需要使用
+        /// </summary>
+        public string PCNode
+        {
+            get { return BasicClass.pcNode.ToString(); }
+        }
+
+        /// <summary>
+        /// 实例化PLC操作对象
+        /// </summary>
+        public EtherNetPLC()
+        {
+            BasicClass.Client = new TcpClient();
+        }
+
+        /// <summary>
+        /// 与PLC建立TCP连接
+        /// </summary>
+        /// <param name="rIP">PLC的IP地址</param>
+        /// <param name="rPort">端口号,默认9600</param>
+        /// <param name="timeOut">超时时间,默认3000毫秒</param>
+        /// <returns></returns>
+        public short Link(string rIP, short rPort, short timeOut = 3000)
+        {
+            if(BasicClass.PingCheck(rIP,timeOut))
+            {
+                BasicClass.Client.Connect(rIP, (int)rPort);
+                BasicClass.Stream = BasicClass.Client.GetStream();
+                Thread.Sleep(10);
+
+                if (BasicClass.SendData(FinsClass.HandShake()) != 0)
+                {
+                    return -1;
+                }
+                else
+                {
+                    //开始读取返回信号
+                    byte[] buffer = new byte[24];
+                    if (BasicClass.ReceiveData(buffer) != 0)
+                    {
+                        return -1;
+                    }
+                    else
+                    {
+                        if (buffer[15] != 0)//TODO:这里的15号是不是ERR信息暂时不能完全肯定
+                            return -1;
+                        else
+                        {
+                            BasicClass.pcNode = buffer[19];
+                            BasicClass.plcNode = buffer[23];
+                            return 0;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                //连接超时
+                return -1;
+            }
+        }
+
+        /// <summary>
+        /// 关闭PLC操作对象的TCP连接
+        /// </summary>
+        /// <returns></returns>
+        public short Close()
+        {
+            try
+            {
+                BasicClass.Stream.Close();
+                BasicClass.Client.Close();
+                return 0;
+            }
+            catch
+            {
+                return -1;
+            }
+        }
+
+        /// <summary>
+        /// 读值方法(多个连续值)
+        /// </summary>
+        /// <param name="mr">地址类型枚举</param>
+        /// <param name="ch">起始地址</param>
+        /// <param name="cnt">地址个数</param>
+        /// <param name="reData">返回值</param>
+        /// <returns></returns>
+        public short ReadWords(PlcMemory mr, short ch, short cnt, out short[] reData)
+        {
+            reData = new short[(int)(cnt)];//储存读取到的数据
+            int num = (int)(30 + cnt * 2);//接收数据(Text)的长度,字节数
+            byte[] buffer = new byte[num];//用于接收数据的缓存区大小
+            byte[] array = FinsClass.FinsCmd(RorW.Read, mr, MemoryType.Word, ch, 00, cnt);
+            if (BasicClass.SendData(array) == 0)
+            {
+                if (BasicClass.ReceiveData(buffer) == 0)
+                {
+                    //命令返回成功,继续查询是否有错误码,然后在读取数据
+                    bool succeed = true;
+                    if (buffer[11] == 3)
+                        succeed = ErrorCode.CheckHeadError(buffer[15]);
+                    if (succeed)//no header error
+                    {
+                        //endcode为fins指令的返回错误码
+                        if (ErrorCode.CheckEndCode(buffer[28], buffer[29]))
+                        {
+                            //完全正确的返回,开始读取返回的具体数值
+                            for (int i = 0; i < cnt; i++)
+                            {
+                                //返回的数据从第30字节开始储存的,
+                                //PLC每个字占用两个字节,且是高位在前,这和微软的默认低位在前不同
+                                //因此无法直接使用,reData[i] = BitConverter.ToInt16(buffer, 30 + i * 2);
+                                //先交换了高低位的位置,然后再使用BitConverter.ToInt16转换
+                                byte[] temp = new byte[] { buffer[30 + i * 2 + 1], buffer[30 + i * 2] };
+                                reData[i] = BitConverter.ToInt16(temp, 0);
+                            }
+                            return 0;
+                        }
+                        else
+                        {
+                            return -1;
+                        }
+                    }
+                    else
+                    {
+                        return -1;
+                    }
+                }
+                else
+                {
+                    return -1;
+                }
+            }
+            else
+            {
+                return -1;
+            }
+        }
+
+        /// <summary>
+        /// 读单个字方法
+        /// </summary>
+        /// <param name="mr"></param>
+        /// <param name="ch"></param>
+        /// <param name="reData"></param>
+        /// <returns></returns>
+        public short ReadWord(PlcMemory mr, short ch, out short reData)
+        {
+            short[] temp;
+            reData = new short();
+            short re = ReadWords(mr, ch, (short)1, out temp);
+            if (re != 0)
+                return -1;
+            else
+            {
+                reData = temp[0];
+                return 0;
+            }
+        }
+
+        /// <summary>
+        /// 写值方法(多个连续值)
+        /// </summary>
+        /// <param name="mr">地址类型枚举</param>
+        /// <param name="ch">起始地址</param>
+        /// <param name="cnt">地址个数</param>
+        /// <param name="inData">写入值</param>
+        /// <returns></returns>
+        public short WriteWords(PlcMemory mr, short ch, short cnt, short[] inData)
+        {            
+            byte[] buffer = new byte[30];
+            byte[] arrayhead = FinsClass.FinsCmd(RorW.Write, mr, MemoryType.Word, ch, 00, cnt);//前34字节和读指令基本一直,还需要拼接下面的输入数据数组
+            byte[] wdata = new byte[(int)(cnt * 2)];
+            //转换写入值到wdata数组
+            for (int i = 0; i < cnt; i++)
+            {
+                byte[] temp = BitConverter.GetBytes(inData[i]);
+                wdata[i * 2] = temp[1];//转换为PLC的高位在前储存方式
+                wdata[i * 2 + 1] = temp[0];
+            }
+            //拼接写入数组
+            byte[] array = new byte[(int)(cnt * 2 + 34)];
+            arrayhead.CopyTo(array, 0);
+            wdata.CopyTo(array, 34);
+            if (BasicClass.SendData(array) == 0)
+            {
+                if (BasicClass.ReceiveData(buffer) == 0)
+                {
+                    //命令返回成功,继续查询是否有错误码,然后在读取数据
+                    bool succeed = true;
+                    if (buffer[11] == 3)
+                        succeed = ErrorCode.CheckHeadError(buffer[15]);
+                    if (succeed)//no header error
+                    {
+                        //endcode为fins指令的返回错误码
+                        if (ErrorCode.CheckEndCode(buffer[28], buffer[29]))
+                        {
+                            //完全正确的返回0
+                            return 0;
+                        }
+                        else
+                        {
+                            return -1;
+                        }
+                    }
+                    else
+                    {
+                        return -1;
+                    }
+                }
+                else
+                {
+                    return -1;
+                }
+            }
+            else
+            {
+                return -1;
+            }
+        }
+
+        /// <summary>
+        /// 写单个字方法
+        /// </summary>
+        /// <param name="mr"></param>
+        /// <param name="ch"></param>
+        /// <param name="inData"></param>
+        /// <returns></returns>
+        public short WriteWord(PlcMemory mr, short ch, short inData)
+        {
+            short[] temp = new short[] { inData };
+            short re = WriteWords(mr, ch, (short)1, temp);
+            if (re != 0)
+                return -1;
+            else
+            {
+                return 0;
+            }
+        }
+
+        /// <summary>
+        /// 读值方法-按位bit(单个)
+        /// </summary>
+        /// <param name="mr">地址类型枚举</param>
+        /// <param name="ch">地址000.00</param>
+        /// <param name="bs">返回开关状态枚举EtherNetPLC.BitState,0/1</param>
+        /// <returns></returns>
+        public short GetBitState(PlcMemory mr, string ch, out short bs)
+        {
+            bs = new short();
+            byte[] buffer = new byte[31];//用于接收数据的缓存区大小
+            short cnInt = short.Parse(ch.Split('.')[0]);
+            short cnBit = short.Parse(ch.Split('.')[1]);
+            byte[] array = FinsClass.FinsCmd(RorW.Read, mr, MemoryType.Bit, cnInt, cnBit, 1);
+            if (BasicClass.SendData(array) == 0)
+            {
+                if (BasicClass.ReceiveData(buffer) == 0)
+                {
+                    //命令返回成功,继续查询是否有错误码,然后在读取数据
+                    bool succeed = true;
+                    if (buffer[11] == 3)
+                        succeed = ErrorCode.CheckHeadError(buffer[15]);
+                    if (succeed)//no header error
+                    {
+                        //endcode为fins指令的返回错误码
+                        if (ErrorCode.CheckEndCode(buffer[28], buffer[29]))
+                        {
+                            //完全正确的返回,开始读取返回的具体数值
+                            bs = (short)buffer[30];
+                            return 0;
+                        }
+                        else
+                        {
+                            return -1;
+                        }
+                    }
+                    else
+                    {
+                        return -1;
+                    }
+                }
+                else
+                {
+                    return -1;
+                }
+            }
+            else
+            {
+                return -1;
+            }
+        }
+
+        /// <summary>
+        /// 写值方法-按位bit(单个)
+        /// </summary>
+        /// <param name="mr">地址类型枚举</param>
+        /// <param name="ch">地址000.00</param>
+        /// <param name="bs">开关状态枚举EtherNetPLC.BitState,0/1</param>
+        /// <returns></returns>
+        public short SetBitState(PlcMemory mr, string ch, BitState bs)
+        {
+            byte[] buffer = new byte[30];
+            short cnInt = short.Parse(ch.Split('.')[0]);
+            short cnBit = short.Parse(ch.Split('.')[1]);
+            byte[] arrayhead = FinsClass.FinsCmd(RorW.Write, mr, MemoryType.Bit, cnInt, cnBit, 1);
+            byte[] array = new byte[35];
+            arrayhead.CopyTo(array, 0);
+            array[34] = (byte)bs;
+            if (BasicClass.SendData(array) == 0)
+            {
+                if (BasicClass.ReceiveData(buffer) == 0)
+                {
+                    //命令返回成功,继续查询是否有错误码,然后在读取数据
+                    bool succeed = true;
+                    if (buffer[11] == 3)
+                        succeed = ErrorCode.CheckHeadError(buffer[15]);
+                    if (succeed)//no header error
+                    {
+                        //endcode为fins指令的返回错误码
+                        if (ErrorCode.CheckEndCode(buffer[28], buffer[29]))
+                        {
+                            //完全正确的返回0
+                            return 0;
+                        }
+                        else
+                        {
+                            return -1;
+                        }
+                    }
+                    else
+                    {
+                        return -1;
+                    }
+                }
+                else
+                {
+                    return -1;
+                }
+            }
+            else
+            {
+                return -1;
+            }
+        }
+
+        /// <summary>
+        /// 读一个浮点数的方法,单精度,在PLC中占两个字
+        /// </summary>
+        /// <param name="mr">地址类型枚举</param>
+        /// <param name="ch">起始地址,会读取两个连续的地址,因为单精度在PLC中占两个字</param>
+        /// <param name="reData">返回一个float型</param>
+        /// <returns></returns>
+        public short ReadReal(PlcMemory mr, short ch,out float reData)
+        {
+            reData = new float();
+            int num = (int)(30 + 2 * 2);//接收数据(Text)的长度,字节数
+            byte[] buffer = new byte[num];//用于接收数据的缓存区大小
+            byte[] array = FinsClass.FinsCmd(RorW.Read, mr, MemoryType.Word, ch, 00, 2);
+            if (BasicClass.SendData(array) == 0)
+            {
+                if (BasicClass.ReceiveData(buffer) == 0)
+                {
+                    //命令返回成功,继续查询是否有错误码,然后在读取数据
+                    bool succeed = true;
+                    if (buffer[11] == 3)
+                        succeed = ErrorCode.CheckHeadError(buffer[15]);
+                    if (succeed)//no header error
+                    {
+                        //endcode为fins指令的返回错误码
+                        if (ErrorCode.CheckEndCode(buffer[28], buffer[29]))
+                        {
+                            //完全正确的返回,开始读取返回的具体数值
+                            byte[] temp = new byte[] { buffer[30 + 1], buffer[30], buffer[30 + 3], buffer[30 + 2] };
+                            reData = BitConverter.ToSingle(temp, 0);
+                            return 0;
+                        }
+                        else
+                        {
+                            return -1;
+                        }
+                    }
+                    else
+                    {
+                        return -1;
+                    }
+                }
+                else
+                {
+                    return -1;
+                }
+            }
+            else
+            {
+                return -1;
+            }
+        }
+    }
+}

+ 188 - 0
BlankApp1/OmronFinsTCP.Net/FinsClass.cs

@@ -0,0 +1,188 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace OmronFinsTCP.Net
+{
+    class FinsClass
+    {
+        /// <summary>
+        /// 获取内存区码
+        /// </summary>
+        /// <param name="mr">寄存器类型</param>
+        /// <param name="mt">地址类型</param>
+        /// <returns></returns>
+        private static byte GetMemoryCode(PlcMemory mr, MemoryType mt)
+        {
+            if (mt == MemoryType.Bit)
+            {
+                switch (mr)
+                {
+                    case PlcMemory.CIO:
+                        return 0x30;
+                    case PlcMemory.WR:
+                        return 0x31;
+                    case PlcMemory.HR:
+                        return 0x32;
+                    case PlcMemory.AR:
+                        return 0x33;  
+                    case PlcMemory.DM:
+                        return 0x02;
+                    default:
+                        return 0x00;
+                }
+            }
+            else
+            {
+                switch (mr)
+                {
+                    case PlcMemory.CIO:
+                        return 0xB0;
+                    case PlcMemory.WR:
+                        return 0xB1;
+                    case PlcMemory.HR:
+                        return 0xB2;
+                    case PlcMemory.AR:
+                        return 0xB3;
+                    case PlcMemory.DM:
+                        return 0x82;
+                    default:
+                        return 0x00;
+                }
+            }
+        }
+
+        /// <summary>
+        /// PC请求连接的握手信号,第一次连接会分配PC节点号
+        /// </summary>
+        /// <returns></returns>
+        internal static byte[] HandShake()
+        {
+            #region fins command
+            byte[] array = new byte[20];
+            array[0] = 0x46;
+            array[1] = 0x49;
+            array[2] = 0x4E;
+            array[3] = 0x53;
+
+            array[4] = 0;
+            array[5] = 0;
+            array[6] = 0;
+            array[7] = 0x0C;
+
+            array[8] = 0;
+            array[9] = 0;
+            array[10] = 0;
+            array[11] = 0;
+
+            array[12] = 0;
+            array[13] = 0;
+            array[14] = 0;
+            array[15] = 0;//ERR?
+
+            array[16] = 0;
+            array[17] = 0;
+            array[18] = 0;
+            array[19] = 0;//TODO:ask for client and server node number, the client node will allocated automatically
+            //array[19] = this.GetIPNode(lIP);//本机IP地址的末位
+            #endregion fins command
+            return array;
+        }
+
+        /// <summary>
+        /// Fins读写指令生成
+        /// </summary>
+        /// <param name="rw">读写类型</param>
+        /// <param name="mr">寄存器类型</param>
+        /// <param name="mt">地址类型</param>
+        /// <param name="ch">起始地址</param>
+        /// <param name="offset">位地址:00-15,字地址则为00</param>
+        /// <param name="cnt">地址个数,按位读写只能是1</param>
+        /// <returns></returns>
+        internal static byte[] FinsCmd(RorW rw, PlcMemory mr, MemoryType mt, short ch, short offset, short cnt)
+        {
+            //byte[] array;
+            //if (rw == RorW.Read)
+            //    array = new byte[34];
+            //else
+            //    array = new byte[(int)(cnt * 2 + 33 + 1)];//长度是如何确定的在fins协议174页
+            byte[] array = new byte[34];//写指令还有后面的写入数组需要拼接在一起!
+            //TCP FINS header
+            array[0] = 0x46;//F
+            array[1] = 0x49;//I
+            array[2] = 0x4E;//N
+            array[3] = 0x53;//S
+
+            array[4] = 0;//cmd length
+            array[5] = 0;
+            //指令长度从下面字节开始计算array[8]
+            if (rw == RorW.Read)
+            {
+                array[6] = 0;
+                array[7] = 0x1A;//26
+            }
+            else
+            {
+                //写数据的时候一个字占两个字节,而一个位只占一个字节
+                if (mt == MemoryType.Word)
+                {
+                    array[6] = (byte)((cnt * 2 + 26) / 256);
+                    array[7] = (byte)((cnt * 2 + 26) % 256);
+                }
+                else
+                {
+                    array[6] = 0;
+                    array[7] = 0x1B;
+                }
+            }
+
+            array[8] = 0;//frame command
+            array[9] = 0;
+            array[10] = 0;
+            array[11] = 0x02;
+
+            array[12] = 0;//err
+            array[13] = 0;
+            array[14] = 0;
+            array[15] = 0;
+            //command frame header
+            array[16] = 0x80;//ICF
+            array[17] = 0x00;//RSV
+            array[18] = 0x02;//GCT, less than 8 network layers
+            array[19] = 0x00;//DNA, local network
+
+            array[20] = BasicClass.plcNode;//DA1
+            array[21] = 0x00;//DA2, CPU unit
+            array[22] = 0x00;//SNA, local network
+            array[23] = BasicClass.pcNode;//SA1
+
+            array[24] = 0x00;//SA2, CPU unit
+            array[25] = 0xFF;
+            //TODO:array[25] = Convert.ToByte(21);//SID//?????----------------------------------00-FF任意值
+
+            //指令码
+            if (rw == RorW.Read)
+            {
+                array[26] = 0x01;//cmdCode--0101
+                array[27] = 0x01;
+            }
+            else
+            {
+                array[26] = 0x01;//write---0102
+                array[27] = 0x02;
+            }
+            //地址
+            //array[28] = (byte)mr;
+            array[28] = GetMemoryCode(mr, mt);
+            array[29] = (byte)(ch / 256);
+            array[30] = (byte)(ch % 256);
+            array[31] = (byte)offset;
+
+            array[32] = (byte)(cnt / 256);
+            array[33] = (byte)(cnt % 256);
+
+            return array;
+        }
+    }
+}

+ 9 - 0
BlankApp1/OmronFinsTCP.Net/OmronFinsTCP.Net.csproj

@@ -0,0 +1,9 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net6.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+</Project>