예제 #1
0
        internal ModbusResponse Deserialize(ResponseBuffer buffer, ModbusRequest request, int timeout)
        {
            ModbusResponse result;

            try
            {
                result = DeserializeResponse(buffer, request, timeout);
            }
            catch (TimeoutException ex)
            {
                throw new ModbusCommException(ModbusCommErrorCode.ResponseTimeout, buffer, ex, request);
            }
            catch (ModbusCommException ex)
            {
                throw new ModbusCommException(ex.Code, buffer, ex.InnerException, request);
            }
            catch (Exception ex)
            {
                throw new ModbusCommException(buffer, ex, request);
            }

            if (result is ModbusCommErrorResponse commErrorResponse)
            {
                throw new ModbusCommException(commErrorResponse.ErrorCode, commErrorResponse.ReceivedBytes, commErrorResponse.Request);
            }

            return(result);
        }
예제 #2
0
        internal override ModbusResponse DeserializeReadRegisterResponse(ResponseBuffer buffer, ModbusReadRequest request, int timeout)
        {
            if (IsException(buffer, request, timeout, out var responseMessage))
            {
                return(responseMessage);
            }

            byte byteLength = Read(buffer, 2, timeout);

            if (IsErrorCRC(buffer, 3 + byteLength, request, timeout))
            {
                throw new ModbusCommException(ModbusCommErrorCode.ErrorCRC, buffer, request);
            }

            if (Read(buffer, 0, timeout) != request.SlaveAddress)
            {
                throw new ModbusCommException(ModbusCommErrorCode.ResponseSlaveAddressDoNotMatch, buffer, request);
            }
            if ((Read(buffer, 1, timeout) & 0x7f) != (byte)request.Function)
            {
                throw new ModbusCommException(ModbusCommErrorCode.ResponseFunctionDoNotMatch, buffer, request);
            }
            if (byteLength != (byte)(request.Length * 2))
            {
                throw new ModbusCommException(ModbusCommErrorCode.ResponseLengthDoNotMatch, buffer, request);
            }

            return(new ModbusReadRegisterResponse(Read(buffer, 3, byteLength, timeout).ToArray(), request));
        }
예제 #3
0
        private bool IsException(ResponseBuffer buffer, ModbusRequest request, int timeout, out ModbusResponse responseMessage)
        {
            if ((Read(buffer, 1, timeout) & 0x80) == 0x80)
            {
                var codeValue = Read(buffer, 2, timeout);

                if (IsErrorCRC(buffer, 3, request, timeout))
                {
                    throw new ModbusCommException(ModbusCommErrorCode.ErrorCRC, buffer, request);
                }

                ModbusExceptionCode exceptionCode = ModbusExceptionCode.NotDefined;
                if (Enum.IsDefined(typeof(ModbusExceptionCode), codeValue))
                {
                    exceptionCode = (ModbusExceptionCode)codeValue;
                }

                responseMessage = new ModbusExceptionResponse(exceptionCode, request);
                return(true);
            }
            else
            {
                responseMessage = null;
                return(false);
            }
        }
예제 #4
0
        internal override ModbusResponse DeserializeReadBooleanResponse(ResponseBuffer buffer, ModbusReadRequest request, int timeout)
        {
            if (IsException(buffer, request, timeout, out var responseMessage))
            {
                return(responseMessage);
            }

            byte byteLength = Read(buffer, 2, timeout);

            if (IsErrorLRC(buffer, 3 + byteLength, request, timeout, out responseMessage))
            {
                return(responseMessage);
            }

            if (Read(buffer, 0, timeout) != request.SlaveAddress)
            {
                return(new ModbusCommErrorResponse(ModbusCommErrorCode.ResponseSlaveAddressDoNotMatch, buffer, request));
            }
            if ((Read(buffer, 1, timeout) & 0x7f) != (byte)request.Function)
            {
                return(new ModbusCommErrorResponse(ModbusCommErrorCode.ResponseFunctionDoNotMatch, buffer, request));
            }
            if (byteLength != (byte)Math.Ceiling(request.Length / 8d))
            {
                return(new ModbusCommErrorResponse(ModbusCommErrorCode.ResponseLengthDoNotMatch, buffer, request));
            }

            return(new ModbusReadBooleanResponse(Read(buffer, 3, byteLength, timeout).SelectMany(b => ByteToBooleanArray(b)).Take(request.Length).ToArray(), request));
        }
