Beispiel #1
0
        /// <summary>
        /// 从三菱PLC中批量读取位软元件,返回读取结果
        /// </summary>
        /// <param name="address">起始地址</param>
        /// <param name="length">读取的长度</param>
        /// <returns>带成功标志的结果数据对象</returns>
        public OperateResult <bool[]> ReadBool(string address, ushort length)
        {
            var result   = new OperateResult <bool[]>( );
            var analysis = AnalysisAddress(address);

            if (!analysis.IsSuccess)
            {
                result.CopyErrorFromOther(analysis);
                return(result);
            }
            else
            {
                if (analysis.Content1.DataType == 0x00)
                {
                    result.Message = "读取位变量数组只能针对位软元件,如果读取字软元件,请自行转化";
                    return(result);
                }
            }
            var read = Read(address, length);

            if (!read.IsSuccess)
            {
                result.CopyErrorFromOther(read);
                return(result);
            }

            result.Content = new bool[read.Content.Length];
            for (int i = 0; i < read.Content.Length; i++)
            {
                result.Content[i] = read.Content[i] == 0x01;
            }
            result.IsSuccess = true;
            return(result);
        }
        /// <summary>
        /// 向PLC中位软元件写入bool数组,返回值说明,比如你写入M100,values[0]对应M100
        /// </summary>
        /// <param name="address">要写入的数据地址</param>
        /// <param name="values">要写入的实际数据,可以指定任意的长度</param>
        /// <returns>返回写入结果</returns>
        public OperateResult Write(string address, bool[] values)
        {
            OperateResult result = new OperateResult( );

            //获取指令
            var command = BuildWriteCommand(address, values.Select(m => m ? (byte)0x01 : (byte)0x00).ToArray( ), true);

            if (!command.IsSuccess)
            {
                result.CopyErrorFromOther(command);
                return(result);
            }

            // 核心数据交互
            OperateResult <byte[]> read = ReadFromCoreServer(command.Content);

            if (!read.IsSuccess)
            {
                result.CopyErrorFromOther(command);
                return(result);
            }

            // 数据有效性分析
            OperateResult <byte[]> valid = ResponseValidAnalysis(read.Content, false);

            if (!valid.IsSuccess)
            {
                result.CopyErrorFromOther(command);
                return(result);
            }

            return(OperateResult.CreateSuccessResult( ));
        }
        /// <summary>
        /// 从欧姆龙PLC中批量读取位软元件,返回读取结果
        /// </summary>
        /// <param name="address">起始地址</param>
        /// <param name="length">读取的长度</param>
        /// <returns>带成功标志的结果数据对象</returns>
        public OperateResult <bool[]> ReadBool(string address, ushort length)
        {
            var result = new OperateResult <bool[]>( );

            //获取指令
            var command = BuildReadCommand(address, length, true);

            if (!command.IsSuccess)
            {
                result.CopyErrorFromOther(command);
                return(result);
            }

            // 核心数据交互
            OperateResult <byte[]> read = ReadFromCoreServer(command.Content);

            if (!read.IsSuccess)
            {
                result.CopyErrorFromOther(command);
                return(result);
            }

            // 数据有效性分析
            OperateResult <byte[]> valid = ResponseValidAnalysis(read.Content, true);

            if (!valid.IsSuccess)
            {
                result.CopyErrorFromOther(command);
                return(result);
            }

            return(OperateResult.CreateSuccessResult(valid.Content.Select(m => m != 0x00 ? true : false).ToArray( )));
        }
        /// <summary>
        /// 使用底层的数据报文来通讯,传入需要发送的消息,返回最终的数据结果
        /// </summary>
        /// <param name="send">发送的数据</param>
        /// <returns>结果对象</returns>
        public OperateResult <byte[], byte[]> ReadFromCoreServer(byte[] send)
        {
            var result = new OperateResult <byte[], byte[]>();

            // LogNet?.WriteDebug( ToString( ), "Command: " + BasicFramework.SoftBasic.ByteToHexString( send ) );
            InteractiveLock.Enter( );

            // 获取有用的网络通道,如果没有,就建立新的连接
            OperateResult <Socket> resultSocket = GetAvailableSocket( );

            if (!resultSocket.IsSuccess)
            {
                IsSocketErrorState = false;
                InteractiveLock.Leave( );
                result.CopyErrorFromOther(resultSocket);
                return(result);
            }

            // 发送数据信息
            OperateResult resultSend = Send(resultSocket.Content, send);

            if (!resultSend.IsSuccess)
            {
                IsSocketErrorState = false;
                InteractiveLock.Leave( );
                resultSocket.Content?.Close( );
                result.CopyErrorFromOther(resultSend);
                return(result);
            }

            // 接收超时时间大于0时才允许接收远程的数据
            if (receiveTimeOut >= 0)
            {
                // 接收数据信息
                OperateResult <TNetMessage> resultReceive = ReceiveMessage(resultSocket.Content);
                if (!resultReceive.IsSuccess)
                {
                    IsSocketErrorState = false;
                    InteractiveLock.Leave();
                    resultSocket.Content?.Close();
                    result.CopyErrorFromOther(resultReceive);
                    return(result);
                }

                // 复制结果
                result.Content1 = resultReceive.Content.HeadBytes;
                result.Content2 = resultReceive.Content.ContentBytes;
            }

            if (!IsPersistentConn)
            {
                resultSocket.Content?.Close( );
            }
            InteractiveLock.Leave( );

            IsSocketErrorState = true;
            result.IsSuccess   = true;
            return(result);
        }
        /// <summary>
        /// 使用底层的数据报文来通讯,传入需要发送的消息,返回一条完整的数据指令
        /// </summary>
        /// <param name="send">发送的完整的报文信息</param>
        /// <returns>接收的完整的报文信息</returns>
        public OperateResult <byte[]> ReadFromCoreServer(byte[] send)
        {
            var result = new OperateResult <byte[]>( );

            // string tmp1 = BasicFramework.SoftBasic.ByteToHexString( send, '-' );

            InteractiveLock.Enter( );

            // 获取有用的网络通道,如果没有,就建立新的连接
            OperateResult <Socket> resultSocket = GetAvailableSocket( );

            if (!resultSocket.IsSuccess)
            {
                IsSocketError = true;
                InteractiveLock.Leave( );
                result.CopyErrorFromOther(resultSocket);
                return(result);
            }

            var read = ReadFromCoreServerBase(resultSocket.Content, send);

            if (read.IsSuccess)
            {
                IsSocketError    = false;
                result.IsSuccess = read.IsSuccess;
                result.Content   = new byte[read.Content1.Length + read.Content2.Length];
                if (read.Content1.Length > 0)
                {
                    read.Content1.CopyTo(result.Content, 0);
                }
                if (read.Content2.Length > 0)
                {
                    read.Content2.CopyTo(result.Content, read.Content1.Length);
                }

                // string tmp2 = BasicFramework.SoftBasic.ByteToHexString( result.Content ) ;
            }
            else
            {
                IsSocketError = true;
                result.CopyErrorFromOther(read);
            }


            InteractiveLock.Leave( );
            if (!IsPersistentConn)
            {
                resultSocket.Content?.Close( );
            }
            return(result);
        }
        /// <summary>
        /// 向PLC写入数据,数据格式为原始的字节类型
        /// </summary>
        /// <param name="address">初始地址</param>
        /// <param name="value">原始的字节数据</param>
        /// <example>
        /// 假设起始地址为D100,D100存储了温度,100.6℃值为1006,D101存储了压力,1.23Mpa值为123,D102,D103存储了产量计数,写入如下:
        /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\MelsecAscii.cs" region="WriteExample2" title="Write示例" />
        /// 以下是读取不同类型数据的示例
        /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\MelsecAscii.cs" region="WriteExample1" title="Write示例" />
        /// </example>
        /// <returns>结果</returns>
        public override OperateResult Write(string address, byte[] value)
        {
            // Console.WriteLine( BasicFramework.SoftBasic.ByteToHexString( value ) );

            OperateResult <byte[]> result = new OperateResult <byte[]>( );

            //获取指令
            var analysis = AnalysisAddress(address);

            if (!analysis.IsSuccess)
            {
                result.CopyErrorFromOther(analysis);
                return(result);
            }

            // 字写入
            byte[] buffer = new byte[value.Length * 2];
            for (int i = 0; i < value.Length; i++)
            {
                BuildBytesFromData(value[i]).CopyTo(buffer, 2 * i);
            }

            OperateResult <byte[]> command = BuildWriteWordCommand(address, buffer);

            if (!command.IsSuccess)
            {
                result.CopyErrorFromOther(command);
                return(result);
            }

            OperateResult <byte[]> read = ReadBase(command.Content);

            if (read.IsSuccess)
            {
                OperateResult checkResult = CheckPlcWriteResponse(read.Content);
                if (!checkResult.IsSuccess)
                {
                    return(checkResult);
                }

                result.IsSuccess = true;
            }
            else
            {
                result.ErrorCode = read.ErrorCode;
                result.Message   = read.Message;
            }

            return(result);
        }
