mirror of
https://github.com/S7NetPlus/s7netplus.git
synced 2026-02-17 14:28:25 +08:00
Merge branch 'develop' into githubActions2
This commit is contained in:
@@ -933,7 +933,14 @@ namespace S7.Net.UnitTest
|
|||||||
S7TestServer.Stop();
|
S7TestServer.Stop();
|
||||||
|
|
||||||
var unreachablePlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 2);
|
var unreachablePlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 2);
|
||||||
Assert.IsFalse(unreachablePlc.IsAvailable);
|
try
|
||||||
|
{
|
||||||
|
unreachablePlc.Open();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
Assert.IsFalse(unreachablePlc.IsConnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
@@ -944,7 +951,8 @@ namespace S7.Net.UnitTest
|
|||||||
S7TestServer.Start(TestServerPort);
|
S7TestServer.Start(TestServerPort);
|
||||||
|
|
||||||
var reachablePlc = CreatePlc();
|
var reachablePlc = CreatePlc();
|
||||||
Assert.IsTrue(reachablePlc.IsAvailable);
|
reachablePlc.Open();
|
||||||
|
Assert.IsTrue(reachablePlc.IsConnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
|||||||
38
S7.Net.UnitTest/TypeTests/BooleanTests.cs
Normal file
38
S7.Net.UnitTest/TypeTests/BooleanTests.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using Boolean = S7.Net.Types.Boolean;
|
||||||
|
|
||||||
|
namespace S7.Net.UnitTest.TypeTests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class BooleanTests
|
||||||
|
{
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(0)]
|
||||||
|
[DataRow(1)]
|
||||||
|
[DataRow(2)]
|
||||||
|
[DataRow(3)]
|
||||||
|
[DataRow(4)]
|
||||||
|
[DataRow(5)]
|
||||||
|
[DataRow(6)]
|
||||||
|
[DataRow(7)]
|
||||||
|
public void TestValidSetBitValues(int index)
|
||||||
|
{
|
||||||
|
Assert.AreEqual(Math.Pow(2, index), Boolean.SetBit(0, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod]
|
||||||
|
[DataRow(0)]
|
||||||
|
[DataRow(1)]
|
||||||
|
[DataRow(2)]
|
||||||
|
[DataRow(3)]
|
||||||
|
[DataRow(4)]
|
||||||
|
[DataRow(5)]
|
||||||
|
[DataRow(6)]
|
||||||
|
[DataRow(7)]
|
||||||
|
public void TestValidClearBitValues(int index)
|
||||||
|
{
|
||||||
|
Assert.AreEqual((byte) ((uint) Math.Pow(2, index) ^ uint.MaxValue), Boolean.ClearBit(byte.MaxValue, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -117,13 +117,24 @@ namespace S7.Net.UnitTest.TypeTests
|
|||||||
AssertToByteArrayAndBackEquals("Abc", 4, 4, 3, (byte) 'A', (byte) 'b', (byte) 'c', 0);
|
AssertToByteArrayAndBackEquals("Abc", 4, 4, 3, (byte) 'A', (byte) 'b', (byte) 'c', 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void OddS7StringByteLength()
|
||||||
|
{
|
||||||
|
AssertVarTypeToByteLength(VarType.S7String, 1, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void EvenS7StringByteLength()
|
||||||
|
{
|
||||||
|
AssertVarTypeToByteLength(VarType.S7String, 2, 4);
|
||||||
|
}
|
||||||
|
|
||||||
private static void AssertFromByteArrayEquals(string expected, params byte[] bytes)
|
private static void AssertFromByteArrayEquals(string expected, params byte[] bytes)
|
||||||
{
|
{
|
||||||
var convertedString = S7String.FromByteArray(bytes);
|
var convertedString = S7String.FromByteArray(bytes);
|
||||||
Assert.AreEqual(expected, convertedString);
|
Assert.AreEqual(expected, convertedString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void AssertToByteArrayAndBackEquals(string value, int reservedLength, params byte[] expected)
|
private static void AssertToByteArrayAndBackEquals(string value, int reservedLength, params byte[] expected)
|
||||||
{
|
{
|
||||||
var convertedData = S7String.ToByteArray(value, reservedLength);
|
var convertedData = S7String.ToByteArray(value, reservedLength);
|
||||||
@@ -131,5 +142,11 @@ namespace S7.Net.UnitTest.TypeTests
|
|||||||
var convertedBack = S7String.FromByteArray(convertedData);
|
var convertedBack = S7String.FromByteArray(convertedData);
|
||||||
Assert.AreEqual(value, convertedBack);
|
Assert.AreEqual(value, convertedBack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AssertVarTypeToByteLength(VarType varType, int count, int expectedByteLength)
|
||||||
|
{
|
||||||
|
var byteLength = Plc.VarTypeToByteLength(varType, count);
|
||||||
|
Assert.AreEqual(expectedByteLength, byteLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,6 +122,17 @@ namespace S7.Net.UnitTest.TypeTests
|
|||||||
Assert.AreEqual(expected, convertedString);
|
Assert.AreEqual(expected, convertedString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void OddS7WStringByteLength()
|
||||||
|
{
|
||||||
|
AssertVarTypeToByteLength(VarType.S7WString, 1, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void EvenS7WStringByteLength()
|
||||||
|
{
|
||||||
|
AssertVarTypeToByteLength(VarType.S7WString, 2, 8);
|
||||||
|
}
|
||||||
|
|
||||||
private static void AssertToByteArrayAndBackEquals(string value, int reservedLength, params byte[] expected)
|
private static void AssertToByteArrayAndBackEquals(string value, int reservedLength, params byte[] expected)
|
||||||
{
|
{
|
||||||
@@ -130,5 +141,11 @@ namespace S7.Net.UnitTest.TypeTests
|
|||||||
var convertedBack = S7WString.FromByteArray(convertedData);
|
var convertedBack = S7WString.FromByteArray(convertedData);
|
||||||
Assert.AreEqual(value, convertedBack);
|
Assert.AreEqual(value, convertedBack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AssertVarTypeToByteLength(VarType varType, int count, int expectedByteLength)
|
||||||
|
{
|
||||||
|
var byteLength = Plc.VarTypeToByteLength(varType, count);
|
||||||
|
Assert.AreEqual(expectedByteLength, byteLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28
S7.Net/Internal/TaskQueue.cs
Normal file
28
S7.Net/Internal/TaskQueue.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace S7.Net.Internal
|
||||||
|
{
|
||||||
|
internal class TaskQueue
|
||||||
|
{
|
||||||
|
private static readonly object Sentinel = new object();
|
||||||
|
|
||||||
|
private Task prev = Task.FromResult(Sentinel);
|
||||||
|
|
||||||
|
public async Task<T> Enqueue<T>(Func<Task<T>> action)
|
||||||
|
{
|
||||||
|
var tcs = new TaskCompletionSource<object>();
|
||||||
|
await Interlocked.Exchange(ref prev, tcs.Task).ConfigureAwait(false);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await action.Invoke().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
tcs.SetResult(Sentinel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using S7.Net.Internal;
|
||||||
using S7.Net.Protocol;
|
using S7.Net.Protocol;
|
||||||
using S7.Net.Types;
|
using S7.Net.Types;
|
||||||
|
|
||||||
@@ -13,6 +15,8 @@ namespace S7.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class Plc : IDisposable
|
public partial class Plc : IDisposable
|
||||||
{
|
{
|
||||||
|
private readonly TaskQueue queue = new TaskQueue();
|
||||||
|
|
||||||
private const int CONNECTION_TIMED_OUT_ERROR_CODE = 10060;
|
private const int CONNECTION_TIMED_OUT_ERROR_CODE = 10060;
|
||||||
|
|
||||||
//TCP connection to device
|
//TCP connection to device
|
||||||
@@ -77,45 +81,24 @@ namespace S7.Net
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns true if a connection to the PLC can be established
|
/// Gets a value indicating whether a connection to the PLC has been established.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsAvailable
|
/// <remarks>
|
||||||
{
|
/// The <see cref="IsConnected"/> property gets the connection state of the Client socket as
|
||||||
//TODO: Fix This
|
/// of the last I/O operation. When it returns <c>false</c>, the Client socket was either
|
||||||
get
|
/// never connected, or is no longer connected.
|
||||||
{
|
///
|
||||||
try
|
/// <para>
|
||||||
{
|
/// Because the <see cref="IsConnected"/> property only reflects the state of the connection
|
||||||
OpenAsync().GetAwaiter().GetResult();
|
/// as of the most recent operation, you should attempt to send or receive a message to
|
||||||
return true;
|
/// determine the current state. After the message send fails, this property no longer
|
||||||
}
|
/// returns <c>true</c>. Note that this behavior is by design. You cannot reliably test the
|
||||||
catch
|
/// state of the connection because, in the time between the test and a send/receive, the
|
||||||
{
|
/// connection could have been lost. Your code should assume the socket is connected, and
|
||||||
return false;
|
/// gracefully handle failed transmissions.
|
||||||
}
|
/// </para>
|
||||||
}
|
/// </remarks>
|
||||||
}
|
public bool IsConnected => tcpClient?.Connected ?? false;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the socket is connected and polls the other peer (the PLC) to see if it's connected.
|
|
||||||
/// This is the variable that you should continously check to see if the communication is working
|
|
||||||
/// See also: http://stackoverflow.com/questions/2661764/how-to-check-if-a-socket-is-connected-disconnected-in-c
|
|
||||||
/// </summary>
|
|
||||||
public bool IsConnected
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (tcpClient == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
//TODO: Actually check communication by sending an empty TPDU
|
|
||||||
return tcpClient.Connected;
|
|
||||||
}
|
|
||||||
catch { return false; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a PLC object with all the parameters needed for connections.
|
/// Creates a PLC object with all the parameters needed for connections.
|
||||||
@@ -263,6 +246,16 @@ namespace S7.Net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Stream GetStreamIfAvailable()
|
||||||
|
{
|
||||||
|
if (_stream == null)
|
||||||
|
{
|
||||||
|
throw new PlcException(ErrorCode.ConnectionError, "Plc is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
return _stream;
|
||||||
|
}
|
||||||
|
|
||||||
#region IDisposable Support
|
#region IDisposable Support
|
||||||
private bool disposedValue = false; // To detect redundant calls
|
private bool disposedValue = false; // To detect redundant calls
|
||||||
|
|
||||||
|
|||||||
@@ -184,13 +184,15 @@ namespace S7.Net
|
|||||||
switch (varType)
|
switch (varType)
|
||||||
{
|
{
|
||||||
case VarType.Bit:
|
case VarType.Bit:
|
||||||
return varCount + 7 / 8;
|
return (varCount + 7) / 8;
|
||||||
case VarType.Byte:
|
case VarType.Byte:
|
||||||
return (varCount < 1) ? 1 : varCount;
|
return (varCount < 1) ? 1 : varCount;
|
||||||
case VarType.String:
|
case VarType.String:
|
||||||
return varCount;
|
return varCount;
|
||||||
case VarType.S7String:
|
case VarType.S7String:
|
||||||
return varCount + 2;
|
return ((varCount + 2) & 1) == 1 ? (varCount + 3) : (varCount + 2);
|
||||||
|
case VarType.S7WString:
|
||||||
|
return (varCount * 2) + 4;
|
||||||
case VarType.Word:
|
case VarType.Word:
|
||||||
case VarType.Timer:
|
case VarType.Timer:
|
||||||
case VarType.Int:
|
case VarType.Int:
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
using S7.Net.Types;
|
using S7.Net.Types;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using S7.Net.Protocol;
|
using S7.Net.Protocol;
|
||||||
using System.IO;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using S7.Net.Protocol.S7;
|
using S7.Net.Protocol.S7;
|
||||||
|
|
||||||
@@ -27,10 +27,15 @@ namespace S7.Net
|
|||||||
{
|
{
|
||||||
var stream = await ConnectAsync().ConfigureAwait(false);
|
var stream = await ConnectAsync().ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
|
{
|
||||||
|
await queue.Enqueue(async () =>
|
||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
await EstablishConnection(stream, cancellationToken).ConfigureAwait(false);
|
await EstablishConnection(stream, cancellationToken).ConfigureAwait(false);
|
||||||
_stream = stream;
|
_stream = stream;
|
||||||
|
|
||||||
|
return default(object);
|
||||||
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch(Exception)
|
catch(Exception)
|
||||||
{
|
{
|
||||||
@@ -47,29 +52,30 @@ namespace S7.Net
|
|||||||
return tcpClient.GetStream();
|
return tcpClient.GetStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task EstablishConnection(NetworkStream stream, CancellationToken cancellationToken)
|
private async Task EstablishConnection(Stream stream, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await RequestConnection(stream, cancellationToken).ConfigureAwait(false);
|
await RequestConnection(stream, cancellationToken).ConfigureAwait(false);
|
||||||
await SetupConnection(stream, cancellationToken).ConfigureAwait(false);
|
await SetupConnection(stream, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RequestConnection(NetworkStream stream, CancellationToken cancellationToken)
|
private async Task RequestConnection(Stream stream, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var requestData = ConnectionRequest.GetCOTPConnectionRequest(CPU, Rack, Slot);
|
var requestData = ConnectionRequest.GetCOTPConnectionRequest(CPU, Rack, Slot);
|
||||||
await stream.WriteAsync(requestData, 0, requestData.Length).ConfigureAwait(false);
|
var response = await NoLockRequestTpduAsync(stream, requestData, cancellationToken).ConfigureAwait(false);
|
||||||
var response = await COTP.TPDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
|
|
||||||
if (response.PDUType != COTP.PduType.ConnectionConfirmed)
|
if (response.PDUType != COTP.PduType.ConnectionConfirmed)
|
||||||
{
|
{
|
||||||
throw new InvalidDataException("Connection request was denied", response.TPkt.Data, 1, 0x0d);
|
throw new InvalidDataException("Connection request was denied", response.TPkt.Data, 1, 0x0d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SetupConnection(NetworkStream stream, CancellationToken cancellationToken)
|
private async Task SetupConnection(Stream stream, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var setupData = GetS7ConnectionSetup();
|
var setupData = GetS7ConnectionSetup();
|
||||||
await stream.WriteAsync(setupData, 0, setupData.Length).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var s7data = await COTP.TSDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
|
var s7data = await NoLockRequestTsduAsync(stream, setupData, 0, setupData.Length, cancellationToken)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (s7data.Length < 2)
|
if (s7data.Length < 2)
|
||||||
throw new WrongNumberOfBytesException("Not enough data received in response to Communication Setup");
|
throw new WrongNumberOfBytesException("Not enough data received in response to Communication Setup");
|
||||||
|
|
||||||
@@ -104,7 +110,7 @@ namespace S7.Net
|
|||||||
{
|
{
|
||||||
//This works up to MaxPDUSize-1 on SNAP7. But not MaxPDUSize-0.
|
//This works up to MaxPDUSize-1 on SNAP7. But not MaxPDUSize-0.
|
||||||
var maxToRead = Math.Min(count, MaxPDUSize - 18);
|
var maxToRead = Math.Min(count, MaxPDUSize - 18);
|
||||||
await ReadBytesWithSingleRequestAsync(dataType, db, startByteAdr + index, resultBytes, index, maxToRead, cancellationToken);
|
await ReadBytesWithSingleRequestAsync(dataType, db, startByteAdr + index, resultBytes, index, maxToRead, cancellationToken).ConfigureAwait(false);
|
||||||
count -= maxToRead;
|
count -= maxToRead;
|
||||||
index += maxToRead;
|
index += maxToRead;
|
||||||
}
|
}
|
||||||
@@ -127,7 +133,7 @@ namespace S7.Net
|
|||||||
public async Task<object?> ReadAsync(DataType dataType, int db, int startByteAdr, VarType varType, int varCount, byte bitAdr = 0, CancellationToken cancellationToken = default)
|
public async Task<object?> ReadAsync(DataType dataType, int db, int startByteAdr, VarType varType, int varCount, byte bitAdr = 0, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
int cntBytes = VarTypeToByteLength(varType, varCount);
|
int cntBytes = VarTypeToByteLength(varType, varCount);
|
||||||
byte[] bytes = await ReadBytesAsync(dataType, db, startByteAdr, cntBytes, cancellationToken);
|
byte[] bytes = await ReadBytesAsync(dataType, db, startByteAdr, cntBytes, cancellationToken).ConfigureAwait(false);
|
||||||
return ParseBytes(varType, bytes, varCount, bitAdr);
|
return ParseBytes(varType, bytes, varCount, bitAdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +148,7 @@ namespace S7.Net
|
|||||||
public async Task<object?> ReadAsync(string variable, CancellationToken cancellationToken = default)
|
public async Task<object?> ReadAsync(string variable, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var adr = new PLCAddress(variable);
|
var adr = new PLCAddress(variable);
|
||||||
return await ReadAsync(adr.DataType, adr.DbNumber, adr.StartByte, adr.VarType, 1, (byte)adr.BitNumber, cancellationToken);
|
return await ReadAsync(adr.DataType, adr.DbNumber, adr.StartByte, adr.VarType, 1, (byte)adr.BitNumber, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -158,7 +164,7 @@ namespace S7.Net
|
|||||||
{
|
{
|
||||||
int numBytes = Types.Struct.GetStructSize(structType);
|
int numBytes = Types.Struct.GetStructSize(structType);
|
||||||
// now read the package
|
// now read the package
|
||||||
var resultBytes = await ReadBytesAsync(DataType.DataBlock, db, startByteAdr, numBytes, cancellationToken);
|
var resultBytes = await ReadBytesAsync(DataType.DataBlock, db, startByteAdr, numBytes, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
// and decode it
|
// and decode it
|
||||||
return Types.Struct.FromBytes(structType, resultBytes);
|
return Types.Struct.FromBytes(structType, resultBytes);
|
||||||
@@ -175,7 +181,7 @@ namespace S7.Net
|
|||||||
/// <returns>Returns a nulable struct. If nothing was read null will be returned.</returns>
|
/// <returns>Returns a nulable struct. If nothing was read null will be returned.</returns>
|
||||||
public async Task<T?> ReadStructAsync<T>(int db, int startByteAdr = 0, CancellationToken cancellationToken = default) where T : struct
|
public async Task<T?> ReadStructAsync<T>(int db, int startByteAdr = 0, CancellationToken cancellationToken = default) where T : struct
|
||||||
{
|
{
|
||||||
return await ReadStructAsync(typeof(T), db, startByteAdr, cancellationToken) as T?;
|
return await ReadStructAsync(typeof(T), db, startByteAdr, cancellationToken).ConfigureAwait(false) as T?;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -197,7 +203,7 @@ namespace S7.Net
|
|||||||
}
|
}
|
||||||
|
|
||||||
// now read the package
|
// now read the package
|
||||||
var resultBytes = await ReadBytesAsync(DataType.DataBlock, db, startByteAdr, numBytes, cancellationToken);
|
var resultBytes = await ReadBytesAsync(DataType.DataBlock, db, startByteAdr, numBytes, cancellationToken).ConfigureAwait(false);
|
||||||
// and decode it
|
// and decode it
|
||||||
Class.FromBytes(sourceClass, resultBytes);
|
Class.FromBytes(sourceClass, resultBytes);
|
||||||
|
|
||||||
@@ -217,7 +223,7 @@ namespace S7.Net
|
|||||||
/// <returns>An instance of the class with the values read from the PLC. If no data has been read, null will be returned</returns>
|
/// <returns>An instance of the class with the values read from the PLC. If no data has been read, null will be returned</returns>
|
||||||
public async Task<T?> ReadClassAsync<T>(int db, int startByteAdr = 0, CancellationToken cancellationToken = default) where T : class
|
public async Task<T?> ReadClassAsync<T>(int db, int startByteAdr = 0, CancellationToken cancellationToken = default) where T : class
|
||||||
{
|
{
|
||||||
return await ReadClassAsync(() => Activator.CreateInstance<T>(), db, startByteAdr, cancellationToken);
|
return await ReadClassAsync(() => Activator.CreateInstance<T>(), db, startByteAdr, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -234,7 +240,7 @@ namespace S7.Net
|
|||||||
public async Task<T?> ReadClassAsync<T>(Func<T> classFactory, int db, int startByteAdr = 0, CancellationToken cancellationToken = default) where T : class
|
public async Task<T?> ReadClassAsync<T>(Func<T> classFactory, int db, int startByteAdr = 0, CancellationToken cancellationToken = default) where T : class
|
||||||
{
|
{
|
||||||
var instance = classFactory();
|
var instance = classFactory();
|
||||||
var res = await ReadClassAsync(instance, db, startByteAdr, cancellationToken);
|
var res = await ReadClassAsync(instance, db, startByteAdr, cancellationToken).ConfigureAwait(false);
|
||||||
int readBytes = res.Item1;
|
int readBytes = res.Item1;
|
||||||
if (readBytes <= 0)
|
if (readBytes <= 0)
|
||||||
{
|
{
|
||||||
@@ -260,14 +266,11 @@ namespace S7.Net
|
|||||||
//replies with bigger PDU size in connection setup.
|
//replies with bigger PDU size in connection setup.
|
||||||
AssertPduSizeForRead(dataItems);
|
AssertPduSizeForRead(dataItems);
|
||||||
|
|
||||||
var stream = GetStreamIfAvailable();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var dataToSend = BuildReadRequestPackage(dataItems.Select(d => DataItem.GetDataItemAddress(d)).ToList());
|
var dataToSend = BuildReadRequestPackage(dataItems.Select(d => DataItem.GetDataItemAddress(d)).ToList());
|
||||||
await stream.WriteAsync(dataToSend, 0, dataToSend.Length);
|
var s7data = await RequestTsduAsync(dataToSend, cancellationToken);
|
||||||
|
|
||||||
var s7data = await COTP.TSDU.ReadAsync(stream, cancellationToken);
|
|
||||||
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
||||||
|
|
||||||
ParseDataIntoDataItems(s7data, dataItems);
|
ParseDataIntoDataItems(s7data, dataItems);
|
||||||
@@ -306,7 +309,7 @@ namespace S7.Net
|
|||||||
while (count > 0)
|
while (count > 0)
|
||||||
{
|
{
|
||||||
var maxToWrite = (int)Math.Min(count, MaxPDUSize - 35);
|
var maxToWrite = (int)Math.Min(count, MaxPDUSize - 35);
|
||||||
await WriteBytesWithASingleRequestAsync(dataType, db, startByteAdr + localIndex, value, localIndex, maxToWrite, cancellationToken);
|
await WriteBytesWithASingleRequestAsync(dataType, db, startByteAdr + localIndex, value, localIndex, maxToWrite, cancellationToken).ConfigureAwait(false);
|
||||||
count -= maxToWrite;
|
count -= maxToWrite;
|
||||||
localIndex += maxToWrite;
|
localIndex += maxToWrite;
|
||||||
}
|
}
|
||||||
@@ -328,7 +331,7 @@ namespace S7.Net
|
|||||||
if (bitAdr < 0 || bitAdr > 7)
|
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));
|
throw new InvalidAddressException(string.Format("Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", bitAdr));
|
||||||
|
|
||||||
await WriteBitWithASingleRequestAsync(dataType, db, startByteAdr, bitAdr, value, cancellationToken);
|
await WriteBitWithASingleRequestAsync(dataType, db, startByteAdr, bitAdr, value, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -347,7 +350,7 @@ namespace S7.Net
|
|||||||
if (value < 0 || value > 1)
|
if (value < 0 || value > 1)
|
||||||
throw new ArgumentException("Value must be 0 or 1", nameof(value));
|
throw new ArgumentException("Value must be 0 or 1", nameof(value));
|
||||||
|
|
||||||
await WriteBitAsync(dataType, db, startByteAdr, bitAdr, value == 1, cancellationToken);
|
await WriteBitAsync(dataType, db, startByteAdr, bitAdr, value == 1, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -370,7 +373,7 @@ namespace S7.Net
|
|||||||
//Must be writing a bit value as bitAdr is specified
|
//Must be writing a bit value as bitAdr is specified
|
||||||
if (value is bool boolean)
|
if (value is bool boolean)
|
||||||
{
|
{
|
||||||
await WriteBitAsync(dataType, db, startByteAdr, bitAdr, boolean, cancellationToken);
|
await WriteBitAsync(dataType, db, startByteAdr, bitAdr, boolean, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else if (value is int intValue)
|
else if (value is int intValue)
|
||||||
{
|
{
|
||||||
@@ -380,11 +383,11 @@ namespace S7.Net
|
|||||||
"Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid",
|
"Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid",
|
||||||
bitAdr), nameof(bitAdr));
|
bitAdr), nameof(bitAdr));
|
||||||
|
|
||||||
await WriteBitAsync(dataType, db, startByteAdr, bitAdr, intValue == 1, cancellationToken);
|
await WriteBitAsync(dataType, db, startByteAdr, bitAdr, intValue == 1, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else 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));
|
||||||
}
|
}
|
||||||
else await WriteBytesAsync(dataType, db, startByteAdr, Serialization.SerializeValue(value), cancellationToken);
|
else await WriteBytesAsync(dataType, db, startByteAdr, Serialization.SerializeValue(value), cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -399,7 +402,7 @@ namespace S7.Net
|
|||||||
public async Task WriteAsync(string variable, object value, CancellationToken cancellationToken = default)
|
public async Task WriteAsync(string variable, object value, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var adr = new PLCAddress(variable);
|
var adr = new PLCAddress(variable);
|
||||||
await WriteAsync(adr.DataType, adr.DbNumber, adr.StartByte, value, adr.BitNumber, cancellationToken);
|
await WriteAsync(adr.DataType, adr.DbNumber, adr.StartByte, value, adr.BitNumber, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -414,7 +417,7 @@ namespace S7.Net
|
|||||||
public async Task WriteStructAsync(object structValue, int db, int startByteAdr = 0, CancellationToken cancellationToken = default)
|
public async Task WriteStructAsync(object structValue, int db, int startByteAdr = 0, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var bytes = Struct.ToBytes(structValue).ToList();
|
var bytes = Struct.ToBytes(structValue).ToList();
|
||||||
await WriteBytesAsync(DataType.DataBlock, db, startByteAdr, bytes.ToArray(), cancellationToken);
|
await WriteBytesAsync(DataType.DataBlock, db, startByteAdr, bytes.ToArray(), cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -430,17 +433,14 @@ namespace S7.Net
|
|||||||
{
|
{
|
||||||
byte[] bytes = new byte[(int)Class.GetClassSize(classValue)];
|
byte[] bytes = new byte[(int)Class.GetClassSize(classValue)];
|
||||||
Types.Class.ToBytes(classValue, bytes);
|
Types.Class.ToBytes(classValue, bytes);
|
||||||
await WriteBytesAsync(DataType.DataBlock, db, startByteAdr, bytes, cancellationToken);
|
await WriteBytesAsync(DataType.DataBlock, db, startByteAdr, bytes, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ReadBytesWithSingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
private async Task ReadBytesWithSingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var stream = GetStreamIfAvailable();
|
|
||||||
|
|
||||||
var dataToSend = BuildReadRequestPackage(new [] { new DataItemAddress(dataType, db, startByteAdr, count)});
|
var dataToSend = BuildReadRequestPackage(new [] { new DataItemAddress(dataType, db, startByteAdr, count)});
|
||||||
await stream.WriteAsync(dataToSend, 0, dataToSend.Length, cancellationToken);
|
|
||||||
|
|
||||||
var s7data = await COTP.TSDU.ReadAsync(stream, cancellationToken);
|
var s7data = await RequestTsduAsync(dataToSend, cancellationToken);
|
||||||
AssertReadResponse(s7data, count);
|
AssertReadResponse(s7data, count);
|
||||||
|
|
||||||
Array.Copy(s7data, 18, buffer, offset, count);
|
Array.Copy(s7data, 18, buffer, offset, count);
|
||||||
@@ -456,13 +456,11 @@ namespace S7.Net
|
|||||||
{
|
{
|
||||||
AssertPduSizeForWrite(dataItems);
|
AssertPduSizeForWrite(dataItems);
|
||||||
|
|
||||||
var stream = GetStreamIfAvailable();
|
|
||||||
|
|
||||||
var message = new ByteArray();
|
var message = new ByteArray();
|
||||||
var length = S7WriteMultiple.CreateRequest(message, dataItems);
|
var length = S7WriteMultiple.CreateRequest(message, dataItems);
|
||||||
await stream.WriteAsync(message.Array, 0, length).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var response = await COTP.TSDU.ReadAsync(stream, CancellationToken.None).ConfigureAwait(false);
|
var response = await RequestTsduAsync(message.Array, 0, length).ConfigureAwait(false);
|
||||||
|
|
||||||
S7WriteMultiple.ParseResponse(response, response.Length, dataItems);
|
S7WriteMultiple.ParseResponse(response, response.Length, dataItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,15 +474,11 @@ namespace S7.Net
|
|||||||
/// <returns>A task that represents the asynchronous write operation.</returns>
|
/// <returns>A task that represents the asynchronous write operation.</returns>
|
||||||
private async Task WriteBytesWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] value, int dataOffset, int count, CancellationToken cancellationToken)
|
private async Task WriteBytesWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] value, int dataOffset, int count, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var stream = GetStreamIfAvailable();
|
|
||||||
var dataToSend = BuildWriteBytesPackage(dataType, db, startByteAdr, value, dataOffset, count);
|
var dataToSend = BuildWriteBytesPackage(dataType, db, startByteAdr, value, dataOffset, count);
|
||||||
|
var s7data = await RequestTsduAsync(dataToSend, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
await stream.WriteAsync(dataToSend, 0, dataToSend.Length, cancellationToken);
|
|
||||||
|
|
||||||
var s7data = await COTP.TSDU.ReadAsync(stream, cancellationToken);
|
|
||||||
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
@@ -499,15 +493,11 @@ namespace S7.Net
|
|||||||
|
|
||||||
private async Task WriteBitWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue, CancellationToken cancellationToken)
|
private async Task WriteBitWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var stream = GetStreamIfAvailable();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var dataToSend = BuildWriteBitPackage(dataType, db, startByteAdr, bitValue, bitAdr);
|
var dataToSend = BuildWriteBitPackage(dataType, db, startByteAdr, bitValue, bitAdr);
|
||||||
|
var s7data = await RequestTsduAsync(dataToSend, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
await stream.WriteAsync(dataToSend, 0, dataToSend.Length);
|
|
||||||
|
|
||||||
var s7data = await COTP.TSDU.ReadAsync(stream, cancellationToken);
|
|
||||||
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
@@ -520,13 +510,33 @@ namespace S7.Net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream GetStreamIfAvailable()
|
private Task<byte[]> RequestTsduAsync(byte[] requestData, CancellationToken cancellationToken = default) =>
|
||||||
|
RequestTsduAsync(requestData, 0, requestData.Length, cancellationToken);
|
||||||
|
|
||||||
|
private Task<byte[]> RequestTsduAsync(byte[] requestData, int offset, int length, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
if (_stream == null)
|
var stream = GetStreamIfAvailable();
|
||||||
|
|
||||||
|
return queue.Enqueue(() =>
|
||||||
|
NoLockRequestTsduAsync(stream, requestData, offset, length, cancellationToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<COTP.TPDU> NoLockRequestTpduAsync(Stream stream, byte[] requestData,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
throw new PlcException(ErrorCode.ConnectionError, "Plc is not connected");
|
await stream.WriteAsync(requestData, 0, requestData.Length, cancellationToken).ConfigureAwait(false);
|
||||||
|
var response = await COTP.TPDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
return _stream;
|
|
||||||
|
private static async Task<byte[]> NoLockRequestTsduAsync(Stream stream, byte[] requestData, int offset, int length,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
await stream.WriteAsync(requestData, offset, length, cancellationToken).ConfigureAwait(false);
|
||||||
|
var response = await COTP.TSDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Sockets;
|
|
||||||
using S7.Net.Protocol;
|
using S7.Net.Protocol;
|
||||||
using S7.Net.Helper;
|
using S7.Net.Helper;
|
||||||
|
|
||||||
@@ -298,7 +296,6 @@ namespace S7.Net
|
|||||||
|
|
||||||
private void ReadBytesWithSingleRequest(DataType dataType, int db, int startByteAdr, byte[] buffer, int offset, int count)
|
private void ReadBytesWithSingleRequest(DataType dataType, int db, int startByteAdr, byte[] buffer, int offset, int count)
|
||||||
{
|
{
|
||||||
var stream = GetStreamIfAvailable();
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// first create the header
|
// first create the header
|
||||||
@@ -309,9 +306,7 @@ namespace S7.Net
|
|||||||
BuildReadDataRequestPackage(package, dataType, db, startByteAdr, count);
|
BuildReadDataRequestPackage(package, dataType, db, startByteAdr, count);
|
||||||
|
|
||||||
var dataToSend = package.ToArray();
|
var dataToSend = package.ToArray();
|
||||||
stream.Write(dataToSend, 0, dataToSend.Length);
|
var s7data = RequestTsdu(dataToSend);
|
||||||
|
|
||||||
var s7data = COTP.TSDU.Read(stream);
|
|
||||||
AssertReadResponse(s7data, count);
|
AssertReadResponse(s7data, count);
|
||||||
|
|
||||||
Array.Copy(s7data, 18, buffer, offset, count);
|
Array.Copy(s7data, 18, buffer, offset, count);
|
||||||
@@ -331,13 +326,11 @@ namespace S7.Net
|
|||||||
{
|
{
|
||||||
AssertPduSizeForWrite(dataItems);
|
AssertPduSizeForWrite(dataItems);
|
||||||
|
|
||||||
var stream = GetStreamIfAvailable();
|
|
||||||
|
|
||||||
var message = new ByteArray();
|
var message = new ByteArray();
|
||||||
var length = S7WriteMultiple.CreateRequest(message, dataItems);
|
var length = S7WriteMultiple.CreateRequest(message, dataItems);
|
||||||
stream.Write(message.Array, 0, length);
|
var response = RequestTsdu(message.Array, 0, length);
|
||||||
|
|
||||||
var response = COTP.TSDU.Read(stream);
|
|
||||||
S7WriteMultiple.ParseResponse(response, response.Length, dataItems);
|
S7WriteMultiple.ParseResponse(response, response.Length, dataItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,12 +338,9 @@ namespace S7.Net
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var stream = GetStreamIfAvailable();
|
|
||||||
var dataToSend = BuildWriteBytesPackage(dataType, db, startByteAdr, value, dataOffset, count);
|
var dataToSend = BuildWriteBytesPackage(dataType, db, startByteAdr, value, dataOffset, count);
|
||||||
|
var s7data = RequestTsdu(dataToSend);
|
||||||
|
|
||||||
stream.Write(dataToSend, 0, dataToSend.Length);
|
|
||||||
|
|
||||||
var s7data = COTP.TSDU.Read(stream);
|
|
||||||
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
||||||
}
|
}
|
||||||
catch (Exception exc)
|
catch (Exception exc)
|
||||||
@@ -425,14 +415,11 @@ namespace S7.Net
|
|||||||
|
|
||||||
private void WriteBitWithASingleRequest(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue)
|
private void WriteBitWithASingleRequest(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue)
|
||||||
{
|
{
|
||||||
var stream = GetStreamIfAvailable();
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var dataToSend = BuildWriteBitPackage(dataType, db, startByteAdr, bitValue, bitAdr);
|
var dataToSend = BuildWriteBitPackage(dataType, db, startByteAdr, bitValue, bitAdr);
|
||||||
|
var s7data = RequestTsdu(dataToSend);
|
||||||
|
|
||||||
stream.Write(dataToSend, 0, dataToSend.Length);
|
|
||||||
|
|
||||||
var s7data = COTP.TSDU.Read(stream);
|
|
||||||
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
||||||
}
|
}
|
||||||
catch (Exception exc)
|
catch (Exception exc)
|
||||||
@@ -453,8 +440,6 @@ namespace S7.Net
|
|||||||
{
|
{
|
||||||
AssertPduSizeForRead(dataItems);
|
AssertPduSizeForRead(dataItems);
|
||||||
|
|
||||||
var stream = GetStreamIfAvailable();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// first create the header
|
// first create the header
|
||||||
@@ -468,9 +453,7 @@ namespace S7.Net
|
|||||||
}
|
}
|
||||||
|
|
||||||
var dataToSend = package.ToArray();
|
var dataToSend = package.ToArray();
|
||||||
stream.Write(dataToSend, 0, dataToSend.Length);
|
var s7data = RequestTsdu(dataToSend);
|
||||||
|
|
||||||
var s7data = COTP.TSDU.Read(stream); //TODO use Async
|
|
||||||
|
|
||||||
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
||||||
|
|
||||||
@@ -481,5 +464,12 @@ namespace S7.Net
|
|||||||
throw new PlcException(ErrorCode.ReadData, exc);
|
throw new PlcException(ErrorCode.ReadData, exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private byte[] RequestTsdu(byte[] requestData) => RequestTsdu(requestData, 0, requestData.Length);
|
||||||
|
|
||||||
|
private byte[] RequestTsdu(byte[] requestData, int offset, int length)
|
||||||
|
{
|
||||||
|
return RequestTsduAsync(requestData, offset, length).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,20 +14,51 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the value of a bit to 1 (true), given the address of the bit
|
/// Sets the value of a bit to 1 (true), given the address of the bit. Returns
|
||||||
|
/// a copy of the value with the bit set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="value">The input value to modify.</param>
|
||||||
|
/// <param name="bit">The index (zero based) of the bit to set.</param>
|
||||||
|
/// <returns>The modified value with the bit at index set.</returns>
|
||||||
public static byte SetBit(byte value, int bit)
|
public static byte SetBit(byte value, int bit)
|
||||||
{
|
{
|
||||||
return (byte)((value | (1 << bit)) & 0xFF);
|
SetBit(ref value, bit);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the value of a bit to 1 (true), given the address of the bit.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to modify.</param>
|
||||||
|
/// <param name="bit">The index (zero based) of the bit to set.</param>
|
||||||
|
public static void SetBit(ref byte value, int bit)
|
||||||
|
{
|
||||||
|
value = (byte) ((value | (1 << bit)) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the value of a bit to 0 (false), given the address of the bit. Returns
|
||||||
|
/// a copy of the value with the bit cleared.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input value to modify.</param>
|
||||||
|
/// <param name="bit">The index (zero based) of the bit to clear.</param>
|
||||||
|
/// <returns>The modified value with the bit at index cleared.</returns>
|
||||||
|
public static byte ClearBit(byte value, int bit)
|
||||||
|
{
|
||||||
|
ClearBit(ref value, bit);
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resets the value of a bit to 0 (false), given the address of the bit
|
/// Resets the value of a bit to 0 (false), given the address of the bit
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static byte ClearBit(byte value, int bit)
|
/// <param name="value">The input value to modify.</param>
|
||||||
|
/// <param name="bit">The index (zero based) of the bit to clear.</param>
|
||||||
|
public static void ClearBit(ref byte value, int bit)
|
||||||
{
|
{
|
||||||
return (byte)((value | (~(1 << bit))) & 0xFF);
|
value = (byte) (value & ~(1 << bit) & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user