using Bodk.Device.Storage.Attributes; using Bodk.Device.Storage.EventArgs; using Bodk.Device.Storage.Modules; using Bodk.Device.Storage.Summary; using Bodk.Extensions.Modbus; namespace Bodk.Device.Storage; public class M9Storage : IStorage { public IReadOnlyList Modules => _modules; private readonly List _modules = new(); private readonly ModbusWrapper _modbusWrapper; private readonly CancellationTokenSource _cancellationTokenSource = new(); private readonly CancellationToken _cancellationToken; public M9Storage(Action alarmEventHandler, Action motionTimeoutAlarmEventHandler) { _cancellationToken = _cancellationTokenSource.Token; _modbusWrapper = new ModbusWrapper("192.168.80.253", 502); _modules.Add(new Turntable(alarmEventHandler, motionTimeoutAlarmEventHandler, _modbusWrapper.WriteCoilsAsync, _modbusWrapper.ReadCoilsAsync, _modbusWrapper.ReadHoldingRegistersAsync, _modbusWrapper.WriteHoldingRegistersAsync)); _modules.Add(new CryogenicRackGripper1(alarmEventHandler, motionTimeoutAlarmEventHandler, _modbusWrapper.WriteCoilsAsync, _modbusWrapper.ReadCoilsAsync, _modbusWrapper.ReadHoldingRegistersAsync, _modbusWrapper.WriteHoldingRegistersAsync)); _modules.Add(new CryogenicRackGripper2(alarmEventHandler, motionTimeoutAlarmEventHandler, _modbusWrapper.WriteCoilsAsync, _modbusWrapper.ReadCoilsAsync, _modbusWrapper.ReadHoldingRegistersAsync, _modbusWrapper.WriteHoldingRegistersAsync)); _modules.Add(new GantryY(alarmEventHandler, motionTimeoutAlarmEventHandler, _modbusWrapper.WriteCoilsAsync, _modbusWrapper.ReadCoilsAsync, _modbusWrapper.ReadHoldingRegistersAsync, _modbusWrapper.WriteHoldingRegistersAsync)); _modules.Add(new Valves(alarmEventHandler, motionTimeoutAlarmEventHandler, _modbusWrapper.WriteCoilsAsync, _modbusWrapper.ReadCoilsAsync, _modbusWrapper.ReadHoldingRegistersAsync, _modbusWrapper.WriteHoldingRegistersAsync)); } public async Task Start() { await _modbusWrapper.ConnectAsync(); Process(); } public void Stop() { _cancellationTokenSource.Cancel(); } private ushort? _accessPositionCircle; public ushort AccessPositionCircle { get { if (_accessPositionCircle is not null) return _accessPositionCircle.Value; var data = _modbusWrapper.ReadHoldingRegistersAsync(AccessPositionAddress, 1).Result; _accessPositionCircle = data[0]; return _accessPositionCircle.Value; } set { _accessPositionCircle = value; _modbusWrapper.WriteHoldingRegistersAsync(AccessPositionAddress, new[] { value }).Wait(); } } private ushort? _accessPositionColumn; private ushort? _accessPositionFloor; public ushort AccessPositionColumn { get { if (_accessPositionColumn is not null) return _accessPositionColumn.Value; var data = _modbusWrapper.ReadHoldingRegistersAsync(AccessPositionAddress + 1, 1).Result; _accessPositionColumn = data[0]; return _accessPositionColumn.Value; } set { _accessPositionColumn = value; _modbusWrapper.WriteHoldingRegistersAsync(AccessPositionAddress + 1, new[] { value }).Wait(); } } public ushort AccessPositionFloor { get { if (_accessPositionFloor is not null) return _accessPositionFloor.Value; var data = _modbusWrapper.ReadHoldingRegistersAsync(AccessPositionAddress + 2, 1).Result; _accessPositionFloor = data[0]; return _accessPositionFloor.Value; } set { _accessPositionFloor = value; _modbusWrapper.WriteHoldingRegistersAsync(AccessPositionAddress + 2, new[] { value }).Wait(); } } public float InCavityTemperature { get; private set; } public float InCavityHumidity { get; private set; } public float LiquidLevel { get; private set; } public float FillPortTemperature { get; private set; } public float ExhaustPortTemperature { get; private set; } public float TankTemperature { get; private set; } [Ignore] public StorageSummary GetSummary() { StorageSummary summary = new(); summary.Summary = typeof(IStorage).GetTypeInfo(); summary.Modules = _modules.Select(m => m.GetDescription()).ToList(); return summary; } public TypeDescription GetModuleSummary(int moduleId) { var module = Modules.FirstOrDefault(m => m.Id == moduleId); if (module is null) throw new Exception("module not found"); return module.GetType().GetTypeInfo(); } [Ignore] public async Task InvokeMethod(int moduleId, string methodName, object?[]? parameters) { if (moduleId == 0) { var method = typeof(IStorage) .GetMethod(methodName); if (method is null) throw new Exception("method not found"); await Task.Run(() => (Task)method.Invoke(this, parameters)); } else { var module = _modules.FirstOrDefault(m => m.Id == moduleId); if (module is null) throw new Exception("module not found"); var method = module.GetType().GetMethod(methodName); if (method is null) throw new Exception("method not found"); await Task.Run(() => (Task)method.Invoke(module, parameters)); } } [Ignore] public object GetPropertyValue(int moduleId, string propertyName) { if (moduleId == 0) { var property = this.GetType().GetProperty(propertyName); if (property is null) throw new Exception("property not found"); return property.GetValue(this); } else { var module = _modules.First(m => m.Id == moduleId); var property = module.GetType().GetProperty(propertyName); if (property is null) throw new Exception("property not found"); return property.GetValue(module); } } [Ignore] public void SetPropertyValue(int moduleId, string propertyName, object value) { if (moduleId == 0) { var property = this.GetType().GetProperty(propertyName); if (property is null) throw new Exception("property not found"); property.SetValue(this, value); } else { var module = _modules.First(m => m.Id == moduleId); var property = module.GetType().GetProperty(propertyName); if (property is null) throw new Exception("property not found"); property.SetValue(module, value); } } public async Task Ready() { await _modbusWrapper.WriteCoilsAsync(ReadyAddress, new[] { true }); while (!(await _modbusWrapper.ReadCoilsAsync(ReadyFlagAddress, 1))[0]) { var modules = _modules.Where(d => d.Alarm || d.MotionTimeoutAlarm).ToList(); if (modules.Count > 0) { throw new Exception($"module has error"); } await Task.Delay(100); } } public Task GotoOrigin() { throw new NotImplementedException(); } private const ushort AccessPositionAddress = 150; private const ushort InCavityTemperatureAddress = 162; private const ushort MotionTimeoutAlarmAddress = 280; private const ushort AlarmAddress = 300; private const ushort EnabledAddress = 330; private const ushort ReadyAddress = 13; private const ushort ReadyFlagAddress = 14; private const ushort GotoOriginAddress = 90; private const ushort OriginFlagAddress = 11; private void Process() { Task.Run(async () => { while (!_cancellationToken.IsCancellationRequested) { try { var data = await _modbusWrapper.ReadHoldingRegistersAsync(InCavityTemperatureAddress, 16); var values = data.ConvertToFloat(); InCavityTemperature = values[0]; InCavityHumidity = values[1]; LiquidLevel = values[2]; FillPortTemperature = values[4]; ExhaustPortTemperature = values[5]; TankTemperature = values[6]; await Task.Delay(100, _cancellationToken); var timeoutFlags = await _modbusWrapper.ReadCoilsAsync(MotionTimeoutAlarmAddress, 20); for (int i = 0; i < timeoutFlags.Length; i++) { var i1 = i; var module = _modules .First(m => m.MotionTimeoutAlarmAddress == MotionTimeoutAlarmAddress + i1); if (timeoutFlags[i] != module.MotionTimeoutAlarm) { module.OnMotionTimeoutAlarmChanged( new MotionTimeoutAlarmChangedEventArg(module, timeoutFlags[i])); } } await Task.Delay(100, _cancellationToken); var alarmFlags = await _modbusWrapper.ReadCoilsAsync(AlarmAddress, 21); for (int i = 0; i < alarmFlags.Length; i++) { var i1 = i; var module = _modules .First(m => m.AlarmAddress == AlarmAddress + i1); if (alarmFlags[i] != module.Alarm) { module.OnAlarmChanged( new AlarmChangedEventArg(module, alarmFlags[i])); } } await Task.Delay(100, _cancellationToken); var enabledFlags = await _modbusWrapper.ReadCoilsAsync(EnabledAddress, 20); for (int i = 0; i < enabledFlags.Length; i++) { var i1 = i; var module = _modules .First(m => m.IsEnabledAddress == EnabledAddress + i1); module.IsEnabled = enabledFlags[i]; } } catch (Exception e) { Console.WriteLine(e.Message); } await Task.Delay(1000, _cancellationToken); } }, _cancellationToken); } }