Beispiel #7
0
        /// <summary>
        /// 使用底层的数据报文来通讯,传入需要发送的消息,返回一条完整的数据指令
        /// </summary>
        /// <param name="send">发送的完整的报文信息</param>
        /// <returns>接收的完整的报文信息</returns>
        /// <remarks>
        /// 本方法用于实现本组件还未实现的一些报文功能,例如有些modbus服务器会有一些特殊的功能码支持,需要收发特殊的报文,详细请看示例
        /// </remarks>
        /// <example>
        /// 此处举例有个modbus服务器,有个特殊的功能码0x09,后面携带子数据0x01即可,发送字节为 0x00 0x00 0x00 0x00 0x00 0x03 0x01 0x09 0x01
        /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Core\NetworkDoubleBase.cs" region="ReadFromCoreServerExample2" title="ReadFromCoreServer示例" />
        /// </example>
        public OperateResult <byte[]> ReadFromCoreServer(byte[] send)
        {
            var result = new OperateResult <byte[]>( );

            // string tmp1 = BasicFramework.SoftBasic.ByteToHexString( send, '-' );

            InteractiveLock.Enter( );

            // 获取有用的网络通道,如果没有,就建立新的连接
            OperateResult <Socket> resultSocket = GetAvailableSocket( );

            if (!resultSocket.IsSuccess)
            {
                IsSocketError = true;
                if (AlienSession != null)
                {
                    AlienSession.IsStatusOk = false;
                }
                InteractiveLock.Leave( );
                result.CopyErrorFromOther(resultSocket);
                return(result);
            }

            OperateResult <byte[]> read = ReadFromCoreServer(resultSocket.Content, send);

            if (read.IsSuccess)
            {
                IsSocketError    = false;
                result.IsSuccess = read.IsSuccess;
                result.Content   = read.Content;
                result.Message   = StringResources.SuccessText;
                //string tmp2 = BasicFramework.SoftBasic.ByteToHexString( result.Content, '-' );
            }
            else
            {
                IsSocketError = true;
                if (AlienSession != null)
                {
                    AlienSession.IsStatusOk = false;
                }
                result.CopyErrorFromOther(read);
            }

            InteractiveLock.Leave( );
            if (!isPersistentConn)
            {
                resultSocket.Content?.Close( );
            }
            return(result);
        }
