using System;
using System.Linq;
using System.Threading.Tasks;
namespace NModbus.Extensions.Enron
{
///
/// Utility extensions for the Enron Modbus dialect.
///
public static class EnronModbus
{
///
/// Reads contiguous block of input registers with 32 bit register size.
///
/// The Modbus master.
/// Address of device to read values from.
/// Address to begin reading.
/// Number of holding registers to read.
/// Input registers status.
public static uint[] ReadInputRegisters32(this IModbusMaster master, byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
var registers = master.ReadInputRegisters(slaveAddress, startAddress, (ushort)(numberOfPoints * 2));
return ConvertTo32(registers);
}
///
/// Reads contiguous block of holding registers.
///
/// The Modbus master.
/// Address of device to read values from.
/// Address to begin reading.
/// Number of holding registers to read.
/// Holding registers status.
public static uint[] ReadHoldingRegisters32(this IModbusMaster master, byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
var registers = master.ReadHoldingRegisters(slaveAddress, startAddress, (ushort)(numberOfPoints * 2));
return ConvertTo32(registers);
}
///
/// Asynchronously reads contiguous block of input registers with 32 bit register size.
///
/// The Modbus master.
/// Address of device to read values from.
/// Address to begin reading.
/// Number of holding registers to read.
/// A task that represents the asynchronous read operation.
public static async Task ReadInputRegisters32Async(this IModbusMaster master, byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
var registers = await master.ReadInputRegistersAsync(slaveAddress, startAddress, (ushort)(numberOfPoints * 2));
return ConvertTo32(registers);
}
///
/// Asynchronously reads contiguous block of holding registers.
///
/// The Modbus master.
/// Address of device to read values from.
/// Address to begin reading.
/// Number of holding registers to read.
/// A task that represents the asynchronous read operation.
public static async Task ReadHoldingRegisters32Async(this IModbusMaster master, byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
var registers = await master.ReadHoldingRegistersAsync(slaveAddress, startAddress, (ushort)(numberOfPoints * 2));
return ConvertTo32(registers);
}
///
/// Write a single 16 bit holding register.
///
/// The Modbus master.
/// Address of the device to write to.
/// Address to write.
/// Value to write.
public static void WriteSingleRegister32(
this IModbusMaster master,
byte slaveAddress,
ushort registerAddress,
uint value)
{
if (master == null) throw new ArgumentNullException(nameof(master));
master.WriteMultipleRegisters32(slaveAddress, registerAddress, new[] { value });
}
///
/// Write a block of contiguous 32 bit holding registers.
///
/// The Modbus master.
/// Address of the device to write to.
/// Address to begin writing values.
/// Values to write.
public static void WriteMultipleRegisters32(
this IModbusMaster master,
byte slaveAddress,
ushort startAddress,
uint[] data)
{
if (master == null) throw new ArgumentNullException(nameof(master));
if (data == null) throw new ArgumentNullException(nameof(data));
master.WriteMultipleRegisters(slaveAddress, startAddress, ConvertFrom32(data).ToArray());
}
/// Convert the 32 bit registers to two 16 bit values.
public static ushort[] ConvertFrom32(uint[] registers)
{
var result = new ushort[registers.Length * 2];
var index = 0;
foreach (var register in registers)
{
var bytes = BitConverter.GetBytes(register);
// low order value
result[index++] = BitConverter.ToUInt16(bytes, 2);
// high order value
result[index++] = BitConverter.ToUInt16(bytes, 0);
}
return result;
}
/// Convert the double 16 bit registers to single 32 bit values.
public static uint[] ConvertTo32(ushort[] registers)
{
if (registers.Length % 2 != 0)
throw new ArgumentException("registers must have an even number of elements.", nameof(registers));
var numberOfResult = registers.Length / 2;
var result = new uint[numberOfResult];
for(var index = 0; index < numberOfResult; index++)
{
result[index] = ((uint)registers[index * 2]) << 16 | registers[(index * 2) + 1];
}
return result;
}
}
}