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? MotionTimeoutAlarmEvent; public event EventHandler? AlarmEvent; public bool MotionTimeoutAlarm { get; private set; } public bool Alarm { get; private set; } public bool IsEnabled { get; internal set; } private readonly Func _writeCoilRegisterFunc; private readonly Func> _readCoilRegisterFunc; private readonly Func> _readHoldingRegistersFunc; private readonly Func _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 alarmEventHandler, Action motionTimeoutAlarmEventHandler, Func writeCoilRegisterFunc, Func> readCoilRegisterFunc, Func> readHoldingRegistersFunc, Func 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 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 }; } }