Beispiel #8
0
        /// <summary>
        /// 读取数据的基础指令,需要指定指令码,地址,长度
        /// </summary>
        /// <param name="code"></param>
        /// <param name="address"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        private OperateResult <byte[]> BuildReadCommandBase(byte code, string address, ushort count)
        {
            var result = new OperateResult <byte[]>( );

            OperateResult <int> analysis = AnalysisAddress(address);

            if (!analysis.IsSuccess)
            {
                result.CopyErrorFromOther(analysis);
                return(result);
            }

            ushort messageId = (ushort)softIncrementCount.GetCurrentValue( );

            byte[] buffer = new byte[12];
            buffer[0]  = (byte)(messageId / 256);
            buffer[1]  = (byte)(messageId % 256);
            buffer[2]  = 0x00;
            buffer[3]  = 0x00;
            buffer[4]  = 0x00;
            buffer[5]  = 0x06;
            buffer[6]  = station;
            buffer[7]  = code;
            buffer[8]  = (byte)(analysis.Content / 256);
            buffer[9]  = (byte)(analysis.Content % 256);
            buffer[10] = (byte)(count / 256);
            buffer[11] = (byte)(count % 256);

            result.Content   = buffer;
            result.IsSuccess = true;
            return(result);
        }
Beispiel #9
0
        /// <summary>
        /// 生成一个读取字数据指令头的通用方法 -> A general method for generating a command header to read a Word data
        /// </summary>
        /// <param name="address">起始地址,格式为M100,I100,Q100,DB1.100 -> Starting address, formatted as M100,I100,Q100,DB1.100</param>
        /// <param name="count">读取数据个数 -> Number of Read data</param>
        /// <returns>带结果对象的报文数据 -> Message data with a result object</returns>
        public static OperateResult <byte[]> BuildReadCommand(string address, ushort count)
        {
            var result = new OperateResult <byte[]>( );

            OperateResult <byte, int, ushort> analysis = AnalysisAddress(address);

            if (!analysis.IsSuccess)
            {
                result.CopyErrorFromOther(analysis);
                return(result);
            }

            byte[] _PLCCommand = new byte[16];
            _PLCCommand[0] = 0x53;
            _PLCCommand[1] = 0x35;
            _PLCCommand[2] = 0x10;
            _PLCCommand[3] = 0x01;
            _PLCCommand[4] = 0x03;
            _PLCCommand[5] = 0x05;
            _PLCCommand[6] = 0x03;
            _PLCCommand[7] = 0x08;

            // 指定数据区 -> Specify Data area
            _PLCCommand[8] = analysis.Content1;
            _PLCCommand[9] = (byte)analysis.Content3;

            // 指定数据地址 -> Specify Data address
            _PLCCommand[10] = (byte)(analysis.Content2 / 256);
            _PLCCommand[11] = (byte)(analysis.Content2 % 256);

            // DB块,定时器,计数器读取长度按照字为单位,1代表2个字节,I,Q,M的1代表1个字节 ->
            // DB block, timer, counter read length per word, 1 for 2 bytes, i,q,m 1 for 1 bytes
            if (analysis.Content1 == 0x01 || analysis.Content1 == 0x06 || analysis.Content1 == 0x07)
            {
                if (count % 2 != 0)
                {
                    result.Message = StringResources.SiemensReadLengthMustBeEvenNumber;
                    return(result);
                }
                else
                {
                    // 指定数据长度 -> Specify data length
                    _PLCCommand[12] = (byte)(count / 2 / 256);
                    _PLCCommand[13] = (byte)(count / 2 % 256);
                }
            }
            else
            {
                // 指定数据长度 -> Specify data length
                _PLCCommand[12] = (byte)(count / 256);
                _PLCCommand[13] = (byte)(count % 256);
            }

            _PLCCommand[14] = 0xff;
            _PLCCommand[15] = 0x02;

            result.Content   = _PLCCommand;
            result.IsSuccess = true;
            return(result);
        }
Beispiel #10
0
        /// <summary>
        /// 将数据写入到PLC数据,地址格式为I100,Q100,DB20.100,M100,以字节为单位
        /// </summary>
        /// <param name="address">起始地址,格式为I100,M100,Q100,DB20.100</param>
        /// <param name="value">写入的数据,长度根据data的长度来指示</param>
        /// <returns></returns>
        public OperateResult Write(string address, byte[] value)
        {
            OperateResult result = new OperateResult();

            OperateResult <byte[]> command = BuildWriteByteCommand(address, value);

            if (!command.IsSuccess)
            {
                result.CopyErrorFromOther(command);
                return(result);
            }


            OperateResult <byte[]> write = ReadFromCoreServer(command.Content);

            if (write.IsSuccess)
            {
                if (write.Content[8] != 0x00)
                {
                    // 写入异常
                    result.Message = "写入数据异常,代号为:" + write.Content[8].ToString();
                }
                else
                {
                    result.IsSuccess = true;  // 写入成功
                }
            }
            else
            {
                result.ErrorCode = write.ErrorCode;
                result.Message   = write.Message;
            }
            return(result);
        }
Beispiel #11
0
        private OperateResult <byte[]> BuildWriteRegisterCommand(string address, byte[] data)
        {
            var result = new OperateResult <byte[]>( );

            OperateResult <int> analysis = AnalysisAddress(address);

            if (!analysis.IsSuccess)
            {
                result.CopyErrorFromOther(analysis);
                return(result);
            }

            ushort messageId = (ushort)softIncrementCount.GetCurrentValue( );

            byte[] buffer = new byte[13 + data.Length];
            buffer[0]  = (byte)(messageId / 256);
            buffer[1]  = (byte)(messageId % 256);
            buffer[2]  = 0x00;
            buffer[3]  = 0x00;
            buffer[4]  = (byte)((buffer.Length - 6) / 256);
            buffer[5]  = (byte)((buffer.Length - 6) % 256);
            buffer[6]  = station;
            buffer[7]  = ModbusInfo.WriteRegister;
            buffer[8]  = (byte)(analysis.Content / 256);
            buffer[9]  = (byte)(analysis.Content % 256);
            buffer[10] = (byte)(data.Length / 2 / 256);
            buffer[11] = (byte)(data.Length / 2 % 256);

            buffer[12] = (byte)(data.Length);
            data.CopyTo(buffer, 13);

            result.Content   = buffer;
            result.IsSuccess = true;
            return(result);
        }