예제 #5
0
        internal virtual ModbusResponse DeserializeResponse(ResponseBuffer buffer, ModbusRequest request, int timeout)
        {
            if (request is ModbusReadRequest readMessage)
            {
                switch (readMessage.ObjectType)
                {
                case ModbusObjectType.DiscreteInput:
                case ModbusObjectType.Coil:
                    return(DeserializeReadBooleanResponse(buffer, readMessage, timeout));

                case ModbusObjectType.InputRegister:
                case ModbusObjectType.HoldingRegister:
                    return(DeserializeReadRegisterResponse(buffer, readMessage, timeout));
                }
            }
            else if (request is ModbusWriteCoilRequest writeCoilMessage)
            {
                return(DeserializeWriteResponse(buffer, writeCoilMessage, timeout));
            }
            else if (request is ModbusWriteHoldingRegisterRequest writeHoldingRegisterMessage)
            {
                return(DeserializeWriteResponse(buffer, writeHoldingRegisterMessage, timeout));
            }

            throw new ArgumentOutOfRangeException(nameof(request));
        }
예제 #6
0
        internal virtual byte Read(ResponseBuffer buffer, int index, int timeout)
        {
            if (index >= buffer.Count)
            {
                buffer.Read((uint)(index - buffer.Count + 1), timeout);
            }

            return(buffer[index]);
        }
예제 #7
0
        internal virtual IEnumerable <byte> Read(ResponseBuffer buffer, int index, int count, int timeout)
        {
            if (index + count > buffer.Count)
            {
                buffer.Read((uint)(index + count - buffer.Count), timeout);
            }

            return(buffer.Skip(index).Take(count));
        }
예제 #8
0
        internal override byte Read(ResponseBuffer buffer, int index, int timeout)
        {
            if (index * 2 >= buffer.Count - 2)
            {
                buffer.Read((uint)(index * 2 - buffer.Count + 3), timeout);
            }

            return(byte.Parse(Encoding.ASCII.GetString(buffer.Skip(index * 2 + 1).Take(2).ToArray()), System.Globalization.NumberStyles.HexNumber, null));
        }
예제 #9
0
        internal override ModbusResponse DeserializeResponse(ResponseBuffer buffer, ModbusRequest request, int timeout)
        {
            ModbusResponse result = null;

            while (result == null ||
                   result is ModbusCommErrorResponse responseCommErrorMessage &&
                   responseCommErrorMessage.ErrorCode != ModbusCommErrorCode.ResponseTimeout)
            {
                if (buffer.Count > 0)
                {
                    errorBuffer.Add(buffer[0]);
                    buffer.RemoveAt(0);
                }

                buffer.Read(timeout);

                try
                {
                    while (buffer[0] != 0x3a)
                    {
                        errorBuffer.Add(buffer[0]);
                        buffer.RemoveAt(0);
                        buffer.Read(timeout);
                    }
                }
                catch
                {
                    return(new ModbusCommErrorResponse(ModbusCommErrorCode.ResponseAsciiStartError, errorBuffer.Concat(buffer), request));
                }

                result = base.DeserializeResponse(buffer, request, timeout);
            }

            if (result is ModbusCommErrorResponse responseCommError)
            {
                result = new ModbusCommErrorResponse(responseCommError.ErrorCode, errorBuffer.Concat(responseCommError.ReceivedBytes), request);
            }
            else
            {
                var asciiEnd = buffer.Read(2, timeout);
                if (!asciiEnd.SequenceEqual(new byte[] { 13, 10 }))
                {
                    return(new ModbusCommErrorResponse(ModbusCommErrorCode.ResponseAsciiEndError, buffer, request));
                }

                if (errorBuffer.Count > 0)
                {
                    RaiseUnrecognized(buffer.Channel, errorBuffer.ToArray());
                    errorBuffer.Clear();
                }
            }

            return(result);
        }
예제 #10
0
        internal override IEnumerable <byte> Read(ResponseBuffer buffer, int index, int count, int timeout)
        {
            if ((index + count) * 2 > buffer.Count - 1)
            {
                buffer.Read((uint)((index + count) * 2 - buffer.Count + 1), timeout);
            }

            var bytes = buffer.Skip(index * 2 + 1).Take(count * 2).ToArray();

            for (int i = 0; i < count; i++)
            {
                yield return(byte.Parse(Encoding.ASCII.GetString(bytes, i * 2, 2), System.Globalization.NumberStyles.HexNumber, null));
            }
        }
