diff --git a/S7.Net.Common/Conversion.cs b/S7.Net.Common/Conversion.cs
index 0b8b00d..360e282 100644
--- a/S7.Net.Common/Conversion.cs
+++ b/S7.Net.Common/Conversion.cs
@@ -5,6 +5,11 @@ namespace S7.Net
{
public static class Conversion
{
+ ///
+ /// Converts a binary string to Int32 value
+ ///
+ ///
+ ///
public static int BinStringToInt32(this string txt)
{
int cnt = 0;
@@ -39,6 +44,11 @@ namespace S7.Net
return null;
}
+ ///
+ /// Converts the value to a binary string
+ ///
+ ///
+ ///
public static string ValToBinString(this object value)
{
int cnt = 0;
@@ -135,6 +145,13 @@ namespace S7.Net
}
}
+ ///
+ /// Helper to get a bit value given a byte and the bit index.
+ /// Example: DB1.DBX0.5 -> var bytes = ReadBytes(DB1.DBW0); bool bit = bytes[0].SelectBit(5);
+ ///
+ ///
+ ///
+ ///
public static bool SelectBit(this byte data, int bitPosition)
{
int mask = 1 << bitPosition;
diff --git a/S7.Net.UnitTest/ConvertersUnitTest.cs b/S7.Net.UnitTest/ConvertersUnitTest.cs
new file mode 100644
index 0000000..abbe4ac
--- /dev/null
+++ b/S7.Net.UnitTest/ConvertersUnitTest.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using S7.Net;
+
+namespace S7.Net.UnitTest
+{
+ [TestClass]
+ public class ConvertersUnitTest
+ {
+ [TestMethod]
+ public void T00_TestSelectBit()
+ {
+ byte dummyByte = 5; // 0000 0101
+ Assert.IsTrue(dummyByte.SelectBit(0));
+ Assert.IsFalse(dummyByte.SelectBit(1));
+ Assert.IsTrue(dummyByte.SelectBit(2));
+ Assert.IsFalse(dummyByte.SelectBit(3));
+ Assert.IsFalse(dummyByte.SelectBit(4));
+ Assert.IsFalse(dummyByte.SelectBit(5));
+ Assert.IsFalse(dummyByte.SelectBit(6));
+ Assert.IsFalse(dummyByte.SelectBit(7));
+
+ }
+ }
+}
diff --git a/S7.Net.UnitTest/S7.Net.UnitTest.csproj b/S7.Net.UnitTest/S7.Net.UnitTest.csproj
index e148f86..025cc39 100644
--- a/S7.Net.UnitTest/S7.Net.UnitTest.csproj
+++ b/S7.Net.UnitTest/S7.Net.UnitTest.csproj
@@ -52,6 +52,7 @@
+
diff --git a/S7.Net/PLC.cs b/S7.Net/PLC.cs
index 27be3e2..f3037db 100644
--- a/S7.Net/PLC.cs
+++ b/S7.Net/PLC.cs
@@ -237,41 +237,6 @@ namespace S7.Net
}
}
- private Types.ByteArray ReadDataRequestPackage(DataType dataType, int DB, int startByteAdr, int count = 1)
- {
- //single data req = 12
- var package = new Types.ByteArray(12);
- package.Add(new byte[] {0x12, 0x0a, 0x10});
- switch (dataType)
- {
- case DataType.Timer:
- case DataType.Counter:
- package.Add((byte)dataType);
- break;
- default:
- package.Add(0x02);
- break;
- }
-
- package.Add(Types.Word.ToByteArray((ushort)(count)));
- package.Add(Types.Word.ToByteArray((ushort)(DB)));
- package.Add((byte)dataType);
- var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
- package.Add((byte)overflow);
- switch (dataType)
- {
- case DataType.Timer:
- case DataType.Counter:
- package.Add(Types.Word.ToByteArray((ushort)(startByteAdr)));
- break;
- default:
- package.Add(Types.Word.ToByteArray((ushort)((startByteAdr) * 8)));
- break;
- }
-
- return package;
- }
-
///
/// Reads multiple vars in a single request.
/// You have to create and pass a list of DataItems and you obtain in response the same list with the values.
@@ -296,7 +261,7 @@ namespace S7.Net
// package.Add(0x02); // datenart
foreach (var dataItem in dataItems)
{
- package.Add(ReadDataRequestPackage(dataItem.DataType, dataItem.DB, dataItem.StartByteAdr, VarTypeToByteLength(dataItem.VarType, dataItem.Count)));
+ package.Add(CreateReadDataRequestPackage(dataItem.DataType, dataItem.DB, dataItem.StartByteAdr, VarTypeToByteLength(dataItem.VarType, dataItem.Count)));
}
_mSocket.Send(package.array, package.array.Length, SocketFlags.None);
@@ -338,11 +303,11 @@ namespace S7.Net
/// If the read was not successful, check LastErrorCode or LastErrorString.
///
/// 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 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.
/// Byte count, if you want to read 120 bytes, set this to 120. This parameter can't be higher than 200. If you need more, use recursion.
/// Returns the bytes in an array
- public byte[] ReadBytes(DataType dataType, int DB, int startByteAdr, int count)
+ public byte[] ReadBytes(DataType dataType, int db, int startByteAdr, int count)
{
byte[] bytes = new byte[count];
@@ -353,7 +318,7 @@ namespace S7.Net
Types.ByteArray package = new ByteArray(packageSize);
package.Add(ReadHeaderPackage());
// package.Add(0x02); // datenart
- package.Add(ReadDataRequestPackage(dataType, DB, startByteAdr, count));
+ package.Add(CreateReadDataRequestPackage(dataType, db, startByteAdr, count));
_mSocket.Send(package.array, package.array.Length, SocketFlags.None);
@@ -380,6 +345,12 @@ namespace S7.Net
}
}
+ ///
+ /// Given a S7 variable type (Bool, Word, DWord, etc.), it returns how many bytes to read.
+ ///
+ ///
+ ///
+ ///
public int VarTypeToByteLength(VarType varType, int varCount = 1)
{
switch (varType)
@@ -404,6 +375,13 @@ namespace S7.Net
}
}
+ ///
+ /// Given a S7 variable type (Bool, Word, DWord, etc.), it converts the bytes in the appropriate C# format.
+ ///
+ ///
+ ///
+ ///
+ ///
public object ParseBytes(VarType varType, byte[] bytes, int varCount)
{
if (bytes == null) return null;
@@ -652,6 +630,16 @@ namespace S7.Net
Types.Class.FromBytes(sourceClass, classType, resultBytes.ToArray());
}
+
+ ///
+ /// 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 read was not successful, check LastErrorCode or LastErrorString.
+ ///
+ /// 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
public ErrorCode WriteBytes(DataType dataType, int db, int startByteAdr, byte[] value)
{
byte[] bReceive = new byte[513];
@@ -701,7 +689,17 @@ namespace S7.Net
}
}
- public object Write(DataType dataType, int db, int startByteAdr, object value)
+ ///
+ /// Takes in input an object and tries to parse it to an array of values. This can be used to write many data, all of the same type.
+ /// You must specify the memory area type, memory are address, byte start address and bytes count.
+ /// If the read was not successful, check LastErrorCode or LastErrorString.
+ ///
+ /// 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
+ public ErrorCode Write(DataType dataType, int db, int startByteAdr, object value)
{
byte[] package = null;
@@ -752,7 +750,14 @@ namespace S7.Net
return WriteBytes(dataType, db, startByteAdr, package);
}
- public object Write(string variable, object value)
+ ///
+ /// Writes a single variable from the plc, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.
+ /// If the write was not successful, check LastErrorCode or LastErrorString.
+ ///
+ /// 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)
{
DataType mDataType;
int mDB;
@@ -918,6 +923,13 @@ namespace S7.Net
}
}
+ ///
+ /// Writes a C# struct to a DB in the plc
+ ///
+ /// 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)
{
var bytes = Types.Struct.ToBytes(structValue).ToList();
@@ -925,6 +937,13 @@ namespace S7.Net
return errCode;
}
+ ///
+ /// Writes a C# class to a DB in the plc
+ ///
+ /// 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)
{
var bytes = Types.Class.ToBytes(classValue).ToList();
@@ -932,6 +951,13 @@ namespace S7.Net
return errCode;
}
+ ///
+ /// Writes multiple bytes to the plc. This uses recursion and it's not limited to 200 bytes.
+ ///
+ /// The bytes values to be written
+ /// Db address
+ /// Start bytes on the plc
+ /// NoError if it was successful, or the error is specified
private ErrorCode WriteMultipleBytes(List bytes, int db, int startByteAdr = 0)
{
ErrorCode errCode = ErrorCode.NoError;
@@ -962,10 +988,10 @@ namespace S7.Net
///
/// Reads a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
///
- ///
- ///
- ///
- ///
+ /// 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.
+ /// Byte count, if you want to read 120 bytes, set this to 120. This parameter can't be higher than 200. If you need more, use recursion.
+ /// Returns the bytes in a list
private List ReadMultipleBytes(int numBytes, int db, int startByteAdr = 0)
{
List resultBytes = new List();
@@ -1005,6 +1031,50 @@ namespace S7.Net
return package;
}
+ ///
+ /// Create the bytes-package to request data from the plc. You have to specify the memory type (dataType),
+ /// the address of the memory, the address of the byte and the bytes count.
+ ///
+ /// MemoryType (DB, Timer, Counter, etc.)
+ /// Address of the memory to be read
+ /// Start address of the byte
+ /// Number of bytes to be read
+ ///
+ private Types.ByteArray CreateReadDataRequestPackage(DataType dataType, int db, int startByteAdr, int count = 1)
+ {
+ //single data req = 12
+ var package = new Types.ByteArray(12);
+ package.Add(new byte[] { 0x12, 0x0a, 0x10 });
+ switch (dataType)
+ {
+ case DataType.Timer:
+ case DataType.Counter:
+ package.Add((byte)dataType);
+ break;
+ default:
+ package.Add(0x02);
+ break;
+ }
+
+ package.Add(Types.Word.ToByteArray((ushort)(count)));
+ package.Add(Types.Word.ToByteArray((ushort)(db)));
+ package.Add((byte)dataType);
+ var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
+ package.Add((byte)overflow);
+ switch (dataType)
+ {
+ case DataType.Timer:
+ case DataType.Counter:
+ package.Add(Types.Word.ToByteArray((ushort)(startByteAdr)));
+ break;
+ default:
+ package.Add(Types.Word.ToByteArray((ushort)((startByteAdr) * 8)));
+ break;
+ }
+
+ return package;
+ }
+
#region IDisposable members