Plc.Clock.cs 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using S7.Net.Helper;
  5. using S7.Net.Types;
  6. using DateTime = System.DateTime;
  7. namespace S7.Net;
  8. partial class Plc
  9. {
  10. private const byte SzlFunctionGroupTimers = 0x07;
  11. private const byte SzlSubFunctionReadClock = 0x01;
  12. private const byte SzlSubFunctionWriteClock = 0x02;
  13. private const byte TransportSizeOctetString = 0x09;
  14. private const int PduErrOffset = 20;
  15. private const int UserDataResultOffset = PduErrOffset + 2;
  16. /// <summary>
  17. /// The length in bytes of DateTime stored in the PLC.
  18. /// </summary>
  19. private const int DateTimeLength = 10;
  20. private static byte[] BuildClockReadRequest()
  21. {
  22. var stream = new MemoryStream();
  23. WriteUserDataRequest(stream, SzlFunctionGroupTimers, SzlSubFunctionReadClock, 4);
  24. stream.Write(new byte[] { 0x0a, 0x00, 0x00, 0x00 });
  25. stream.SetLength(stream.Position);
  26. return stream.ToArray();
  27. }
  28. private static DateTime ParseClockReadResponse(byte[] message)
  29. {
  30. const int udLenOffset = UserDataResultOffset + 2;
  31. const int udValueOffset = udLenOffset + 2;
  32. const int dateTimeSkip = 2;
  33. AssertPduResult(message);
  34. AssertUserDataResult(message, 0xff);
  35. var len = Word.FromByteArray(message.Skip(udLenOffset).Take(2).ToArray());
  36. if (len != DateTimeLength)
  37. {
  38. throw new Exception($"Unexpected response length {len}, expected {DateTimeLength}.");
  39. }
  40. // Skip first 2 bytes from date time value because DateTime.FromByteArray doesn't parse them.
  41. return Types.DateTime.FromByteArray(message.Skip(udValueOffset + dateTimeSkip)
  42. .Take(DateTimeLength - dateTimeSkip).ToArray());
  43. }
  44. private static byte[] BuildClockWriteRequest(DateTime value)
  45. {
  46. var stream = new MemoryStream();
  47. WriteUserDataRequest(stream, SzlFunctionGroupTimers, SzlSubFunctionWriteClock, 14);
  48. stream.Write(new byte[] { 0xff, TransportSizeOctetString, 0x00, DateTimeLength });
  49. // Start of DateTime value, DateTime.ToByteArray only serializes the final 8 bytes
  50. stream.Write(new byte[] { 0x00, 0x19 });
  51. stream.Write(Types.DateTime.ToByteArray(value));
  52. stream.SetLength(stream.Position);
  53. return stream.ToArray();
  54. }
  55. private static void ParseClockWriteResponse(byte[] message)
  56. {
  57. AssertPduResult(message);
  58. AssertUserDataResult(message, 0x0a);
  59. }
  60. private static void AssertPduResult(byte[] message)
  61. {
  62. var pduErr = Word.FromByteArray(message.Skip(PduErrOffset).Take(2).ToArray());
  63. if (pduErr != 0)
  64. {
  65. throw new Exception($"Response from PLC indicates error 0x{pduErr:X4}.");
  66. }
  67. }
  68. private static void AssertUserDataResult(byte[] message, byte expected)
  69. {
  70. var dtResult = message[UserDataResultOffset];
  71. if (dtResult != expected)
  72. {
  73. throw new Exception($"Response from PLC was 0x{dtResult:X2}, expected 0x{expected:X2}.");
  74. }
  75. }
  76. }