Beispiel #12
0
        /***************************************************************************************
         *
         *    主要的数据交互分为4步
         *    1. 连接服务器,或是获取到旧的使用的网络信息
         *    2. 发送数据信息
         *    3. 接收反馈的数据信息
         *    4. 关闭网络连接,如果是短连接的话
         *
         **************************************************************************************/

        /// <summary>
        /// 获取本次操作的可用的网络套接字
        /// </summary>
        /// <returns>是否成功,如果成功,使用这个套接字</returns>
        private OperateResult <Socket> GetAvailableSocket( )
        {
            var result = new OperateResult <Socket>( );

            if (IsPersistentConn)
            {
                // 长连接模式
                if (IsSocketError || CoreSocket == null)
                {
                    OperateResult connect = ConnectServer( );
                    if (!connect.IsSuccess)
                    {
                        IsSocketError = true;
                        result.CopyErrorFromOther(connect);
                        return(result);
                    }
                    else
                    {
                        IsSocketError = false;
                        return(OperateResult.CreateSuccessResult(CoreSocket));
                    }
                }
                else
                {
                    return(OperateResult.CreateSuccessResult(CoreSocket));
                }
            }
            else
            {
                // 短连接模式
                return(CreateSocketAndInitialication( ));
            }
        }
        /// <summary>
        /// 在其他指定的套接字上,使用报文来通讯,传入需要发送的消息,返回一条完整的数据指令
        /// </summary>
        /// <param name="socket">指定的套接字</param>
        /// <param name="send">发送的完整的报文信息</param>
        /// <remarks>
        /// 无锁的基于套接字直接进行叠加协议的操作。
        /// </remarks>
        /// <example>
        /// 假设你有一个自己的socket连接了设备,本组件可以直接基于该socket实现modbus读取,三菱读取,西门子读取等等操作,前提是该服务器支持多协议,虽然这个需求听上去比较变态,但本组件支持这样的操作。
        /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Core\NetworkDoubleBase.cs" region="ReadFromCoreServerExample1" title="ReadFromCoreServer示例" />
        /// </example>
        /// <returns>接收的完整的报文信息</returns>
        public OperateResult <byte[]> ReadFromCoreServer(Socket socket, byte[] send)
        {
            var result = new OperateResult <byte[]>( );

            var read = ReadFromCoreServerBase(socket, send);

            if (read.IsSuccess)
            {
                result.IsSuccess = read.IsSuccess;
                result.Content   = new byte[read.Content1.Length + read.Content2.Length];
                if (read.Content1.Length > 0)
                {
                    read.Content1.CopyTo(result.Content, 0);
                }
                if (read.Content2.Length > 0)
                {
                    read.Content2.CopyTo(result.Content, read.Content1.Length);
                }
            }
            else
            {
                result.CopyErrorFromOther(read);
            }
            return(result);
        }
Beispiel #14
0
        private OperateResult <byte[]> BuildWriteOneCoilCommand(string address, bool value)
        {
            var result = new OperateResult <byte[]>( );

            OperateResult <int> analysis = AnalysisAddress(address);

            if (!analysis.IsSuccess)
            {
                result.CopyErrorFromOther(analysis);
                return(result);
            }

            ushort messageId = (ushort)softIncrementCount.GetCurrentValue( );

            byte[] buffer = new byte[12];
            buffer[0]  = (byte)(messageId / 256);
            buffer[1]  = (byte)(messageId % 256);
            buffer[2]  = 0x00;
            buffer[3]  = 0x00;
            buffer[4]  = 0x00;
            buffer[5]  = 0x06;
            buffer[6]  = station;
            buffer[7]  = ModbusInfo.WriteOneCoil;
            buffer[8]  = (byte)(analysis.Content / 256);
            buffer[9]  = (byte)(analysis.Content % 256);
            buffer[10] = (byte)(value ? 0xFF : 0x00);
            buffer[11] = 0x00;

            result.Content   = buffer;
            result.IsSuccess = true;
            return(result);
        }
        /// <summary>
        /// 接收一条完整的数据,使用异步接收完成,包含了指令头信息
        /// </summary>
        /// <param name="socket">已经打开的网络套接字</param>
        /// <returns>数据的接收结果对象</returns>
        protected OperateResult <TNetMessage> ReceiveMessage(Socket socket)
        {
            TNetMessage netMsg = new TNetMessage();
            OperateResult <TNetMessage> result = new OperateResult <TNetMessage>();

            // 接收指令头
            OperateResult <byte[]> headResult = Receive(socket, netMsg.ProtocolHeadBytesLength);

            if (!headResult.IsSuccess)
            {
                result.CopyErrorFromOther(headResult);
                return(result);
            }

            netMsg.HeadBytes = headResult.Content;
            if (!netMsg.CheckHeadBytesLegal(Token.ToByteArray()))
            {
                // 令牌校验失败
                socket?.Close();
                LogNet?.WriteError(ToString(), StringResources.TokenCheckFailed);
                result.Message = StringResources.TokenCheckFailed;
                return(result);
            }


            int contentLength = netMsg.GetContentLengthByHeadBytes();

            if (contentLength == 0)
            {
                netMsg.ContentBytes = new byte[0];
            }
            else
            {
                OperateResult <byte[]> contentResult = Receive(socket, contentLength);
                if (!headResult.IsSuccess)
                {
                    result.CopyErrorFromOther(contentResult);
                    return(result);
                }

                netMsg.ContentBytes = contentResult.Content;
            }

            result.Content   = netMsg;
            result.IsSuccess = true;
            return(result);
        }
