Innovenergy_trunk/csharp/Lib/Protocols/Modbus/Reflection/Batches.cs

100 lines
3.8 KiB
C#

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<ModbusRegister>;
using ModbusBooleans = IReadOnlyList<ModbusBoolean>;
using UInt16s = IReadOnlyList<UInt16>;
using Booleans = IReadOnlyList<Boolean>;
internal static class Batches
{
internal static IEnumerable<ModbusRegister[]> GetModbusRegisterBatches<T>(this Object statusRecord) where T : ModbusRegisterAttribute
{
var modbusRegisters = from mi in statusRecord.GetDataMembers()
from a in mi.GetCustomAttributes<T>()
select new ModbusRegister(a, mi, statusRecord);
return modbusRegisters.SplitIntoFrameSizedBatches();
}
internal static IEnumerable<ModbusBoolean[]> GetModbusBooleanBatches<T>(this Object statusRecord) where T : ModbusBooleanAttribute
{
var modbusBooleans = from mi in statusRecord.GetDataMembers()
from a in mi.GetCustomAttributes<T>()
select new ModbusBoolean(a, mi, statusRecord);
return modbusBooleans.SplitIntoFrameSizedBatches();
}
private static IEnumerable<MemberInfo> 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<MemberInfo>(props);
}
private static IEnumerable<T[]> SplitIntoFrameSizedBatches<T>(this IEnumerable<T> 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<UInt16> 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<UInt16> 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);
}
}