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

98 lines
2.7 KiB
C#

using System.Reflection;
using InnovEnergy.Lib.Protocols.Modbus.Reflection.Attributes;
using InnovEnergy.Lib.Utils;
#pragma warning disable CS8509
namespace InnovEnergy.Lib.Protocols.Modbus.Reflection;
internal readonly struct ModbusRegister : IAddress
{
public UInt16 Address => _Attribute.Address;
public Decimal Offset => (Decimal)_Attribute.Offset;
public Decimal Scale => (Decimal)_Attribute.Scale;
private readonly Object _Record;
private readonly ModbusRegisterAttribute _Attribute;
private readonly MemberInfo _MemberInfo;
private static readonly Type[] UnsignedTypes =
{
typeof(Byte),
typeof(UInt16),
typeof(UInt32),
typeof(UInt64),
};
private Boolean IsUnsigned
{
get
{
var type = _MemberInfo switch
{
FieldInfo fi => fi.FieldType,
PropertyInfo pi => pi.PropertyType
};
type = type.IsEnum
? Enum.GetUnderlyingType(type)
: type;
return UnsignedTypes.Contains(type);
}
}
public ModbusRegister(ModbusRegisterAttribute attribute, MemberInfo memberInfo, Object record)
{
_Record = record;
_Attribute = attribute;
_MemberInfo = memberInfo;
}
[Obsolete] public ModbusRegister() => throw new Exception("Forbidden");
public UInt16 SetStatusRecordMemberFromRawModbusValue(UInt16 rawRegisterValue)
{
var raw = IsUnsigned
? (Decimal)rawRegisterValue
: (Int16)rawRegisterValue; // if it is signed we must first reinterpret cast the native UInt16 to Int16
var transformed = (raw + Offset) * Scale;
if (_MemberInfo is FieldInfo fi)
{
var converted = transformed.ConvertTo(fi.FieldType);
fi.SetValue(_Record, converted);
}
else if (_MemberInfo is PropertyInfo pi)
{
var converted = transformed.ConvertTo(pi.PropertyType);
pi.SetValue(_Record, converted);
}
return Address;
}
public UInt16 GetRawModbusValueFromControlRecord()
{
var value = _MemberInfo switch
{
FieldInfo fi => fi.GetValue(_Record),
PropertyInfo pi => pi.GetValue(_Record),
_ => throw new ArgumentException(nameof(_MemberInfo))
};
var transformed = value!
.CastTo<IConvertible>()
.ConvertTo<Decimal>() / Scale - Offset;
return IsUnsigned
? transformed.ConvertTo<UInt16>()
: transformed.ConvertTo<UInt16>().CastTo<UInt16>();
}
}