IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> C#使用欧姆龙PLC的Fins协议读写PLC地址(基本封装) -> 正文阅读

[网络协议]C#使用欧姆龙PLC的Fins协议读写PLC地址(基本封装)

FINS通讯概述

FINS(factory interface network service)通信协议是欧姆龙公司开发的用于工业自动化控制网络的指令/响应系统。运用 FINS指令可实现各种网络间的无缝通信,通过编程发送FINS指令,上位机或PLC就能够读写另一个PLC数据区的内容,甚至控制其运行状态,从而简化了用户程序。FINS协议支持工业以太网,这就为OMRON PLC与上位机以太网通信的实现提供了途径。

FINS-TCP需要握手命令成功后方可真正连接上PLC。

以下命令均为十六进制 字节数据流:

1. 握手指令

1.1. 发送

46494E53?0000000C 00000000 00000000 00000018

46494E53:ASCII编码:FINS;

0000000C:指后面跟的字节长度;12个字节

00000000:固定命令;

00000000:错误代码;

00000018:PC节点IP,当设置为0时,会自动获取节点IP。

1.2. 反馈

46494E53 00000010 00000001 00000000 00000018 00000017

46494E53:ASCII编码:FINS;

00000010:指后面跟的字节长度;16个字节

00000001:固定命令;

00000000:错误代码;

00000018:本机电脑节点IP;

00000017:PLC节点IP。

2. 读取指令

读D100开始的2个地址,注:一次最多读1000个地址【以字为单位,也就是2000个字节】。

2.1. 发送

46494E53 0000001A 00000002 00000000 80 00 02 001700 001800 FF 0101 82 006400 0002

46494E53:ASCII编码:FINS;

0000001A:指后面跟的字节长度;26个字节

00000002:固定命令;

00000000:错误代码;

80:ICF;

00:RSV;

02:GCT;

00:PLC网络地址;

17:PLC节点地址;

00:PLC单元地址;

00:PC网络地址;

18:PC节点地址;

00:PC单元地址;

FF:SID;

0101:读指令;

82:读地址区(D位:02,D字:82,W位:31,C位:30,W字:B1,C字:B0);

006400:起始地址;

0002:读个数。读取字【WORD】个数,也就是【WORD*2】个字节

2.2. 反馈

46494E53?0000001A 00000002 00000000 C0 00 02 001800 001700 FF 0101 0000 AABB CCDD

46494E53:ASCII编码:FINS;

0000001A:指后面跟的字节长度;

00000002:固定命令;

00000000:错误代码;

C0:ICF;

00:RSV;

02:GCT;

00:PC网络地址;

18:PC节点地址;

00:PC单元地址;

00:PLC网络地址;

17:PLC节点地址;

00:PLC单元地址;

FF:SID;

0101:读指令;

0000:读取成功标识;

AABB CCDD:读到的数据。

3. 写入指令

往W10,W11写入AABB,CCDD

3.1. 发送

46494E53 0000001E 00000002 00000000 80 00 02 001700 001800 FF 0102 B1 000A00 0002 AABBCCDD

46494E53:ASCII编码:FINS;

0000001E:指后面跟的字节长度;

00000002:固定命令;

00000000:错误代码;

80:ICF;

00:RSV;

02:GCT;

00:PLC网络地址;

17:PLC节点地址;

00:PLC单元地址;

00:PC网络地址;

18:PC节点地址;

00:PC单元地址;

FF:SID;

0102:写指令;

B1:写地址区(D位:02,D字:82,W位:31,C位:30,W字:B1,C字:B0);

000A00:起始地址;【2的24次方-1】,十进制范围【0~16777215】

0002:写个数;写入的字【WORD】个数,也就是【WORD*2】个字节

AABBCCDD:写入数据。?

3.2. 反馈

46494E53 00000016 00000002 00000000 C0 00 02 001800 001700 FF 0102 0000

46494E53:ASCII编码:FINS;

00000016:指后面跟的字节长度;

00000002:固定命令;