예제 #11
0
        internal override ModbusResponse DeserializeWriteResponse(ResponseBuffer buffer, ModbusWriteHoldingRegisterRequest request, int timeout)
        {
            if (IsException(buffer, request, timeout, out var responseMessage))
            {
                return(responseMessage);
            }

            if (IsErrorCRC(buffer, 6, request, timeout))
            {
                throw new ModbusCommException(ModbusCommErrorCode.ErrorCRC, buffer, request);
            }

            if (Read(buffer, 0, timeout) != request.SlaveAddress)
            {
                throw new ModbusCommException(ModbusCommErrorCode.ResponseSlaveAddressDoNotMatch, buffer, request);
            }
            if ((Read(buffer, 1, timeout) & 0x7f) != (byte)request.Function)
            {
                throw new ModbusCommException(ModbusCommErrorCode.ResponseFunctionDoNotMatch, buffer, request);
            }
            if (ToUInt16(buffer, 2) != request.Address)
            {
                throw new ModbusCommException(ModbusCommErrorCode.ResponseAddressDoNotMatch, buffer, request);
            }

            ushort value = ToUInt16(buffer, 4);

            switch (request.Function)
            {
            case ModbusFunction.WriteSingleHoldingRegister:
                if (value != request.SingleRegisterValue)
                {
                    throw new ModbusCommException(ModbusCommErrorCode.ResponseWritedValueDoNotMatch, buffer, request);
                }
                break;

            case ModbusFunction.WriteMultipleHoldingRegisters:
                if (value != request.Length)
                {
                    throw new ModbusCommException(ModbusCommErrorCode.ResponseWritedLengthDoNotMatch, buffer, request);
                }
                break;
            }

            return(new ModbusWriteResponse(request));
        }
예제 #12
0
        internal override ModbusResponse DeserializeWriteResponse(ResponseBuffer buffer, ModbusWriteCoilRequest request, int timeout)
        {
            if (IsException(buffer, request, timeout, out var responseMessage))
            {
                return(responseMessage);
            }

            if (IsErrorCRC(buffer, 6, request, timeout))
            {
                throw new ModbusCommException(ModbusCommErrorCode.ErrorCRC, buffer, request);
            }

            if (Read(buffer, 0, timeout) != request.SlaveAddress)
            {
                throw new ModbusCommException(ModbusCommErrorCode.ResponseSlaveAddressDoNotMatch, buffer, request);
            }
            if ((Read(buffer, 1, timeout) & 0x7f) != (byte)request.Function)
            {
                throw new ModbusCommException(ModbusCommErrorCode.ResponseFunctionDoNotMatch, buffer, request);
            }
            if (ToUInt16(buffer, 2) != request.Address)
            {
                throw new ModbusCommException(ModbusCommErrorCode.ResponseAddressDoNotMatch, buffer, request);
            }

            switch (request.Function)
            {
            case ModbusFunction.WriteSingleCoil:
                if (Read(buffer, 4, timeout) != (request.SingleBooleanValue ? 0xff : 0x00) ||
                    Read(buffer, 5, timeout) != 0x00)
                {
                    throw new ModbusCommException(ModbusCommErrorCode.ResponseWritedValueDoNotMatch, buffer, request);
                }
                break;

            case ModbusFunction.WriteMultipleCoils:
                if (ToUInt16(buffer, 4) != request.Length)
                {
                    throw new ModbusCommException(ModbusCommErrorCode.ResponseWritedLengthDoNotMatch, buffer, request);
                }
                break;
            }

            return(new ModbusWriteResponse(request));
        }
예제 #13
0
        internal override ModbusResponse DeserializeResponse(ResponseBuffer buffer, ModbusRequest request, int timeout)
        {
            var responseWaitHandle = this.responseWaitHandles[request.TransactionID] = new ResponseWaitHandle(buffer, request, timeout);

            Task.Run(() => RunReceive(buffer.Channel));

            responseWaitHandle.WaitOne(timeout);

            var result = responseWaitHandle.Response;

            if (result == null)
            {
                this.responseWaitHandles.Remove(request.TransactionID);
                return(new ModbusCommErrorResponse(ModbusCommErrorCode.ResponseTimeout, new byte[0], request));
            }

            return(result);
        }
예제 #14
0
        private bool IsErrorLRC(ResponseBuffer buffer, int messageLength, ModbusRequest request, int timeout, out ModbusResponse responseMessage)
        {
            byte lrc = 0;

            foreach (var b in Read(buffer, 0, messageLength, timeout))
            {
                lrc += b;
            }

            lrc = (byte)(-lrc & 0xff);

            if (lrc != Read(buffer, messageLength, timeout))
            {
                responseMessage = new ModbusCommErrorResponse(ModbusCommErrorCode.ErrorLRC, buffer, request);
                return(true);
            }
            else
            {
                responseMessage = null;
                return(false);
            }
        }
