コード例 #1
0
        internal static RTUResponse CreateNew(Memory <byte> message, RTURequest request)
        {
            if (message.Length < 2)
            {
                throw new RTUException("The RTU Response Message Length was too short");
            }

            RTUResponse response = new RTUResponse();

            byte[] command = message.Slice(0, 2).ToArray();

            if (ValidateFunctionCode(command[0]) == false)
            {
                throw new RTUException("Invalid Function Code '" + command[0].ToString() + "'");
            }

            response.FunctionCode = command[0];

            throwIfResponseError(command[0], command[1]);

            if (response.FunctionCode != request.FunctionCode)
            {
                throw new RTUException("Unexpected Function Code '" + Enum.GetName(typeof(enFunctionCode), response.FunctionCode) + "' - Expecting '" + Enum.GetName(typeof(enFunctionCode), request.FunctionCode) + "'");
            }

            response.Data = message.Length > 1 ? message.Slice(1, message.Length - 1).ToArray() : new byte[0];

            return(response);
        }
コード例 #2
0
        private async Task <ReceiveMessageResult> receiveMessageAsync(RTURequest request, byte unitId, int timeout, CancellationToken cancellationToken)
        {
            ReceiveMessageResult result = new ReceiveMessageResult
            {
                Bytes   = 0,
                Packets = 0,
                Message = new Memory <byte>(),
            };

            try
            {
                List <byte> receivedData   = new List <byte>();
                DateTime    startTimestamp = DateTime.UtcNow;

                while (DateTime.UtcNow.Subtract(startTimestamp).TotalMilliseconds < timeout && receivedData.Count < RTUResponse.GetMessageLengthHint(request, receivedData) + 3)
                {
                    Memory <byte> buffer         = new byte[300];
                    TimeSpan      receiveTimeout = TimeSpan.FromMilliseconds(timeout).Subtract(DateTime.UtcNow.Subtract(startTimestamp));

                    if (receiveTimeout.TotalMilliseconds >= 50)
                    {
                        int receivedBytes = await _client.ReceiveAsync(buffer, receiveTimeout, cancellationToken);

                        if (receivedBytes > 0)
                        {
                            receivedData.AddRange(buffer.Slice(0, receivedBytes).ToArray());

                            result.Bytes   += receivedBytes;
                            result.Packets += 1;
                        }
                    }
                }

                if (receivedData.Count == 0)
                {
                    throw new ModbusException("Failed to Receive RTU Message from Modbus Device ID '" + unitId + "' on '" + RemoteHost + ":" + Port + "' - No Data was Received");
                }

                if (receivedData.Count < RTUResponse.GetMessageLengthHint(request, receivedData) + 3)
                {
                    throw new ModbusException("Failed to Receive RTU Message within the Timeout Period from Modbus Device ID '" + unitId + "' on '" + RemoteHost + ":" + Port + "'");
                }

                if (receivedData[0] != unitId)
                {
                    throw new ModbusException("Failed to Receive RTU Message from Modbus Device ID '" + unitId + "' on '" + RemoteHost + ":" + Port + "' - The Unit ID did not Match");
                }

                receivedData.RemoveRange(0, 1);

                receivedData.RemoveRange(receivedData.Count - 2, 2);

                result.Message = receivedData.ToArray();
            }
            catch (ObjectDisposedException)
            {
                throw new ModbusException("Failed to Receive RTU Message from Modbus Device ID '" + unitId + "' on '" + RemoteHost + ":" + Port + "' - The underlying Socket Connection has been Closed");
            }
            catch (TimeoutException)
            {
                throw new ModbusException("Failed to Receive RTU Message within the Timeout Period from Modbus Device ID '" + unitId + "' on '" + RemoteHost + ":" + Port + "'");
            }
            catch (System.Net.Sockets.SocketException e)
            {
                throw new ModbusException("Failed to Receive RTU Message from Modbus Device ID '" + unitId + "' on '" + RemoteHost + ":" + Port + "'", e);
            }

            return(result);
        }
