using System; using System.Collections.Generic; using System.Linq; namespace AMWD.Protocols.Modbus.Common { /// /// Custom extensions for s. /// public static class ModbusDecimalExtensions { /// /// 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 float 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 float GetSingle(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.ToSingle(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 double 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 double GetDouble(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.ToDouble(blob, 0); } /// /// Converts a value to a list of s. /// /// The float value. /// The first register address. /// Indicates whehter the taken registers should be reversed. /// The list of registers. public static IEnumerable ToRegister(this float 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 double value. /// The first register address. /// Indicates whehter the taken registers should be reversed. /// The list of registers. public static IEnumerable ToRegister(this double 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] }; } } } }