Beispiel #16
0
        /// <summary>
        /// 生成一个读取字数据指令头的通用方法
        /// </summary>
        /// <param name="address"></param>
        /// <param name="count"></param>
        /// <returns>携带有命令字节</returns>
        private OperateResult <byte[]> BuildReadCommand(string address, ushort count)
        {
            var result = new OperateResult <byte[]>( );

            OperateResult <byte, int, ushort> analysis = AnalysisAddress(address);

            if (!analysis.IsSuccess)
            {
                result.CopyErrorFromOther(analysis);
                return(result);
            }

            byte[] _PLCCommand = new byte[16];
            _PLCCommand[0] = 0x53;
            _PLCCommand[1] = 0x35;
            _PLCCommand[2] = 0x10;
            _PLCCommand[3] = 0x01;
            _PLCCommand[4] = 0x03;
            _PLCCommand[5] = 0x05;
            _PLCCommand[6] = 0x03;
            _PLCCommand[7] = 0x08;

            //指定数据区
            _PLCCommand[8] = analysis.Content1;
            _PLCCommand[9] = (byte)analysis.Content3;

            //指定数据地址
            _PLCCommand[10] = (byte)(analysis.Content2 / 256);
            _PLCCommand[11] = (byte)(analysis.Content2 % 256);

            if (analysis.Content1 == 0x01 || analysis.Content1 == 0x06 || analysis.Content1 == 0x07)
            {
                if (count % 2 != 0)
                {
                    result.Message = "读取的数据长度必须为偶数";
                    return(result);
                }
                else
                {
                    //指定数据长度
                    _PLCCommand[12] = (byte)(count / 2 / 256);
                    _PLCCommand[13] = (byte)(count / 2 % 256);
                }
            }
            else
            {
                //指定数据长度
                _PLCCommand[12] = (byte)(count / 256);
                _PLCCommand[13] = (byte)(count % 256);
            }

            _PLCCommand[14] = 0xff;
            _PLCCommand[15] = 0x02;

            result.Content   = _PLCCommand;
            result.IsSuccess = true;
            return(result);
        }
        /// <summary>
        /// 从三菱PLC中读取想要的数据,返回读取结果
        /// </summary>
        /// <param name="address">读取地址,格式为"M100","D100","W1A0"</param>
        /// <param name="length">读取的数据长度,字最大值960,位最大值7168</param>
        /// <returns>带成功标志的结果数据对象</returns>
        public OperateResult <byte[]> Read(string address, ushort length)
        {
            var result = new OperateResult <byte[]>();
            //获取指令
            var command = BuildReadCommand(address, length);

            if (!command.IsSuccess)
            {
                result.CopyErrorFromOther(command);
                return(result);
            }

            var read = ReadFromCoreServer(command.Content2);

            if (read.IsSuccess)
            {
                result.ErrorCode = read.Content[1]; //这里的结束代码是一个字节
                if (result.ErrorCode == 0)
                {
                    if (command.Content1.DataType == 0x01)
                    {
                        result.Content = new byte[(read.Content.Length - 2) * 2];
                        for (int i = 2; i < read.Content.Length; i++)
                        {
                            if ((read.Content[i] & 0x10) == 0x10)
                            {
                                result.Content[(i - 2) * 2 + 0] = 0x01;
                            }

                            if ((read.Content[i] & 0x01) == 0x01)
                            {
                                result.Content[(i - 2) * 2 + 1] = 0x01;
                            }
                        }
                    }
                    else
                    {
                        result.Content = new byte[read.Content.Length - 2];
                        Array.Copy(read.Content, 2, result.Content, 0, result.Content.Length);
                    }
                    result.IsSuccess = true;
                }
                else
                {
                    result.Message = "读取过程异常发生, 异常代码为:" + read.Content[1].ToString();
                    //在A兼容1E协议中,结束代码后面紧跟的是异常信息的代码
                }
            }
            else
            {
                result.ErrorCode = read.ErrorCode;
                result.Message   = read.Message;
            }

            return(result);
        }
