#region << 版 本 注 释 >> /*---------------------------------------------------------------- * 命名空间:WIDESEAWCS_QuartzJob * 创建者:胡童庆 * 创建时间:2024/8/2 16:13:36 * 版本:V1.0.0 * 描述:一般堆垛机实现类,实现堆垛机接口层 * * ---------------------------------------------------------------- * 修改人: * 修改时间: * 版本:V1.0.1 * 修改说明: * *----------------------------------------------------------------*/ #endregion << 版 本 注 释 >> using HslCommunication; using Microsoft.AspNetCore.Http; using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using WIDESEAWCS_Communicator; using WIDESEAWCS_Core.Enums; using WIDESEAWCS_QuartzJob.DeviceBase; using WIDESEAWCS_QuartzJob.DTO; using WIDESEAWCS_QuartzJob.StackerCrane; using WIDESEAWCS_QuartzJob.StackerCrane.Enum; namespace WIDESEAWCS_QuartzJob { /// /// 一般堆垛机实现类,实现堆垛机接口层 /// [Description("堆垛机")] public class CommonStackerCrane : IStackerCrane { #region Private Member /// /// 堆垛机通讯对象 /// private BaseCommunicator _communicator; /// /// 堆垛机协议信息 /// private readonly List _deviceProDTOs; /// /// 堆垛机协议明细信息 /// private readonly List _deviceProtocolDetailDTOs; /// /// 设备编号 /// public readonly string _deviceCode; /// /// 设备名称 /// public readonly string _deviceName; /// /// 上一次任务号 /// private int _lastTaskNum; private bool _isChecked = false; private bool _heartStatr = true; private bool _isConnected = true; #endregion Private Member #region Public Member /// /// 堆垛机通讯对象 /// public BaseCommunicator Communicator => _communicator; /// /// 堆垛机协议信息 /// public List DeviceProDTOs => _deviceProDTOs; /// /// 堆垛机协议明细信息 /// public List DeviceProtocolDetailDTOs => _deviceProtocolDetailDTOs; /// /// 设备状态(空闲/运行中...) /// public DeviceStatus Status => GetStatus(); /// /// 上一次执行的任务号 /// public int LastTaskNum => _lastTaskNum; /// /// 当前正在执行的任务号 /// public int CurrentTaskNum => GetCurrentTaskNum(); /// /// 堆垛机状态 /// public StackerCraneStatus StackerCraneStatusValue => GetStackerCraneStatus(); /// /// 堆垛机状态中文说明 /// public string StackerCraneStatusDes => GetEnumDes(StackerCraneStatusValue); /// /// 手自动状态 /// public StackerCraneAutoStatus StackerCraneAutoStatusValue => GetStackerCraneAutoStatus(); /// /// 手自动状态中文说明 /// public string StackerCraneAutoStatusDes => GetEnumDes(StackerCraneAutoStatusValue); /// /// 作业状态 /// public StackerCraneWorkStatus StackerCraneWorkStatusValue => GetStackerCraneWorkStatus(); /// /// 作业状态中文说明 /// public string StackerCraneWorkStatusDes => GetEnumDes(StackerCraneWorkStatusValue); /// /// 设备编号 /// public string DeviceCode => _deviceCode; /// /// 设备名称 /// public string DeviceName => _deviceName; /// /// 堆垛机是否有故障 /// public bool IsFault => StackerCraneStatusValue == StackerCraneStatus.Fault; /// /// 通讯是否已连接 /// public bool IsConnected => Communicator.IsConnected && _isConnected; /// /// 堆垛机任务完成事件 /// public event EventHandler StackerCraneTaskCompletedEventHandler; /// /// 堆垛机任务命令对象 /// public object StackerCraneTaskCommand { get; set; } /// /// 堆垛机完成事件是否已订阅 /// public bool IsEventSubscribed => StackerCraneTaskCompletedEventHandler != null; /// /// 堆垛机与MOM连接状态 /// public bool StackerOnline { get; set; } = false; public int? LastTaskType { get; set; } = null; #endregion #region Constructor Function /// /// 构造函数 /// /// 堆垛机通讯对象 /// 堆垛机协议信息 /// 堆垛机协议明细信息 /// 设备编号 /// 设备名称 public CommonStackerCrane(BaseCommunicator communicator, List deviceProDTOs, List deviceProtocolDetailDTOs, string deviceCode, string deviceName) { _communicator = communicator; _deviceProDTOs = deviceProDTOs; _deviceProtocolDetailDTOs = deviceProtocolDetailDTOs; _deviceCode = deviceCode; _deviceName = deviceName; CheckConnect(); } #endregion #region Private Method /// /// 根据协议读取堆垛机状态 /// /// /// private DeviceStatus GetStatus() { if (IsFault) { return DeviceStatus.Fault; } else if (!IsConnected) { return DeviceStatus.Offline; } if (StackerCraneStatusValue == StackerCraneStatus.Normal && StackerCraneAutoStatusValue == StackerCraneAutoStatus.Automatic) { if (StackerCraneWorkStatusValue == StackerCraneWorkStatus.Standby) { return DeviceStatus.Idle; } else if (StackerCraneWorkStatusValue == StackerCraneWorkStatus.Putting || StackerCraneWorkStatusValue == StackerCraneWorkStatus.PickUp || StackerCraneWorkStatusValue == StackerCraneWorkStatus.PickUpCompleted || StackerCraneWorkStatusValue == StackerCraneWorkStatus.PutCompleted) { return DeviceStatus.Working; } } return DeviceStatus.Unkonw; } private int GetCurrentTaskNum() { DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(CurrentTaskNum)); return devicePro == null ? throw new Exception() : (int)Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType); } /// /// 获取堆垛机设备状态 /// /// private StackerCraneStatus GetStackerCraneStatus() { return Enum.Parse(GetStatus(nameof(StackerCraneStatus))); } /// /// 获取堆垛机手自动状态 /// /// private StackerCraneAutoStatus GetStackerCraneAutoStatus() { return Enum.Parse(GetStatus(nameof(StackerCraneAutoStatus))); } /// /// 获取堆垛机工作状态 /// /// private StackerCraneWorkStatus GetStackerCraneWorkStatus() { return Enum.Parse(GetStatus(nameof(StackerCraneWorkStatus))); } /// /// 获取枚举说明 /// /// 枚举泛型 /// /// private string GetEnumDes(T value) where T : Enum { FieldInfo? fieldInfo = typeof(T).GetField(value.ToString()); if (fieldInfo != null) { DescriptionAttribute? descriptionAttribute = fieldInfo.GetCustomAttribute(); if (descriptionAttribute != null) { return descriptionAttribute.Description; } return "未定义"; } return "未知"; } /// /// 根据协议参数类型获取状态 /// /// 协议参数类型 /// /// private string GetStatus(string protocolParamType) { if (Communicator.IsConnected) { List devicePros = _deviceProDTOs.Where(x => x.DeviceProParamType == protocolParamType).ToList(); if (devicePros.Count == 0) { throw new Exception("未获取到协议信息"); } for (int i = 0; i < devicePros.Count; i++) { object readStatus = Communicator.ReadAsObj(devicePros[i].DeviceProAddress, devicePros[i].DeviceDataType); //todo 协议明细信息未获取到时抛出异常 DeviceProtocolDetailDTO? deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == devicePros[i].DeviceProParamName) ?? throw new Exception(); deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == devicePros[i].DeviceProParamType && x.ProtocalDetailValue.Equals(readStatus.ToString())); if (deviceProtocolDetail != null) { return deviceProtocolDetail.ProtocolDetailType; } return StackerCraneStatus.Unkonw.ToString(); } } //todo 通讯未连接时抛出异常 return StackerCraneStatus.Unkonw.ToString(); } /// /// 比较两个值是否相等。 /// /// 第一个值。 /// 第二个值。 /// 返回比较结果。 private bool Compare(object value, object paramValue) { return value.Equals(paramValue); } private void CheckConnect() { Task.Run(() => { while (_heartStatr) { try { DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(); if (devicePro == null) _isConnected = false; else Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType); _isConnected = true; } catch (Exception ex) { _isConnected = false; } Thread.Sleep(500); } }); } #endregion #region Public Method /// /// 发送任务命令 /// /// 任务命令 /// public bool SendCommand(T command) where T : IDataTransfer, new() { if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络"); DeviceProDTO? devicePro = _deviceProDTOs.Where(x => x.DeviceProParamType == nameof(DeviceCommand)).OrderBy(x => x.DeviceProOffset).FirstOrDefault(); if (devicePro == null) { return false; } if (Communicator.WriteCustomer(devicePro.DeviceProAddress, command)) { StackerCraneTaskCommand = command; CheckStackerCraneTaskCompleted(); return true; } return false; } /// /// 监测堆垛机任务是否完成(防止任务完成事件监测超时,定义手动触发功能) /// public void CheckStackerCraneTaskCompleted() { if (_isChecked) return; Task.Run(() => { _isChecked = true; try { DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(StackerCraneWorkStatus)); if (devicePro != null) { DeviceProtocolDetailDTO? deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == devicePro.DeviceProParamName && x.ProtocolDetailType == StackerCraneWorkStatus.WorkCompleted.ToString()); if (deviceProtocolDetail != null) { OperateResult operateResult = new OperateResult(); TypeCode typeCode = SiemensDBDataType.GetTypeCode(devicePro.DeviceDataType); switch (typeCode) { case TypeCode.Boolean: operateResult = Communicator.Wait(devicePro.DeviceProAddress, 1500, 20 * 6000, Convert.ToBoolean(deviceProtocolDetail.ProtocalDetailValue)); break; case TypeCode.Byte: operateResult = Communicator.Wait(devicePro.DeviceProAddress, 1500, 20 * 6000, Convert.ToByte(deviceProtocolDetail.ProtocalDetailValue)); break; case TypeCode.Int16: operateResult = Communicator.Wait(devicePro.DeviceProAddress, 1500, 20 * 6000, Convert.ToInt16(deviceProtocolDetail.ProtocalDetailValue)); break; case TypeCode.Int32: operateResult = Communicator.Wait(devicePro.DeviceProAddress, 1500, 20 * 6000, Convert.ToInt32(deviceProtocolDetail.ProtocalDetailValue)); break; case TypeCode.UInt16: operateResult = Communicator.Wait(devicePro.DeviceProAddress, 1500, 20 * 6000, Convert.ToUInt16(deviceProtocolDetail.ProtocalDetailValue)); break; case TypeCode.UInt32: operateResult = Communicator.Wait(devicePro.DeviceProAddress, 1500, 20 * 6000, Convert.ToUInt32(deviceProtocolDetail.ProtocalDetailValue)); break; default: break; } int taskNum = CurrentTaskNum; if (operateResult.IsSuccess /*&& LastTaskNum != taskNum*/) { StackerCraneTaskCompletedEventArgs args = new(taskNum); StackerCraneTaskCompletedEventHandler?.Invoke(this, args); _lastTaskNum = taskNum; } } } } catch (Exception ex) { } finally { _isChecked = false; } }); } /// /// 根据参数名称读取堆垛机对应的数据。 /// /// 参数名称枚举类型。 /// 读取结果的返回值类型。 /// 参数名称。 /// 返回读取到的数据。 /// public TRsult GetValue(TEnum value) where TEnum : Enum { if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络"); DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == value.ToString()); return devicePro == null ? throw new Exception() : (TRsult)Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType); } /// /// 与设备的心跳 /// public void Heartbeat() { } /// /// 根据参数名称写入堆垛机对应的数据。 /// /// 参数名称枚举类型。 /// 要写入的数据类型。 /// 参数名称。 /// 要写入的数据。 /// 返回写入成功或失败 /// public bool SetValue(TEnum @enum, TValue value) where TEnum : Enum where TValue : notnull { if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络"); DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == @enum.ToString()); return devicePro == null ? throw new Exception() : Communicator.WriteObj(devicePro.DeviceProAddress, devicePro.DeviceDataType, value); } public void Dispose() { _heartStatr = false; _communicator.Dispose(); GC.SuppressFinalize(this); } #endregion } }