00000000:错误代码;

C0:ICF;

00:RSV;

02:GCT;

00:PC网络地址;

18:PC节点地址;

00:PC单元地址;

00:PLC网络地址;

17:PLC节点地址;

00:PLC单元地址;

FF:SID;

0102:写指令;

0000:写入成功标识。

下面C#封装程序【类FinsTcpUtil】,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace OmronFinsDemo
{
    /// <summary>
    /// FINS(factory interface network service)通信协议是欧姆龙公司开发的用于工业自动化控制网络的指令-响应系统。
    /// 我们只使用欧姆龙PLC的FINS-TCP协议,FINS协议可以读写位(Bit)、字(WORD)操作
    /// 斯内科
    /// </summary>
    public class FinsTcpUtil
    {
        /// <summary>
        /// 是否已连接
        /// </summary>
        private bool connected;
        /// <summary>
        /// 连接PLC的客户端对象
        /// </summary>
        TcpClient msender;
        /// <summary>
        /// 发送命令 和 接收反馈的套接字对象
        /// </summary>
        Socket msock;
        /// <summary>
        /// 工控机【上位机PC】的IP地址的尾节点
        /// </summary>
        private byte clientIpTail;
        /// <summary>
        /// 服务端【欧姆龙PLC】的IP地址的尾节点
        /// </summary>
        private byte serverIpTail;

        /// <summary>
        /// 记录FINS的发送和接收数据包事件
        /// 第一个参数是发送的数据包,第二个参数是响应的数据包,第三个参数的获取到响应数据包所花费的时间(ms)
        /// </summary>
        public event Action<byte[], byte[], double> RecordDataEvent;
        /// <summary>
        /// 是否已连接上欧姆龙PLC【握手成功后才连接成功】
        /// </summary>
        public bool IsConnected
        {
            get
            {
                return connected;
            }
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        public void Disconnect()
        {
            if (connected)
            {
                msender.Close();
                connected = false;
            }
        }

        /// <summary>
        /// 初始化TCP,并发送握手协议命令,尝试连接欧姆龙PLC
        /// </summary>
        /// <param name="ip">PLC的IP地址</param>
        /// <param name="port">端口号,默认为9600</param>
        /// <param name="frame"></param>
        /// <returns></returns>
        public bool ConnectPlc(string ip, int port = 9600, int frame = 0)
        {
            if (!connected)
            {
                msender = new TcpClient(ip, port);
                msender.ReceiveTimeout = 3000;
                msock = msender.Client;
                //握手协议 共20个字节【标识头4个字节,长度4个字节,命令码4个字节,错误代码4个字节,客户端节点地址4个字节】
                byte[] handshakeProtocol = new byte[20];
                //标识头命令:固定FINS
                handshakeProtocol[0] = 0x46;//F
                handshakeProtocol[1] = 0x49;//I
                handshakeProtocol[2] = 0x4E;//N
                handshakeProtocol[3] = 0x53;//S
                //数据长度:4个字节
                handshakeProtocol[4] = 0;
                handshakeProtocol[5] = 0;
                handshakeProtocol[6] = 0;
                handshakeProtocol[7] = 0x0C;//Length长度:后面跟的字节长度:12个字节
                //00000000:固定命令;【索引 8~11】
                //00000000:错误代码;【索引 12~15】
                handshakeProtocol[16] = 0;
                handshakeProtocol[17] = 0;
                handshakeProtocol[18] = 0;
                handshakeProtocol[19] = (byte)frame;//FINS Frame (工控机IP节点的最后一个字节,如 192.168.1.139 就填入139),frame为0时服务端为客户端自动分配IP尾号

                msock.Send(handshakeProtocol);
                //【握手的】反馈结果 共24个字节【标识头4个字节,长度4个字节,命令码4个字节,错误代码4个字节,客户端节点地址4个字节,服务端节点地址4个字节】
                /*
                 * 46494E53:ASCII编码:FINS;
                 * 00000010:指后面跟的字节长度;16个字节
                 * 00000001:固定命令;
                 * 00000000:错误代码;
                 * 00000018:本机电脑节点IP;
                 * 00000017:PLC节点IP。
                */
                byte[] feedbackBuffer = new byte[24];//反馈结果
                msock.Receive(feedbackBuffer, SocketFlags.None);
                if (handshakeProtocol[0] == feedbackBuffer[0] && handshakeProtocol[1] == feedbackBuffer[1] && handshakeProtocol[2] == feedbackBuffer[2] && handshakeProtocol[3] == feedbackBuffer[3]
                    && feedbackBuffer[7] == 0x10 && feedbackBuffer[11] == 0x01 && feedbackBuffer[15] == 0x00 && (handshakeProtocol[19] == 0 || feedbackBuffer[19] == handshakeProtocol[19]))
                {
                    //反馈结果 需满足 按照FINS开头,字节长度一定是16,错误代码为0
                    //客户端IP尾号frame为0时服务端将为客户端自动分配IP尾号
                    clientIpTail = feedbackBuffer[19];
                    serverIpTail = feedbackBuffer[23];
                    connected = true;
                }
            }
            return connected;
        }

        /// <summary>
        /// 获取欧姆龙地址类型对应的 FINS通信标识
        /// </summary>
        /// <param name="omronAddressType">欧姆龙地址类型枚举</param>
        /// <param name="isBitProcess">是否位处理。true:位处理,false:字处理</param>
        /// <returns></returns>
        private byte GetAreaTypeFlag(OmronAddressType omronAddressType, bool isBitProcess)
        {
            if (isBitProcess)
            {
                //位处理
                switch (omronAddressType)
                {
                    case OmronAddressType.CIO:
                        return 0x30;
                    case OmronAddressType.WR:
                        return 0x31;
                    case OmronAddressType.DM:
                        return 0x02;
                    case OmronAddressType.HR:
                        return 0x32;
                    case OmronAddressType.TIM:
                        return 0x09;
                    case OmronAddressType.AR:
                        return 0x33;
                    case OmronAddressType.CNT:
                        return 0x09;
                    default:
                        return 0x00;
                }
            }
            else
            {
                //字处理
                switch (omronAddressType)
                {
                    case OmronAddressType.CIO:
                        return 0xB0;
                    case OmronAddressType.WR:
                        return 0xB1;
                    case OmronAddressType.DM:
                        return 0x82;
                    case OmronAddressType.HR:
                        return 0xB2;
                    case OmronAddressType.TIM:
                        return 0x89;
                    case OmronAddressType.AR:
                        return 0xB3;
                    case OmronAddressType.CNT:
                        return 0x89;
                    default:
                        return 0x00;
                }
            }
        }

        /// <summary>
        /// 用于排他锁,确保在多线程调用该接口时,不会同时调用。确保在处理当前命令时,其他命令请等待
        /// </summary>
        static int lockedValue = 0;

        /// <summary>
        /// 发送命令并解析反馈【关键方法】,需要进行加锁操作,防止同时操作一个地址时出现脏读等异常情况
        /// </summary>
        /// <param name="omronAddressType">欧姆龙PLC存储区域类别枚举</param>
        /// <param name="address">起始地址</param>
        /// <param name="bitIndexOrWordLength">要读写的位索引 或者 字长度。读字时,一次最多读1000个字【也就是2000个字节】</param>
        /// <param name="isBitProcess">是否位处理。true:位处理,false:字【WORD】处理</param>
        /// <param name="isRead">读内存区域还是写内存区域 true:读,false:写</param>
        /// <param name="receiveData">读取时反馈的数据流,写入操作时该参数无意义</param>
        /// <param name="errMsg">处理时的异常错误信息,默认为空</param>
        /// <param name="writeData">需要写入的连续字节流,读取操作时该参数无意义,写入操作【isRead为false】时该参数不能为空</param>
        /// <returns>返回的错误号,0代表操作成功</returns>
        public int SendCommandAndParseFeedback(OmronAddressType omronAddressType, ushort address, ushort bitIndexOrWordLength, bool isBitProcess, bool isRead, ref byte[] receiveData, out string errMsg, byte[] writeData = null)
        {
            errMsg = string.Empty;
            if (!IsConnected)
            {
                errMsg = $"【尚未连接】连接PLC失败或者握手协议失败";
                return 2000;
            }
            if (!isRead && (writeData == null || writeData.Length == 0 || writeData.Length > 2000))
            {
                errMsg = $"【参数非法】写入操作时,需要写入的数据为空 或者 写入数据流的字节长度不在【1~2000】之间";
                return 1000;
            }
            byte serviceId = 0x15;//SID:SID用于标识数据发送的过程。【服务标识】,可以任意指定,返回数据包的SID和发送包的SID一致 
            int commandLength = 34;//发送命令的长度【读取命令 固定34位】
            if (!isRead)
            {
                commandLength = 34 + writeData.Length;
            }
            byte[] sendBytes = new byte[commandLength];
            //标识头命令:固定FINS
            sendBytes[0] = 0x46;//F
            sendBytes[1] = 0x49;//I
            sendBytes[2] = 0x4E;//N
            sendBytes[3] = 0x53;//S
                                //数据长度:4个字节
            sendBytes[4] = 0;
            sendBytes[5] = 0;
            sendBytes[6] = 0;
            sendBytes[7] = 0x1A;//Length长度:后面跟的字节长度:26个字节
            if (!isRead)
            {
                sendBytes[7] = (byte)(26 + writeData.Length);
            }
            //命令码 固定 00 00 00 02
            sendBytes[8] = 0;
            sendBytes[9] = 0;
            sendBytes[10] = 0;
            sendBytes[11] = 0x02;//frame command 
            //【索引12~15】错误码 00 00 00 00
            sendBytes[16] = 0x80;//ICF
            sendBytes[17] = 0x00;//RSV
            sendBytes[18] = 0x02;//GCT, less than 8 network layers
            sendBytes[19] = 0x00;//DNA, local network
            sendBytes[20] = serverIpTail;//DA1 PLC的IP节点尾号
            sendBytes[21] = 0x00;//DA2, CPU unit
            sendBytes[22] = 0x00;//SNA, local network
            sendBytes[23] = clientIpTail;//SA1 工控机IP节点尾号
            sendBytes[24] = 0x00;//SA2, CPU unit
            sendBytes[25] = serviceId;//SID:SID用于标识数据发送的过程。 【服务标识】
            //SID能够设置为00到FF十六进制的任何数字。SID用于检测响应请求是否正确,当发送节点与响应节点的SID值相同,表明响应的数据是请求的数据,不相同,表明响应的数据非请求数据。

            if (isRead)
            {
                //读命令 01 01
                sendBytes[26] = 0x01;
                sendBytes[27] = 0x01;
            }
            else
            {
                //写命令 01 02
                sendBytes[26] = 0x01;
                sendBytes[27] = 0x02;
            }
            //地址区域标识
            sendBytes[28] = GetAreaTypeFlag(omronAddressType, isBitProcess);
            byte[] addressParts = BitConverter.GetBytes(address);
            //起始地址【索引 29~30】
            sendBytes[29] = addressParts[1];
            sendBytes[30] = addressParts[0];

            //读取的字【Word】的长度
            byte[] lengthParts = BitConverter.GetBytes(bitIndexOrWordLength);
            if (isBitProcess)
            {
                //位处理时,表示读取的位的索引
                sendBytes[31] = lengthParts[0];
                sendBytes[32] = 0x00;
                sendBytes[33] = 0x01;//每次只读取一位
            }
            else
            {
                //字处理时,按零处理
                sendBytes[31] = 0x00;//字处理时,备用地址,暂不使用
                sendBytes[32] = lengthParts[1];
                sendBytes[33] = lengthParts[0];
            }
            //要写入的字节流数据
            if (!isRead)
            {
                Array.Copy(writeData, 0, sendBytes, 34, writeData.Length);
            }

            //添加锁
            while (Interlocked.Exchange(ref lockedValue, 1) != 0) { }
            System.Diagnostics.Stopwatch stopwatch = System.Diagnostics.Stopwatch.StartNew();
            try
            {
                msock.Send(sendBytes, SocketFlags.None);
            }
            catch (SocketException ex)
            {
                connected = false;
                errMsg = $"发送数据时出现套接字异常,【{omronAddressType}.{address}.{bitIndexOrWordLength}】【{ex.SocketErrorCode}】,{ex.Message}";
                Interlocked.Exchange(ref lockedValue, 0);//将current重置为0
                return 1001;
            }
            catch (Exception ex)
            {
                connected = false;
                errMsg = $"发送数据时出现异常,【{omronAddressType}.{address}.{bitIndexOrWordLength}】【{ex.Message}】";
                Interlocked.Exchange(ref lockedValue, 0);//将current重置为0
                return 1002;
            }

            byte[] buffer = new byte[2048];
            byte[] receiveByts = null;//接收的有效字节流
            int rcvCount = 0;//收到的字节数
            try
            {
                rcvCount = msock.Receive(buffer);
                receiveByts = new ArraySegment<byte>(buffer, 0, rcvCount).ToArray();
                stopwatch.Stop();
                RecordDataEvent?.Invoke(sendBytes, receiveByts, stopwatch.Elapsed.TotalMilliseconds);
                /*
                 * 反馈数据流
                 * 46494E53?0000001A       00000002 00000000 C0   00   02   001800   001700   FF   0101    0000       AABB CCDD XXXX XXXX 
                 * 标识头 后面跟的字节长度  固定    错误代码 ICF  RSV  GCT  工控机IP PLC的IP  SID  读命令  成功标识   实际读取到的数据,索引30开始
                */
            }
            catch (SocketException ex)
            {
                connected = false;
                errMsg = $"【网络异常】接收数据失败,【{omronAddressType}.{address}.{bitIndexOrWordLength}】,套接字错误【{ex.SocketErrorCode}】,【{ex.Message}】";
                //释放锁
                Interlocked.Exchange(ref lockedValue, 0);//将current重置为0
                return 1003;
            }
            catch (Exception ex)
            {
                connected = false;
                errMsg = $"【处理异常】接收数据失败,【{omronAddressType}.{address}.{bitIndexOrWordLength}】【{ex.Message}】";
                //释放锁
                Interlocked.Exchange(ref lockedValue, 0);//将current重置为0
                return 1004;
            }
            if (receiveByts == null || receiveByts.Length < 30)
            {
                errMsg = $"接收数据为空,或者低于30个字节,接收数据为【{(receiveByts == null ? "" : string.Join(",", receiveByts))}】";
                Interlocked.Exchange(ref lockedValue, 0);//将current重置为0
                return 1005;
            }
            if (receiveByts[0] != sendBytes[0] || receiveByts[1] != sendBytes[1] || receiveByts[2] != sendBytes[2] || receiveByts[3] != sendBytes[3])
            {
                errMsg = $"接收数据头非法,不是从【FINS】开始,接收数据为【{string.Join(",", receiveByts)}】";
                Interlocked.Exchange(ref lockedValue, 0);//将current重置为0
                return 1006;
            }
            if (receiveByts[11] != 2 || receiveByts[15] != 0)
            {
                errMsg = $"数据非法,解析时出现错误,错误号【{receiveByts[15]}】,接收数据为【{string.Join(",", receiveByts)}】";
                Interlocked.Exchange(ref lockedValue, 0);//将current重置为0
                return 1007;
            }
            if (receiveByts[25] != serviceId)
            {
                errMsg = $"服务标识非法,发送的SID【{serviceId}】与接收的SID【{receiveByts[25]}】不一致,接收数据为【{string.Join(",", receiveByts)}】";
                Interlocked.Exchange(ref lockedValue, 0);//将current重置为0
                return 1008;
            }
            if (receiveByts[26] != sendBytes[26] || receiveByts[27] != sendBytes[27])
            {
                errMsg = $"读写命令不匹配,发送命令【{sendBytes[26].ToString("X2")}{sendBytes[27].ToString("X2")}】,反馈命令【{receiveByts[26].ToString("X2")}{receiveByts[27].ToString("X2")}】";
                Interlocked.Exchange(ref lockedValue, 0);//将current重置为0
                return 1009;
            }
            if (receiveByts[28] != 0 || receiveByts[29] != 0)
            {
                errMsg = GetErrorMessage(receiveByts[28], receiveByts[29]);
                Interlocked.Exchange(ref lockedValue, 0);//将current重置为0
                return 1010;
            }

            //抓取读取到的实际字节流
            if (isRead)
            {
                if (receiveData == null)
                {
                    receiveData = new byte[0];
                }
                Array.Copy(receiveByts, 30, receiveData, 0, receiveData.Length);
            }

            //释放锁
            Interlocked.Exchange(ref lockedValue, 0);//将current重置为0
            return 0;
        }

        /// <summary>
        /// 获得反馈指定错误消息描述
        /// </summary>
        /// <param name="errCode1"></param>
        /// <param name="errCode2"></param>
        /// <returns></returns>
        private string GetErrorMessage(byte errCode1, byte errCode2)
        {
            string msg = $"错误代码【{errCode1.ToString("X2")} {errCode2.ToString("X2")}】";
            switch (errCode1)
            {
                case 0x00:
                    if (errCode2 == 0x01)
                        msg += "service canceled";
                    break;
                case 0x01:
                    switch (errCode2)
                    {
                        case 0x01: msg += "Ip配置错误:local node not in network"; break; 
                        case 0x02: msg += "权限出错:token timeout"; break;
                        case 0x03: msg += "retries failed"; break;
                        case 0x04: msg += "too many send frames"; break; 
                        case 0x05: msg += "node address range error"; break;
                        case 0x06: msg += "node address duplication"; break; 
                    }
                    break;
                case 0x02:
                    switch (errCode2)
                    {
                        case 0x01: msg += "destination node not in network"; break; 
                        case 0x02: msg += "unit missing"; break; 
                        case 0x03: msg += "third node missing"; break;
                        case 0x04: msg += "destination node busy"; break; 
                        case 0x05: msg += "response timeout"; break; 
                    }
                    break;
                case 0x03:
                    switch (errCode2)
                    {
                        case 0x01: msg += "communications controller error"; break; 
                        case 0x02: msg += "CPU unit error"; break; 
                        case 0x03: msg += "控制器错误:controller error"; break; 
                        case 0x04: msg += "unit number error"; break; 
                    }
                    break;
                case 0x04:
                    switch (errCode2)
                    {
                        case 0x01: msg += "未定义的指令:undefined command"; break;
                        case 0x02: msg += "不支持的模式:not supported by model/version"; break; 
                    }
                    break;
                case 0x05:
                    switch (errCode2)
                    {
                        case 0x01: msg += "destination address setting error"; break; 
                        case 0x02: msg += "no routing tables"; break; 
                        case 0x03: msg += "routing table error"; break; 
                        case 0x04: msg += "too many relays"; break; 
                    }
                    break;
                case 0x10:
                    switch (errCode2)
                    {
                        case 0x01: msg += "指令太长:command too long"; break;
                        case 0x02: msg += "command too short"; break; 
                        case 0x03: msg += "数据与长度不匹配:elements/data don't match"; break; 
                        case 0x04: msg += "command format error"; break; 
                        case 0x05: msg += "header error"; break; 
                    }
                    break;
                case 0x11:
                    switch (errCode2)
                    {
                        case 0x01: msg += "area classification missing"; break; 
                        case 0x02: msg += "access size error"; break; 
                        case 0x03: msg += "address range error"; break; 
                        case 0x04: msg += "address range exceeded"; break; 
                        case 0x06: msg += "program missing"; break; 
                        case 0x09: msg += "relational error"; break; 
                        case 0x0a: msg += "duplicate data access"; break; 
                        case 0x0b: msg += "response too long"; break; 
                        case 0x0c: msg += "parameter error"; break; 
                    }
                    break;
                case 0x20:
                    switch (errCode2)
                    {
                        case 0x02: msg += "protected"; break; 
                        case 0x03: msg += "table missing"; break; 
                        case 0x04: msg += "data missing"; break; 
                        case 0x05: msg += "program missing"; break; 
                        case 0x06: msg += "file missing"; break; 
                        case 0x07: msg += "data mismatch"; break; 
                    }
                    break;
                case 0x21:
                    switch (errCode2)
                    {
                        case 0x01: msg += "read-only"; break; 
                        case 0x02: msg += "protected,cannot write data link table"; break; 
                        case 0x03: msg += "cannot register"; break; 
                        case 0x05: msg += "program missing"; break; 
                        case 0x06: msg += "file missing"; break; 
                        case 0x07: msg += "file name already exists"; break; 
                        case 0x08: msg += "cannot change"; break; 
                    }
                    break;
                case 0x22:
                    switch (errCode2)
                    {
                        case 0x01: msg += "not possible during execution"; break; 
                        case 0x02: msg += "not possible while running"; break; 
                        case 0x03: msg += "wrong PLC mode"; break; 
                        case 0x04: msg += "wrong PLC mode"; break; 
                        case 0x05: msg += "wrong PLC mode"; break; 
                        case 0x06: msg += "wrong PLC mode"; break; 
                        case 0x07: msg += "specified node not polling node"; break; 
                        case 0x08: msg += "step cannot be executed"; break; 
                    }
                    break;
                case 0x23:
                    switch (errCode2)
                    {
                        case 0x01: msg += "file device missing"; break; 
                        case 0x02: msg += "memory missing"; break; 
                        case 0x03: msg += "clock missing"; break; 
                    }
                    break;
                case 0x24:
                    if (errCode2 == 0x01) msg += "table missing"; 
                    break;
                case 0x25:
                    switch (errCode2)
                    {
                        case 0x02: msg += "memory error"; break; 
                        case 0x03: msg += "I/O setting error"; break; 
                        case 0x04: msg += "too many I/O points"; break; 
                        case 0x05: msg += "CPU bus error"; break; 
                        case 0x06: msg += "I/O duplication"; break; 
                        case 0x07: msg += "CPU bus error"; break; 
                        case 0x09: msg += "SYSMAC BUS/2 error"; break; 
                        case 0x0a: msg += "CPU bus unit error"; break; 
                        case 0x0d: msg += "SYSMAC BUS No. duplication"; break; 
                        case 0x0f: msg += "memory error"; break; 
                        case 0x10: msg += "SYSMAC BUS terminator missing"; break; 
                    }
                    break;
                case 0x26:
                    switch (errCode2)
                    {
                        case 0x01: msg += "no protection"; break; 
                        case 0x02: msg += "incorrect password"; break; 
                        case 0x04: msg += "protected"; break; 
                        case 0x05: msg += "service already executing"; break; 
                        case 0x06: msg += "service stopped"; break; 
                        case 0x07: msg += "no execution right"; break; 
                        case 0x08: msg += "settings required before execution"; break; 
                        case 0x09: msg += "necessary items not set"; break; 
                        case 0x0a: msg += "number already defined"; break; 
                        case 0x0b: msg += "error will not clear"; break; 
                    }
                    break;
                case 0x30:
                    if (errCode2 == 0x01)  
                        msg += "无访问权限:no access right";
                    break;
                case 0x40:
                    if (errCode2 == 0x01) 
                        msg += "服务未开启:service aborted";
                    break;
            }
            return msg;
        }
    }
}

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-11-15 16:11:28  更:2021-11-15 16:12:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年7日历 -2024/7/3 21:00:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码