Skip to content

Commit

Permalink
Merge pull request #506 from bonk-dev/s5-date
Browse files Browse the repository at this point in the history
Add support for reading/writing the legacy DATE (IEC date) datatype
  • Loading branch information
mycroes authored Sep 7, 2023
2 parents 76a7ea0 + 130eead commit ab6308e
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 0 deletions.
5 changes: 5 additions & 0 deletions S7.Net/Enums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ public enum VarType
/// DateTIme variable type
/// </summary>
DateTime,

/// <summary>
/// IEC date (legacy) variable type
/// </summary>
Date,

/// <summary>
/// DateTimeLong variable type
Expand Down
23 changes: 23 additions & 0 deletions S7.Net/Helper/DateTimeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using S7.Net.Types;
using DateTime = System.DateTime;

namespace S7.Net.Helper
{
public static class DateTimeExtensions
{
public static ushort GetDaysSinceIecDateStart(this DateTime dateTime)
{
if (dateTime < Date.IecMinDate)
{
throw new ArgumentOutOfRangeException($"DateTime must be at least {Date.IecMinDate:d}");
}
if (dateTime > Date.IecMaxDate)
{
throw new ArgumentOutOfRangeException($"DateTime must be lower than {Date.IecMaxDate:d}");
}

return (ushort)(dateTime - Date.IecMinDate).TotalDays;
}
}
}
10 changes: 10 additions & 0 deletions S7.Net/PLCHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,15 @@ private static void BuildReadDataRequestPackage(System.IO.MemoryStream stream, D
{
return TimeSpan.ToArray(bytes);
}
case VarType.Date:
if (varCount == 1)
{
return Date.FromByteArray(bytes);
}
else
{
return Date.ToArray(bytes);
}
default:
return null;
}
Expand Down Expand Up @@ -280,6 +289,7 @@ internal static int VarTypeToByteLength(VarType varType, int varCount = 1)
case VarType.Timer:
case VarType.Int:
case VarType.Counter:
case VarType.Date:
return varCount * 2;
case VarType.DWord:
case VarType.DInt:
Expand Down
5 changes: 5 additions & 0 deletions S7.Net/Protocol/Serialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ public static byte[] SerializeDataItem(DataItem dataItem)
_ => Types.String.ToByteArray(s, dataItem.Count)
};

if (dataItem.VarType == VarType.Date)
{
return Date.ToByteArray((System.DateTime)dataItem.Value);
}

return SerializeValue(dataItem.Value);
}

Expand Down
82 changes: 82 additions & 0 deletions S7.Net/Types/Date.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System;
using S7.Net.Helper;

namespace S7.Net.Types
{
/// <summary>
/// Contains the conversion methods to convert Words from S7 plc to C#.
/// </summary>
public static class Date
{
/// <summary>
/// Minimum allowed date for the IEC date type
/// </summary>
public static System.DateTime IecMinDate { get; } = new(year: 1990, month: 01, day: 01);

/// <summary>
/// Maximum allowed date for the IEC date type
/// <remarks>
/// Although the spec allows only a max date of 31-12-2168, the PLC IEC date goes up to 06-06-2169 (which is the actual
/// WORD max value - 65535)
/// </remarks>
/// </summary>
public static System.DateTime IecMaxDate { get; } = new(year: 2169, month: 06, day: 06);

private static readonly ushort MaxNumberOfDays = (ushort)(IecMaxDate - IecMinDate).TotalDays;

/// <summary>
/// Converts a word (2 bytes) to IEC date (<see cref="System.DateTime"/>)
/// </summary>
public static System.DateTime FromByteArray(byte[] bytes)
{
if (bytes.Length != 2)
{
throw new ArgumentException("Wrong number of bytes. Bytes array must contain 2 bytes.");
}

var daysSinceDateStart = Word.FromByteArray(bytes);
if (daysSinceDateStart > MaxNumberOfDays)
{
throw new ArgumentException($"Read number exceeded the number of maximum days in the IEC date (read: {daysSinceDateStart}, max: {MaxNumberOfDays})",
nameof(bytes));
}

return IecMinDate.AddDays(daysSinceDateStart);
}

/// <summary>
/// Converts a <see cref="System.DateTime"/> to word (2 bytes)
/// </summary>
public static byte[] ToByteArray(System.DateTime dateTime) => Word.ToByteArray(dateTime.GetDaysSinceIecDateStart());

/// <summary>
/// Converts an array of <see cref="System.DateTime"/>s to an array of bytes
/// </summary>
public static byte[] ToByteArray(System.DateTime[] value)
{
var arr = new ByteArray();
foreach (var date in value)
arr.Add(ToByteArray(date));
return arr.Array;
}

/// <summary>
/// Converts an array of bytes to an array of <see cref="System.DateTime"/>s
/// </summary>
public static System.DateTime[] ToArray(byte[] bytes)
{
var values = new System.DateTime[bytes.Length / sizeof(ushort)];

for (int i = 0; i < values.Length; i++)
{
values[i] = FromByteArray(
new[]
{
bytes[i], bytes[i + 1]
});
}

return values;
}
}
}

0 comments on commit ab6308e

Please sign in to comment.