private ReadOnlyMemory <byte> buildFinsTcpMessage(enTCPCommandCode command, ReadOnlyMemory <byte> message) { List <byte> tcpMessage = new List <byte>(); // FINS Message Identifier tcpMessage.Add((byte)'F'); tcpMessage.Add((byte)'I'); tcpMessage.Add((byte)'N'); tcpMessage.Add((byte)'S'); // Length of Message tcpMessage.AddRange(BitConverter.GetBytes(Convert.ToUInt32(4 + 4 + message.Length)).Reverse()); // Command + Error Code + Message Data // Command tcpMessage.Add(0); tcpMessage.Add(0); tcpMessage.Add(0); tcpMessage.Add((byte)command); // Error Code tcpMessage.Add(0); tcpMessage.Add(0); tcpMessage.Add(0); tcpMessage.Add(0); tcpMessage.AddRange(message.ToArray()); return(tcpMessage.ToArray()); }
private async Task <SendMessageResult> sendMessageAsync(enTCPCommandCode command, ReadOnlyMemory <byte> message, int timeout, CancellationToken cancellationToken) { SendMessageResult result = new SendMessageResult { Bytes = 0, Packets = 0, }; ReadOnlyMemory <byte> tcpMessage = buildFinsTcpMessage(command, message); try { result.Bytes += await _client.SendAsync(tcpMessage, timeout, cancellationToken); result.Packets += 1; } catch (ObjectDisposedException) { throw new OmronException("Failed to Send FINS Message to Omron PLC '" + RemoteHost + ":" + Port + "' - The underlying Socket Connection was Closed"); } catch (TimeoutException) { throw new OmronException("Failed to Send FINS Message within the Timeout Period to Omron PLC '" + RemoteHost + ":" + Port + "'"); } catch (System.Net.Sockets.SocketException e) { throw new OmronException("Failed to Send FINS Message to Omron PLC '" + RemoteHost + ":" + Port + "'", e); } return(result); }
private async Task <ReceiveMessageResult> receiveMessageAsync(enTCPCommandCode command, 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 < TCP_HEADER_LENGTH) { Memory <byte> buffer = new byte[4096]; 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 OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - No Data was Received"); } if (receivedData.Count < TCP_HEADER_LENGTH) { throw new OmronException("Failed to Receive FINS Message within the Timeout Period from Omron PLC '" + RemoteHost + ":" + Port + "'"); } if (receivedData[0] != 'F' || receivedData[1] != 'I' || receivedData[2] != 'N' || receivedData[3] != 'S') { throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - The TCP Header was Invalid"); } byte[] tcpHeader = receivedData.GetRange(0, TCP_HEADER_LENGTH).ToArray(); int tcpMessageDataLength = (int)BitConverter.ToUInt32(new byte[] { receivedData[7], receivedData[6], receivedData[5], receivedData[4] }) - 8; if (tcpMessageDataLength <= 0 || tcpMessageDataLength > short.MaxValue) { throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - The TCP Message Length was Invalid"); } if (receivedData[11] == 3 || receivedData[15] != 0) { switch (receivedData[15]) { case 1: throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - Omron TCP Error: The FINS Identifier (ASCII Code) was Invalid."); case 2: throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - Omron TCP Error: The Data Length is too Long."); case 3: throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - Omron TCP Error: The Command is not Supported."); case 20: throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - Omron TCP Error: All Connections are in Use."); case 21: throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - Omron TCP Error: The Specified Node is already Connected."); case 22: throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - Omron TCP Error: Attempt to Access a Protected Node from an Unspecified IP Address."); case 23: throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - Omron TCP Error: The Client FINS Node Address is out of Range."); case 24: throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - Omron TCP Error: The same FINS Node Address is being used by the Client and Server."); case 25: throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - Omron TCP Error: All the Node Addresses Available for Allocation have been Used."); default: throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - Omron TCP Error: Unknown Code '" + receivedData[15] + "'"); } } if (receivedData[8] != 0 || receivedData[9] != 0 || receivedData[10] != 0 || receivedData[11] != (byte)command) { throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - The TCP Command Received '" + receivedData[11] + "' did not match Expected Command '" + (byte)command + "'"); } if (command == enTCPCommandCode.FINSFrame && tcpMessageDataLength < FINSResponse.HEADER_LENGTH + FINSResponse.COMMAND_LENGTH + FINSResponse.RESPONSE_CODE_LENGTH) { throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - The TCP Message Length was too short for a FINS Frame"); } receivedData.RemoveRange(0, TCP_HEADER_LENGTH); if (receivedData.Count < tcpMessageDataLength) { startTimestamp = DateTime.UtcNow; while (DateTime.UtcNow.Subtract(startTimestamp).TotalMilliseconds < timeout && receivedData.Count < tcpMessageDataLength) { Memory <byte> buffer = new byte[4096]; 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 OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - No Data was Received after TCP Header"); } if (receivedData.Count < tcpMessageDataLength) { throw new OmronException("Failed to Receive FINS Message within the Timeout Period from Omron PLC '" + RemoteHost + ":" + Port + "'"); } if (command == enTCPCommandCode.FINSFrame && receivedData[0] != 0xC0 && receivedData[0] != 0xC1) { throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - The FINS Header was Invalid"); } result.Message = receivedData.ToArray(); } catch (ObjectDisposedException) { throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "' - The underlying Socket Connection was Closed"); } catch (TimeoutException) { throw new OmronException("Failed to Receive FINS Message within the Timeout Period from Omron PLC '" + RemoteHost + ":" + Port + "'"); } catch (System.Net.Sockets.SocketException e) { throw new OmronException("Failed to Receive FINS Message from Omron PLC '" + RemoteHost + ":" + Port + "'", e); } return(result); }