using System;
using System.Collections.Generic;
using System.Linq;
namespace AMWD.Protocols.Modbus.Common
{
///
/// Custom extensions for s.
///
public static class ModbusSignedExtensions
{
///
/// Converts a into a value.
///
/// The Modbus object.
/// The objects signed byte value.
/// when the object is null.
/// when the wrong types are provided.
public static sbyte GetSByte(this ModbusObject obj)
{
#if NET8_0_OR_GREATER
ArgumentNullException.ThrowIfNull(obj);
#else
if (obj == null)
throw new ArgumentNullException(nameof(obj));
#endif
if (obj is HoldingRegister holdingRegister)
return (sbyte)holdingRegister.Value;
if (obj is InputRegister inputRegister)
return (sbyte)inputRegister.Value;
throw new ArgumentException($"The object type '{obj.GetType()}' is invalid", nameof(obj));
}
///
/// Converts a into a value.
///
/// The Modbus object.
/// The objects short value.
/// when the object is null.
/// when the wrong types are provided.
public static short GetInt16(this ModbusObject obj)
{
#if NET8_0_OR_GREATER
ArgumentNullException.ThrowIfNull(obj);
#else
if (obj == null)
throw new ArgumentNullException(nameof(obj));
#endif
if (obj is HoldingRegister holdingRegister)
return (short)holdingRegister.Value;
if (obj is InputRegister inputRegister)
return (short)inputRegister.Value;
throw new ArgumentException($"The object type '{obj.GetType()}' is invalid", nameof(obj));
}
///
/// Converts multiple s into a value.
///
/// The list of Modbus objects.
/// The first index to use.
/// Indicates whehter the taken registers should be reversed.
/// The objects int value.
/// when the list is null.
/// when the list is too short or the list contains mixed/incompatible objects.
/// when the is too high.
public static int GetInt32(this IEnumerable list, int startIndex = 0, bool reverseRegisterOrder = false)
{
#if NET8_0_OR_GREATER
ArgumentNullException.ThrowIfNull(list);
#else
if (list == null)
throw new ArgumentNullException(nameof(list));
#endif
int count = list.Count();
if (count < 2)
throw new ArgumentException("At least two registers required", nameof(list));
if (startIndex < 0 || startIndex + 2 > count)
throw new ArgumentOutOfRangeException(nameof(startIndex));
if (!list.All(o => o.Type == ModbusObjectType.HoldingRegister) && !list.All(o => o.Type == ModbusObjectType.InputRegister))
throw new ArgumentException("Mixed object typs found", nameof(list));
var registers = list.OrderBy(o => o.Address).Skip(startIndex).Take(2).ToArray();
if (reverseRegisterOrder)
Array.Reverse(registers);
byte[] blob = new byte[registers.Length * 2];
for (int i = 0; i < registers.Length; i++)
{
blob[i * 2] = registers[i].HighByte;
blob[i * 2 + 1] = registers[i].LowByte;
}
blob.SwapBigEndian();
return BitConverter.ToInt32(blob, 0);
}
///
/// Converts multiple s into a value.
///
/// The list of Modbus objects.
/// The first index to use.
/// Indicates whehter the taken registers should be reversed.
/// The objects long value.
/// when the list is null.
/// when the list is too short or the list contains mixed/incompatible objects.
/// when the is too high.
public static long GetInt64(this IEnumerable list, int startIndex = 0, bool reverseRegisterOrder = false)
{
#if NET8_0_OR_GREATER
ArgumentNullException.ThrowIfNull(list);
#else
if (list == null)
throw new ArgumentNullException(nameof(list));
#endif
int count = list.Count();
if (count < 4)
throw new ArgumentException("At least four registers required", nameof(list));
if (startIndex < 0 || startIndex + 4 > count)
throw new ArgumentOutOfRangeException(nameof(startIndex));
if (!list.All(o => o.Type == ModbusObjectType.HoldingRegister) && !list.All(o => o.Type == ModbusObjectType.InputRegister))
throw new ArgumentException("Mixed object typs found", nameof(list));
var registers = list.OrderBy(o => o.Address).Skip(startIndex).Take(4).ToArray();
if (reverseRegisterOrder)
Array.Reverse(registers);
byte[] blob = new byte[registers.Length * 2];
for (int i = 0; i < registers.Length; i++)
{
blob[i * 2] = registers[i].HighByte;
blob[i * 2 + 1] = registers[i].LowByte;
}
blob.SwapBigEndian();
return BitConverter.ToInt64(blob, 0);
}
///
/// Converts a value to a .
///
/// The signed byte value.
/// The register address.
/// The register.
public static HoldingRegister ToRegister(this sbyte value, ushort address)
{
return new HoldingRegister
{
Address = address,
LowByte = (byte)value
};
}
///
/// Converts a value to a .
///
/// The short value.
/// The register address.
/// The register.
public static HoldingRegister ToRegister(this short value, ushort address)
{
byte[] blob = BitConverter.GetBytes(value);
blob.SwapBigEndian();
return new HoldingRegister
{
Address = address,
HighByte = blob[0],
LowByte = blob[1]
};
}
///
/// Converts a value to a list of s.
///
/// The int value.
/// The first register address.
/// Indicates whehter the taken registers should be reversed.
/// The list of registers.
public static IEnumerable ToRegister(this int value, ushort address, bool reverseRegisterOrder = false)
{
byte[] blob = BitConverter.GetBytes(value);
blob.SwapBigEndian();
int numRegisters = blob.Length / 2;
for (int i = 0; i < numRegisters; i++)
{
int addr = reverseRegisterOrder
? address + numRegisters - 1 - i
: address + i;
yield return new HoldingRegister
{
Address = (ushort)addr,
HighByte = blob[i * 2],
LowByte = blob[i * 2 + 1]
};
}
}
///
/// Converts a value to a list of s.
///
/// The long value.
/// The first register address.
/// Indicates whehter the taken registers should be reversed.
/// The list of registers.
public static IEnumerable ToRegister(this long value, ushort address, bool reverseRegisterOrder = false)
{
byte[] blob = BitConverter.GetBytes(value);
blob.SwapBigEndian();
int numRegisters = blob.Length / 2;
for (int i = 0; i < numRegisters; i++)
{
int addr = reverseRegisterOrder
? address + numRegisters - 1 - i
: address + i;
yield return new HoldingRegister
{
Address = (ushort)addr,
HighByte = blob[i * 2],
LowByte = blob[i * 2 + 1]
};
}
}
}
}