iotgateway/Plugins/Drivers/DriverModbusMaster/NModbus4/IO/ModbusRtuTransport.cs

143 lines
4.6 KiB
C#

namespace Modbus.IO
{
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Message;
using Utility;
/// <summary>
/// Refined Abstraction - http://en.wikipedia.org/wiki/Bridge_Pattern
/// </summary>
internal class ModbusRtuTransport : ModbusSerialTransport
{
public const int RequestFrameStartLength = 7;
public const int ResponseFrameStartLength = 4;
internal ModbusRtuTransport(IStreamResource streamResource)
: base(streamResource)
{
Debug.Assert(streamResource != null, "Argument streamResource cannot be null.");
}
public static int RequestBytesToRead(byte[] frameStart)
{
byte functionCode = frameStart[1];
int numBytes;
switch (functionCode)
{
case Modbus.ReadCoils:
case Modbus.ReadInputs:
case Modbus.ReadHoldingRegisters:
case Modbus.ReadInputRegisters:
case Modbus.WriteSingleCoil:
case Modbus.WriteSingleRegister:
case Modbus.Diagnostics:
numBytes = 1;
break;
case Modbus.WriteMultipleCoils:
case Modbus.WriteMultipleRegisters:
byte byteCount = frameStart[6];
numBytes = byteCount + 2;
break;
default:
string msg = $"Function code {functionCode} not supported.";
Debug.WriteLine(msg);
throw new NotImplementedException(msg);
}
return numBytes;
}
public static int ResponseBytesToRead(byte[] frameStart)
{
byte functionCode = frameStart[1];
// exception response
if (functionCode > Modbus.ExceptionOffset)
{
return 1;
}
int numBytes;
switch (functionCode)
{
case Modbus.ReadCoils:
case Modbus.ReadInputs:
case Modbus.ReadHoldingRegisters:
case Modbus.ReadInputRegisters:
numBytes = frameStart[2] + 1;
break;
case Modbus.WriteSingleCoil:
case Modbus.WriteSingleRegister:
case Modbus.WriteMultipleCoils:
case Modbus.WriteMultipleRegisters:
case Modbus.Diagnostics:
numBytes = 4;
break;
default:
string msg = $"Function code {functionCode} not supported.";
Debug.WriteLine(msg);
throw new NotImplementedException(msg);
}
return numBytes;
}
public virtual byte[] Read(int count)
{
byte[] frameBytes = new byte[count];
int numBytesRead = 0;
while (numBytesRead != count)
{
numBytesRead += StreamResource.Read(frameBytes, numBytesRead, count - numBytesRead);
}
return frameBytes;
}
internal override byte[] BuildMessageFrame(IModbusMessage message)
{
var messageFrame = message.MessageFrame;
var crc = ModbusUtility.CalculateCrc(messageFrame);
var messageBody = new MemoryStream(messageFrame.Length + crc.Length);
messageBody.Write(messageFrame, 0, messageFrame.Length);
messageBody.Write(crc, 0, crc.Length);
return messageBody.ToArray();
}
internal override bool ChecksumsMatch(IModbusMessage message, byte[] messageFrame)
{
return BitConverter.ToUInt16(messageFrame, messageFrame.Length - 2) ==
BitConverter.ToUInt16(ModbusUtility.CalculateCrc(message.MessageFrame), 0);
}
internal override IModbusMessage ReadResponse<T>()
{
byte[] frameStart = Read(ResponseFrameStartLength);
byte[] frameEnd = Read(ResponseBytesToRead(frameStart));
byte[] frame = Enumerable.Concat(frameStart, frameEnd).ToArray();
Debug.WriteLine($"RX: {string.Join(", ", frame)}");
return CreateResponse<T>(frame);
}
internal override byte[] ReadRequest()
{
byte[] frameStart = Read(RequestFrameStartLength);
byte[] frameEnd = Read(RequestBytesToRead(frameStart));
byte[] frame = Enumerable.Concat(frameStart, frameEnd).ToArray();
Debug.WriteLine($"RX: {string.Join(", ", frame)}");
return frame;
}
}
}