98 lines
2.7 KiB
C#
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>();
|
|
}
|
|
|
|
|
|
} |