using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using Modbus.Data;
using Modbus.IO;
using Modbus.Message;
using Modbus.Utility;
namespace Modbus.Device
{
///
/// Modbus master device.
///
public abstract class ModbusMaster : ModbusDevice, IModbusMaster
{
internal ModbusMaster(ModbusTransport transport)
: base(transport)
{
}
///
/// Read from 1 to 2000 contiguous coils status.
///
/// Address of device to read values from.
/// Address to begin reading.
/// Number of coils to read.
/// Coils status
public bool[] ReadCoils(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
ValidateNumberOfPoints("numberOfPoints", numberOfPoints, 2000);
return ReadDiscretes(Modbus.ReadCoils, slaveAddress, startAddress, numberOfPoints);
}
///
/// Read from 1 to 2000 contiguous discrete input status.
///
/// Address of device to read values from.
/// Address to begin reading.
/// Number of discrete inputs to read.
/// Discrete inputs status
public bool[] ReadInputs(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
ValidateNumberOfPoints("numberOfPoints", numberOfPoints, 2000);
return ReadDiscretes(Modbus.ReadInputs, slaveAddress, startAddress, numberOfPoints);
}
///
/// Read contiguous block of holding registers.
///
/// Address of device to read values from.
/// Address to begin reading.
/// Number of holding registers to read.
/// Holding registers status
public ushort[] ReadHoldingRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
ValidateNumberOfPoints("numberOfPoints", numberOfPoints, 125);
return ReadRegisters(Modbus.ReadHoldingRegisters, slaveAddress, startAddress, numberOfPoints);
}
///
/// Read contiguous block of input registers.
///
/// Address of device to read values from.
/// Address to begin reading.
/// Number of holding registers to read.
/// Input registers status
public ushort[] ReadInputRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
ValidateNumberOfPoints("numberOfPoints", numberOfPoints, 125);
return ReadRegisters(Modbus.ReadInputRegisters, slaveAddress, startAddress, numberOfPoints);
}
///
/// Write a single coil value.
///
/// Address of the device to write to.
/// Address to write value to.
/// Value to write.
public void WriteSingleCoil(byte slaveAddress, ushort coilAddress, bool value)
{
WriteSingleCoilRequestResponse request = new WriteSingleCoilRequestResponse(slaveAddress, coilAddress, value);
Transport.UnicastMessage(request);
}
///
/// Write a single holding register.
///
/// Address of the device to write to.
/// Value to write.
/// Value to write.
public void WriteSingleRegister(byte slaveAddress, ushort registerAddress, ushort value)
{
WriteSingleRegisterRequestResponse request = new WriteSingleRegisterRequestResponse(slaveAddress, registerAddress, value);
Transport.UnicastMessage(request);
}
///
/// Write a block of 1 to 123 contiguous registers.
///
/// Address of the device to write to.
/// Address to begin writing values.
/// Values to write.
public void WriteMultipleRegisters(byte slaveAddress, ushort startAddress, ushort[] data)
{
ValidateData("data", data, 123);
WriteMultipleRegistersRequest request = new WriteMultipleRegistersRequest(slaveAddress, startAddress, new RegisterCollection(data));
Transport.UnicastMessage(request);
}
///
/// Force each coil in a sequence of coils to a provided value.
///
/// Address of the device to write to.
/// Address to begin writing values.
/// Values to write.
public void WriteMultipleCoils(byte slaveAddress, ushort startAddress, bool[] data)
{
ValidateData("data", data, 1968);
WriteMultipleCoilsRequest request = new WriteMultipleCoilsRequest(slaveAddress, startAddress, new DiscreteCollection(data));
Transport.UnicastMessage(request);
}
///
/// Performs a combination of one read operation and one write operation in a single Modbus transaction.
/// The write operation is performed before the read.
///
/// Address of device to read values from.
/// Address to begin reading (Holding registers are addressed starting at 0).
/// Number of registers to read.
/// Address to begin writing (Holding registers are addressed starting at 0).
/// Register values to write.
public ushort[] ReadWriteMultipleRegisters(byte slaveAddress, ushort startReadAddress, ushort numberOfPointsToRead, ushort startWriteAddress, ushort[] writeData)
{
ValidateNumberOfPoints("numberOfPointsToRead", numberOfPointsToRead, 125);
ValidateData("writeData", writeData, 121);
ReadWriteMultipleRegistersRequest request = new ReadWriteMultipleRegistersRequest(slaveAddress, startReadAddress, numberOfPointsToRead, startWriteAddress, new RegisterCollection(writeData));
ReadHoldingInputRegistersResponse response = Transport.UnicastMessage(request);
return CollectionUtility.ToArray(response.Data);
}
///
/// Executes the custom message.
///
/// The type of the response.
/// The request.
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
[SuppressMessage("Microsoft.Usage", "CA2223:MembersShouldDifferByMoreThanReturnType")]
public TResponse ExecuteCustomMessage(IModbusMessage request) where TResponse : IModbusMessage, new()
{
return Transport.UnicastMessage(request);
}
internal static void ValidateData(string argumentName, T[] data, int maxDataLength)
{
if (data == null)
throw new ArgumentNullException("data");
if (data.Length == 0 || data.Length > maxDataLength)
{
throw new ArgumentException(String.Format(CultureInfo.InvariantCulture,
"The length of argument {0} must be between 1 and {1} inclusive.", argumentName, maxDataLength));
}
}
internal static void ValidateNumberOfPoints(string argumentName, ushort numberOfPoints, ushort maxNumberOfPoints)
{
if (numberOfPoints < 1 || numberOfPoints > maxNumberOfPoints)
{
throw new ArgumentException(String.Format(CultureInfo.InvariantCulture,
"Argument {0} must be between 1 and {1} inclusive.", argumentName, maxNumberOfPoints));
}
}
internal ushort[] ReadRegisters(byte functionCode, byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
ReadHoldingInputRegistersRequest request = new ReadHoldingInputRegistersRequest(functionCode, slaveAddress, startAddress, numberOfPoints);
ReadHoldingInputRegistersResponse response = Transport.UnicastMessage(request);
return CollectionUtility.ToArray(response.Data);
}
internal bool[] ReadDiscretes(byte functionCode, byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
ReadCoilsInputsRequest request = new ReadCoilsInputsRequest(functionCode, slaveAddress, startAddress, numberOfPoints);
ReadCoilsInputsResponse response = Transport.UnicastMessage(request);
return CollectionUtility.Slice(response.Data, 0, request.NumberOfPoints);
}
}
}