You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
295 lines
10 KiB
295 lines
10 KiB
4 months ago
|
using Bodk.Device.Storage.Attributes;
|
||
|
using Bodk.Device.Storage.EventArgs;
|
||
|
using Bodk.Extensions.Modbus;
|
||
|
|
||
|
namespace Bodk.Device.Storage.Modules;
|
||
|
|
||
|
public abstract class ModuleBase : IModule
|
||
|
{
|
||
|
[Ignore]
|
||
|
public abstract string Name { get; }
|
||
|
|
||
|
[Ignore]
|
||
|
public abstract string Descirption { get; }
|
||
|
|
||
|
[Ignore]
|
||
|
public abstract int Id { get; }
|
||
|
|
||
|
public float? CurrentPosition =>
|
||
|
CurrentPositionAddress is null ? null : ReadFloat(CurrentPositionAddress.Value).Result;
|
||
|
|
||
|
public float? ManualSpeed
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (ManualSpeedAddress is null)
|
||
|
throw new Exception($"Current module [{Name}] has not [manual speed] property");
|
||
|
return _manualSpeed ??= ReadFloat(ManualSpeedAddress.Value).Result;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (ManualSpeedAddress is null || value is null)
|
||
|
throw new Exception($"Current module [{Name}] has not [manual speed] property");
|
||
|
_manualSpeed = value;
|
||
|
WriteFloat(ManualSpeedAddress.Value, value.Value).Wait();
|
||
|
_manualSpeed = ReadFloat(ManualSpeedAddress.Value).Result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public float? AutoSpeed
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (AutoSpeedAddress is null)
|
||
|
throw new Exception($"Current module [{Name}] has not [manual speed] property");
|
||
|
return _autoSpeed ??= ReadFloat(AutoSpeedAddress.Value).Result;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (AutoSpeedAddress is null || value is null)
|
||
|
throw new Exception($"Current module [{Name}] has not [auto speed] property");
|
||
|
_autoSpeed = value;
|
||
|
WriteFloat(AutoSpeedAddress.Value, value.Value).Wait();
|
||
|
_autoSpeed = ReadFloat(AutoSpeedAddress.Value).Result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public float? AccDec
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (AccDecAddress is null)
|
||
|
throw new Exception($"Current module [{Name}] has not [acc/dec speed] property");
|
||
|
return _accDec ??= ReadFloat(AccDecAddress.Value).Result;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (AccDecAddress is null || value is null)
|
||
|
throw new Exception($"Current module [{Name}] has not [acc/dec speed] property");
|
||
|
_accDec = value;
|
||
|
WriteFloat(AccDecAddress.Value, value.Value).Wait();
|
||
|
_accDec = ReadFloat(AccDecAddress.Value).Result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public float? GotoOriginHighSpeed
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (GotoOriginHighSpeedAddress is null)
|
||
|
throw new Exception($"Current module [{Name}] has not [goto origin high speed] property");
|
||
|
return _gotoOriginHighSpeed ??= ReadFloat(GotoOriginHighSpeedAddress.Value).Result;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (GotoOriginHighSpeedAddress is null || value is null)
|
||
|
throw new Exception($"Current module [{Name}] has not [goto origin high speed] property");
|
||
|
_gotoOriginHighSpeed = value;
|
||
|
WriteFloat(GotoOriginHighSpeedAddress.Value, value.Value).Wait();
|
||
|
_gotoOriginHighSpeed = ReadFloat(GotoOriginHighSpeedAddress.Value).Result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public float? GotoOriginLowSpeed
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (GotoOriginLowSpeedAddress is null)
|
||
|
throw new Exception($"Current module [{Name}] has not [goto origin low speed] property");
|
||
|
return _gotoOriginLowSpeed ??= ReadFloat(GotoOriginLowSpeedAddress.Value).Result;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (GotoOriginLowSpeedAddress is null || value is null)
|
||
|
throw new Exception($"Current module [{Name}] has not [goto origin low speed] property");
|
||
|
_gotoOriginLowSpeed = value;
|
||
|
WriteFloat(GotoOriginLowSpeedAddress.Value, value.Value).Wait();
|
||
|
_gotoOriginLowSpeed = ReadFloat(GotoOriginLowSpeedAddress.Value).Result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private float? _manualSpeed;
|
||
|
|
||
|
private float? _autoSpeed;
|
||
|
|
||
|
private float? _accDec;
|
||
|
|
||
|
private float? _gotoOriginHighSpeed;
|
||
|
|
||
|
private float? _gotoOriginLowSpeed;
|
||
|
|
||
|
public event EventHandler<MotionTimeoutAlarmChangedEventArg>? MotionTimeoutAlarmEvent;
|
||
|
public event EventHandler<AlarmChangedEventArg>? AlarmEvent;
|
||
|
public bool MotionTimeoutAlarm { get; private set; }
|
||
|
public bool Alarm { get; private set; }
|
||
|
public bool IsEnabled { get; internal set; }
|
||
|
|
||
|
|
||
|
private readonly Func<ushort, bool[], Task> _writeCoilRegisterFunc;
|
||
|
|
||
|
private readonly Func<ushort, ushort, Task<bool[]>> _readCoilRegisterFunc;
|
||
|
|
||
|
private readonly Func<ushort, ushort, Task<ushort[]>> _readHoldingRegistersFunc;
|
||
|
|
||
|
private readonly Func<ushort, ushort[], Task> _writeHoldingRegistersFunc;
|
||
|
|
||
|
|
||
|
public virtual Task EnableAsync(bool enable)
|
||
|
{
|
||
|
return EnableAddress is null
|
||
|
? Task.FromException(new Exception($"current module [{Name}] does not support [enable] function"))
|
||
|
: _writeCoilRegisterFunc.Invoke(EnableAddress.Value, new[] { enable });
|
||
|
}
|
||
|
|
||
|
public Task ResetAsync()
|
||
|
{
|
||
|
return ResetAddress is null
|
||
|
? Task.FromException(new Exception($"current module [{Name}] does not support [reset] function"))
|
||
|
: _writeCoilRegisterFunc.Invoke(ResetAddress.Value, new[] { true });
|
||
|
}
|
||
|
|
||
|
public Task CleanAsync()
|
||
|
{
|
||
|
return CleanAddress is null
|
||
|
? Task.FromException(new Exception($"current module [{Name}] does not support [clean] function"))
|
||
|
: _writeCoilRegisterFunc.Invoke(CleanAddress.Value, new[] { true });
|
||
|
}
|
||
|
|
||
|
public async Task GotoOriginAsync()
|
||
|
{
|
||
|
if (GotoOriginAddress is null)
|
||
|
throw new Exception($"current module [{Name}] does not support [goto origin] function");
|
||
|
while (!(await _readCoilRegisterFunc.Invoke(OriginFlagAddress.Value, 1))[0])
|
||
|
{
|
||
|
await Task.Delay(100);
|
||
|
}
|
||
|
|
||
|
if (!(await _readCoilRegisterFunc.Invoke(OriginFlagAddress.Value, 1))[0])
|
||
|
{
|
||
|
await _writeCoilRegisterFunc(2, new[] { true });
|
||
|
throw new Exception($"current module [{Name}] goto origin failed");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Task ForwardAsync(bool open)
|
||
|
{
|
||
|
return ForwardAddress is null
|
||
|
? Task.FromException(new Exception($"current module [{Name}] does not support [forward] function"))
|
||
|
: _writeCoilRegisterFunc.Invoke(ForwardAddress.Value, new[] { open });
|
||
|
}
|
||
|
|
||
|
public Task BackwardAsync(bool open)
|
||
|
{
|
||
|
return BackwardAddress is null
|
||
|
? Task.FromException(new Exception($"current module [{Name}] does not support [backward] function"))
|
||
|
: _writeCoilRegisterFunc.Invoke(BackwardAddress.Value, new[] { open });
|
||
|
}
|
||
|
|
||
|
public async Task RelativeMoveAsync(float destination)
|
||
|
{
|
||
|
if (MoveDistanceAddress is null)
|
||
|
throw new Exception($"current module [{Name}] does not support [relative move] function");
|
||
|
await WriteFloat(MoveDistanceAddress.Value, destination);
|
||
|
if (RelativeMoveAddress is null)
|
||
|
throw new Exception($"current module [{Name}] does not support [relative move] function");
|
||
|
await _writeCoilRegisterFunc.Invoke(RelativeMoveAddress.Value, new[] { true });
|
||
|
}
|
||
|
|
||
|
public async Task AbsoluteMoveAsync(float destination)
|
||
|
{
|
||
|
if (MoveDistanceAddress is null)
|
||
|
throw new Exception($"current module [{Name}] does not support [absolute move] function");
|
||
|
await WriteFloat(MoveDistanceAddress.Value, destination);
|
||
|
if (AbsoluteMoveAddress is null)
|
||
|
throw new Exception($"current module [{Name}] does not support [absolute move] function");
|
||
|
await _writeCoilRegisterFunc.Invoke(AbsoluteMoveAddress.Value, new[] { true });
|
||
|
}
|
||
|
|
||
|
|
||
|
protected ModuleBase(Action<object?, AlarmChangedEventArg> alarmEventHandler,
|
||
|
Action<object?, MotionTimeoutAlarmChangedEventArg> motionTimeoutAlarmEventHandler,
|
||
|
Func<ushort, bool[], Task> writeCoilRegisterFunc, Func<ushort, ushort, Task<bool[]>> readCoilRegisterFunc,
|
||
|
Func<ushort, ushort, Task<ushort[]>> readHoldingRegistersFunc,
|
||
|
Func<ushort, ushort[], Task> writeHoldingRegistersFunc)
|
||
|
{
|
||
|
_writeCoilRegisterFunc = writeCoilRegisterFunc;
|
||
|
_readCoilRegisterFunc = readCoilRegisterFunc;
|
||
|
_readHoldingRegistersFunc = readHoldingRegistersFunc;
|
||
|
_writeHoldingRegistersFunc = writeHoldingRegistersFunc;
|
||
|
MotionTimeoutAlarmEvent += (sender, e) => motionTimeoutAlarmEventHandler(sender, e);
|
||
|
AlarmEvent += (sender, e) => alarmEventHandler(sender, e);
|
||
|
}
|
||
|
|
||
|
|
||
|
internal Task WriteFloat(ushort address, float value)
|
||
|
{
|
||
|
var shorts = value.ConvertToUShort();
|
||
|
return _writeHoldingRegistersFunc.Invoke(address, shorts);
|
||
|
}
|
||
|
|
||
|
internal async Task<float> ReadFloat(ushort address)
|
||
|
{
|
||
|
var shorts = await _readHoldingRegistersFunc.Invoke(address, 2);
|
||
|
var value = shorts.ConvertToFloat();
|
||
|
return value[0];
|
||
|
}
|
||
|
|
||
|
internal void OnMotionTimeoutAlarmChanged(MotionTimeoutAlarmChangedEventArg e)
|
||
|
{
|
||
|
MotionTimeoutAlarm = e.Status;
|
||
|
MotionTimeoutAlarmEvent?.Invoke(this, e);
|
||
|
}
|
||
|
|
||
|
internal void OnAlarmChanged(AlarmChangedEventArg e)
|
||
|
{
|
||
|
Alarm = e.Status;
|
||
|
AlarmEvent?.Invoke(this, e);
|
||
|
}
|
||
|
|
||
|
internal virtual ushort? MotionTimeoutAlarmAddress => null;
|
||
|
internal virtual ushort? AlarmAddress => null;
|
||
|
|
||
|
internal virtual ushort? IsEnabledAddress => null;
|
||
|
|
||
|
internal virtual ushort? EnableAddress => null;
|
||
|
|
||
|
internal virtual ushort? ResetAddress => null;
|
||
|
|
||
|
internal virtual ushort? CleanAddress => null;
|
||
|
|
||
|
internal virtual ushort? GotoOriginAddress => null;
|
||
|
|
||
|
internal virtual ushort? OriginFlagAddress => null;
|
||
|
|
||
|
internal virtual ushort? ForwardAddress => null;
|
||
|
|
||
|
internal virtual ushort? BackwardAddress => null;
|
||
|
|
||
|
internal virtual ushort? AbsoluteMoveAddress => null;
|
||
|
|
||
|
internal virtual ushort? RelativeMoveAddress => null;
|
||
|
|
||
|
internal virtual ushort? MoveDistanceAddress => null;
|
||
|
|
||
|
internal virtual ushort? CurrentPositionAddress => null;
|
||
|
|
||
|
internal virtual ushort? ManualSpeedAddress => null;
|
||
|
|
||
|
internal virtual ushort? AutoSpeedAddress => null;
|
||
|
|
||
|
internal virtual ushort? AccDecAddress => null;
|
||
|
|
||
|
internal virtual ushort? GotoOriginHighSpeedAddress => null;
|
||
|
|
||
|
internal virtual ushort? GotoOriginLowSpeedAddress => null;
|
||
|
|
||
|
internal ModuleDescription GetDescription()
|
||
|
{
|
||
|
return new ModuleDescription
|
||
|
{
|
||
|
Name = Name,
|
||
|
Id = Id,
|
||
|
Description = Descirption
|
||
|
};
|
||
|
}
|
||
|
}
|