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); } } }