예제 #15
0
        internal override ModbusResponse DeserializeResponse(ResponseBuffer buffer, ModbusRequest request, int timeout)
        {
            ModbusResponse result = base.DeserializeResponse(buffer, request, timeout);

            while (result is ModbusCommErrorResponse responseCommErrorMessage &&
                   responseCommErrorMessage.ErrorCode != ModbusCommErrorCode.ResponseTimeout)
            {
                errorBuffer.Add(buffer[0]);
                buffer.RemoveAt(0);
                result = base.DeserializeResponse(buffer, request, timeout);
            }

            if (result is ModbusCommErrorResponse responseCommError)
            {
                result = new ModbusCommErrorResponse(responseCommError.ErrorCode, errorBuffer.Concat(responseCommError.ReceivedBytes), request);
            }
            else if (errorBuffer.Count > 0)
            {
                RaiseUnrecognized(buffer.Channel, errorBuffer.ToArray());
                errorBuffer.Clear();
            }

            return(result);
        }
예제 #16
0
 internal ushort ToUInt16(ResponseBuffer buffer, int index, int timeout)
 {
     return(ToUInt16(Read(buffer, index, 2, timeout).ToArray(), 0));
 }
예제 #17
0
 public ResponseWaitHandle(ResponseBuffer buffer, ModbusRequest request, int timeout) : base(false, EventResetMode.ManualReset)
 {
     ResponseBuffer = buffer;
     Request        = request;
     Timeout        = timeout;
 }
예제 #18
0
 internal abstract ModbusResponse DeserializeWriteResponse(ResponseBuffer buffer, ModbusWriteHoldingRegisterRequest request, int timeout);
예제 #19
0
 internal abstract ModbusResponse DeserializeWriteResponse(ResponseBuffer buffer, ModbusWriteCoilRequest request, int timeout);
예제 #20
0
 internal abstract ModbusResponse DeserializeReadRegisterResponse(ResponseBuffer buffer, ModbusReadRequest request, int timeout);
예제 #21
0
        private bool IsErrorCRC(ResponseBuffer buffer, int messageLength, ModbusRequest request, int timeout)
        {
            var crc = Read(buffer, messageLength, 2, timeout).ToArray();

            return(!CalculateCrc(buffer.Take(messageLength)).SequenceEqual(crc));
        }
예제 #22
0
        private void RunReceive(ModbusChannel channel)
        {
            lock (responseWaitHandles)
            {
                if (!isReceiving)
                {
                    isReceiving = true;
                    try
                    {
                        var readBuffer = new ResponseBuffer(channel);

                        while (responseWaitHandles.Count > 0)
                        {
                            if (errorBuffer.Count >= 256)
                            {
                                RaiseUnrecognized(channel, errorBuffer.ToArray());
                                errorBuffer.Clear();
                            }

                            readBuffer.Read(2, 0);

                            ushort transactionID = (ushort)((readBuffer[0] << 8) | readBuffer[1]);
                            if (!responseWaitHandles.TryGetValue(transactionID, out var responseWaitHandle))
                            {
                                errorBuffer.AddRange(readBuffer);
                                readBuffer.Clear();
                                continue;
                            }

                            readBuffer.Read(2, responseWaitHandle.Timeout);
                            if (readBuffer[2] != 0 ||
                                readBuffer[3] != 0)
                            {
                                errorBuffer.AddRange(readBuffer);
                                readBuffer.Clear();

                                responseWaitHandle.Response = new ModbusCommErrorResponse(ModbusCommErrorCode.ModbusTcpSymbolError, errorBuffer, responseWaitHandle.Request);
                                continue;
                            }

                            var result = base.DeserializeResponse(readBuffer, responseWaitHandle.Request, responseWaitHandle.Timeout);

                            if (result is ModbusCommErrorResponse responseCommErrorMessage)
                            {
                                errorBuffer.AddRange(readBuffer.Take(4));
                                readBuffer.RemoveRange(0, 4);

                                responseWaitHandle.Response = result;
                                continue;
                            }

                            if (readBuffer.Count - 6 != (ushort)((readBuffer[4] << 8) | readBuffer[5]))
                            {
                                errorBuffer.AddRange(readBuffer.Take(4));
                                readBuffer.RemoveRange(0, 4);

                                responseWaitHandle.Response = new ModbusCommErrorResponse(ModbusCommErrorCode.ResponseTcpLengthDoNotMatch, readBuffer, responseWaitHandle.Request);
                                continue;
                            }


                            if (errorBuffer.Count > 0)
                            {
                                RaiseUnrecognized(channel, errorBuffer.ToArray());
                                errorBuffer.Clear();
                            }

                            responseWaitHandle.ResponseBuffer.AddRange(readBuffer);

                            readBuffer.Clear();
                            responseWaitHandle.Response = result;
                            responseWaitHandle.Set();
                            this.responseWaitHandles.Remove(transactionID);
                        }
                    }
                    catch
                    {
                    }
                    isReceiving = false;
                }
            }
        }