Skip to content

Commit

Permalink
Add more extensive response code validation.
Browse files Browse the repository at this point in the history
  • Loading branch information
scamille committed Sep 16, 2020
1 parent 36a9ecb commit 1069641
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 27 deletions.
28 changes: 28 additions & 0 deletions S7.Net.UnitTest/ProtocolTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

using System.IO;
using System.Threading.Tasks;
using S7.Net.Protocol;
using System.Collections;

namespace S7.Net.UnitTest
{
Expand Down Expand Up @@ -64,6 +66,32 @@ public static byte[] StringToByteArray(string hex)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}


[TestMethod]
public void TestResponseCode()
{
var expected = StringToByteArray("320700000400000800080001120411440100ff09000400000000");
var m = new MemoryStream(StringToByteArray("0300000702f0000300000702f0000300002102f080320700000400000800080001120411440100ff09000400000000"));
var t = COTP.TSDU.Read(m);
Assert.IsTrue(expected.SequenceEqual(t));


// Test all possible byte values. Everything except 0xff should throw an exception.
var testData = Enumerable.Range(0, 256).Select(i => new { StatusCode = (ReadWriteErrorCode)i, ThrowsException = i != (byte)ReadWriteErrorCode.Success });

foreach (var entry in testData)
{
if (entry.ThrowsException)
{
Assert.ThrowsException<Exception>(() => Plc.ValidateResponseCode(entry.StatusCode));
}
else
{
Plc.ValidateResponseCode(entry.StatusCode);
}
}
}
}

}
28 changes: 25 additions & 3 deletions S7.Net/PLC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using S7.Net.Protocol;
using S7.Net.Types;


Expand Down Expand Up @@ -234,13 +235,34 @@ PlcException NotEnoughBytes() =>

if (s7Data.Length < 15) throw NotEnoughBytes();

if (s7Data[14] != 0xff)
throw new PlcException(ErrorCode.ReadData,
$"Invalid response from PLC: '{BitConverter.ToString(s7Data)}'.");
ValidateResponseCode((ReadWriteErrorCode)s7Data[14]);

if (s7Data.Length < expectedLength) throw NotEnoughBytes();
}

internal static void ValidateResponseCode(ReadWriteErrorCode statusCode)
{
switch (statusCode)
{
case ReadWriteErrorCode.ObjectDoesNotExist:
throw new Exception($"Received error from PLC: Object does not exist.");
case ReadWriteErrorCode.DataTypeInconsistent:
throw new Exception($"Received error from PLC: Data type inconsistent.");
case ReadWriteErrorCode.DataTypeNotSupported:
throw new Exception($"Received error from PLC: Data type not supported.");
case ReadWriteErrorCode.AccessingObjectNotAllowed:
throw new Exception($"Received error from PLC: Accessing object not allowed.");
case ReadWriteErrorCode.AddressOutOfRange:
throw new Exception($"Received error from PLC: Address out of range.");
case ReadWriteErrorCode.HardwareFault:
throw new Exception($"Received error from PLC: Hardware fault.");
case ReadWriteErrorCode.Success:
break;
default:
throw new Exception( $"Invalid response from PLC: statusCode={(byte)statusCode}.");
}
}

#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls

Expand Down
13 changes: 3 additions & 10 deletions S7.Net/PlcAsynchronous.cs
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,7 @@ public async Task<List<DataItem>> ReadMultipleVarsAsync(List<DataItem> dataItems
await stream.WriteAsync(dataToSend, 0, dataToSend.Length);

var s7data = await COTP.TSDU.ReadAsync(stream, cancellationToken); //TODO use Async
if (s7data == null || s7data[14] != 0xff)
throw new PlcException(ErrorCode.WrongNumberReceivedBytes);
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);

ParseDataIntoDataItems(s7data, dataItems);
}
Expand Down Expand Up @@ -483,10 +482,7 @@ private async Task WriteBytesWithASingleRequestAsync(DataType dataType, int db,
await stream.WriteAsync(dataToSend, 0, dataToSend.Length, cancellationToken);

var s7data = await COTP.TSDU.ReadAsync(stream, cancellationToken);
if (s7data == null || s7data[14] != 0xff)
{
throw new PlcException(ErrorCode.WrongNumberReceivedBytes);
}
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
}
catch (OperationCanceledException)
{
Expand All @@ -509,10 +505,7 @@ private async Task WriteBitWithASingleRequestAsync(DataType dataType, int db, in
await stream.WriteAsync(dataToSend, 0, dataToSend.Length);

var s7data = await COTP.TSDU.ReadAsync(stream, cancellationToken);
if (s7data == null || s7data[14] != 0xff)
{
throw new PlcException(ErrorCode.WrongNumberReceivedBytes);
}
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
}
catch (OperationCanceledException)
{
Expand Down
14 changes: 4 additions & 10 deletions S7.Net/PlcSynchronous.cs
Original file line number Diff line number Diff line change
Expand Up @@ -398,10 +398,7 @@ private void WriteBytesWithASingleRequest(DataType dataType, int db, int startBy
stream.Write(dataToSend, 0, dataToSend.Length);

var s7data = COTP.TSDU.Read(stream);
if (s7data == null || s7data[14] != 0xff)
{
throw new PlcException(ErrorCode.WrongNumberReceivedBytes);
}
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
}
catch (Exception exc)
{
Expand Down Expand Up @@ -483,10 +480,7 @@ private void WriteBitWithASingleRequest(DataType dataType, int db, int startByte
stream.Write(dataToSend, 0, dataToSend.Length);

var s7data = COTP.TSDU.Read(stream);
if (s7data == null || s7data[14] != 0xff)
{
throw new PlcException(ErrorCode.WrongNumberReceivedBytes);
}
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
}
catch (Exception exc)
{
Expand Down Expand Up @@ -524,8 +518,8 @@ public void ReadMultipleVars(List<DataItem> dataItems)
stream.Write(dataToSend, 0, dataToSend.Length);

var s7data = COTP.TSDU.Read(stream); //TODO use Async
if (s7data == null || s7data[14] != 0xff)
throw new PlcException(ErrorCode.WrongNumberReceivedBytes);

ValidateResponseCode((ReadWriteErrorCode)s7data[14]);

ParseDataIntoDataItems(s7data, dataItems);
}
Expand Down
15 changes: 15 additions & 0 deletions S7.Net/Protocol/ReadWriteErrorCode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

namespace S7.Net.Protocol
{
internal enum ReadWriteErrorCode : byte
{
Reserved = 0x00,
HardwareFault = 0x01,
AccessingObjectNotAllowed = 0x03,
AddressOutOfRange = 0x05,
DataTypeNotSupported = 0x06,
DataTypeInconsistent = 0x07,
ObjectDoesNotExist = 0x0a,
Success = 0xff
}
}
13 changes: 9 additions & 4 deletions S7.Net/Protocol/S7WriteMultiple.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,16 @@ public static void ParseResponse(byte[] message, int length, DataItem[] dataItem

for (int i = 0; i < dataItems.Length; i++)
{
var result = itemResults[i];
if (result == 0xff) continue;
try
{
Plc.ValidateResponseCode((ReadWriteErrorCode)itemResults[i]);
}
catch(Exception e)
{
if (errors == null) errors = new List<Exception>();
errors.Add(new Exception($"Write of dataItem {dataItems[i]} failed: {e.Message}."));
}

if (errors == null) errors = new List<Exception>();
errors.Add(new Exception($"Write of dataItem {dataItems[i]} failed with error code {result}."));
}

if (errors != null)
Expand Down

0 comments on commit 1069641

Please sign in to comment.