mirror of
https://github.com/S7NetPlus/s7netplus.git
synced 2026-02-17 14:28:25 +08:00
documentation, cleanup and unit tests.
Signed-off-by: Michele Cattafesta <michele.cattafesta@mesta-automation.com>
This commit is contained in:
@@ -5,6 +5,11 @@ namespace S7.Net
|
||||
{
|
||||
public static class Conversion
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a binary string to Int32 value
|
||||
/// </summary>
|
||||
/// <param name="txt"></param>
|
||||
/// <returns></returns>
|
||||
public static int BinStringToInt32(this string txt)
|
||||
{
|
||||
int cnt = 0;
|
||||
@@ -39,6 +44,11 @@ namespace S7.Net
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the value to a binary string
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static string ValToBinString(this object value)
|
||||
{
|
||||
int cnt = 0;
|
||||
@@ -135,6 +145,13 @@ namespace S7.Net
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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);
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="bitPosition"></param>
|
||||
/// <returns></returns>
|
||||
public static bool SelectBit(this byte data, int bitPosition)
|
||||
{
|
||||
int mask = 1 << bitPosition;
|
||||
|
||||
28
S7.Net.UnitTest/ConvertersUnitTest.cs
Normal file
28
S7.Net.UnitTest/ConvertersUnitTest.cs
Normal file
@@ -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));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,7 @@
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
<ItemGroup>
|
||||
<Compile Include="ConvertersUnitTest.cs" />
|
||||
<Compile Include="Helpers\ConsoleManager.cs" />
|
||||
<Compile Include="Helpers\NativeMethods.cs" />
|
||||
<Compile Include="Helpers\S7TestServer.cs" />
|
||||
|
||||
160
S7.Net/PLC.cs
160
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
/// <param name="DB">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.</param>
|
||||
/// <param name="db">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.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <param name="count">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.</param>
|
||||
/// <returns>Returns the bytes in an array</returns>
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a S7 variable type (Bool, Word, DWord, etc.), it returns how many bytes to read.
|
||||
/// </summary>
|
||||
/// <param name="varType"></param>
|
||||
/// <param name="varCount"></param>
|
||||
/// <returns></returns>
|
||||
public int VarTypeToByteLength(VarType varType, int varCount = 1)
|
||||
{
|
||||
switch (varType)
|
||||
@@ -404,6 +375,13 @@ namespace S7.Net
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a S7 variable type (Bool, Word, DWord, etc.), it converts the bytes in the appropriate C# format.
|
||||
/// </summary>
|
||||
/// <param name="varType"></param>
|
||||
/// <param name="bytes"></param>
|
||||
/// <param name="varCount"></param>
|
||||
/// <returns></returns>
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
/// <param name="db">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.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <param name="value">Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion.</param>
|
||||
/// <returns>NoError if it was successful, or the error is specified</returns>
|
||||
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)
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
/// <param name="db">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.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <param name="value">Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion.</param>
|
||||
/// <returns>NoError if it was successful, or the error is specified</returns>
|
||||
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)
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="variable">Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.</param>
|
||||
/// <param name="value">Value to be written to the plc</param>
|
||||
/// <returns>NoError if it was successful, or the error is specified</returns>
|
||||
public ErrorCode Write(string variable, object value)
|
||||
{
|
||||
DataType mDataType;
|
||||
int mDB;
|
||||
@@ -918,6 +923,13 @@ namespace S7.Net
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a C# struct to a DB in the plc
|
||||
/// </summary>
|
||||
/// <param name="structValue">The struct to be written</param>
|
||||
/// <param name="db">Db address</param>
|
||||
/// <param name="startByteAdr">Start bytes on the plc</param>
|
||||
/// <returns>NoError if it was successful, or the error is specified</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a C# class to a DB in the plc
|
||||
/// </summary>
|
||||
/// <param name="classValue">The class to be written</param>
|
||||
/// <param name="db">Db address</param>
|
||||
/// <param name="startByteAdr">Start bytes on the plc</param>
|
||||
/// <returns>NoError if it was successful, or the error is specified</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes multiple bytes to the plc. This uses recursion and it's not limited to 200 bytes.
|
||||
/// </summary>
|
||||
/// <param name="bytes">The bytes values to be written</param>
|
||||
/// <param name="db">Db address</param>
|
||||
/// <param name="startByteAdr">Start bytes on the plc</param>
|
||||
/// <returns>NoError if it was successful, or the error is specified</returns>
|
||||
private ErrorCode WriteMultipleBytes(List<byte> bytes, int db, int startByteAdr = 0)
|
||||
{
|
||||
ErrorCode errCode = ErrorCode.NoError;
|
||||
@@ -962,10 +988,10 @@ namespace S7.Net
|
||||
/// <summary>
|
||||
/// Reads a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
||||
/// </summary>
|
||||
/// <param name="numBytes"></param>
|
||||
/// <param name="db"></param>
|
||||
/// <param name="startByteAdr"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="db">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.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <param name="numBytes">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.</param>
|
||||
/// <returns>Returns the bytes in a list</returns>
|
||||
private List<byte> ReadMultipleBytes(int numBytes, int db, int startByteAdr = 0)
|
||||
{
|
||||
List<byte> resultBytes = new List<byte>();
|
||||
@@ -1005,6 +1031,50 @@ namespace S7.Net
|
||||
return package;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="dataType">MemoryType (DB, Timer, Counter, etc.)</param>
|
||||
/// <param name="db">Address of the memory to be read</param>
|
||||
/// <param name="startByteAdr">Start address of the byte</param>
|
||||
/// <param name="count">Number of bytes to be read</param>
|
||||
/// <returns></returns>
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user