143 lines
4.7 KiB
C#
143 lines
4.7 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;
|
|
}
|
|
}
|
|
}
|