ModbusRtuTransport.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. using System;
  2. using System.Diagnostics;
  3. using System.IO;
  4. using System.Linq;
  5. using NModbus.Extensions;
  6. using NModbus.Logging;
  7. using NModbus.Utility;
  8. namespace NModbus.IO
  9. {
  10. /// <summary>
  11. /// Refined Abstraction - http://en.wikipedia.org/wiki/Bridge_Pattern
  12. /// </summary>
  13. internal class ModbusRtuTransport : ModbusSerialTransport, IModbusRtuTransport
  14. {
  15. public const int RequestFrameStartLength = 7;
  16. public const int ResponseFrameStartLength = 4;
  17. internal ModbusRtuTransport(IStreamResource streamResource, IModbusFactory modbusFactory, IModbusLogger logger)
  18. : base(streamResource, modbusFactory, logger)
  19. {
  20. if (modbusFactory == null) throw new ArgumentNullException(nameof(modbusFactory));
  21. Debug.Assert(streamResource != null, "Argument streamResource cannot be null.");
  22. }
  23. internal int RequestBytesToRead(byte[] frameStart)
  24. {
  25. byte functionCode = frameStart[1];
  26. IModbusFunctionService service = ModbusFactory.GetFunctionServiceOrThrow(functionCode);
  27. return service.GetRtuRequestBytesToRead(frameStart);
  28. }
  29. internal int ResponseBytesToRead(byte[] frameStart)
  30. {
  31. byte functionCode = frameStart[1];
  32. if (functionCode > Modbus.ExceptionOffset)
  33. {
  34. return 1;
  35. }
  36. IModbusFunctionService service = ModbusFactory.GetFunctionServiceOrThrow(functionCode);
  37. return service.GetRtuResponseBytesToRead(frameStart);
  38. }
  39. public virtual byte[] Read(int count)
  40. {
  41. byte[] frameBytes = new byte[count];
  42. int numBytesReadTotal = 0;
  43. while (numBytesReadTotal != count)
  44. {
  45. int numBytesRead = StreamResource.Read(frameBytes, numBytesReadTotal, count - numBytesReadTotal);
  46. if (numBytesRead == 0)
  47. {
  48. throw new IOException("Read resulted in 0 bytes returned.");
  49. }
  50. numBytesReadTotal += numBytesRead;
  51. }
  52. return frameBytes;
  53. }
  54. public override byte[] BuildMessageFrame(IModbusMessage message)
  55. {
  56. var messageFrame = message.MessageFrame;
  57. var crc = ModbusUtility.CalculateCrc(messageFrame);
  58. var messageBody = new MemoryStream(messageFrame.Length + crc.Length);
  59. messageBody.Write(messageFrame, 0, messageFrame.Length);
  60. messageBody.Write(crc, 0, crc.Length);
  61. return messageBody.ToArray();
  62. }
  63. public override bool ChecksumsMatch(IModbusMessage message, byte[] messageFrame)
  64. {
  65. ushort messageCrc = BitConverter.ToUInt16(messageFrame, messageFrame.Length - 2);
  66. ushort calculatedCrc = BitConverter.ToUInt16(ModbusUtility.CalculateCrc(message.MessageFrame), 0);
  67. return messageCrc == calculatedCrc;
  68. }
  69. public override IModbusMessage ReadResponse<T>()
  70. {
  71. byte[] frame = ReadResponse();
  72. Logger.LogFrameRx(frame);
  73. return CreateResponse<T>(frame);
  74. }
  75. private byte[] ReadResponse()
  76. {
  77. byte[] frameStart = Read(ResponseFrameStartLength);
  78. byte[] frameEnd = Read(ResponseBytesToRead(frameStart));
  79. byte[] frame = frameStart.Concat(frameEnd).ToArray();
  80. return frame;
  81. }
  82. public override void IgnoreResponse()
  83. {
  84. byte[] frame = ReadResponse();
  85. Logger.LogFrameIgnoreRx(frame);
  86. }
  87. public override byte[] ReadRequest()
  88. {
  89. byte[] frameStart = Read(RequestFrameStartLength);
  90. byte[] frameEnd = Read(RequestBytesToRead(frameStart));
  91. byte[] frame = frameStart.Concat(frameEnd).ToArray();
  92. Logger.LogFrameRx(frame);
  93. return frame;
  94. }
  95. }
  96. }