Beispiel #18
0
        /// <summary>
        /// 从三菱PLC中读取想要的数据,返回读取结果
        /// </summary>
        /// <param name="address">读取地址,格式为"M100","D100","W1A0"</param>
        /// <param name="length">读取的数据长度,字最大值960,位最大值7168</param>
        /// <returns>带成功标志的结果数据对象</returns>
        public OperateResult <byte[]> Read(string address, ushort length)
        {
            var result = new OperateResult <byte[]>( );
            //获取指令
            var command = BuildReadCommand(address, length);

            if (!command.IsSuccess)
            {
                result.CopyErrorFromOther(command);
                return(result);
            }

            var read = ReadFromCoreServer(command.Content2);

            if (read.IsSuccess)
            {
                result.ErrorCode = BitConverter.ToUInt16(read.Content, 9);
                if (result.ErrorCode == 0)
                {
                    if (command.Content1.DataType == 0x01)
                    {
                        result.Content = new byte[(read.Content.Length - 11) * 2];
                        for (int i = 11; i < read.Content.Length; i++)
                        {
                            if ((read.Content[i] & 0x10) == 0x10)
                            {
                                result.Content[(i - 11) * 2 + 0] = 0x01;
                            }

                            if ((read.Content[i] & 0x01) == 0x01)
                            {
                                result.Content[(i - 11) * 2 + 1] = 0x01;
                            }
                        }
                    }
                    else
                    {
                        result.Content = new byte[read.Content.Length - 11];
                        Array.Copy(read.Content, 11, result.Content, 0, result.Content.Length);
                    }
                    result.IsSuccess = true;
                }
                else
                {
                    result.Message = "请翻查三菱通讯手册来查看具体的信息。";
                }
            }
            else
            {
                result.ErrorCode = read.ErrorCode;
                result.Message   = read.Message;
            }

            return(result);
        }
        /// <summary>
        /// 强制写入位数据的通断,支持的类型为X,Y,M,S,C,T
        /// </summary>
        /// <param name="address">地址信息</param>
        /// <param name="value">是否为通</param>
        /// <returns>是否写入成功的结果对象</returns>
        public OperateResult Write(string address, bool value)
        {
            OperateResult <byte[]> result = new OperateResult <byte[]>( );

            // 获取指令
            var analysis = AnalysisAddress(address);

            if (!analysis.IsSuccess)
            {
                result.CopyErrorFromOther(analysis);
                return(result);
            }

            // 单个的位写入操作
            OperateResult <byte[]> command = BuildWriteBoolCommand(address, value);

            if (!command.IsSuccess)
            {
                result.CopyErrorFromOther(command);
                return(result);
            }

            OperateResult <byte[]> read = ReadBase(command.Content);

            if (read.IsSuccess)
            {
                OperateResult checkResult = CheckPlcWriteResponse(read.Content);
                if (!checkResult.IsSuccess)
                {
                    return(checkResult);
                }

                result.IsSuccess = true;
            }
            else
            {
                result.ErrorCode = read.ErrorCode;
                result.Message   = read.Message;
            }

            return(result);
        }
Beispiel #20
0
        /// <summary>
        /// 结果转换操作的基础方法,需要支持类型,及转换的委托
        /// </summary>
        /// <typeparam name="TResult">结果类型</typeparam>
        /// <param name="result"></param>
        /// <param name="translator"></param>
        /// <returns></returns>
        private OperateResult <TResult> GetResultFromBytes <TResult>(OperateResult <byte[]> result, Func <byte[], TResult> translator)
        {
            var tmp = new OperateResult <TResult>( );

            if (result.IsSuccess)
            {
                tmp.Content = translator(result.Content);
            }
            tmp.IsSuccess = result.IsSuccess;
            tmp.CopyErrorFromOther(result);
            return(tmp);
        }
        /// <summary>
        /// 从三菱PLC中批量读取位软元件,返回读取结果
        /// </summary>
        /// <param name="address">起始地址</param>
        /// <param name="length">读取的长度</param>
        /// <returns>带成功标志的结果数据对象</returns>
        /// <remarks>
        /// 地址支持的列表如下:
        /// <list type="table">
        ///   <listheader>
        ///     <term>地址名称</term>
        ///     <term>示例</term>
        ///     <term>地址范围</term>
        ///     <term>地址进制</term>
        ///   </listheader>
        ///   <item>
        ///     <term>内部继电器</term>
        ///     <term>M100,M200</term>
        ///     <term>M0-M1023,M8000-M8255</term>
        ///     <term>10</term>
        ///   </item>
        ///   <item>
        ///     <term>输入继电器</term>
        ///     <term>X100,X1A0</term>
        ///     <term>X0-X177</term>
        ///     <term>8</term>
        ///   </item>
        ///   <item>
        ///     <term>输出继电器</term>
        ///     <term>Y10,Y20</term>
        ///     <term>Y0-Y177</term>
        ///     <term>8</term>
        ///   </item>
        ///   <item>
        ///     <term>步进继电器</term>
        ///     <term>S100,S200</term>
        ///     <term>S0-S999</term>
        ///     <term>10</term>
        ///   </item>
        ///   <item>
        ///     <term>定时器</term>
        ///     <term>T10,T20</term>
        ///     <term>T0-T255</term>
        ///     <term>10</term>
        ///   </item>
        ///   <item>
        ///     <term>计数器</term>
        ///     <term>C10,C20</term>
        ///     <term>C0-C255</term>
        ///     <term>10</term>
        ///   </item>
        /// </list>
        /// </remarks>
        /// <example>
        ///  <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\MelsecAscii.cs" region="ReadBool" title="Bool类型示例" />
        /// </example>
        public OperateResult <bool[]> ReadBool(string address, ushort length)
        {
            var result = new OperateResult <bool[]>( );
            //获取指令
            var command = BuildReadBoolCommand(address, length);

            if (!command.IsSuccess)
            {
                result.CopyErrorFromOther(command);
                return(result);
            }

            var read = ReadBase(command.Content1);

            if (read.IsSuccess)
            {
                OperateResult ackResult = CheckPlcReadResponse(read.Content);
                if (!ackResult.IsSuccess)
                {
                    return(OperateResult.CreateFailedResult <bool[]>(ackResult));
                }

                // 提取真实的数据
                result.Content = new bool[length];

                byte[] data = new byte[(read.Content.Length - 4) / 2];

                for (int i = 0; i < result.Content.Length; i++)
                {
                    byte[] buffer = new byte[2];
                    buffer[0] = read.Content[i * 2 + 1];
                    buffer[1] = read.Content[i * 2 + 2];

                    data[i] = Convert.ToByte(Encoding.ASCII.GetString(buffer), 16);
                }

                // 转化bool数组
                bool[] array = BasicFramework.SoftBasic.ByteToBoolArray(data, data.Length * 8);
                for (int i = 0; i < length; i++)
                {
                    result.Content[i] = array[i + command.Content2];
                }

                result.IsSuccess = true;
            }
            else
            {
                result.ErrorCode = read.ErrorCode;
                result.Message   = read.Message;
            }

            return(result);
        }
        /// <summary>
        /// 使用底层的数据报文来通讯,传入需要发送的消息,返回最终的数据结果,被拆分成了头子节和内容字节信息
        /// </summary>
        /// <param name="socket">网络套接字</param>
        /// <param name="send">发送的数据</param>
        /// <returns>结果对象</returns>
        protected OperateResult <byte[], byte[]> ReadFromCoreServerBase(Socket socket, byte[] send)
        {
            var result = new OperateResult <byte[], byte[]>( );
            // LogNet?.WriteDebug( ToString( ), "Command: " + BasicFramework.SoftBasic.ByteToHexString( send ) );
            TNetMessage netMsg = new TNetMessage
            {
                SendBytes = send
            };

            // 发送数据信息
            OperateResult resultSend = Send(socket, send);

            if (!resultSend.IsSuccess)
            {
                socket?.Close( );
                result.CopyErrorFromOther(resultSend);
                return(result);
            }

            // 接收超时时间大于0时才允许接收远程的数据
            if (receiveTimeOut >= 0)
            {
                // 接收数据信息
                OperateResult <TNetMessage> resultReceive = ReceiveMessage(socket, receiveTimeOut, netMsg);
                if (!resultReceive.IsSuccess)
                {
                    socket?.Close( );
                    result.CopyErrorFromOther(resultReceive);
                    return(result);
                }

                // 复制结果
                result.Content1 = resultReceive.Content.HeadBytes;
                result.Content2 = resultReceive.Content.ContentBytes;
            }

            result.IsSuccess = true;
            return(result);
        }