コード例 #3
0
        public async Task <ProcessRequestResult> ProcessRequestAsync(RTURequest request, int timeout, int retries, int?delayBetweenMessages, CancellationToken cancellationToken)
        {
            int           attempts        = 0;
            Memory <byte> responseMessage = new Memory <byte>();
            int           bytesSent       = 0;
            int           packetsSent     = 0;
            int           bytesReceived   = 0;
            int           packetsReceived = 0;
            DateTime      startTimestamp  = DateTime.UtcNow;

            while (attempts <= retries)
            {
                try
                {
                    await _requestSemaphore.WaitAsync(cancellationToken);

                    if (attempts > 0)
                    {
                        await destroyAndInitializeClient(request.UnitID, timeout, cancellationToken);
                    }

                    // Build the Request into a Message we can Send
                    ReadOnlyMemory <byte> requestMessage = request.BuildMessage();

                    TimeSpan timeSinceLastMessage = DateTime.UtcNow.Subtract(_lastMessageTimestamp);

                    if (delayBetweenMessages.HasValue && delayBetweenMessages.Value > 0 && timeSinceLastMessage.TotalMilliseconds < delayBetweenMessages.Value)
                    {
                        await Task.Delay(TimeSpan.FromMilliseconds(delayBetweenMessages.Value - timeSinceLastMessage.TotalMilliseconds), cancellationToken);
                    }

                    // Send the Message
                    SendMessageResult sendResult = await sendMessageAsync(request.UnitID, requestMessage, timeout, cancellationToken);

                    bytesSent   += sendResult.Bytes;
                    packetsSent += sendResult.Packets;

                    // Receive a Response
                    ReceiveMessageResult receiveResult = await receiveMessageAsync(request, request.UnitID, timeout, cancellationToken);

                    bytesReceived   += receiveResult.Bytes;
                    packetsReceived += receiveResult.Packets;
                    responseMessage  = receiveResult.Message;

                    break;
                }
                catch (Exception)
                {
                    if (attempts >= retries)
                    {
                        throw;
                    }
                }
                finally
                {
                    _requestSemaphore.Release();
                }

                // Increment the Attempts
                attempts++;
            }

            try
            {
                return(new ProcessRequestResult
                {
                    BytesSent = bytesSent,
                    PacketsSent = packetsSent,
                    BytesReceived = bytesReceived,
                    PacketsReceived = packetsReceived,
                    Duration = DateTime.UtcNow.Subtract(startTimestamp).TotalMilliseconds,
                    Response = RTUResponse.CreateNew(responseMessage, request),
                });
            }
            catch (RTUException e)
            {
                throw new ModbusException("Received an RTU Error Response from Modbus Device ID '" + request.UnitID + "' on '" + _remoteHost + ":" + _port + "'", e);
            }
        }
コード例 #4
0
        internal static int GetMessageLengthHint(RTURequest request, List <byte> receivedData)
        {
            if (receivedData.Count > 0 && receivedData[0] >= 0x80)
            {
                byte functionCode = receivedData[0];

                functionCode -= 0x80;

                if (Enum.IsDefined(typeof(enFunctionCode), functionCode))
                {
                    return(2); // Function Code + Exception Code
                }
            }

            int byteCount = 1; // Function Code

            if (request is ReadHoldingCoilsRequest readHoldingCoils)
            {
                byteCount += 1; // Byte Count

                if (readHoldingCoils.Length > 0)
                {
                    byteCount += readHoldingCoils.Length / 8; // One Byte for 8 Bits
                }

                if (readHoldingCoils.Length % 8 != 0)
                {
                    byteCount += 1; // Additional Byte for Extra Bits
                }
            }
            else if (request is ReadInputCoilsRequest readInputCoils)
            {
                byteCount += 1; // Byte Count

                if (readInputCoils.Length > 0)
                {
                    byteCount += readInputCoils.Length / 8; // One Byte for 8 Bits
                }

                if (readInputCoils.Length % 8 != 0)
                {
                    byteCount += 1; // Additional Byte for Extra Bits
                }
            }
            else if (request is ReadHoldingRegistersRequest readHoldingRegisters)
            {
                byteCount += 1;                               // Byte Count

                byteCount += readHoldingRegisters.Length * 2; // Value Bytes
            }
            else if (request is ReadInputRegistersRequest readInputRegisters)
            {
                byteCount += 1;                             // Byte Count

                byteCount += readInputRegisters.Length * 2; // Value Bytes
            }
            else if (request is WriteHoldingCoilRequest || request is WriteHoldingCoilsRequest || request is WriteHoldingRegisterRequest || request is WriteHoldingRegistersRequest)
            {
                byteCount += 4; // Address + Single Value or Start Address + Length
            }

            if (byteCount < 2)
            {
                byteCount = 2;
            }

            return(byteCount);
        }