diff --git a/S7.Net.UnitTest/S7NetTestsAsync.cs b/S7.Net.UnitTest/S7NetTestsAsync.cs index 48d9ae1..0adb91b 100644 --- a/S7.Net.UnitTest/S7NetTestsAsync.cs +++ b/S7.Net.UnitTest/S7NetTestsAsync.cs @@ -226,10 +226,8 @@ namespace S7.Net.UnitTest IntVariable111 = 201 }; plc.WriteStruct(tc, DB2); - Assert.AreEqual(ErrorCode.NoError, plc.LastErrorCode); // Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct TestLongStruct tc2 = (TestLongStruct)await plc.ReadStructAsync(typeof(TestLongStruct), DB2); - Assert.AreEqual(ErrorCode.NoError, plc.LastErrorCode); Assert.AreEqual(tc.IntVariable0, tc2.IntVariable0); Assert.AreEqual(tc.IntVariable1, tc2.IntVariable1); Assert.AreEqual(tc.IntVariable10, tc2.IntVariable10); @@ -292,11 +290,9 @@ namespace S7.Net.UnitTest IntVariable111 = 201 }; await plc.WriteClassAsync(tc, DB2); - Assert.AreEqual(ErrorCode.NoError, plc.LastErrorCode); // Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct TestLongClass tc2 = new TestLongClass(); await plc.ReadClassAsync(tc2, DB2); - Assert.AreEqual(ErrorCode.NoError, plc.LastErrorCode); Assert.AreEqual(tc.IntVariable0, tc2.IntVariable0); Assert.AreEqual(tc.IntVariable1, tc2.IntVariable1); Assert.AreEqual(tc.IntVariable10, tc2.IntVariable10); @@ -571,7 +567,7 @@ namespace S7.Net.UnitTest [TestMethod] [ExpectedException(typeof(NullReferenceException))] - public async Task Test_Async_ReadBytesThrowsExceptionIfPlcIsNotConnected() + public async Task Test_Async_ReadBytesReturnsNullIfPlcIsNotConnected() { using (var notConnectedPlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 0)) { @@ -831,11 +827,9 @@ namespace S7.Net.UnitTest { double test_value = 55.66; await plc.WriteAsync("DB1.DBD0", test_value); - Assert.AreEqual(plc.LastErrorCode, ErrorCode.NoError, "Write Double"); var helper = await plc.ReadAsync("DB1.DBD0"); double test_value2 = Conversion.ConvertToDouble((uint)helper); - Assert.AreEqual(plc.LastErrorCode, ErrorCode.NoError, "Read Double"); Assert.AreEqual(test_value, test_value2, 0.01, "Compare Write/Read"); //Need delta here because S7 only has 32 bit reals } @@ -844,11 +838,9 @@ namespace S7.Net.UnitTest { float test_value = 55.6632f; await plc.WriteAsync("DB1.DBD0", test_value); - Assert.AreEqual(plc.LastErrorCode, ErrorCode.NoError, "Write Single"); var helper = await plc.ReadAsync("DB1.DBD0"); float test_value2 = Conversion.ConvertToFloat((uint)helper); - Assert.AreEqual(plc.LastErrorCode, ErrorCode.NoError, "Read Single"); Assert.AreEqual(test_value, test_value2, "Compare Write/Read"); //No delta, datatype matches } diff --git a/S7.Net.UnitTest/S7NetTestsSync.cs b/S7.Net.UnitTest/S7NetTestsSync.cs index 151b1bd..a3b01c9 100644 --- a/S7.Net.UnitTest/S7NetTestsSync.cs +++ b/S7.Net.UnitTest/S7NetTestsSync.cs @@ -81,8 +81,14 @@ namespace S7.Net.UnitTest { if (plc.IsConnected == false) { - var error = plc.Open(); - Assert.AreEqual(ErrorCode.NoError, error, "If you have s7 installed you must close s7oiehsx64 service."); + try + { + plc.Open(); + } + catch (Exception e) + { + throw new Exception("If you have s7 installed you must close s7oiehsx64 service.", e); + } } } @@ -257,10 +263,8 @@ namespace S7.Net.UnitTest tc.IntVariable110 = 200; tc.IntVariable111 = 201; plc.WriteStruct(tc, DB2); - Assert.AreEqual(ErrorCode.NoError, plc.LastErrorCode); // Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct TestLongStruct tc2 = (TestLongStruct)plc.ReadStruct(typeof(TestLongStruct), DB2); - Assert.AreEqual(ErrorCode.NoError, plc.LastErrorCode); Assert.AreEqual(tc.IntVariable0, tc2.IntVariable0); Assert.AreEqual(tc.IntVariable1, tc2.IntVariable1); Assert.AreEqual(tc.IntVariable10, tc2.IntVariable10); @@ -321,11 +325,9 @@ namespace S7.Net.UnitTest tc.IntVariable110 = 200; tc.IntVariable111 = 201; plc.WriteClass(tc, DB2); - Assert.AreEqual(ErrorCode.NoError, plc.LastErrorCode); // Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct TestLongClass tc2 = new TestLongClass(); plc.ReadClass(tc2, DB2); - Assert.AreEqual(ErrorCode.NoError, plc.LastErrorCode); Assert.AreEqual(tc.IntVariable0, tc2.IntVariable0); Assert.AreEqual(tc.IntVariable1, tc2.IntVariable1); Assert.AreEqual(tc.IntVariable10, tc2.IntVariable10); @@ -596,19 +598,14 @@ namespace S7.Net.UnitTest } - [TestMethod] - public void T13_ReadBytesReturnsEmptyArrayIfPlcIsNotConnected() + [TestMethod, ExpectedException(typeof(PlcException))] + public void T13_ReadBytesThrowsIfPlcIsNotConnected() { using (var notConnectedPlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 0)) { Assert.IsFalse(notConnectedPlc.IsConnected); - - int expectedReadBytes = 0; // 0 bytes, because no connection was established - TestClass tc = new TestClass(); int actualReadBytes = notConnectedPlc.ReadClass(tc, DB2); - - Assert.AreEqual(expectedReadBytes, actualReadBytes); } } @@ -642,8 +639,8 @@ namespace S7.Net.UnitTest Assert.AreEqual(tc2.DWordVariable, tc2Generic.DWordVariable); } - [TestMethod] - public void T15_ReadClassWithGenericReturnsNullIfPlcIsNotConnected() + [TestMethod, ExpectedException(typeof(PlcException))] + public void T15_ReadClassWithGenericThrowsIfPlcIsNotConnected() { using (var notConnectedPlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 0)) { @@ -684,8 +681,8 @@ namespace S7.Net.UnitTest Assert.AreEqual(tc2Generic.DWordVariable, tc2GenericWithClassFactory.DWordVariable); } - [TestMethod] - public void T17_ReadClassWithGenericAndClassFactoryReturnsNullIfPlcIsNotConnected() + [TestMethod, ExpectedException(typeof(PlcException))] + public void T17_ReadClassWithGenericAndClassFactoryThrowsIfPlcIsNotConnected() { using (var notConnectedPlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 0)) { @@ -697,8 +694,8 @@ namespace S7.Net.UnitTest } } - [TestMethod] - public void T18_ReadStructReturnsNullIfPlcIsNotConnected() + [TestMethod, ExpectedException(typeof(PlcException))] + public void T18_ReadStructThrowsIfPlcIsNotConnected() { using (var notConnectedPlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 0)) { @@ -739,8 +736,8 @@ namespace S7.Net.UnitTest Assert.AreEqual(ts2.DWordVariable, ts2Generic.DWordVariable); } - [TestMethod] - public void T20_ReadStructWithGenericReturnsNullIfPlcIsNotConnected() + [TestMethod, ExpectedException(typeof(PlcException))] + public void T20_ReadStructThrowsIfPlcIsNotConnected() { using (var notConnectedPlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 0)) { @@ -883,11 +880,9 @@ namespace S7.Net.UnitTest { double test_value = 55.66; plc.Write("DB1.DBD0", test_value); - Assert.AreEqual(plc.LastErrorCode, ErrorCode.NoError, "Write Double"); var helper = plc.Read("DB1.DBD0"); double test_value2 = Conversion.ConvertToDouble((uint)helper); - Assert.AreEqual(plc.LastErrorCode, ErrorCode.NoError, "Read Double"); Assert.AreEqual(test_value, test_value2, 0.01, "Compare Write/Read"); //Need delta here because S7 only has 32 bit reals } @@ -929,19 +924,17 @@ namespace S7.Net.UnitTest Assert.AreEqual(tc.Bool1, tc2.Bool1); } - [TestMethod] - public void T29_Read_Write_ExceptionHandlingWhenPlcIsNotReachable() + [TestMethod, ExpectedException(typeof(PlcException))] + public void T29_Read_Write_ThrowsWhenPlcIsNotReachable() { // leave plc Open S7TestServer.Stop(); double test_value = 55.66; plc.Write("DB1.DBD0", test_value); - Assert.AreEqual(plc.LastErrorCode, ErrorCode.WriteData, "No Write Error."); var helper = plc.Read("DB1.DBD0"); Assert.AreEqual(helper, null, "Value in Read."); - Assert.AreEqual(plc.LastErrorCode, ErrorCode.ReadData, "No Read Error."); } [TestMethod] @@ -949,11 +942,9 @@ namespace S7.Net.UnitTest { float test_value = 55.6632f; plc.Write("DB1.DBD0", test_value); - Assert.AreEqual(plc.LastErrorCode, ErrorCode.NoError, "Write Single"); var helper = plc.Read("DB1.DBD0"); float test_value2 = Conversion.ConvertToFloat((uint)helper); - Assert.AreEqual(plc.LastErrorCode, ErrorCode.NoError, "Read Single"); Assert.AreEqual(test_value, test_value2, "Compare Write/Read"); //No delta, datatype matches } diff --git a/S7.Net/PLC.cs b/S7.Net/PLC.cs index 80cefba..284b81b 100644 --- a/S7.Net/PLC.cs +++ b/S7.Net/PLC.cs @@ -48,7 +48,15 @@ namespace S7.Net //TODO: Fix This get { - return Connect() == ErrorCode.NoError; + try + { + Connect(); + return true; + } + catch + { + return false; + } } } @@ -72,16 +80,6 @@ namespace S7.Net catch { return false; } } } - - /// - /// Contains the last error registered when executing a function - /// - public string LastErrorString { get; private set; } - - /// - /// Contains the last error code registered when executing a function - /// - public ErrorCode LastErrorCode { get; private set; } /// /// Creates a PLC object with all the parameters needed for connections. diff --git a/S7.Net/PLCHelpers.cs b/S7.Net/PLCHelpers.cs index 2136b36..6f772a7 100644 --- a/S7.Net/PLCHelpers.cs +++ b/S7.Net/PLCHelpers.cs @@ -312,15 +312,6 @@ namespace S7.Net } } - /// - /// Sets the to and to . - /// - public void ClearLastError() - { - LastErrorCode = ErrorCode.NoError; - LastErrorString = string.Empty; - } - /// /// Given a S7 (Bool, Word, DWord, etc.), it returns how many bytes to read. /// @@ -367,7 +358,7 @@ namespace S7.Net { // check for Return Code = Success if (s7data[offset] != 0xff) - throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString()); + throw new PlcException(ErrorCode.WrongNumberReceivedBytes); // to Data bytes offset += 4; diff --git a/S7.Net/PlcAsynchronous.cs b/S7.Net/PlcAsynchronous.cs index c829963..cde83b8 100644 --- a/S7.Net/PlcAsynchronous.cs +++ b/S7.Net/PlcAsynchronous.cs @@ -14,10 +14,9 @@ namespace S7.Net public partial class Plc { /// - /// Open a and connects to the PLC, sending all the corrected package - /// and returning if the connection was successful () of it was wrong. + /// Connects to the PLC and performs a COTP ConnectionRequest and S7 CommunicationSetup. /// - /// Returns ErrorCode.NoError if the connection was successful, otherwise check the ErrorCode + /// A task that represents the asynchronous open operation. public async Task OpenAsync() { await ConnectAsync(); @@ -227,19 +226,17 @@ namespace S7.Net var s7data = await COTP.TSDU.ReadAsync(stream); //TODO use Async if (s7data == null || s7data[14] != 0xff) - throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString()); + throw new PlcException(ErrorCode.WrongNumberReceivedBytes); ParseDataIntoDataItems(s7data, dataItems); } catch (SocketException socketException) { - LastErrorCode = ErrorCode.ReadData; - LastErrorString = socketException.Message; + throw new PlcException(ErrorCode.ReadData, socketException); } catch (Exception exc) { - LastErrorCode = ErrorCode.ReadData; - LastErrorString = exc.Message; + throw new PlcException(ErrorCode.ReadData, exc); } return dataItems; } @@ -252,8 +249,8 @@ namespace S7.Net /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. /// Start byte address. If you want to write DB1.DBW200, this is 200. /// Bytes to write. If more than 200, multiple requests will be made. - /// NoError if it was successful, or the error is specified - public async Task WriteBytesAsync(DataType dataType, int db, int startByteAdr, byte[] value) + /// A task that represents the asynchronous write operation. + public async Task WriteBytesAsync(DataType dataType, int db, int startByteAdr, byte[] value) { int localIndex = 0; int count = value.Length; @@ -263,15 +260,10 @@ namespace S7.Net //Snap7 seems to choke on PDU sizes above 256 even if snap7 //replies with bigger PDU size in connection setup. var maxToWrite = (int)Math.Min(count, 200); - ErrorCode lastError = await WriteBytesWithASingleRequestAsync(dataType, db, startByteAdr + localIndex, value.Skip(localIndex).Take(maxToWrite).ToArray()); - if (lastError != ErrorCode.NoError) - { - return lastError; - } + await WriteBytesWithASingleRequestAsync(dataType, db, startByteAdr + localIndex, value.Skip(localIndex).Take(maxToWrite).ToArray()); count -= maxToWrite; localIndex += maxToWrite; } - return ErrorCode.NoError; } /// @@ -282,19 +274,13 @@ namespace S7.Net /// Start byte address. If you want to write DB1.DBW200, this is 200. /// The address of the bit. (0-7) /// Bytes to write. If more than 200, multiple requests will be made. - /// NoError if it was successful, or the error is specified - public async Task WriteBitAsync(DataType dataType, int db, int startByteAdr, int bitAdr, bool value) + /// A task that represents the asynchronous write operation. + public async Task WriteBitAsync(DataType dataType, int db, int startByteAdr, int bitAdr, bool value) { if (bitAdr < 0 || bitAdr > 7) throw new InvalidAddressException(string.Format("Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", bitAdr)); - ErrorCode lastError = await WriteBitWithASingleRequestAsync(dataType, db, startByteAdr, bitAdr, value); - if (lastError != ErrorCode.NoError) - { - return lastError; - } - - return ErrorCode.NoError; + await WriteBitWithASingleRequestAsync(dataType, db, startByteAdr, bitAdr, value); } /// @@ -305,13 +291,13 @@ namespace S7.Net /// Start byte address. If you want to write DB1.DBW200, this is 200. /// The address of the bit. (0-7) /// Bytes to write. If more than 200, multiple requests will be made. - /// NoError if it was successful, or the error is specified - public async Task WriteBitAsync(DataType dataType, int db, int startByteAdr, int bitAdr, int value) + /// A task that represents the asynchronous write operation. + public async Task WriteBitAsync(DataType dataType, int db, int startByteAdr, int bitAdr, int value) { if (value < 0 || value > 1) throw new ArgumentException("Value must be 0 or 1", nameof(value)); - return await WriteBitAsync(dataType, db, startByteAdr, bitAdr, value == 1); + await WriteBitAsync(dataType, db, startByteAdr, bitAdr, value == 1); } /// @@ -324,26 +310,29 @@ namespace S7.Net /// Start byte address. If you want to read DB1.DBW200, this is 200. /// Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion. /// The address of the bit. (0-7) - /// NoError if it was successful, or the error is specified - public async Task WriteAsync(DataType dataType, int db, int startByteAdr, object value, int bitAdr = -1) + /// A task that represents the asynchronous write operation. + public async Task WriteAsync(DataType dataType, int db, int startByteAdr, object value, int bitAdr = -1) { if (bitAdr != -1) { //Must be writing a bit value as bitAdr is specified if (value is bool) { - return await WriteBitAsync(dataType, db, startByteAdr, bitAdr, (bool)value); + await WriteBitAsync(dataType, db, startByteAdr, bitAdr, (bool) value); } else if (value is int intValue) { if (intValue < 0 || intValue > 7) - throw new ArgumentOutOfRangeException(string.Format("Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", bitAdr), nameof(bitAdr)); + throw new ArgumentOutOfRangeException( + string.Format( + "Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", + bitAdr), nameof(bitAdr)); - return await WriteBitAsync(dataType, db, startByteAdr, bitAdr, intValue == 1); + await WriteBitAsync(dataType, db, startByteAdr, bitAdr, intValue == 1); } - throw new ArgumentException("Value must be a bool or an int to write a bit", nameof(value)); + else throw new ArgumentException("Value must be a bool or an int to write a bit", nameof(value)); } - return await WriteBytesAsync(dataType, db, startByteAdr, Serialization.SerializeValue(value)); + else await WriteBytesAsync(dataType, db, startByteAdr, Serialization.SerializeValue(value)); } /// @@ -352,11 +341,11 @@ namespace S7.Net /// /// Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc. /// Value to be written to the PLC - /// NoError if it was successful, or the error is specified - public async Task WriteAsync(string variable, object value) + /// A task that represents the asynchronous write operation. + public async Task WriteAsync(string variable, object value) { var adr = new PLCAddress(variable); - return await WriteAsync(adr.dataType, adr.DBNumber, adr.Address, value, adr.BitNumber); + await WriteAsync(adr.dataType, adr.DBNumber, adr.Address, value, adr.BitNumber); } /// @@ -365,12 +354,11 @@ namespace S7.Net /// The struct to be written /// Db address /// Start bytes on the PLC - /// NoError if it was successful, or the error is specified - public async Task WriteStructAsync(object structValue, int db, int startByteAdr = 0) + /// A task that represents the asynchronous write operation. + public async Task WriteStructAsync(object structValue, int db, int startByteAdr = 0) { var bytes = Struct.ToBytes(structValue).ToList(); - var errCode = await WriteBytesAsync(DataType.DataBlock, db, startByteAdr, bytes.ToArray()); - return errCode; + await WriteBytesAsync(DataType.DataBlock, db, startByteAdr, bytes.ToArray()); } /// @@ -379,12 +367,11 @@ namespace S7.Net /// The class to be written /// Db address /// Start bytes on the PLC - /// NoError if it was successful, or the error is specified - public async Task WriteClassAsync(object classValue, int db, int startByteAdr = 0) + /// A task that represents the asynchronous write operation. + public async Task WriteClassAsync(object classValue, int db, int startByteAdr = 0) { var bytes = Types.Class.ToBytes(classValue).ToList(); - var errCode = await WriteBytesAsync(DataType.DataBlock, db, startByteAdr, bytes.ToArray()); - return errCode; + await WriteBytesAsync(DataType.DataBlock, db, startByteAdr, bytes.ToArray()); } private async Task ReadBytesWithSingleRequestAsync(DataType dataType, int db, int startByteAdr, int count) @@ -402,7 +389,7 @@ namespace S7.Net var s7data = await COTP.TSDU.ReadAsync(stream); if (s7data == null || s7data[14] != 0xff) - throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString()); + throw new PlcException(ErrorCode.WrongNumberReceivedBytes); for (int cnt = 0; cnt < count; cnt++) bytes[cnt] = s7data[cnt + 18]; @@ -427,15 +414,14 @@ namespace S7.Net } /// - /// Writes up to 200 bytes to the PLC and returns NoError if successful. You must specify the memory area type, memory are address, byte start address and bytes count. - /// If the write was not successful, check LastErrorCode or LastErrorString. + /// Writes up to 200 bytes to the PLC. You must specify the memory area type, memory are address, byte start address and bytes count. /// /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. /// Start byte address. If you want to read DB1.DBW200, this is 200. /// Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion. - /// NoError if it was successful, or the error is specified - private async Task WriteBytesWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] value) + /// A task that represents the asynchronous write operation. + private async Task WriteBytesWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] value) { byte[] bReceive = new byte[513]; int varCount = 0; @@ -471,27 +457,23 @@ namespace S7.Net var s7data = await COTP.TSDU.ReadAsync(stream); if (s7data == null || s7data[14] != 0xff) { - throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString()); + throw new PlcException(ErrorCode.WrongNumberReceivedBytes); } - - return ErrorCode.NoError; } catch (Exception exc) { - LastErrorCode = ErrorCode.WriteData; - LastErrorString = exc.Message; - return LastErrorCode; + throw new PlcException(ErrorCode.WriteData, exc); } } - private async Task WriteBitWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue) + private async Task WriteBitWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue) { byte[] bReceive = new byte[513]; int varCount = 0; try { - var value = new[] { bitValue ? (byte)1 : (byte)0 }; + var value = new[] {bitValue ? (byte) 1 : (byte) 0}; varCount = value.Length; // first create the header int packageSize = 35 + value.Length; @@ -520,15 +502,11 @@ namespace S7.Net var s7data = await COTP.TSDU.ReadAsync(stream); if (s7data == null || s7data[14] != 0xff) - throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString()); - - return ErrorCode.NoError; + throw new PlcException(ErrorCode.WrongNumberReceivedBytes); } catch (Exception exc) { - LastErrorCode = ErrorCode.WriteData; - LastErrorString = exc.Message; - return LastErrorCode; + throw new PlcException(ErrorCode.WriteData, exc); } } } diff --git a/S7.Net/PlcException.cs b/S7.Net/PlcException.cs new file mode 100644 index 0000000..772060b --- /dev/null +++ b/S7.Net/PlcException.cs @@ -0,0 +1,39 @@ +using System; + +namespace S7.Net +{ + #if NET_FULL + [Serializable] + #endif + public class PlcException : Exception + { + public ErrorCode ErrorCode { get; } + + public PlcException(ErrorCode errorCode) : this(errorCode, $"PLC communication failed with error '{errorCode}'.") + { + } + + public PlcException(ErrorCode errorCode, Exception innerException) : this(errorCode, innerException.Message, + innerException) + { + } + + public PlcException(ErrorCode errorCode, string message) : base(message) + { + ErrorCode = errorCode; + } + + public PlcException(ErrorCode errorCode, string message, Exception inner) : base(message, inner) + { + ErrorCode = errorCode; + } + + #if NET_FULL + protected PlcException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) + { + ErrorCode = (ErrorCode) info.GetInt32(nameof(ErrorCode)); + } + #endif + } +} \ No newline at end of file diff --git a/S7.Net/PlcSynchronous.cs b/S7.Net/PlcSynchronous.cs index 8f1b5bc..35847a5 100644 --- a/S7.Net/PlcSynchronous.cs +++ b/S7.Net/PlcSynchronous.cs @@ -11,16 +11,12 @@ namespace S7.Net public partial class Plc { /// - /// Open a and connects to the PLC, sending all the corrected package - /// and returning if the connection was successful () of it was wrong. + /// Connects to the PLC and performs a COTP ConnectionRequest and S7 CommunicationSetup. /// - /// Returns ErrorCode.NoError if the connection was successful, otherwise check the ErrorCode - public ErrorCode Open() + public void Open() { - if (Connect() != ErrorCode.NoError) - { - return LastErrorCode; - } + Connect(); + try { stream.Write(ConnectionRequest.GetCOTPConnectionRequest(CPU, Rack, Slot), 0, 22); @@ -41,14 +37,12 @@ namespace S7.Net } catch (Exception exc) { - LastErrorCode = ErrorCode.ConnectionError; - LastErrorString = string.Format("Couldn't establish the connection to {0}.\nMessage: {1}", IP, exc.Message); - return ErrorCode.ConnectionError; + throw new PlcException(ErrorCode.ConnectionError, + $"Couldn't establish the connection to {IP}.\nMessage: {exc.Message}", exc); } - return ErrorCode.NoError; } - private ErrorCode Connect() + private void Connect() { try { @@ -59,23 +53,15 @@ namespace S7.Net catch (SocketException sex) { // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx - if (sex.SocketErrorCode == SocketError.TimedOut) - { - LastErrorCode = ErrorCode.IPAddressNotAvailable; - } - else - { - LastErrorCode = ErrorCode.ConnectionError; - } - - LastErrorString = sex.Message; + throw new PlcException( + sex.SocketErrorCode == SocketError.TimedOut + ? ErrorCode.IPAddressNotAvailable + : ErrorCode.ConnectionError, sex); } catch (Exception ex) { - LastErrorCode = ErrorCode.ConnectionError; - LastErrorString = ex.Message; + throw new PlcException(ErrorCode.ConnectionError, ex); } - return LastErrorCode; } /// @@ -231,8 +217,7 @@ namespace S7.Net /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. /// Start byte address. If you want to write DB1.DBW200, this is 200. /// Bytes to write. If more than 200, multiple requests will be made. - /// NoError if it was successful, or the error is specified - public ErrorCode WriteBytes(DataType dataType, int db, int startByteAdr, byte[] value) + public void WriteBytes(DataType dataType, int db, int startByteAdr, byte[] value) { int localIndex = 0; int count = value.Length; @@ -241,16 +226,11 @@ namespace S7.Net //TODO: Figure out how to use MaxPDUSize here //Snap7 seems to choke on PDU sizes above 256 even if snap7 //replies with bigger PDU size in connection setup. - var maxToWrite = (int)Math.Min(count, 200); - ErrorCode lastError = WriteBytesWithASingleRequest(dataType, db, startByteAdr + localIndex, value.Skip(localIndex).Take(maxToWrite).ToArray()); - if (lastError != ErrorCode.NoError) - { - return lastError; - } + var maxToWrite = Math.Min(count, 200); + WriteBytesWithASingleRequest(dataType, db, startByteAdr + localIndex, value.Skip(localIndex).Take(maxToWrite).ToArray()); count -= maxToWrite; localIndex += maxToWrite; } - return ErrorCode.NoError; } /// @@ -261,36 +241,28 @@ namespace S7.Net /// Start byte address. If you want to write DB1.DBW200, this is 200. /// The address of the bit. (0-7) /// Bytes to write. If more than 200, multiple requests will be made. - /// NoError if it was successful, or the error is specified - public ErrorCode WriteBit(DataType dataType, int db, int startByteAdr, int bitAdr, bool value) + public void WriteBit(DataType dataType, int db, int startByteAdr, int bitAdr, bool value) { if (bitAdr < 0 || bitAdr > 7) throw new InvalidAddressException(string.Format("Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", bitAdr)); - ErrorCode lastError = WriteBitWithASingleRequest(dataType, db, startByteAdr, bitAdr, value); - if (lastError != ErrorCode.NoError) - { - return lastError; - } - - return ErrorCode.NoError; + WriteBitWithASingleRequest(dataType, db, startByteAdr, bitAdr, value); } /// - /// Write a single bit from a DB with the specified index. + /// Write a single bit to a DB with the specified index. /// /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. - /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. + /// Address of the memory area (if you want to write DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. /// Start byte address. If you want to write DB1.DBW200, this is 200. /// The address of the bit. (0-7) - /// Bytes to write. If more than 200, multiple requests will be made. - /// NoError if it was successful, or the error is specified - public ErrorCode WriteBit(DataType dataType, int db, int startByteAdr, int bitAdr, int value) + /// Value to write (0 or 1). + public void WriteBit(DataType dataType, int db, int startByteAdr, int bitAdr, int value) { if (value < 0 || value > 1) throw new ArgumentException("Value must be 0 or 1", nameof(value)); - return WriteBit(dataType, db, startByteAdr, bitAdr, value == 1); + WriteBit(dataType, db, startByteAdr, bitAdr, value == 1); } /// @@ -303,26 +275,29 @@ namespace S7.Net /// Start byte address. If you want to read DB1.DBW200, this is 200. /// Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion. /// The address of the bit. (0-7) - /// NoError if it was successful, or the error is specified - public ErrorCode Write(DataType dataType, int db, int startByteAdr, object value, int bitAdr = -1) + public void Write(DataType dataType, int db, int startByteAdr, object value, int bitAdr = -1) { if (bitAdr != -1) { //Must be writing a bit value as bitAdr is specified if (value is bool) { - return WriteBit(dataType, db, startByteAdr, bitAdr, (bool)value); + WriteBit(dataType, db, startByteAdr, bitAdr, (bool) value); } else if (value is int intValue) { if (intValue < 0 || intValue > 7) - throw new ArgumentOutOfRangeException(string.Format("Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", bitAdr), nameof(bitAdr)); + throw new ArgumentOutOfRangeException( + string.Format( + "Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", + bitAdr), nameof(bitAdr)); - return WriteBit(dataType, db, startByteAdr, bitAdr, intValue == 1); + WriteBit(dataType, db, startByteAdr, bitAdr, intValue == 1); } - throw new ArgumentException("Value must be a bool or an int to write a bit", nameof(value)); + else + throw new ArgumentException("Value must be a bool or an int to write a bit", nameof(value)); } - return WriteBytes(dataType, db, startByteAdr, Serialization.SerializeValue(value)); + else WriteBytes(dataType, db, startByteAdr, Serialization.SerializeValue(value)); } /// @@ -331,11 +306,10 @@ namespace S7.Net /// /// Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc. /// Value to be written to the PLC - /// NoError if it was successful, or the error is specified - public ErrorCode Write(string variable, object value) + public void Write(string variable, object value) { var adr = new PLCAddress(variable); - return Write(adr.dataType, adr.DBNumber, adr.Address, value, adr.BitNumber); + Write(adr.dataType, adr.DBNumber, adr.Address, value, adr.BitNumber); } /// @@ -344,10 +318,9 @@ namespace S7.Net /// The struct to be written /// Db address /// Start bytes on the PLC - /// NoError if it was successful, or the error is specified - public ErrorCode WriteStruct(object structValue, int db, int startByteAdr = 0) + public void WriteStruct(object structValue, int db, int startByteAdr = 0) { - return WriteStructAsync(structValue, db, startByteAdr).Result; + WriteStructAsync(structValue, db, startByteAdr).GetAwaiter().GetResult(); } /// @@ -356,10 +329,9 @@ namespace S7.Net /// The class to be written /// Db address /// Start bytes on the PLC - /// NoError if it was successful, or the error is specified - public ErrorCode WriteClass(object classValue, int db, int startByteAdr = 0) + public void WriteClass(object classValue, int db, int startByteAdr = 0) { - return WriteClassAsync(classValue, db, startByteAdr).Result; + WriteClassAsync(classValue, db, startByteAdr).GetAwaiter().GetResult(); } private byte[] ReadBytesWithSingleRequest(DataType dataType, int db, int startByteAdr, int count) @@ -378,24 +350,16 @@ namespace S7.Net var s7data = COTP.TSDU.Read(stream); if (s7data == null || s7data[14] != 0xff) - throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString()); + throw new PlcException(ErrorCode.WrongNumberReceivedBytes); for (int cnt = 0; cnt < count; cnt++) bytes[cnt] = s7data[cnt + 18]; return bytes; } - catch (SocketException socketException) - { - LastErrorCode = ErrorCode.ReadData; - LastErrorString = socketException.Message; - return null; - } catch (Exception exc) { - LastErrorCode = ErrorCode.ReadData; - LastErrorString = exc.Message; - return null; + throw new PlcException(ErrorCode.ReadData, exc); } } @@ -414,7 +378,7 @@ namespace S7.Net S7WriteMultiple.ParseResponse(response, response.Length, dataItems); } - private ErrorCode WriteBytesWithASingleRequest(DataType dataType, int db, int startByteAdr, byte[] value) + private void WriteBytesWithASingleRequest(DataType dataType, int db, int startByteAdr, byte[] value) { int varCount = 0; try @@ -448,26 +412,22 @@ namespace S7.Net var s7data = COTP.TSDU.Read(stream); if (s7data == null || s7data[14] != 0xff) { - throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString()); + throw new PlcException(ErrorCode.WrongNumberReceivedBytes); } - - return ErrorCode.NoError; } catch (Exception exc) { - LastErrorCode = ErrorCode.WriteData; - LastErrorString = exc.Message; - return LastErrorCode; + throw new PlcException(ErrorCode.WriteData, exc); } } - private ErrorCode WriteBitWithASingleRequest(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue) + private void WriteBitWithASingleRequest(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue) { int varCount = 0; try { - var value = new[] { bitValue ? (byte)1 : (byte)0 }; + var value = new[] {bitValue ? (byte) 1 : (byte) 0}; varCount = value.Length; // first create the header int packageSize = 35 + value.Length; @@ -496,15 +456,11 @@ namespace S7.Net var s7data = COTP.TSDU.Read(stream); if (s7data == null || s7data[14] != 0xff) - throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString()); - - return ErrorCode.NoError; + throw new PlcException(ErrorCode.WrongNumberReceivedBytes); } catch (Exception exc) { - LastErrorCode = ErrorCode.WriteData; - LastErrorString = exc.Message; - return LastErrorCode; + throw new PlcException(ErrorCode.WriteData, exc); } } @@ -531,7 +487,7 @@ namespace S7.Net { // first create the header int packageSize = 19 + (dataItems.Count * 12); - Types.ByteArray package = new ByteArray(packageSize); + ByteArray package = new ByteArray(packageSize); package.Add(ReadHeaderPackage(dataItems.Count)); // package.Add(0x02); // datenart foreach (var dataItem in dataItems) @@ -543,19 +499,13 @@ namespace S7.Net var s7data = COTP.TSDU.Read(stream); //TODO use Async if (s7data == null || s7data[14] != 0xff) - throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString()); + throw new PlcException(ErrorCode.WrongNumberReceivedBytes); ParseDataIntoDataItems(s7data, dataItems); } - catch (SocketException socketException) - { - LastErrorCode = ErrorCode.ReadData; - LastErrorString = socketException.Message; - } catch (Exception exc) { - LastErrorCode = ErrorCode.ReadData; - LastErrorString = exc.Message; + throw new PlcException(ErrorCode.ReadData, exc); } } }