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.
280 lines
9.7 KiB
280 lines
9.7 KiB
4 months ago
|
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<IModule> Modules => _modules;
|
||
|
|
||
|
private readonly List<ModuleBase> _modules = new();
|
||
|
|
||
|
private readonly ModbusWrapper _modbusWrapper;
|
||
|
|
||
|
private readonly CancellationTokenSource _cancellationTokenSource = new();
|
||
|
|
||
|
private readonly CancellationToken _cancellationToken;
|
||
|
|
||
|
public M9Storage(Action<object?, AlarmChangedEventArg> alarmEventHandler,
|
||
|
Action<object?, MotionTimeoutAlarmChangedEventArg> 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));
|
||
|
}
|
||
|
|
||
|
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 Task Ready()
|
||
|
{
|
||
|
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 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);
|
||
|
}
|
||
|
}
|