Add S7 Time type (C# TimeSpan)

Adds the S7 TIME (IEC) type (32 bits long)
It is deserialized to C# TimeSpan and serialized as S7 DInt.
This commit is contained in:
Dawid Pągowski
2023-07-19 20:30:32 +02:00
parent e869d19587
commit 0d2817661e
4 changed files with 113 additions and 3 deletions

View File

@@ -1006,7 +1006,7 @@ namespace S7.Net.UnitTest
var db = 2;
randomEngine.NextBytes(data);
cancellationSource.CancelAfter(TimeSpan.FromMilliseconds(5));
cancellationSource.CancelAfter(System.TimeSpan.FromMilliseconds(5));
try
{
await plc.WriteBytesAsync(DataType.DataBlock, db, 0, data, cancellationToken);
@@ -1045,7 +1045,7 @@ namespace S7.Net.UnitTest
var db = 2;
randomEngine.NextBytes(data.Span);
cancellationSource.CancelAfter(TimeSpan.FromMilliseconds(5));
cancellationSource.CancelAfter(System.TimeSpan.FromMilliseconds(5));
try
{
await plc.WriteBytesAsync(DataType.DataBlock, db, 0, data, cancellationToken);

View File

@@ -206,6 +206,11 @@
/// <summary>
/// DateTimeLong variable type
/// </summary>
DateTimeLong
DateTimeLong,
/// <summary>
/// S7 TIME variable type - serialized as S7 DInt and deserialized as C# TimeSpan
/// </summary>
Time
}
}

View File

@@ -167,6 +167,15 @@ namespace S7.Net
{
return DateTimeLong.ToArray(bytes);
}
case VarType.Time:
if (varCount == 1)
{
return TimeSpan.FromByteArray(bytes);
}
else
{
return TimeSpan.ToArray(bytes);
}
default:
return null;
}
@@ -200,6 +209,7 @@ namespace S7.Net
case VarType.DWord:
case VarType.DInt:
case VarType.Real:
case VarType.Time:
return varCount * 4;
case VarType.LReal:
case VarType.DateTime:

95
S7.Net/Types/TimeSpan.cs Normal file
View File

@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
namespace S7.Net.Types
{
public static class TimeSpan
{
/// <summary>
/// The minimum <see cref="T:System.TimeSpan"/> value supported by the specification.
/// </summary>
public static readonly System.TimeSpan SpecMinimumTimeSpan = System.TimeSpan.FromMilliseconds(int.MinValue);
/// <summary>
/// The maximum <see cref="T:System.TimeSpan"/> value supported by the specification.
/// </summary>
public static readonly System.TimeSpan SpecMaximumTimeSpan = System.TimeSpan.FromMilliseconds(int.MaxValue);
/// <summary>
/// Parses a <see cref="T:System.TimeSpan"/> value from bytes.
/// </summary>
/// <param name="bytes">Input bytes read from PLC.</param>
/// <returns>A <see cref="T:System.TimeSpan"/> object representing the value read from PLC.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when the length of
/// <paramref name="bytes"/> is not 4 or any value in <paramref name="bytes"/>
/// is outside the valid range of values.</exception>
public static System.TimeSpan FromByteArray(byte[] bytes)
{
var milliseconds = DInt.FromByteArray(bytes);
return System.TimeSpan.FromMilliseconds(milliseconds);
}
/// <summary>
/// Parses an array of <see cref="T:System.TimeSpan"/> values from bytes.
/// </summary>
/// <param name="bytes">Input bytes read from PLC.</param>
/// <returns>An array of <see cref="T:System.TimeSpan"/> objects representing the values read from PLC.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when the length of
/// <paramref name="bytes"/> is not a multiple of 4 or any value in
/// <paramref name="bytes"/> is outside the valid range of values.</exception>
public static System.TimeSpan[] ToArray(byte[] bytes)
{
const int singleTimeSpanLength = 4;
if (bytes.Length % singleTimeSpanLength != 0)
throw new ArgumentOutOfRangeException(nameof(bytes), bytes.Length,
$"Parsing an array of {nameof(System.TimeSpan)} requires a multiple of {singleTimeSpanLength} bytes of input data, input data is '{bytes.Length}' long.");
var cnt = bytes.Length / singleTimeSpanLength;
var result = new System.TimeSpan[bytes.Length / singleTimeSpanLength];
var milliseconds = DInt.ToArray(bytes);
for (var i = 0; i < milliseconds.Length; i++)
result[i] = System.TimeSpan.FromMilliseconds(milliseconds[i]);
return result;
}
/// <summary>
/// Converts a <see cref="T:System.DateTime"/> value to a byte array.
/// </summary>
/// <param name="timeSpan">The DateTime value to convert.</param>
/// <returns>A byte array containing the S7 date time representation of <paramref name="timeSpan"/>.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when the value of
/// <paramref name="timeSpan"/> is before <see cref="P:SpecMinimumDateTime"/>
/// or after <see cref="P:SpecMaximumDateTime"/>.</exception>
public static byte[] ToByteArray(System.TimeSpan timeSpan)
{
if (timeSpan < SpecMinimumTimeSpan)
throw new ArgumentOutOfRangeException(nameof(timeSpan), timeSpan,
$"Time span '{timeSpan}' is before the minimum '{SpecMinimumTimeSpan}' supported in S7 time representation.");
if (timeSpan > SpecMaximumTimeSpan)
throw new ArgumentOutOfRangeException(nameof(timeSpan), timeSpan,
$"Time span '{timeSpan}' is after the maximum '{SpecMaximumTimeSpan}' supported in S7 time representation.");
return DInt.ToByteArray(Convert.ToInt32(timeSpan.TotalMilliseconds));
}
/// <summary>
/// Converts an array of <see cref="T:System.DateTime"/> values to a byte array.
/// </summary>
/// <param name="timeSpans">The DateTime values to convert.</param>
/// <returns>A byte array containing the S7 date time representations of <paramref name="dateTime"/>.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when any value of
/// <paramref name="timeSpans"/> is before <see cref="P:SpecMinimumDateTime"/>
/// or after <see cref="P:SpecMaximumDateTime"/>.</exception>
public static byte[] ToByteArray(System.TimeSpan[] timeSpans)
{
var bytes = new List<byte>(timeSpans.Length * 4);
foreach (var timeSpan in timeSpans) bytes.AddRange(ToByteArray(timeSpan));
return bytes.ToArray();
}
}
}