Beispiel #23
0
        /// <summary>
        /// 读取线圈,需要指定起始地址
        /// </summary>
        /// <param name="address">起始地址,格式为"1234"</param>
        /// <returns>带有成功标志的bool对象</returns>
        public OperateResult <bool> ReadCoil(string address)
        {
            var result = new OperateResult <bool>( );
            var read   = ReadModBusBase(ModbusInfo.ReadCoil, address, 1);

            if (!read.IsSuccess)
            {
                result.CopyErrorFromOther(read);
                return(result);
            }

            return(GetBoolResultFromBytes(read));
        }
Beispiel #24
0
        /// <summary>
        /// 从PLC读取数据,地址格式为I100,Q100,DB20.100,M100,以位为单位
        /// </summary>
        /// <param name="address">起始地址,格式为I100,M100,Q100,DB20.100</param>
        /// <returns></returns>
        private OperateResult <byte[]> ReadBitFromPLC(string address)
        {
            OperateResult <byte[]> result = new OperateResult <byte[]>( );

            OperateResult <byte[]> command = BuildBitReadCommand(address);

            if (!command.IsSuccess)
            {
                result.CopyErrorFromOther(command);
                return(result);
            }

            OperateResult <byte[]> read = ReadFromCoreServer(command.Content);

            if (read.IsSuccess)
            {
                int receiveCount = 1;

                if (read.Content.Length >= 21 && read.Content[20] == 1)
                {
                    // 分析结果
                    byte[] buffer = new byte[receiveCount];

                    if (22 < read.Content.Length)
                    {
                        if (read.Content[21] == 0xFF &&
                            read.Content[22] == 0x03)
                        {
                            // 有数据
                            buffer[0] = read.Content[25];
                        }
                    }

                    result.Content   = buffer;
                    result.IsSuccess = true;
                }
                else
                {
                    result.ErrorCode = read.ErrorCode;
                    result.Message   = "数据块长度校验失败";
                }
            }
            else
            {
                result.ErrorCode = read.ErrorCode;
                result.Message   = read.Message;
            }

            return(result);
        }
Beispiel #25
0
        /// <summary>
        /// 从Modbus服务器批量读取寄存器的信息,需要指定起始地址,读取长度
        /// </summary>
        /// <param name="address">起始地址,格式为"1234"</param>
        /// <param name="length">读取的数量</param>
        /// <returns>带有成功标志的字节信息</returns>
        public OperateResult <byte[]> Read(string address, ushort length)
        {
            var result  = new OperateResult <byte[]>( );
            var command = BuildReadCommandBase(ModbusInfo.ReadRegister, address, length);

            if (!command.IsSuccess)
            {
                result.CopyErrorFromOther(command);
                return(result);
            }

            var read = ReadModBusBase(ModbusInfo.ReadRegister, address, length);

            return(result);
        }
Beispiel #26
0
        /// <summary>
        /// 批量的离散变量,需要指定起始地址,读取长度
        /// </summary>
        /// <param name="address">起始地址,格式为"1234"</param>
        /// <param name="length">读取长度</param>
        /// <returns>带有成功标志的bool数组对象</returns>
        public OperateResult <bool[]> ReadDiscrete(string address, ushort length)
        {
            var result = new OperateResult <bool[]>( );
            var read   = ReadModBusBase(ModbusInfo.ReadDiscrete, address, length);

            if (!read.IsSuccess)
            {
                result.CopyErrorFromOther(read);
                return(result);
            }

            result.Content   = SoftBasic.ByteToBoolArray(read.Content, length);
            result.IsSuccess = true;
            return(result);
        }
