Пример #1
0
        internal async Task <ProcessRequestResult> ProcessRequestAsync(FINSRequest request, int timeout, int retries, 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
                {
                    if (!_semaphore.Wait(0))
                    {
                        await _semaphore.WaitAsync(cancellationToken);
                    }

                    if (attempts > 0)
                    {
                        await DestroyAndInitializeClient(timeout, cancellationToken);
                    }

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

                    // Send the Message
                    SendMessageResult sendResult = await SendMessageAsync(requestMessage, timeout, cancellationToken);

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

                    // Receive a Response
                    ReceiveMessageResult receiveResult = await ReceiveMessageAsync(timeout, cancellationToken);

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

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

                // Increment the Attempts
                attempts++;
            }

            try
            {
                return(new ProcessRequestResult
                {
                    BytesSent = bytesSent,
                    PacketsSent = packetsSent,
                    BytesReceived = bytesReceived,
                    PacketsReceived = packetsReceived,
                    Duration = DateTime.UtcNow.Subtract(startTimestamp).TotalMilliseconds,
                    Response = FINSResponse.CreateNew(responseMessage, request),
                });
            }
            catch (FINSException e)
            {
                if (e.Message.Contains("Service ID") && responseMessage.Length >= 9 && responseMessage.Span[9] != request.ServiceID)
                {
                    try
                    {
                        if (!_semaphore.Wait(0))
                        {
                            await _semaphore.WaitAsync(cancellationToken);
                        }

                        await PurgeReceiveBuffer(timeout, cancellationToken);
                    }
                    catch
                    {
                    }
                    finally
                    {
                        _semaphore.Release();
                    }
                }

                throw new OmronException("Received a FINS Error Response from Omron PLC '" + _remoteHost + ":" + _port + "'", e);
            }
        }
Пример #2
0
        internal static FINSResponse CreateNew(Memory <byte> message, FINSRequest request)
        {
            if (message.Length < HEADER_LENGTH + COMMAND_LENGTH + RESPONSE_CODE_LENGTH)
            {
                throw new FINSException("The FINS Response Message Length was too short");
            }

            FINSResponse response = new FINSResponse();

            byte[] header = message.Slice(0, HEADER_LENGTH).ToArray();

            response.ServiceID = header[9];

            byte[] command = message.Slice(HEADER_LENGTH, COMMAND_LENGTH).ToArray();

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

            response.FunctionCode = command[0];

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

            if (ValidateSubFunctionCode(command[0], command[1]) == false)
            {
                throw new FINSException("Invalid Sub Function Code '" + command[1].ToString() + "' for Function Code '" + command[0].ToString() + "'");
            }

            response.SubFunctionCode = command[1];

            if (response.SubFunctionCode != request.SubFunctionCode)
            {
                throw new FINSException("Unexpected Sub Function Code '" + getSubFunctionCodeName(response.FunctionCode, response.SubFunctionCode) + "' - Expecting '" + getSubFunctionCodeName(request.FunctionCode, request.SubFunctionCode) + "'");
            }

            byte[] responseCode = message.Slice(HEADER_LENGTH + COMMAND_LENGTH, RESPONSE_CODE_LENGTH).ToArray();

            if (hasNetworkRelayError(responseCode[0]))
            {
                throw new FINSException("A Network Relay Error has occurred");
            }

            response.MainResponseCode = getMainResponseCode(responseCode[0]);

            response.SubResponseCode = getSubResponseCode(responseCode[1]);

            throwIfResponseError(response.MainResponseCode, response.SubResponseCode);

            if (request.ServiceID != response.ServiceID)
            {
                throw new FINSException("The Service ID for the FINS Request '" + request.ServiceID + "' did not match the FINS Response '" + response.ServiceID + "'");
            }

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

            return(response);
        }