using System.Reflection; using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames; using InnovEnergy.Lib.Protocols.Modbus.Reflection.Attributes; using InnovEnergy.Lib.Utils; using static System.Reflection.BindingFlags; namespace InnovEnergy.Lib.Protocols.Modbus.Reflection; using ModbusRegisters = IReadOnlyList; using ModbusBooleans = IReadOnlyList; using UInt16s = IReadOnlyList; using Booleans = IReadOnlyList; internal static class Batches { internal static IEnumerable GetModbusRegisterBatches(this Object statusRecord) where T : ModbusRegisterAttribute { var modbusRegisters = from mi in statusRecord.GetDataMembers() from a in mi.GetCustomAttributes() select new ModbusRegister(a, mi, statusRecord); return modbusRegisters.SplitIntoFrameSizedBatches(); } internal static IEnumerable GetModbusBooleanBatches(this Object statusRecord) where T : ModbusBooleanAttribute { var modbusBooleans = from mi in statusRecord.GetDataMembers() from a in mi.GetCustomAttributes() select new ModbusBoolean(a, mi, statusRecord); return modbusBooleans.SplitIntoFrameSizedBatches(); } private static IEnumerable GetDataMembers(this Object statusRecord) { const BindingFlags bindingFlags = Instance | Public | NonPublic | FlattenHierarchy; var type = statusRecord.GetType(); var fields = type.GetFields(bindingFlags); var props = type.GetProperties(bindingFlags); return fields.Concat(props); } private static IEnumerable SplitIntoFrameSizedBatches(this IEnumerable members) where T : IAddress { return members .OrderBy(m => m.Address) .GroupWhile((a, b) => b.Address - a.Address > 1) // split when there is a gap between consecutive addresses .SelectMany(g => g.Chunk(Constants.MaxRegs)); // group cannot be larger than Constants.MaxRegs } public static IEnumerable SetStatusRecordMembersFromRawModbusValues(this ModbusRegisters modbusBooleans, UInt16s rawRegisterValues) { foreach (var modbusBoolean in modbusBooleans) { var index = modbusBoolean.Address - modbusBooleans[0].Address; var rawRegisterValue = rawRegisterValues[index]; modbusBoolean.SetStatusRecordMemberFromRawModbusValue(rawRegisterValue); yield return modbusBoolean.Address; } } public static UInt16[] GetRawModbusValuesFromControlRecord(this ModbusRegisters modbusBooleans) { return modbusBooleans .Select(v => v.GetRawModbusValueFromControlRecord()) .ToArray(modbusBooleans.Count); } public static IEnumerable SetStatusRecordMembersFromRawModbusValues(this ModbusBooleans modbusBooleans, Booleans rawRegisterValues) { foreach (var modbusBoolean in modbusBooleans) { var index = modbusBoolean.Address - modbusBooleans[0].Address; var rawRegisterValue = rawRegisterValues[index]; modbusBoolean.SetStatusRecordMemberFromRawModbusValue(rawRegisterValue); yield return modbusBoolean.Address; } } public static Boolean[] GetRawModbusValuesFromControlRecord(this ModbusBooleans modbusBooleans) { return modbusBooleans .Select(v => v.GetRawModbusValueFromControlRecord()) .ToArray(modbusBooleans.Count); } }