Beispiel #27
0
        /// <summary>
        /// 生成一个写入字节数据的指令
        /// </summary>
        /// <param name="address"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        private OperateResult <byte[]> BuildWriteByteCommand(string address, byte[] data)
        {
            if (data == null)
            {
                data = new byte[0];
            }
            var result = new OperateResult <byte[]>();

            OperateResult <byte, int, ushort> analysis = AnalysisAddress(address);

            if (!analysis.IsSuccess)
            {
                result.CopyErrorFromOther(analysis);
                return(result);
            }

            byte[] _PLCCommand = new byte[16 + data.Length];
            _PLCCommand[0] = 0x53;
            _PLCCommand[1] = 0x35;
            _PLCCommand[2] = 0x10;
            _PLCCommand[3] = 0x01;
            _PLCCommand[4] = 0x03;
            _PLCCommand[5] = 0x03;
            _PLCCommand[6] = 0x03;
            _PLCCommand[7] = 0x08;

            //指定数据区
            _PLCCommand[8] = analysis.Content1;
            _PLCCommand[9] = (byte)analysis.Content3;

            //指定数据地址
            _PLCCommand[10] = (byte)(analysis.Content2 / 256);
            _PLCCommand[11] = (byte)(analysis.Content2 % 256);

            //指定数据长度
            _PLCCommand[12] = (byte)(data.Length / 256);
            _PLCCommand[13] = (byte)(data.Length % 256);

            _PLCCommand[14] = 0xff;
            _PLCCommand[15] = 0x02;

            //放置数据
            Array.Copy(data, 0, _PLCCommand, 16, data.Length);

            result.Content   = _PLCCommand;
            result.IsSuccess = true;
            return(result);
        }
        /// <summary>
        /// 连接并初始化网络套接字
        /// </summary>
        /// <returns>带有socket的结果对象</returns>
        private OperateResult <Socket> CreateSocketAndInitialication( )
        {
            OperateResult <Socket> result = CreateSocketAndConnect(new IPEndPoint(IPAddress.Parse(ipAddress), port), connectTimeOut);

            if (result.IsSuccess)
            {
                // 初始化
                OperateResult initi = InitializationOnConnect(result.Content);
                if (!initi.IsSuccess)
                {
                    result.Content?.Close( );
                    result.IsSuccess = initi.IsSuccess;
                    result.CopyErrorFromOther(initi);
                }
            }
            return(result);
        }
        /// <summary>
        /// 从三菱PLC中读取想要的数据,返回读取结果
        /// </summary>
        /// <param name="address">读取地址,格式为"M100","D100","W1A0"</param>
        /// <param name="length">读取的数据长度,字最大值960,位最大值7168</param>
        /// <returns>带成功标志的结果数据对象</returns>
        /// <remarks>
        /// 地址支持的列表如下:
        /// <list type="table">
        ///   <listheader>
        ///     <term>地址名称</term>
        ///     <term>示例</term>
        ///     <term>地址进制</term>
        ///   </listheader>
        ///   <item>
        ///     <term>数据寄存器</term>
        ///     <term>D1000,D2000</term>
        ///     <term>10</term>
        ///   </item>
        ///   <item>
        ///     <term>定时器的值</term>
        ///     <term>T100,T200</term>
        ///     <term>10</term>
        ///   </item>
        ///   <item>
        ///     <term>计数器的值</term>
        ///     <term>C100,C200</term>
        ///     <term>10</term>
        ///   </item>
        /// </list>
        /// </remarks>
        /// <example>
        /// 假设起始地址为D100,D100存储了温度,100.6℃值为1006,D101存储了压力,1.23Mpa值为123,D102,D103存储了产量计数,读取如下:
        /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\MelsecAscii.cs" region="ReadExample2" title="Read示例" />
        /// 以下是读取不同类型数据的示例
        /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\MelsecAscii.cs" region="ReadExample1" title="Read示例" />
        /// </example>
        public override OperateResult <byte[]> Read(string address, ushort length)
        {
            var result = new OperateResult <byte[]>( );
            //获取指令
            var command = BuildReadWordCommand(address, length);

            if (!command.IsSuccess)
            {
                result.CopyErrorFromOther(command);
                return(result);
            }

            var read = ReadBase(command.Content);

            if (read.IsSuccess)
            {
                OperateResult ackResult = CheckPlcReadResponse(read.Content);
                if (!ackResult.IsSuccess)
                {
                    return(OperateResult.CreateFailedResult <byte[]>(ackResult));
                }

                result.Content = new byte[(read.Content.Length - 4) / 2];
                for (int i = 0; i < result.Content.Length / 2; i++)
                {
                    byte[] buffer = new byte[4];
                    buffer[0] = read.Content[i * 4 + 1];
                    buffer[1] = read.Content[i * 4 + 2];
                    buffer[2] = read.Content[i * 4 + 3];
                    buffer[3] = read.Content[i * 4 + 4];

                    ushort tmp = Convert.ToUInt16(Encoding.ASCII.GetString(buffer), 16);
                    BitConverter.GetBytes(tmp).CopyTo(result.Content, i * 2);
                }

                result.IsSuccess = true;
            }
            else
            {
                result.ErrorCode = read.ErrorCode;
                result.Message   = read.Message;
            }

            return(result);
        }
Beispiel #30
0
        /// <summary>
        /// 一次性从PLC获取所有的数据,按照先后顺序返回一个统一的Buffer,需要按照顺序处理,两个数组长度必须一致
        /// </summary>
        /// <param name="address">起始地址数组</param>
        /// <param name="length">数据长度数组</param>
        /// <returns></returns>
        /// <exception cref="NullReferenceException"></exception>
        public OperateResult <byte[]> Read(string[] address, ushort[] length)
        {
            OperateResult <byte[]> result = new OperateResult <byte[]>( );

            OperateResult <byte, int, ushort>[] addressResult = new OperateResult <byte, int, ushort> [address.Length];
            for (int i = 0; i < address.Length; i++)
            {
                OperateResult <byte, int, ushort> tmp = AnalysisAddress(address[i]);
                if (!tmp.IsSuccess)
                {
                    result.CopyErrorFromOther(tmp);
                    return(result);
                }

                addressResult[i] = tmp;
            }

            return(Read(addressResult, length));
        }